feature image

2022年5月1日 | ブログ記事

CPCTF22 作問者writeup by mazrean

こんにちは。19Bの@mazreanです。普段はSysAd班でanke-toやtraP Collectionというアプリケーションの開発・運用などを行なっています。

この記事は本日行われたCPCTF22で自分が作問したGenerate ORiginal Memoの作問者writeupです。

500点問題で、5ACでした。

問題のリポジトリはhttps://github.com/CPCTF2022/Web_Generate_ORiginal_Memoです。

問題

あなただけのメモを作ろう!
generate-original-memo.cpctf.space
source.zip

解説

で解説されている、GORMの仕様を利用した少し特殊なSQL Injectionの問題です。

devtoolを見ると、各リクエストで実行されたSQLが見れるようになっているので、これをみながら進めていきます。

このアプリケーションで利用されているGORMにはRetrieving objects with primary keyという機能があります。

この機能は実行時にWhere条件の文字列が数字か判定し、数字の場合はprimary keyがその文字列という条件になります。

問題のアプリケーションでこれを実際に使用しているのが

https://github.com/CPCTF2022/Web_Generate_ORiginal_Memo/blob/bf309f0535aa798637ed29a8a31ecf671808d97a/server/gorm.go#L128

です。

しかし、memoIDにid=1のような値が入った場合、この値は数字ではないため通常のWhere条件として解釈されてしまいSQL Injectionが成立します。
今回の場合、id=1にあたる条件にすることで最初にINSERTされるadminのmemoを取得することでflagを取得すれば良いです。
これを考えると、https://generate-original-memo.cpctf.space/memos/id=1;--にアクセスするという考えに至るのですが、これを実行するとfailed to get memo(sql: expected 0 arguments, got 1): SELECT * FROM `memos` WHERE id=1;-- AND user_id = 2 ORDER BY `memos`.`id` LIMIT 1というエラーになります。
これはPrepared Statementの引数がないために起きるエラーなので、Prepared StatementのPlaceholder?(urlエンコードして%3F)を使うように修正した、https://generate-original-memo.cpctf.space/memos/id={{自分のuserID}}+1-%3F;--にアクセスすることで、flagを得られます。
競技時間中、飛んできたリクエストを眺めていたのですが、SQL Injectionが可能な箇所まで気がついたものの、Prepared Statementへの対応に苦しんでいた方が多かったようです。

最後に

参加してくださって本当にありがとうございました。他のCPCTF関連の記事も出ると思うので、ぜひ読んでみてください。


宣伝

今回の問題を見て「GORM以外のGolangのORM系ライブラリないの?」となった方、ぜひGenORMを試してみてください!

Genericsを使いミスを防ぐSQL Builder「GenORM」
mazrean icon
この記事を書いた人
mazrean

SysAd班で活動したり、百合漫画の布教をしたりしている人。

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2023年3月13日
GoでWebSocketのテスト書く
Ras icon Ras
2022年4月5日
アーキテクチャとディレクトリ構造
mazrean icon mazrean
2021年5月16日
CPCTFを支えたインフラ
mazrean icon mazrean
2019年4月22日
アセンブリを読んでみよう【新歓ブログリレー2019 45日目】
eiya icon eiya
記事一覧 タグ一覧 Google アナリティクスについて