きなこもち。

(´・ω・`)

GrimmCon CTF writeup

f:id:kinako_mochimochi:20201231202718p:plain
GrimmCon CTF

12/30に行われたGrimmCon CTFに参加できませんでしたが、writeupを見ず解けたもののwriteupを残しておきます。 (というか書いた時点では参加者のwriteupが見当たらなかったです)

Web

Lottery [misc-ish web, easy]

Did you win the lottery? Find out online!

f:id:kinako_mochimochi:20201231202901p:plain
Lottery

Investigation

  • 問題ページにアクセスすると数字を入力して当選かどうか調べるアプリが稼働しています
  • 問題がeasyカテゴリーかつ桁数も多そうなので、一先ずブルートフォースではないと考えます
  • ソースを見ると<!-- proudly developed in GNU nano, the omnipotent IDE -->という一文が書いてあることに気づきます。Web問にnano?と思い調べると、nanoはファイルを編集した後、backupファイルとして<ファイル名>~という名前のファイルを作成することが分かりました
    • というわけでindex.php~にアクセスするとindex.php~のソースが見れます

f:id:kinako_mochimochi:20201231203040p:plain

Exploit

  • flagが出るのはpreg_match("/^94519372$/")にマッチする数値、つまり94519372だと思ったのですが、入力してもflagが出てこなかったです😅
    • よーーーーーーーーーーく見ると、最後の$が全角です!なので94519372$が正解でしたw

f:id:kinako_mochimochi:20201231203048p:plain

  • flag{fb163d62a1670e6fcbb8b03a3daf31ab}
  • easyなのにsolveが少なかったのは多分これが理由。全角に馴染みがある自分でさえ気づかなかったから、まして海外のプレイヤーは...😂

Syringe [ UNION-based SQLi, easy]

Doctors love their databases! Here is a library of words and semantics relating to medical words, like "syringe", or "x-ray", or "injection". Find whatever you need, just by searching for it!

f:id:kinako_mochimochi:20201231203143p:plain
Syringe

Investigation

  • 化学系の単語が格納されたDBから単語を検索できるようです。
  • 問題はシリンジ、注射器の意味→SQL injection
  • ソースを見るとコメントに<!-- if ( isset($_GET["debug"])){ echo($sql_query); } -->という一文があるのでSQLのクエリを可視化できる

Exploit

  • 使っているクエリはSELECT * FROM semantics WHERE name LIKE "%<input>%";

    • %"を入れるとLIKE句を抜けることができる。その後UNION-based SQLiへ移行
    • group_concat関数でtable_nameをダンプするとき、テーブル名が多すぎて途中で見切れてしまうのでLIMIT句で出力を調整する
      • hoge%" union select table_name from information_schema.tables limit 100 -- - f:id:kinako_mochimochi:20201231203208p:plain
  • テーブル名がダンプできた。flagテーブルがあるのでcolumnダンプする。flagカラムがあるようなので↓でフィニッシュ

  • hoge%" union select flag from flag -- -

    • flag{f2a5006b1b07cc08362772807322ef62}

fruitify [GraphQL injection?, medium]

Come grab a tasty freshly made juice, they are delicious

f:id:kinako_mochimochi:20201231203247p:plain
fruitify

Investigation

  • 問題サーバにアクセスするとフルーツジュース?のサイトが表示されます
  • 色々観察すると、WebアプリがReactか何かでフロントエンドが構築され、webpackを使っていることも分かったのでdevtoolからcomponentを見てみます

    • するとGraphQLを使っていることが分かりました!これはもうGQLiしかないとアタリをつけます f:id:kinako_mochimochi:20201231203253p:plain
  • GQLiはやったことないのでこのサイトを参考にGraphQL Playgroundをインストールし、APIエンドポイントであるhttp://challenge.ctf.games:32355/graphqlを設定して自動でGraphQLの情報を調べます

GraphQL Playgroundというツールをインストールし、APIのエンドポイントであるURLを指定すると、自動的にインスペクションクエリを送信した上で、スキーマを可視化してくれます。

f:id:kinako_mochimochi:20201231203325p:plain

Exploit

  • flagというスキーマ?があるので送ってみます
query UserQuery {
  flag
}

するとflagが帰ってきました。

{
  "data": {
    "flag": "flag{5e4e716b08873b04ed7ee8c2d88a5a2e}"
  }
}

Key To The Castle [ jwk spoofing, medium]

Are you the king of the castle? Did you get locked out?

f:id:kinako_mochimochi:20201231203432p:plain
Key To The Castle

Investigation

  • 問題ページにアクセスするとログイン画面があり、admin以外の任意の名前でログインできます
  • Cookieを見てみるとJWTがセッションとして使われていたので、jwt.ioでデコードしてみます

f:id:kinako_mochimochi:20201231203447p:plain

  • JWTのheaderがデカすぎてスクショに収まり切りませんでしたが、重要なポイントは以下の3つです

    • RS256で署名している
    • headerの部分にjwkが含まれている(本来はjkuなどでjwks.jsonに書かれるべきものです)
    • payloadのguestをadminに書き換えればよさそう
  • よって、この問題のゴールは自前のJWKを用意し、usernameをadminに書き換えた後自分の用意したRSAの公開鍵と秘密鍵で署名することです。

    • 実はこのGrimmCon CTFの主催は半年ほど前に同じJWKS Spoofingの問題を出題しており、今回も似たような手法で解けるとアタリをつけて取り組みました。

Exploit

  • まずmkjwk.orgで自前のJWKを生成します
    • KeySizeは2048、Key UseはSignature、AlgorithmはRS256、そしてKey IDはkidのことなのでJWT中に記載されているkey-1を使います

f:id:kinako_mochimochi:20201231203502p:plain

  • 画面左のオレンジのボタンで自前のJWKをコピーしたら、8gwifi.orgでJWK-to-PEMを使って自前の公開鍵と秘密鍵を生成しましょう

f:id:kinako_mochimochi:20201231203524p:plain

これで生成した公開鍵と秘密鍵をjwt.ioでデコードしたJWTのSignatureの部分に貼り付け、headerのjwk中のnをmkjwk.orgで生成したJWKに含まれているnに置き換えればJWTを自由に改ざんできます

nと f:id:kinako_mochimochi:20201231203540p:plain 公開鍵&秘密鍵 f:id:kinako_mochimochi:20201231203550p:plain

あとはjwt.ioの左側で表示されているJWTをセットしてアクセスすればadminとしてログインできるのでflagが表示されます

f:id:kinako_mochimochi:20201231203606p:plain

Bake The World [ UNION-based SQLi with double percent encoding, medium]

We had a vulnerability in a legacy service. We implemented a proxy to sanitize a parameter.

f:id:kinako_mochimochi:20201231203701p:plain
Bake The World

Investigation

  • 問題ページにアクセスするとflaskで稼働しているブログが表示されます
  • バックエンドはwerkzeug 1.0.1というpythonWSGI utility libraryが使われているらしい

    • 以前見た問題に、このバックエンドのwerkzeugの特定のverでCVEのPoCを使ってファイルを読み出すものがあったので、1.0.1のCVEを探す
      • デバッグモードがオンだと/consoleにアクセスしてOSコマンドインジェクションができるっぽいが、/consoleにはアクセスできず。
      • 問題文のWe implemented a proxy to sanitize a parameter/consoleに向けてのものではなさそう
  • ふりだしに戻る。個々の記事へアクセスするとURLがhttp://challenge.ctf.games:31848/post/1となり、この/post/XXXのXXXをいじるとエラー画面が出る

f:id:kinako_mochimochi:20201231203721p:plain

  • ここでSSTIができるのでは?と思ったがそれすらも不可。問題文のsanitizeはSSTIに対するものでもないらしい

  • ここで半ば諦めていたところ、/post/XXXのXXXを6'にするとシングルクォートがフィルタリングされていることに気づく

f:id:kinako_mochimochi:20201231203735p:plain

  • ダブルクォートなどはフィルタリングされていないので不審に思い、どうにかシングルクォートをしこめないか考えていると、ダブルパーセントエンコーディングを使うことを思いつく
    • %27%2527

f:id:kinako_mochimochi:20201231203746p:plain

  • ビンゴ!どうやら問題文のproxyでサニタイズしているのはシングルクォートだったようです。

  • あとはSQLiteのSQLiを組み立てるだけです。

    • 色々試したところ、UNION-based SQLiでカラム数は9個でした。
    • http://challenge.ctf.games:31848/post/6%2527%20union%20select%201,group_concat(flag),3,4,5,6,7,8,9 from flag%20--%20-

f:id:kinako_mochimochi:20201231203841p:plain

感想

  • 最近のCTFでは連敗続きだったので、久々に「解けた」という感覚を思い出せてよかったです!
  • GrimmCon CTFは主催者の1人がJohn Hammond氏ということで、半年前のNahamCon CTFと同じ良問揃いだろうと思って解きましたが、程よい難易度で流石だと思いました
  • このCTFで今年のCTF仕舞いです!良いお年を!