フルスタックエンジニアへの道

「フルスタックエンジニアになりたい。。。いや、なってやる!」という備忘録

8946 Take#5

今回は「http://www.hackerschool.jp/hack/」の正答率が9番目に高い(2019/08/04現在)「Take#5」を解いていきたいと思います。

http://www.hackerschool.jp/hack/www.hackerschool.jp

環境

Take#5

Take#5にアクセスすると、下図のような「id」と「パスワード」を入力するフォームがあるページが出てくると思います。今回は、このidとパスワードを入手しなければならないようですね。

f:id:ryasshi:20190804173251p:plain

手始めに、「突破する!」を押すとどのような動作をするのかを確認していこうと思います。
[F12]」(もしくは、右クリックをして「検証」)を押して、デベロッパーツールを開き、「突破する!」のボタンの箇所を特定します。
デベロッパーツールが出たら、突破する!のタグがどこにあるかを確認します。上図左上にある赤枠のマウスのカーソルのようなマークをクリックして、「突破する!」をクリックします。すると、「突破する!」の箇所がハイライトされるはずです。

f:id:ryasshi:20190804173429p:plain

onclick属性もなければ、周辺に特に怪しいJavaScriptなどもありません。
別の場所にヒントが無いかと思い、URLを見てみても特に変わりはありません。
コードを眺めても怪しいところが見当たらなかったので、一度フォームに適当に入力してみましょう。(初めにやるべきかな?笑)

f:id:ryasshi:20190804173814p:plain

失敗しましたが、何やら変わった文章が、、、

f:id:ryasshi:20190804174349p:plain

Warning: pg_query() [function.pg-query]: Query failed: ERROR: syntax error at or near "abc"

ERROR: syntax error at or near "abc"」この文言が、構文エラーを示しているようです。
ですが、他の部分が何を表しているかわからなかったので「pg_query()」でググってみました。 ググった結果、「pg_query()*1」は、PHPで「PostgreSQL」のデータベースで「クエリ(SQL)」を実行するための関数だそうです。
ということは、SQLを実行した結果をページに表示しているのでしょうか?
また、参考にした「クエリを実行する - PHP」にこのような記述がありました。

f:id:ryasshi:20190804180929p:plain

大ヒントですね!
データベースのサービスを使っていることを示すエラー文と、この「SQLインジェクション」の警告を見て試さない手はないでしょう!
ってことで、やってみます。
と思ったのですが、念のためSQLがどんなものだったか確認します。

まず、このような「USERS」表(Table)があったとします。

id name password
1 tanaka tanaka123
2 suzuki 51ichiro
3 yamada hogehogeta

上の表から「id」と「password」の両方が一致する行(横)のすべての列(縦、id, name, passwordのこと)を出すSQL文がこちらです。

SELECT * FROM USERS
--idが2かつpasswordが51ichiroの行という条件
WHERE id = '2' AND password = '51ichiro'

SELECT」は、取り出したい列を指定します。今回の「*」は、全ての列という意味です。
FROM」は、どの表に対して実行するのかを表名(Table)で指定します。
WHERE」は、取り出す行の条件を指定します。今回は「id」が「2」かつ「password」が「51ichiro」という条件です。
上記のSQLには、WHEREの上に「--」がありますが、これはPostgreSQLで「コメント」を記述するときに使います。「--」の後ろに書かれた文字(一行)はコメントとして扱われます。

と、ここまででSQL文のイメージはついたと思います。
おそらく、SQLインジェクション脆弱性があれば、今回のログインも似たような形で、id = '2' AND password = '51ichiro'が下記のようになっていると推測されます。

SELECT * FROM USERS
WHERE id = '入力されたid' AND password = '入力されたパスワード'

このようなSQLの場合であれば、SQLインジェクションは「入力されたid」の場所で行えるのではないかと思うので、idに「' or 1=1 --」と入力してみます。
ちなみに、この文字列を入力すると下記のようなSQLになります。

SELECT * FROM USERS
WHERE id = '' or 1=1 --' AND password = '入力されたパスワード'

つまり、「id=空 or 1=1」という条件になり、すべての行が条件をクリアします。
また、AND以降は「--」でコメント化されるので、パスワードの入力はSQLに反映されません

f:id:ryasshi:20190804192713p:plain

おっと、パスワードが入力されていないと怒られました。
おそらく、PHPで入力されているかどうか検証しているのでしょう。
今度は、パスワードに適当な文字を入れてやってみましょう。

f:id:ryasshi:20190804193956p:plain

表が出ました!(※わざと黒塗りにしています)
あとはここに書かれているidとパスワードを入力して

f:id:ryasshi:20190804194454p:plain

突破できました!
あとは解説を読んで終了です。

f:id:ryasshi:20190804194548p:plain


参考:
http://www.hackerschool.jp/hack/
https://www.php.net/manual/ja/function.pg-query.php

*1:

pg_query — クエリを実行する
クエリを実行する - PHP