CTF for BBA

ゲーム時々CTFやるBBAの日常。

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の生成はオンラインサービスで可能。

CyberChef


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}