← News
/PLAYBOOK · 2026-09-08

/tmp Hardening: noexec Mount Against WebShells

Malicious files dropped via web vulns usually land in /tmp or /dev/shm; once executable they yield reverse shells and lateral movement. noexec/nodev/nosuid mounts, systemd tmp.mount tmpfs, /dev/shm hardening, MySQL/PHP dependency checks, false-positive handling, fstab recovery.

Applicable scenarios

Prerequisites

How it works

In many intrusions, attackers write a malicious ELF or script to globally writable dirs (/tmp, /dev/shm) via upload, command injection, or deserialization, then execute for a reverse shell. These dirs default to 1777 (sticky bit); any user can write; most distros mount without exec restriction. noexec blocks direct execution of binaries on that mount; nosuid ignores SUID; nodev forbids device nodes. Combined, write-to-temp drops from high-risk to mostly harmless — files land, they don't run.

Note: noexec only blocks direct binary execution. Indirect execution via the dynamic linker (e.g. `/lib64/ld-linux-x86-64.so.2 ./payload`) can still bypass. Defense in depth, not a substitute for privilege reduction and detection.

Procedure

1. Confirm current mount

`findmnt /tmp
df -hT /tmp /dev/shm`

Record whether /tmp is a separate partition or part of root; that picks the path below.

2. Path 1: /tmp is a separate partition — edit fstab

`cp /etc/fstab /etc/fstab.bak.$(date +%F)
# Find the /tmp line; append to the fourth-column mount options:
# defaults,noexec,nodev,nosuid`

If the line already points at a disk partition (e.g. `LABEL=xxx /tmp xfs defaults 0 0`), only append ,noexec,nodev,nosuid. Do not replace the whole line with tmpfs — that can fill RAM.

3. Path 2: /tmp is on root — enable systemd tmp.mount

Simplest: make /tmp a tmpfs:

`systemctl unmask tmp.mount
systemctl enable --now tmp.mount
# Confirm Options in /usr/lib/systemd/system/tmp.mount include:
# mode=1777,strictatime,noexec,nodev,nosuid`

Also harden /dev/shm. Append to /etc/fstab:

`tmpfs /dev/shm tmpfs defaults,noexec,nodev,nosuid 0 0
mount -o remount /dev/shm`

4. Apply disk-partition options immediately

`mount -o remount,noexec,nodev,nosuid /tmp`

5. Verify execution is blocked

`cp /bin/ls /tmp/ls_test
/tmp/ls_test
# Expected: bash: /tmp/ls_test: Permission denied`

Verification

`findmnt -no OPTIONS /tmp      # expect noexec,nodev,nosuid
findmnt -no OPTIONS /dev/shm`

Reboot once. Confirm fstab or tmp.mount still applies after reboot — that's the baseline acceptance check.

FAQ

FAQ 1: Services break after noexec?

Common hits: MySQL temp tables (set `tmpdir = /var/lib/mysql-tmp` in my.cnf, create and chmod the dir), PHP session and upload temp dirs (confirm `session.save_path` and `upload_tmp_dir` do not point at /tmp), install scripts that unpack to /tmp then execute. Relocate those dirs; do not drop noexec to accommodate a service.

FAQ 2: How much RAM does tmpfs use?

tmp.mount defaults to half of physical RAM, charged by actual use. On small boxes, cap it: `mount -o remount,size=512M /tmp`, and persist size in tmp.mount or fstab.

FAQ 3: Bad fstab, reboot won't boot?

systemd drops to emergency shell on mount failure. Root is read-only; run `mount -o remount,rw /`, comment or fix the bad /etc/fstab line, reboot. That's why OOB console is required before this change.

Summary

Hardening /tmp and /dev/shm cuts the temp-dir execution path at negligible cost: separate partition — append noexec,nodev,nosuid in fstab; root partition — enable systemd tmp.mount. Pick one. /dev/shm must be done in either case. Inventory MySQL tmpdir, PHP session, etc. before go-live; accept with findmnt and an exec test; fold into periodic baseline checks.