CTFtime.org / TSG CTF 2020 / Beginner's web
なぜ人々は物事を難しく考えすぎるんでしょうね?
http://35.221.81.216:59101/
初心者向けヒント: とりあえず、上のリンクを開いてみてください。適当にいじってください。で、添付したソースコードを読んでください。⋯⋯flagとかいう怪しい変数があるのが見えますね? やることは簡単、このWebアプリケーションをハックしてflagを吐き出させるだけです。では、やってみましょう。 添付ファイル:CTF-Docs/Beginners-Web.md at master · TeamUnderdawgs/CTF-DocsのCode for Challenge部分
えー、さっぱりわからなかった。
FLAGのフィルタリングの突破方法をずっと探していた。
作問者解説
TSG CTF 2020 作問感想 - 博多電光
なるほど?
解説をさらに見る
なるほど!
Prototype Pollution Attack
const result = await new Promise((resolve, reject) => { converters[request.body.converter](request.body.input, (error, result) => { if (error) { reject(error); } else { resolve(result); } }); });
ここなんですが、bodyのconverterとinputがconverter配列に入れられているし、何やら特殊な感じになっている。
Prototype汚染方針で考えてみると、これに使えそうなものが出てくる。
Object.prototype.defineSetter() - JavaScript | MDN
2回リクエストを投げて情報を抜き取る。
① converter=__defineSetter__&input=FLAG_oMKJNJGhxUdXBweIYrbZcDAbs1H1QBub
これをやると、converter部分は
converters['__defineSetter__']('FLAG_oMKJNJGhxUdXBweIYrbZcDAbs1H1QBub', (error, result) => {
となって、FLAG_oMKJNJGhxUdXBweIYrbZcDAbs1H1QBub
に代入するときに、後ろの関数が呼ばれる形になる。
で、ここで大事なのが、これがPromiseの中で、awaitされているという点。
つまり、converter=__defineSetter__&input=FLAG_oMKJNJGhxUdXBweIYrbZcDAbs1H1QBub
でアクセスすると、rejectかresolveが呼ばれるまでawaitで待ち合わせることになる。
この待ち合わせているときに、② converter=base64&input=xxxxxxxxxx
を呼んだとしよう。
すると、色々あって
converters[`FLAG_${request.session.sessionId}`] = flagConverter;
が呼ばれるので、
これが呼ばれた段階で、先ほどawaitされている関数が呼ばれて、errorにflagConverterが入って、rejectでflagConverterが入るのだが、ここでto_stringされて関数が文字列に変換されてしまう。
それが①のレスポンスとして帰ってくるので、その中身を見るとフラグが書いてある。
これってrace conditionなの?
Discordでちょっとだけそういう話が出てたけど、race conditionではないとしている。
予期せぬ順序やタイミングで予期せぬ結果が出てくるもので、それに当てはまるかというと、攻撃タイミングを作って突いているからrace conditionではないのか。
そういわれればそうか。