Round 2 candidate 17b6d7f6 on 17ea0dbc. 22 of 23 mutants killed, joined-value
equivalent; probes cover repeated Host, proxy Host, HEAD and absolute-form.
r1/ holds the round 1 findings sent to Dewey in place of a verdict.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
33 lines
3.1 KiB
Bash
33 lines
3.1 KiB
Bash
#!/bin/bash
|
|
# Row 74 review: what the Console does with a request that a proxy forwarded after rewriting Host
|
|
# to its upstream address (nginx's default, proxy_set_header Host $proxy_host). Loopback only, no
|
|
# config (MOSAIC_CONFIG names a missing file), board on a closed port.
|
|
export TMPDIR=~/darkwing-scratch/rv74r2/tmp
|
|
cd ~/darkwing-scratch/rv74r2/wt
|
|
NAME=preview.example.com HEADER=x-example-uid ID=jason LOG=$TMPDIR/host-rewrite-serve.log
|
|
MOSAIC_CONFIG=$TMPDIR/no-config.json node packages/webui/src/cli.mjs serve --port 0 \
|
|
--board http://127.0.0.1:9 --public-host $NAME --auth-header $HEADER --allow-user $ID > $LOG 2>&1 &
|
|
SRV=$!; trap 'kill $SRV' EXIT
|
|
until grep -q '^Mosaic Console' $LOG; do sleep 0.2; done
|
|
PORT=$(sed -n 's|^Mosaic Console: http://127.0.0.1:\([0-9]*\)/$|\1|p' $LOG); U=http://127.0.0.1:$PORT
|
|
c() { local what=$1 out; shift; out=$(curl -s -o /dev/stdout -w '\n%{http_code}' "$@"); printf '%-58s %s %.80s\n' "$what" "${out##*$'\n'}" "$(printf '%s' "${out%$'\n'*}" | tr -d '\n')"; }
|
|
c "Host NAME, HEADER=mallory" -H "Host: $NAME" -H "$HEADER: mallory" $U/api/config
|
|
c "Host NAME, no HEADER" -H "Host: $NAME" $U/api/config
|
|
c "Host 127.0.0.1:PORT (rewritten), HEADER=mallory" -H "Host: 127.0.0.1:$PORT" -H "$HEADER: mallory" $U/api/config
|
|
c "Host 127.0.0.1:PORT (rewritten), no HEADER" -H "Host: 127.0.0.1:$PORT" $U/api/config
|
|
c "Host 127.0.0.1:PORT, X-Forwarded-For, HEADER=mallory" -H "Host: 127.0.0.1:$PORT" -H "X-Forwarded-For: 203.0.113.9" -H "$HEADER: mallory" $U/api/config
|
|
c "Host localhost:PORT, HEADER=mallory" -H "Host: localhost:$PORT" -H "$HEADER: mallory" $U/api/config
|
|
c "POST /api/seen, Host 127.0.0.1:PORT, HEADER=mallory" -H "Host: 127.0.0.1:$PORT" -H "$HEADER: mallory" -H 'Content-Type: application/json' -d '{}' $U/api/seen
|
|
echo "== HEAD (deviation 4)"
|
|
c "HEAD /api/config, Host NAME, no HEADER" -I -H "Host: $NAME" $U/api/config
|
|
c "HEAD /api/config, Host NAME, HEADER=jason" -I -H "Host: $NAME" -H "$HEADER: $ID" $U/api/config
|
|
echo "== repeated Host, raw socket"
|
|
raw() { local what=$1; shift; printf '%-58s %s\n' "$what" "$(node -e '
|
|
const s=require("net").connect(+process.argv[1],"127.0.0.1",()=>s.end(process.argv[2].replace(/\\n/g,"\r\n")));let d="";s.on("data",c=>d+=c);s.on("end",()=>console.log(d.split("\r\n")[0]+" "+d.split("\r\n\r\n")[1]))' $PORT "$1" | cut -c1-80)"; }
|
|
raw "loopback Host then Host NAME, no HEADER" "GET /api/config HTTP/1.1\nHost: 127.0.0.1:$PORT\nHost: $NAME\nConnection: close\n\n"
|
|
raw "Host NAME then Host NAME, HEADER=jason" "GET /api/config HTTP/1.1\nHost: $NAME\nHost: $NAME\n$HEADER: $ID\nConnection: close\n\n"
|
|
raw "no Host (HTTP/1.0)" "GET /api/config HTTP/1.0\n\n"
|
|
raw "absolute-form NAME, loopback Host, no HEADER" "GET http://$NAME/api/config HTTP/1.1\nHost: 127.0.0.1:$PORT\nConnection: close\n\n"
|
|
raw "HEADER present but empty, loopback Host" "GET /api/config HTTP/1.1\nHost: 127.0.0.1:$PORT\n$HEADER:\nConnection: close\n\n"
|
|
raw "Host [::1]:PORT, HEADER=mallory" "GET /api/config HTTP/1.1\nHost: [::1]:$PORT\n$HEADER: mallory\nConnection: close\n\n"
|