我目前正在编写一个shellcode,它利用了使用该puts函数的目标程序.该程序如下所示:
#include <stdio.h>
main() {
char buf[123];
puts(gets(buf));
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是溢出这个缓冲区并execve使用一些参数调用.我有一个用c/inline程序集编写的测试程序,可以execve用一些参数调用,然后我用来gdb从这个程序中获取shellcode.根据我的理解,堆栈布局如下所示:
| -------缓冲液(+填充)--------- | --------- --------- 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
Run Code Online (Sandbox Code Playgroud)
我认为缓冲区和填充占用128个字节,sfp和返回地址各占8个字节,因此总共有144个字节.基于此,我的nop sled,payload和新的返回地址(等于缓冲区的地址)组合(即我的shellcode)也应该是144个字节.例如,如果我的有效载荷是36个字节,因为返回地址占用8个字节,我的nop sled将是100个字节.但是当我这样做的时候它没有用.所以我想也许我理解堆栈布局的方式是错误的.这是错的吗?
请注意,在我的情况下,缓冲区地址是已知的,并且堆栈通过使用设置为可执行,execstack并且使用了ASLR setarch.因此,如果返回地址被缓冲区的地址覆盖,则写入该缓冲区的代码将运行.
我正在研发x86 64位机器.
如果我对堆栈布局的理解是正确的,我将提供有关我的shellcode的更多信息.
1)您没有利用易受攻击的代码,因为它有puts()函数,您利用它是因为它正在使用gets()函数,这很容易受到堆栈溢出的影响。
2) 当你有一个 char 时buf[123],如果你输入 122 个字符,然后输入一个空终止符,堆栈就可以了。但当您输入的内容超过这个数量时,就会发生以下情况:
让我们假设它是 buf[4],当你执行 gets() 时
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
Run Code Online (Sandbox Code Playgroud)
现在您还将覆盖函数返回地址,因此它也将是 AAAA 0x41414141!从那里您需要将返回地址指向您的 shellcode 地址才能执行 shellcode。
因此,当调用函数和溢出时,布局是:
Buffer for temporary storage
local variables
The saved EBP
Function return address
Function's arguments
Stack frame
Run Code Online (Sandbox Code Playgroud)
所以是从下到上。实际上,对于大变量,最好使用metasploit pattern_offset.rb,它会生成大字符串,当您找到EIP值时,您可以使用patter_offset.rb它的输出来检测覆盖EIP以执行shellcode所需的精确填充。
所以实际上要覆盖函数返回地址,大多数情况下你需要[变量大小] + 8。但这取决于局部变量、它们的大小、它们的顺序等。还取决于编译器、体系结构等。大多数情况下它是通过尝试来完成的和pattern_offset.rb等。
| 归档时间: |
|
| 查看次数: |
996 次 |
| 最近记录: |