Student Festival Puzzle Solved in 33 Lines

贵系今年学生节海报谜题:

Part 1

wget "http://www.net9.org/StudentFestival/1001/OnlinePoster.jpg"  # 原链接已失效,可用上面图片代替
exiftool OnlinePoster.jpg | grep Text | tail -n 1 | sed 's/,.*//g;s/ //g;s/^.*://g' > zeroone.txt
echo "ibase=2;obase=10000;$(cat zeroone.txt)" | bc | tr -d '\\\n' | xxd -r -p > bin
file bin
tar xjvf bin
file 1001/*
chmod +x 1001/key
objdump -d 1001/key > key.s     # RTFSC

第一行下载图片..=.=

第二行从jpg图片的exif信息中中提取Text Layer, 也即图片中的01串, 将其写入zeroone.txt文件中.

第三行利用bc将01串转为16进制字符串, 再利用xxd转为二进制写入到文件bin中.

这里bc的效率好低..求更好的能一行写出来的方法.. python是快了很多, 不过要写好几行:

import itertools, sys
s = open('zeroone.txt').readline().strip()
l = itertools.izip_longest(*([iter(s)] * 8))
l = [int(''.join(x), 2for x in l]
[sys.stdout.write(chr(k)) for k in l]

依云同学指出还可以这样写:

python2 -c 'while True: import sys; sys.stdout.write(chr(int(sys.stdin.read(8).strip() or sys.exit(), 2)))' < zeroone.txt > bin

wjf学长表示:

python2 -c 'import binascii; print binascii.unhexlify(hex(int(open("zeroone.txt").readline().strip(), 2))[2:-1].encode())' > bin

第四行查看bin的类型, 发现是bz2, 第五行解压之.

第六行查看解压出的文件的类型, 发现一个是32bit stripped ELF, 一个是zip. zip是带密码的, 于是密码要从ELF中获取了.

第七行加上执行权限, 第八行dump出来汇编, 然后开始艰苦的RTFSC + gdb.

Part 2

perl -pne 's/\xcd\x80/\x90\x90/g' < 1001/key > 1001/key.modified
python2 << EOF > keys.txt
for n in (t for t in xrange(987654) if t % 223 == 0):
    if str(n).zfill(10)[-3] == str(n).zfill(10)[-5]:
        if n / 651 % 100 == n / 651 / 100 % 100 + 1:
            print n
EOF

直接运行这个ELF, 会询问密码, 输错就喵的一下退出了. 一尝试gdb 就会发现进入了死循环, 调试不能, 非常坑爹.

读汇编发现程序里通过26号系统调用ptrace判断了自己是否被gdb, 看到这里就觉得这程序只能是宋教授写的了..

于是第1行用perl把系统调用的指令强行换成了两条nop, 得到新的可执行程序去gdb. 配合着汇编看, 大致可以搞清楚程序的正常流程: 读入一个数字, 如果其满足一定数学条件就输出"I don't know the secret.", 否则喵你一下. 接下来6行用python枚举出了所有满足它的条件的数, 共有5个.

但是这些数无论怎么yy, 都不是那个zip的密码...

然而宋教授表示"显然应该让ELF吐密码啊".. 再仔细看看汇编,发现有一段可疑的函数从来没有被运行到过,其中还调用了putchar. 于是猜想在什么特定条件下会进入这段函数, 后来Blahgeek发现其实是直接强行调它就好了..

 1 gdb ./1001/key <<< "set pagination off
 2 b __libc_start_main
 3 r
 4 set \$eip=0x8048623
 5 b *0x8048634
 6 c
 7 set \$ebx=$(tail -n 1 keys.txt)
 8 b *0x8048649
 9 disp \$ecx
10 $(for i in {1..14}; do echo "c"; done)
11 q" | egrep -o 'ecx = [0-9]+' | sed 's/.*= //g' > asciipass.txt
12 while read line; do
13   ascii "\d$line" | grep -o 'prints as `.' | sed 's/.*`//g'
14 done < asciipass.txt | paste -sd '' > realpass.txt

用gdb进入ELF, 强行设了eip寄存器以调用可疑代码, 将调用参数设为了keys.txt中的最后一个数(其实是教授的生日), 然后会输出一个长度为14的字符串作为密码.

Part 3

unzip -oP $(cat realpass.txt) 1001/box
sed 's/^  \([^ ][^ ]\) .* \(..\)$/\1\2/; s/ //g;' UrbanMuller.txt | paste -sd '' > rawbf.txt
perl -pe 's/(.)/chr (ord($1) - 1)/gie' rawbf.txt > final.bf
chromium $(pybf -i final.bf)

解压后得到UrbanMuller.txt, 文件名是brainfuck语言的作者, 打开发现里面长的也比较像一个brainfuck程序.

仔细观察发现把所有字符的ASCII码减1, 就会得到一个合法bf程序. 再用pybf运行一下, 就输出了最终答案.

答案是个link, 访问它就好了..

广告..

今年的两个精彩视频:

开场DV: http://video.sina.com.cn/v/b/122479361-2128472472.html

计科20 万万没想到: http://v.youku.com/v_show/id_XNjUxNjY0OTIw.html

Comments