为什么 ret2libc 攻击必须遵循“system(),exit(),command?

信息安全 开发 缓冲区溢出 开发开发 glibc 堆栈溢出
2021-09-01 04:12:40

在 ret2libc 攻击中,我知道返回地址可以被系统命令的地址覆盖,系统命令的地址以命令字符串作为参数。在这种情况下,命令字符串的地址不应该直接在 system() 的地址之后吗?但是,我见过的大多数教程都遵循以下格式:system() 的地址。exit() 的地址。命令字符串的地址。

为什么必须包含 exit() 的地址?如果exit() 被排除,攻击仍然有效吗?

2个回答

ret2libc(和面向返回的编程 (ROP))技术依赖于覆盖堆栈来创建调用系统函数的新堆栈帧。这篇维基百科文章非常详细地解释了堆栈帧:https : //en.wikipedia.org/wiki/Call_stack#Stack_and_frame_pointers

堆栈帧指示函数调用和参数的写入顺序:

function address return address parameters

因此,在你比如你要打电话system()cmdstring和返回exit()功能,当system()调用返回。因此,您编写了以下堆栈帧:

system_addr exit_addr cmdstring_addr

如果删除退出地址,则会将堆栈帧更改为以下内容:

system_addr cmdstring_addr existingdataonstack_aka_junk

因此,现在您使用system()垃圾地址参数进行调用,并在函数完成后尝试返回您的命令字符串。这就是它失败的原因。您可以将exit()地址替换为其他数据,例如 调用完成0x41414141后将导致segfault的地址。system()或者你可以用一个位置的地址替换它,pop pop ret然后在下面写更多的堆栈帧。现在这是一个ROP有效载荷。这是堆栈上的外观的基本示例:

system_addr poppopret_addr cmdstring_addr printf_addr exit_addr addr_of_string_to_printf

这将允许您You got hacked在退出之前打印类似的内容。

包括在内的原因exit()是为了优雅地终止程序。如果您exit()在链的末尾没有,程序将继续奇怪地运行,或者很可能以分段错误终止。包含对 的调用不是强制性的exit()理想情况下,您将以这样一种方式构建您的漏洞利用程序,之后程序继续照常运行,因此没有人会因为他们的服务不再运行而产生怀疑。