9

我目前正在编写一个利用使用该puts函数的目标程序的 shellcode。该程序如下所示:

#include <stdio.h>
main() {
    char buf[123];
    puts(gets(buf));
}

我想要做的是溢出这个缓冲区并execve用一些参数调用。我有一个用 c/inline 程序集编写的测试程序,它可以execve使用一些参数调用,然后我用来gdb从这个程序中获取 shellcode。据我了解,堆栈布局如下所示:

|-------buffer(+padding)---------|---------sfp---------|------- ret--------------|

通过查看gcc生成的目标程序的部分汇编代码:

.cfi_startproc                  
pushq   %rbp                    
.cfi_def_cfa_offset 16          
.cfi_offset 6, -16              
movq    %rsp, %rbp              
.cfi_def_cfa_register 6         
addq    $-128, %rsp             
leaq    -128(%rbp), %rax        
movq    %rax, %rdi              
call    gets                    
movq    %rax, %rdi              
call    puts                    
leave                           
.cfi_def_cfa 7, 8               
ret                             
.cfi_endproc       

我认为缓冲区和填充占用128个字节,而 sfp 和返回地址各占用8个字节,所以总共是144个字节。基于此,我的 nop sled 、有效负载和新的返回地址(等于缓冲区的地址)组合(即我的 shellcode)也应该是144字节。例如,如果我的有效载荷是 36 个字节,由于返回地址占用 8 个字节,我的 nop sled 将是 100 个字节。但是当我这样做时,它不起作用。所以我想也许我理解堆栈布局的方式是错误的。这是错的吗?

请注意,在我的情况下,缓冲区地址是已知的,并且通过 using 将堆栈设置为可执行文件,execstack并且通过 using 关闭了 ASLR setarch。因此,如果返回地址被缓冲区地址覆盖,则写入该缓冲区的代码将运行。

我正在使用 x86 64 位机器。

如果我对堆栈布局的理解是正确的,我将提供有关我的 shellcode 的更多信息。

4

2 回答 2

1

当例程开始时,它的返回地址在堆栈上。我将假设 的值,rsp = 0x428以便我们可以查看真实的(但任意选择的)数字:

0x428 return addr

然后我们推rbp

0x428 return addr (8 bytes)
0x420 original rbp (8 bytes)

然后我们分配缓冲区,即 123 字节 + padding =0x80

0x428 return addr (8 bytes)
0x420 original rbp (8 bytes)
0x418 last eight bytes of buffer+padding 
  ...
0x3a0 buffer (128 bytes)

因此,如果您希望在 0x428 处粉碎返回地址,那么您的响应gets()总长度必须为 144 个字节,最后 8 个字节由您的 shellcode 修改以指向其他地方(通常指向缓冲区本身)。

假设堆栈图中的sfp表示“保存的帧指针”(也称为rbp),那么是的,您的理解是正确的。 如果它对你不起作用,那么可能是你的 shellcode 有问题。(这可能是一个单独的问题。)

于 2014-01-31T18:15:31.297 回答
1

1)你没有利用易受攻击的代码,因为它有puts()函数,你正在利用它,因为它正在使用gets()函数,这里容易受到堆栈溢出的影响。

2)当你有一个 charbuf[123]时,如果你输入 122 个字符,然后输入一个空终止符,堆栈就可以了。但是,当您输入更多内容时,会发生以下情况:

让我们想象它是 buf[4],当你得到()

input AAAA
EBP - 4 => will be AAAA

input AAAAAAAA (8 bytes)
EBP -4 => AAAA
EBP also => AAAA

if you enter 12x A
function return address will be 0x41414141

现在您还将覆盖函数返回地址,所以它也将是 AAAA 0x41414141!从那里你需要将返回地址指向你的 shellcode 地址以执行 shellcode。

所以在调用函数和溢出时,布局是:

Buffer for temporary storage
local variables
The saved EBP
Function return address
Function's arguments
Stack frame

所以它是从下到上。实际上对于大变量最好使用 metasploit pattern_offset.rb,它会生成大字符串,当您找到 EIP 值时,您可以使用patter_offset.rb's 的输出来检测覆盖 EIP 所需的精确填充以执行 shellcode。

所以实际上要覆盖函数返回地址,主要是你需要[变量大小] + 8。但这取决于局部变量,它们的大小,它们的顺序等。还取决于编译器,架构等。主要是通过尝试来完成和 pattern_offset.rb 等。

于 2014-01-31T17:51:25.487 回答