Leaking libc address with ROP
Last updated
Last updated
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
找到 溢出 偏移量
找到 POP_RDI
gadget、PUTS_PLT
和 MAIN
gadgets
使用之前的 gadgets 泄露 puts 或其他 libc 函数的内存地址 并 找到 libc 版本 (下载它)
使用库,计算 ROP 并进行利用
本教程将利用本教程中提出的代码/二进制文件:https://tasteofsecurity.com/security/ret2libc-unknown-libc/ 另一个有用的教程:https://made0x78.com/bseries-ret2libc/,https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
文件名:vuln.c
下载漏洞利用程序并将其放置在与易受攻击的二进制文件相同的目录中,并向脚本提供所需的数据:
Leaking libc - template模板在继续进行漏洞利用之前需要一个偏移量。如果提供了任何偏移量,它将执行必要的代码来查找它(默认 OFFSET = ""
):
执行 python template.py
将打开一个 GDB 控制台,程序将崩溃。在该 GDB 控制台 中执行 x/wx $rsp
以获取将要覆盖 RIP 的 字节。最后使用 python 控制台获取 偏移量:
在找到偏移量(在这种情况下为 40)后,使用该值更改模板中的 OFFSET 变量。
OFFSET = "A" * 40
另一种方法是使用: pattern create 1000
-- 执行直到 ret -- pattern seach $rsp
从 GEF。
现在我们需要在二进制文件中找到 ROP gadgets。这些 ROP gadgets 将用于调用 puts
以找到正在使用的 libc,并随后 启动最终的利用。
The PUTS_PLT
是调用 function puts 所需的。
The MAIN_PLT
是在一次交互后再次调用 main function 所需的,以 exploit 溢出 again(无限轮次的利用)。它在每个 ROP 的末尾用于再次调用程序。
The POP_RDI 是需要 pass 一个 parameter 给被调用的函数。
在这一步你不需要执行任何操作,因为所有内容将在执行过程中由 pwntools 找到。
现在是时候找出正在使用的 libc 库的版本了。为此,我们将 leak function puts
在内存中的 address,然后我们将 search 在该地址中 library version 的 puts 版本。
要做到这一点,执行代码中最重要的一行是:
这将发送一些字节,直到覆盖****RIP成为可能:OFFSET
。
然后,它将设置小工具POP_RDI
的地址,以便下一个地址(FUNC_GOT
)将被保存在RDI寄存器中。这是因为我们想要调用 puts,传递它PUTS_GOT
的地址,因为 puts 函数在内存中的地址保存在指向PUTS_GOT
的地址中。
之后,将调用PUTS_PLT
(RDI中包含PUTS_GOT
),因此 puts 将读取PUTS_GOT
中的内容(内存中 puts 函数的地址)并将其打印出来。
最后,再次调用主函数,以便我们可以再次利用溢出。
通过这种方式,我们已经欺骗了 puts 函数,使其打印出内存中puts函数的地址(它在libc库中)。现在我们有了这个地址,我们可以搜索正在使用的 libc 版本。
由于我们正在利用某个本地二进制文件,因此不需要弄清楚正在使用哪个版本的libc(只需在/lib/x86_64-linux-gnu/libc.so.6
中找到库)。
但是,在远程利用的情况下,我将在这里解释如何找到它:
您可以在网页上搜索正在使用的库:https://libc.blukat.me/ 它还允许您下载发现的libc版本
您还可以执行:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
这将需要一些时间,请耐心等待。 为了使其工作,我们需要:
Libc 符号名称:puts
泄露的 libc 地址:0x7ff629878690
我们可以找出最有可能使用的libc。
我们得到了 2 个匹配(如果第一个不工作,你应该尝试第二个)。下载第一个:
将 libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
中的 libc 复制到我们的工作目录。
在这一点上,我们应该知道使用的 libc 库。由于我们正在利用一个本地二进制文件,我将只使用:/lib/x86_64-linux-gnu/libc.so.6
因此,在 template.py
的开头将 libc 变量更改为: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #设置库路径当知道时
给 libc 库 提供 路径 后,其余的利用将会自动计算。
在 get_addr
函数内部,libc 的基地址 将会被计算:
注意,最终的libc基地址必须以00结尾。如果不是这种情况,您可能泄露了不正确的库。
然后,函数system
的地址和字符串_"/bin/sh"_的地址将从libc的基地址计算得出,并给定libc库。
最后,将准备发送 /bin/sh 执行漏洞:
让我们解释这个最终的 ROP。
最后的 ROP (rop1
) 再次调用了主函数,然后我们可以 再次利用 这个 溢出(这就是 OFFSET
再次出现的原因)。然后,我们想要调用 POP_RDI
指向 "/bin/sh" 的 地址 (BINSH
),并调用 system 函数 (SYSTEM
),因为 "/bin/sh" 的地址将作为参数传递。
最后,退出函数的地址 被 调用,这样进程 优雅地退出,不会生成任何警报。
这样,利用将执行一个 _/bin/sh_** shell.**
你也可以使用 ONE_GADGET 来获取一个 shell,而不是使用 system 和 "/bin/sh"。ONE_GADGET 将在 libc 库中找到一些方法,只需一个 ROP 地址 即可获得一个 shell。
然而,通常会有一些限制,最常见且容易避免的限制是 [rsp+0x30] == NULL
。由于你控制 RSP 中的值,你只需发送更多的 NULL 值,以便避免这个限制。
您可以在这里找到利用此漏洞的模板:
Leaking libc - template如果“main”符号不存在。然后您可以找到主代码的位置:
并手动设置地址:
如果二进制文件没有使用Puts,您应该检查它是否使用
sh: 1: %s%s%s%s%s%s%s%s: 未找到
如果在创建所有漏洞利用后发现此错误:sh: 1: %s%s%s%s%s%s%s%s: 未找到
尝试将“/bin/sh”的地址减去64字节:
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)