RACTF 2020 復習編 その2
C0llide?
const bodyParser = require("body-parser") const express = require("express") const fs = require("fs") const customhash = require("./customhash") const app = express() app.use(bodyParser.json()) const port = 3000 const flag = "flag" const secret_key = "Y0ure_g01nG_t0_h4v3_t0_go_1nto_h4rdc0r3_h4ck1ng_m0d3" app.get('/', (req, res) => { console.log("[-] Source view") res.type("text") return fs.readFile("index.js", (err,data) => res.send(data.toString().replace(flag, "flag"))) }) app.post('/getflag', (req, res) => { console.log("[-] Getflag post") if (!req.body) {return res.send("400")} let one = req.body.one let two = req.body.two console.log(req.body) if (!one || !two) { return res.send("400") } if ((one.length !== two.length) || (one === two)) { return res.send("Strings are either too different or not different enough") } one = customhash.hash(secret_key + one) two = customhash.hash(secret_key + two) if (one == two) { console.log("[*] Flag get!") return res.send(flag) } else { return res.send(`${one} did not match ${two}!`) } }) app.listen(port, () => console.log(`Listening on port ${port}`))
curlの-d 'one=1&two=2'
では値が入ってくれなくて、body-parserを使っている場合json形式のデータを受け取るらしい。
$ curl http://88.198.219.20:11993/getflag -X POST -H "Content-Type: application/json" -d '{"one":1, "two":2}' 75465de2045788dd0c5816b7f325d7f3 did not match 190bba7b59ef3ad7b06b764a912d837f!
ハッシュ生成のロジックがわからないので、jsのif文の回避を考える。
JavaScriptのarrayの比較では、同じ変数を比較した場合のみTrueになる。
逆に言えば、if ['a'] === ['a'] はfalseになる。これは"==="でも"=="でも同じらしい。
$ curl http://88.198.219.20:11993/getflag -X POST -H "Content-Type: application/json" -d '{"one":["a"], "two":["a"]}' ractf{Y0u_R_ab0uT_2_h4Ck_t1Me__4re_u_sur3?}
flag: ractf{Y0u_R_ab0uT_2_h4Ck_t1Me__4re_u_sur3?}
ちなみにhash関数のコードは終了後にdiscordで公開されてた。
const crypto = require("crypto") exports.hash = function(content) { // Super secret combination of hashing algos let hash = crypto.createHash('sha256').update(content).digest('base64') hash = crypto.createHash('md5').update(hash).digest('hex') return hash.toString().split("").reverse().join("") }
Quarantine - Hidden information
手つけてなくて、今やってみたらスルッと解けた。ぐぬぬ。
/robots.txtを見て、そこに書いてあるURL(/admin-stash)に飛べばフラグ。
flag: ractf{1m_n0t_4_r0b0T}
Xtremely Memorable Listing
タイトルと問題文の「サーチエンジンに提供したファイル」というのがヒント。
'sitemap.xml'はGoogle等のサーチエンジンにインデックスされるのに有効なファイル。
/static?f=sitemap.xmlにアクセスすると、.bakがあることがわかるので/static?f=sitemap.xml.bakにアクセスするとダウンロードできる。
そこに記載されている/_journal.txtにアクセスするとフラグ。
flag: ractf{4l13n1nv4s1on?}
Quarantine
"'"を入力するとInternal Server Errorになるので脆弱性がある。
"' OR '1' == '1';--"を入力すると"Attempting to login as more than one user!??"と言われるので、"' OR '1' == '1' limit 1;--"とすればログインできる。
flag: ractf{Y0u_B3tt3r_N0t_h4v3_us3d_sqlm4p}
Getting admin
Quarantineのログイン後にクッキーを見ると、"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogIkhhcnJ5IiwgInByaXZpbGVnZSI6IDF9.A7OHDo-b3PB5XONTRuTYq6jm2Ab8iaT353oc-VPPNMU"のようになっている。
.で分けられた3つのパートがそれぞれbase64された文字列。
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"をデコードすると'{"typ":"JWT","alg":"HS256"}'となり、JWTであることがわかる。
3つのパートはそれぞれヘッダー、ペイロード、署名。
JSON Web Token(JWT)の紹介とYahoo! JAPANにおけるJWTの活用 - Yahoo! JAPAN Tech Blog
"eyJ1c2VyIjogIkhhcnJ5IiwgInByaXZpbGVnZSI6IDF9"をデコードすると'{"user": "Harry", "privilege": 1}'。これをadminにする。
JWTの生成はオンラインサービスで可能。
flag: ractf{j4va5cr1pt_w3b_t0ken}
Finding server information
問題文から、app.pyというファイルを見る必要があることがわかる。
動画を見られるページのURLとソースを見ると、"/watch/+ファイル名"にアクセスした場合、そのファイルがソース内に読み込まれる仕様になっているらしい。
ので、"/watch/app.py"にアクセスすればよい。
flag: ractf{qu3ry5tr1ng_m4n1pul4ti0n}
Insert witty name
ソースを見ると/static?f=index.cssという書き方でファイルを読み込んでいる部分があるので、ファイル名の部分を変えれば任意のファイルを見られそう。
問題タイトルがヒントで、ユーザ名に"'"を入れるとエラーを起こすことができ、アプリのファイル名が得られる。
そのファイル名を見ればフラグが記載されている。URLはhttp://88.198.219.20:12539/static?f=main.py
。
flag: ractf{d3velopersM4keM1stake5}
Entrypoint
ソース内のコメントに怪しい/backup.txtという記載があって、このファイルを上記の方法で見ると、ユーザ名とパスワードが得られる。
問題文から、このパスワードがフラグとのこと。
flag: ractf{developerBackupCode4321}
Baiting
SQLインジェクションがあることはわかっているので、loginToGetFlagでログインするだけ。
loginToGetFlag'--
とかでいいみたい。
flag: ractf{injectingSQLLikeNobody'sBusiness}
Admin Attack
上の構文は通じない。' OR username='jimmyTehAdmin' --
で入れるらしい。
(SQLインジェクション苦手なのでこの辺コピペメモですみません。。。勉強します)
flag: ractf{!!!4dm1n4buse!!!}
Vandalism
管理画面を探せとのこと。
サーバからのレスポンスヘッダにX-OptionalHeader: Location: /__adminPortal
が入っているので、アクセスすると、
アスキーアートと表示されない文字列の入ったページに飛ぶ。
表示されない部分を切り取り、読めるアルファベットを抜き出すと、適当な文字列の中にフラグが入っている。
$ cat adminPortal_.raw | tr -cd 'abcdefghijklmnopqrstuvwxyz1234567890{}_' oremipsumdolor...(snip)...ractf{h1dd3n1npl4n3s1ght}...(snip)
flag: ractf{h1dd3n1npl4n3s1ght}