Writeup: CyberEDU Web
CyberEDU は セキュリティ教育を目的にした常設CTF で簡単なものから難しいものまで段階的に問題が配置されています。picoCTF と同様、無料で遊ぶことができ、ゲーム感覚で問題を解いているうちに知識が身に付きます。
CTF初心者でも取り組み易いのでお薦めです。
下記のサイトから登録してすぐに始めることができます。
今回はCyberEDUのWeb問題を幾つか解いてみたので、Writeup を書いておこうと思います。
このサイトはあまり有名ではないのか、日本語のWriteup は皆無です。とりあえず、このサイトの遊びかたから書いておくことにします。
この記事を見て興味を持ってくれる人が1人でも増えると嬉しいです。
0.CyberEDU の遊びかた
ユーザー登録に必要なものはメールアドレスだけです。上記のリンクから
登録を済ませてログインし、画面左側のメニューの上から2番目をクリックすると問題が表示されます。
適当な問題を選んで開いた後、[ Unlock Challenge ]をクリックします。
画面左側の [ Start Task ] を押してしばらく待ちます。
1~2分待つと、画面に黄色い文字でアドレスが表示されます。
このアドレスをコピーして、ブラウザのアドレスバーに貼り付けて [ Enter ] キーを押せば、問題のサイトにアクセスできます。
あとはこのサイトを分析したり、攻撃したりしてフラグを探します。
さぁ、サイトに隠されたフラグを探しましょう。フラグは CTF{・・・} の形の文字列になっています。
1.robots
サイトにアクセスしてみると、1行メッセージが書いてあるだけでした。
この問題のタイトルからして、robots.txtにヒントが書いてありそうなので、/robots.txt をブラウザで開いてみます。
robots.txt に書いてある /g00d_old_mus1c.php をブラウザで開くとフラグが表示されました。
2.include-this
サイトにアクセスすると、何やら怪しげなリンクがあります。
"Your test" をクリックしてみます。
何の変哲もない普通の表示のように見えますが、URLに注目してみます。
/?file=test.txt となっています。画面には test.txt ファイルの中身が表示されているのかもしれません。
確かめてみましょう。/?file=/etc/passwd をブラウザで開いてみます。
何やらエラーのようなものが表示されていますが、赤枠部分に着目します。
どうやら file に指定した内容は 「test/ が付加されたパス名」で include() に渡されているようです。
今度は、 /?file=../../../../../../etc/passwd にしてみます。
エラー表示をみると、 "../" という文字列を削除してから include()に渡されることが判りました。
ということは、"….//" という文字列なら削除後は "../" になるはずです。
今度は /?file=….//….//….//….//etc/passd をブラウザで開いてみます。
うまくいきました。あとはフラグの場所を探すだけです。
幾つか試して "/?file=….//….//….//….//flag.txt" でフラグが表示されました。
3.injector
サイトにアクセスすると以下のような画面でした。
host= に指定したアドレスに ping を送信してくれるようです。
もしかすると "hostに指定した文字列" をそのまま system() などの関数に渡しているのかもしれません。だとしたら、シェルの区切り文字";" に続けて、他のコマンドを入力すれば、そのまま実行されることになります。
試してみましょう。 "/index.php?host=127.0.0.1;ls" をブラウザで開きます。
うまくいきました。ファイルの一覧が表示されています。
今度は "/index.php?host=127.0.0.1;cat flag.php" としてみたいところですが、phpファイルはそのまま cat しても、Webサーバ側でファイルの内容が実行されるだけで、ファイルの中身が表示されるわけではありません。
base64 にエンコードしてから画面に表示させることにします。
"/index.php?host=127.0.0.1;cat flag.php | base64" をブラウザで開きます。
想定通り、flag.php を base64エンコードした文字列が表示されました。
あとはこれを デコードすれば、元のflag.php の内容が判ります。
これでフラグが入手できました。
4.web-intro
サイトにアクセスすると、いきなり「Access Denied」の表示。
試しに curl でアクセスしてみます。
サーバのレスポンスヘッダの情報に何かヒントがあるかもしれません。
"Server: Werkzeug/2.0.3 Python/3.6.9" となっているので、このサーバーはApacheなどではなく、Pythonのフレームワークで動いていることが判ります。有名なフレームワークとしては、flask , Django などがあります。
次にセッションクッキーに注目します。
Base64エンコードらしい文字列がピリオドで3か所に区切られています。
ピリオドで3か所に区切られたクッキーというと、ぱっと思いつくものとしては JWT (JSON Web Token) がありますが、JWTは通常、ピリオド区切りの真ん中の文字列(ボディ)が長くなる傾向にあるので、どうも違うようです。
JWTについては下記のサイトでエンコード/デコードができるので、試してみるとすぐに判ります。
調べているうちにこの形のクッキーで「真ん中の文字列が短いもの」は flask の cookie だということが判りました。
最初のピリオドまでをbase64デコードすると、{"logged_in":false} になりました。このクッキーを {"logged_in":True} に置き換えて送信することで、フラグが得られるかもしれません。
クッキーの後ろの部分は、何かの鍵で署名されたものなので、署名鍵となる文字列を見つければクッキーを改竄することができます。
flask のクッキーから署名鍵をクラックするツールを探すと、flask-unsign というツールが見つかりました。使い方は下記のサイトが参考になりました。
署名鍵は 'password' であることが判りました。
これでクッキーを改竄することができます。
この署名鍵を使って {"logged_in":True} を表すセッションクッキーを作成します。ここでも flask-unsign を使用します。
作成したクッキーを元のサイトに送信すると、フラグが表示されました。
5.para-code
アクセスすると、PHPのソースコードが表示されていました。
処理内容は ざっと見たところ
・GET のパラメータ "start" が無い場合はソースを表示する、
・"start" に何か指定してある時は 5文字未満のコマンドだったら実行して
結果を表示
・ただし $blackListに定義している文字に一致したら実行しない、
というもののようです。
最初に "require __DIR__ . '/flag.php' " と書いてあるので、flag.php はこのスクリプト(index.php)と同じディレクトリに置いてあるものと思われます。
つまり、"cat *"で同じディレクトリのflag.phpが表示できるのですが、これだとコマンドの長さが5文字になってしまうので実行されません。
cat と同様、指定したファイルを表示できて、且つ 2文字のコマンドを探す必要があります。
調べるうちに、 "m4" というコマンドが該当することが判りました。
"m4" は引数に指定されたファイルにマクロが含まれていれば必要な変換を行い、マクロ以外の部分はそのまま表示します。
つまり "/?start=m4 *" でflag.php が読み出せることになります。
ブラウザで開いてみます。
画面には何も表示されていませんが、ソースを見るとフラグが表示されていることが確認できました。
6.file-crawe
サイトにアクセスすると「立ち入り禁止」みたいな看板の写真が表示されていました。
ソースを見ると面白そうな記述が見つかります。
/local?image_name=file で file がそのまま表示できそうな予感です。
curl で /local?image_name=/etc/passwd に アクセスしてみると、予想通りパスワードファイルが表示されました。ビンゴです。
あとはフラグの場所が判れば良いのですが・・・と思って、もう一度問題文を読み返してみると、「フラグはテンポラリフォルダに有る」と書いてありました。 linux で「テンポラリフォルダ」といえば /tmp です。
curl で /local?image_name=/tmp/flag にアクセスしてみると、フラグが表示されました。
7.recon
サイトにアクセスすると、犬の写真が表示されていました。
笑っている顔?なんとなくドヤ顔に見えなくもありません。
ソースを見ても何の手がかりもなかったので、ディレクトリをスキャンしてみることにします。
Webサイトのディレクトリスキャンには gobuster がお勧めです。
Kali Linux に標準で入っているし、コマンドラインも単純で使いやすいです。
コマンドラインは以下のような感じになります。 -u は スキャン対象のURL、 -w にはスキャンに用いる辞書を指定します。辞書に載っている単語のディレクトリが無いか、アクセスを試みて結果を表示してくれます。
gobuster dir -u http://34.89.210.219:30658/ -w /usr/share/wordlists/dirb/common.txt
結果、index.php があること以外は分かりませんでした。
う~ん、果てしなく空振りに近い結果。。
気を取り直して、別の観点でスキャンが行えないか考えてみます。
php ファイルはよく $_GET["hoge"] などの引数を取ることが多いので、例えば /index.php?hoge=foo みたいな形式の指定で何か動作が変わるかもしれません。
こういった調査をするには、ffuf がお勧めです。
ffuf は URLやリクエストの一部を辞書にある文字に置き換えてひたすら試してみて結果を知らせてくれるツールです。
ffuf で使う辞書は SecLists がお勧めです。
今回のような リクエストパラメータや、ディレクトリ検出、ユーザー名の検出、パスワードアタックに至るまで様々な用途に応じた辞書が収められています。手元にダウンロードしておいて損はありません。
というわけで、ffuf を使ってみます。コマンドラインはこんな感じです。
-u はURL, FUZZ は辞書の文字で置き換える箇所、-w は辞書、-fs 76 はサーバーの応答が 76バイトだったら画面に表示しない、というオプションです。
最初に幾つか試してみて、何も変化が無い場合の応答のサイズを調べてみると76バイトだったので、それを指定しています。
ffuf -u 'http://34.89.210.219:30658/index.php?FUZZ=test' -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt -fs 76
結果は以下の通り。
応答サイズが76バイト以外のものが幾つかあったようですが、応答に含まれている単語の数が1つだけ違うものがあります。
つまり、 /index.php?m=test の場合だけ、他とは違う応答があったということになります。
/index.php?m=test をブラウザで開いてみると、フラグが表示されました。
この記事が気に入ったらサポートをしてみませんか?