IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Student Festival Puzzle Solved in 33 Lines

    Yuxin Wu (ppwwyyxxc@gmail.com)发表于 2014-12-27 17:28:52
    love 0

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

    Part 1

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

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

    1 unzip -oP $(cat realpass.txt) 1001/box
    2 sed 's/^  \([^ ][^ ]\) .* \(..\)$/\1\2/; s/ //g;' UrbanMuller.txt | paste -sd '' > rawbf.txt
    3 perl -pe 's/(.)/chr (ord($1) - 1)/gie' rawbf.txt > final.bf
    4 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



沪ICP备19023445号-2号
友情链接