OtterCTF: Gotta Go Deeper

問題

問題文

Rick and morty played with the configurations of the portal gun and accidentally got stuck in this picture.

Help us get them out.

GottaGoDeeper.png

問題概要

png ファイルが与えられる.

解答例

指針

  • binwalk + 青空白猫

解説

与えられたファイルを binwalk を使って解析した.

binwalk はファイルの中に埋め込まれたファイルを確認, 抽出することできる.

https://github.com/ReFirmLabs/binwalk

同様のことができるツールとして, foremost があるが, 今回 foremost を使った場合, 埋め込まれたファイルのうち一つだけ, 見つけ出すことができなかった.

$ binwalk GottaGoDeeper.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 952 x 536, 8-bit/color RGB, non-interlaced
140           0x8C            Zlib compressed data, best compression
517387        0x7E50B         PNG image, 960 x 640, 8-bit/color RGB, non-interlaced
517540        0x7E5A4         Zlib compressed data, best compression
1355842       0x14B042        TIFF image data, big-endian, offset of first image directory: 8
1355982       0x14B0CE        PNG image, 2186 x 3300, 8-bit/color RGBA, non-interlaced
1356067       0x14B123        Zlib compressed data, best compression
1358910       0x14BC3E        Unix path: /www.w3.org/1999/02/22-rdf-syntax-ns#">
1359017       0x14BCA9        Unix path: /ns.adobe.com/xap/1.0/mm/"
1359075       0x14BCE3        Unix path: /ns.adobe.com/xap/1.0/sType/ResourceEvent#"
1359150       0x14BD2E        Unix path: /ns.adobe.com/xap/1.0/sType/ResourceRef#"
1359220       0x14BD74        Unix path: /purl.org/dc/elements/1.1/"
1379914       0x150E4A        Zlib compressed data, best compression
8965470       0x88CD5E        PNG image, 1172 x 501, 8-bit/color RGB, non-interlaced
8965623       0x88CDF7        Zlib compressed data, best compression
9207969       0x8C80A1        TIFF image data, big-endian, offset of first image directory: 8
9208109       0x8C812D        PNG image, 1920 x 1081, 8-bit/color RGB, non-interlaced
9461212       0x905DDC        TIFF image data, big-endian, offset of first image directory: 8

-D オプションを付与すると, 拡張子をつけて抽出できる.

$ binwalk -D 'png image:png' GottaGoDeeper.png

(snip)

$ ls _GottaGoDeeper.png.extracted/
0.png       14B123       150E4A       7E50B.png  7E5A4.zlib  88CDF7       8C          8C.zlib
14B0CE.png  14B123.zlib  150E4A.zlib  7E5A4      88CD5E.png  88CDF7.zlib  8C812D.png

Window マシンから sftp を使って, 抽出したファイルを Windows マシンに転送した.

caster は私の Linux のマシンの hostname.

$ sftp caster
Connected to caster.
sftp> get -r Downloads/_GottaGoDeeper.png.extracted/
Fetching /home/kira/Downloads/_GottaGoDeeper.png.extracted/ to _GottaGoDeeper.png.extracted
Retrieving /home/kira/Downloads/_GottaGoDeeper.png.extracted
/home/kira/Downloads/_GottaGoDeeper.png.extracted/8C              100% 1495KB   4.9MB/s   00:00

(snip)

sftp>

得られた png ファイルは以下のようなものである.

f:id:kira000:20181214031859p:plain

f:id:kira000:20181214032057p:plain

f:id:kira000:20181214032138p:plain

f:id:kira000:20181214032212p:plain

f:id:kira000:20181214032248p:plain

png ファイルにはそれぞれ文字列が書かれており, これは base64エンコードされた文字列の一部であると推測できる.

14B0CE.png には base64エンコードされた文字列一部が書かれていないので, うさみみハリケーンに同梱されている汎用ファイルアナライザ, 青い空を見上げればいつもそこに白い猫 で解析した.

うさみみハリケーンのインストールについては以下のリンクが参考になる.

「うさみみハリケーン」のダウンロード・インストール・使用方法(messiahcat氏提供)

うさみみハリケーンWindows でしか動作しないため, わざわざ sftp を用いて Windows マシンにファイルを転送した,

14B0CE.png を青空白猫で解析すると以下のような文字列が一瞬で見つかった.

f:id:kira000:20181214033024p:plain

これまで見つかった文字列をまとめると次のようになる.

7E50B.png  => TWICE RnlaWDA9
8C812D.png => ZmxhZ
14B0CE.png => ZXJXZU
88CD5E.png => tEZWVw

7E50B.png に書かれている TWICE という文字列の意味を最初は 2 回用いると解釈したがこれは誤りで, base64 で 2 回 encode されたことを意味していた.

$ echo RnlaWDA9 | base64 -d
FyZX0=

次に, FyZX0=, ZmxhZ, ZXJXZU, tEZWVw を並び替えてつなげた文字列を base64 decode することを考える. FyZX0= は末尾に "=" があることから末尾の文字列であると推測できる.

itertools の permutation を用いて並び替えて base64 デコードを試すがうまくいかなかった.

#!/usr/bin/env python3
# coding: utf-8

from base64 import b64decode
from itertools import permutations

L = ["RnlaWDA9", "ZmxhZ", "ZXJXZU", "tEZWVw"]

for i in list(permutations(L[1:])):
    i = list(i)
    i += [b64decode(L[0]).decode("utf-8")]
    s = "".join(i)

    try:
        ret = b64decode(s)
        print (ret)
    except:
        print ("Error")
  • 実行結果
$ python solve.py
Error
Error
Error
Error
Error
Error

一文字だけ欠けていると推測 (guessing) しその一文字 brute-force すると flag が得られた.

#!/usr/bin/env python3
# coding: utf-8

from base64 import b64decode
from itertools import permutations

T = []
for i in range(26):
    T += [chr(ord('A') + i)]
    T += [chr(ord('a') + i)]
for i in "0123456789+/":
    T += [i]

L = ["RnlaWDA9", "ZmxhZ", "ZXJXZU", "tEZWVw"]

for t in T:
    for i in list(permutations(L[1:] + [t])):
        i = list(i)
        i += [b64decode(L[0]).decode("utf-8")]
        s = "".join(i)

        try:
            ret = b64decode(s)
            if not "\\x" in str(ret) and "flag" in str(ret):
                print (ret.decode("utf-8"))
        except:
            print ("Error")
  • 実行結果
flag+DeeperWeAre}
erWeKDeepflag!re}
flag;DeeperWeAre}
erWeKDeepflag1re}
flagKDeeperWeAre}
erWeKDeepflagAre}
flag[DeeperWeAre}
erWeKDeepflagQre}
flagkDeeperWeAre}
erWeKDeepflagare}
flag{DeeperWeAre}
erWeKDeepflagqre}

flag: flag{DeeperWeAre}