こんにちは。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がその文字列という条件になります。
問題のアプリケーションでこれを実際に使用しているのが
です。
しかし、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を試してみてください!