Format String Vulnerability
printf("%s", user_input)
printf(user_input)
- 读取栈上的任意欸容
- 写任意内存
printf 如何解析格式化字符串
- 遇到普通字符:原样打印
- 遇到 %:需要从栈上提取一个参数
%d
%x
%p
%s
%n
AAAA %7$p
位置选择
%1$x
%2$x
%10$p
%14$s
Arbitrary Read
payload = <8字节地址> + “%7$s” (截断)
- 泄露 stack canary
- 泄露 libc 地址 -> 立刻可以ROP
- 泄露 GOT 表内容
- 泄露指针 -> 推算ASLR偏移
Arbitrary Write
- %n 会把已打印字符数量写入指定地址
AAAA %n <addr bytes>
- hhn / hn
典型攻击场景
- GOT entries
- 函数指针
- vtable
- dtors
- libc hooks (_malloc_hook, _free_hook)
- atexit handlers
- 全局变量中的函数指针
标准解题步骤
- 找漏洞点
printf(user_input)
fprint(log, user_input)
syslog(user_input)
sprintf(buffer, user_input)
- 找buffer在第几个参数的位置
AAAABBBB %1$p
AAAABBBB %2$p
AAAABBBB %3$p
...
- Arbitrary Read
%<index>$s
%<index>$p
- canary
- return address
- libc address
- PIE base
- GOT 内容
-
计算目标地址(system, win, GOT)
-
Arbitrary Write
%<width>x%<index>$hhn
- 重定向控制流
overwrite exit@got -> win
overwrite printf@got -> system
Return Oriented Programming
不用写任何shellcode,只使用程序已有的代码片段(gadgets)实现任意i计算。
- NX
- 现代ASLR配合信息泄露
- 无法放shellcode的情况(过滤输入字符)
为什么要ROP
- NX
- PIE / ASLR
- RELRO
ROP 的基本单位: gadget
pop rdi; ret
pop rsi; ret
pop rdx; ret
syscall; ret
ROP chain (*)
system("/bin/sh")
[padding]
[pop rdi; ret]
["/bin/sh" 地址]
[system 地址]
[exit 地址]
Bypass ASLR
- 某个libc函数的运行时地址 (puts / printf / gets)
puts(puts@got)
libc_base = leaked_puts - offset_puts
system = libc_base + offset_system
binsh = libc_base + offset_binsh
system("/bin/sh")
System unavailable -> Syscall ROP
用syscall gadget 手写 Linux系统调用,例如 execve
控制 rax (系统调用号)
控制 rdi (argv[0])
控制 rsi
控制 rdx
控制 rcx ...
exevce("/bin/sh", NULL, NULL)
Stack Pivot
- xchg rsp, rax
- add rsp, 0x80
- 覆盖rbp 让 ret 到其他地方
让栈指向更大的buffer
解题方法
- 找出溢出点,找可以覆盖 return addr 的位置
- 检查保护(checksec)
- NX on -> 必考 ROP
- PIE on -> 必须信息泄露
- RELRO full -> 不能改GOT
- 泄露地址(information leak)
puts(puts@got)
printf(%7$p)
得到libc地址
- 计算libc基址,找到system和“/bin/sh”
- 构造ROP chain
- stack alignment
- 执行ret2libc / ROP 获取 shell
ROP 失败的常见原因
- Stack Alignment
- 没有 control rdi(pop rdi; ret)
pop rdi; pop rsi; ret
pop rdi; pop r15; ret
mov
add
syscall ROP -> system
- libc version
- 参数搞反了
- 距离算错
- slide
- /bin/sh 指针
- bad characters
0x0a (换行)
0x00 (字符串结束符)
0x20 (空格)
payload提前截断