Trace Ghost File Changes & Kill Server Backdoors with inotifywait
Files changing with no deploy? Learn how Australian site owners SSH in, watch creations live with inotifywait, pin the PID with lsof, and stop unauthorised loops—plus when to book Fixwebnode.
If your Linux server is rewriting PHP, configs, or web roots with no deploy in the log, this guide walks you through live kernel event monitoring, process isolation, and safe termination—so you can stop ghost modifications before they become a full backdoor.
This is written for Australian homeowners, agencies, and small businesses running Ubuntu or similar VPS hosts who can SSH as a privileged user. You will deploy inotifywait, catch create/modify events in real time, map them to a PID with lsof and ps, break unauthorised process loops, and harden paths so the same vector does not return. When the trail goes deeper than a single rogue process, Fixwebnode Linux server support can take over remotely across Australia.
Why ghost file modifications matter on production servers
Unauthorised writes rarely announce themselves. A dropped webshell, a cron that re-infects wp-includes, or a compromised CI key can touch files while your panel still shows “healthy.” Under pressure—checkout failures, sudden CPU spikes, or SEO malware warnings—you need a terminal workflow, not guesswork. Live inotify watches on the root web tree, combined with open-file and process inspection, turn “something changed” into “this PID, this binary, this loop.”
Fixwebnode provides direct remote server support for this exact class of incident in Australia: tracing ghost writes, killing backdoor loops, and locking down what should never be writable by the web user. We are a specialist provider, not a freelance marketplace.
How do I trace and block ghost file modifications on a Linux server in Australia?
SSH in as root or with sudo, install inotify-tools, watch your web and config paths for create/modify/attrib events, then use lsof and ps to map the writing PID and stop the parent loop. Block the vector by fixing ownership, permissions, cron, and any unexpected listeners—call Fixwebnode if reinfection continues after you kill the process.
| Symptom | Quick fix | When to call Fixwebnode |
|---|---|---|
| Files rewrite with no deploy | inotifywait on web root + lsof on the path | Writer returns after kill or hides in kernel/module space |
| CPU loop, same script respawns | ps/pstree, kill parent, purge cron/@reboot | Multiple hosts or unknown persistence mechanisms |
| New PHP/shell in uploads or /tmp | Quarantine file, block PHP execution in upload dirs | Lateral movement, stolen keys, or panel compromise |
Common issues Australian servers hit with ghost writes and backdoors
1. Web root files change with no Git or panel deploy
Timestamps on index.php, theme files, or .htaccess jump overnight. Diffs show obfuscated eval payloads. No human deploy appears in your history.
2. Unauthorised process loops that respawn after kill
A PHP or bash process pegs CPU, dies when you kill it, then returns within seconds. Parent may be cron, a systemd user unit, or a reverse shell watchdog.
3. Dropped shells and “new” binaries under /tmp, uploads, or cache
World-writable directories accumulate .php, .phtml, or oddly named ELF binaries. Site scanners flag malware; visitors get redirects.
4. Config and SSH authorised_keys quietly altered
sshd_config, nginx site files, or ~/.ssh/authorized_keys gain unknown keys or Listen directives. Persistence outlives a simple file restore.
Issue 1 — Trace live ghost modifications with inotifywait
Goal: see create/modify events as they happen on the paths that matter, then attribute them.
Step 1 — SSH and confirm you are on the right host
ssh -t you@your-server.example 'sudo -i'
hostnamectl
pwd
whoamiWork from a root shell only if your access model allows it; otherwise use sudo per command. Confirm hostname matches the affected VPS.
Step 2 — Install inotify-tools (Ubuntu/Debian)
apt-get update
apt-get install -y inotify-tools lsof psmiscinotifywait comes from inotify-tools; lsof and fuser/pstree help map writers.
Step 3 — Baseline what should not change
find /var/www -type f \( -name '*.php' -o -name '.htaccess' -o -name 'wp-config.php' \) -printf '%T+ %p\n' | sort | tail -n 40
ls -la /etc/nginx/sites-enabled/ /etc/apache2/sites-enabled/ 2>/dev/null
crontab -l
ls -la /etc/cron.* /var/spool/cron/crontabs 2>/dev/nullNote recent mtimes and any unexpected cron entries before you start the watch.
Step 4 — Deploy a live kernel event watch on critical trees
inotifywait -m -r -e create,modify,move,delete,attrib \
--timefmt '%Y-%m-%d %H:%M:%S' \
--format '%T %w%f %e' \
/var/www /etc/nginx /etc/apache2 /tmp /var/tmpLeave this running in one terminal (or under tmux/screen). Reproduce traffic or wait; every create/modify prints path and event type. Narrow paths if event volume is high (for example only /var/www/html).
Step 5 — Optional CSV log for later review
inotifywait -m -r -e create,modify,move,delete \
--timefmt '%Y-%m-%dT%H:%M:%S' \
--format '%T,%w%f,%e' \
/var/www > /root/inotify-www.log 2>&1 &
echo $!
tail -f /root/inotify-www.logBackground only when you understand disk growth; rotate or stop the logger after the incident window.
Step 6 — When a path fires, identify the writer with lsof
# Replace path with the file inotify just reported
lsof -- /var/www/html/index.php
lsof +D /var/www/html 2>/dev/null | head -n 50
fuser -v /var/www/html/index.php 2>&1Note COMMAND, PID, USER. If lsof is empty, the write may already have finished—keep the watch running and catch the next event, or sample with short loops:
while true; do
lsof +D /var/www/html 2>/dev/null | grep -E 'REG|W'
sleep 0.5
doneWhen to call Fixwebnode: Events continue but no userland PID holds the file, or watches span many vhosts and you need coordinated containment. Book remote help via Ubuntu Linux server support.
Issue 2 — Isolate the PID and stop unauthorised process loops
Goal: turn a suspicious PID into a full process tree, kill safely, and remove respawn sources.
Step 1 — Inspect the process
ps -fp <PID>
ps -o pid,ppid,user,lstart,cmd -p <PID>
lsof -p <PID>
ls -l /proc/<PID>/exe /proc/<PID>/cwd
tr '\0' ' ' < /proc/<PID>/cmdline; echo
cat /proc/<PID>/status | head -n 20Confirm the binary path (often under /tmp, upload dirs, or a hijacked project folder). Note PPID for the parent.
Step 2 — Map the tree
pstree -asp <PID>
ps -ef --forest | head -n 80Kill the watchdog parent, not only the leaf child, or the loop returns.
Step 3 — Terminate cleanly, then verify
kill -TERM <PID>
sleep 2
ps -p <PID> || echo 'process gone'
# If still present:
kill -KILL <PID>
# If parent must go too:
kill -TERM <PPID>Avoid blind kill -9 -1. Prefer TERM, confirm, then KILL on the specific PID/PPID.
Step 4 — Hunt respawn: cron, systemd, rc
grep -RniE 'curl|wget|php |/tmp/|base64|bash -i' /etc/cron* /var/spool/cron 2>/dev/null
systemctl list-units --type=service --state=running
systemctl list-timers --all
ls -la /etc/systemd/system /lib/systemd/system | head
crontab -u www-data -l 2>/dev/null
crontab -u ubuntu -l 2>/dev/nullRemove malicious cron lines, disable unknown user services, and delete dropped binaries only after you have a copy for forensics:
mkdir -p /root/incident-quarantine
cp -a /path/to/suspicious-binary /root/incident-quarantine/
rm -f /path/to/suspicious-binaryStep 5 — Confirm the loop is dead
sleep 30
ps aux | grep -E 'suspicious-name|/tmp/' | grep -v grep
tail -n 20 /root/inotify-www.logNo new matching processes and no fresh inotify storms on the same paths means the immediate loop is broken.
When to call Fixwebnode: The parent is unclear, systemd units reappear after deletion, or multiple servers share the same payload. Remote incident handling is available through our service areas across Australia.
Issue 3 — Block dropped shells and lock writable paths
Goal: remove web-executable junk and stop the web user from writing code paths.
Step 1 — Find recent and suspicious files
find /var/www -type f -mtime -3 -printf '%T+ %u:%g %p\n' | sort
find /var/www /tmp /var/tmp -type f \( -name '*.php' -o -name '*.phtml' -o -name '*.so' \) -mtime -7
find /var/www -type f -name '*.php' -size -20k -exec grep -lE 'eval\(|base64_decode|gzinflate|shell_exec|assert\(' {} \; 2>/dev/null | headStep 2 — Quarantine, do not only delete blindly
mkdir -p /root/incident-quarantine/www
# Example move after review:
mv /var/www/html/uploads/odd-shell.php /root/incident-quarantine/www/Step 3 — Harden upload and cache directories (nginx example)
Deny script execution in upload trees via server config, then reload:
# Inside the server block or a dedicated location:
# location ^~ /uploads/ {
# location ~* \.php$ { deny all; }
# }
nginx -t && systemctl reload nginxApache equivalent often uses php_admin_flag engine off in a directory block or removing handlers for that path—test on staging first.
Step 4 — Ownership and permissions that match production reality
# Example: code owned by deploy user, not writable by www-data
chown -R deploy:deploy /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# Only specific writable dirs if the app requires them:
chown -R www-data:www-data /var/www/html/wp-content/uploads
chmod -R u+rwX,g+rwX,o-rwx /var/www/html/wp-content/uploadsAdjust user/group names to your stack. The principle: the PHP-FPM pool user must not own application code.
Step 5 — Restart app stacks cleanly after cleanup
systemctl restart php8.2-fpm 2>/dev/null || systemctl restart php-fpm 2>/dev/null
systemctl reload nginx 2>/dev/null || systemctl reload apache2 2>/dev/null
journalctl -u nginx -u php8.2-fpm -n 50 --no-pagerWhen to call Fixwebnode: You cannot tell clean code from infected legacy trees, or you need a structured audit. For Melbourne CBD codebases with long history, see legacy code refactoring and security audits and custom full-stack web apps support.
Issue 4 — Catch persistence in SSH keys and service configs
Step 1 — Audit authorised keys and sshd
ls -la /root/.ssh/ /home/*/.ssh/ 2>/dev/null
grep -R "" /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys 2>/dev/null
sshd -T | egrep 'permitrootlogin|passwordauthentication|pubkeyauthentication|port '
grep -E '^[A-Z]' /etc/ssh/sshd_configRemove unknown keys, keep a known-good backup offline, then:
systemctl reload sshd || systemctl reload sshStep 2 — Diff web server and PHP pool configs against known good
nginx -T 2>/dev/null | head -n 5
ls -la /etc/nginx/sites-enabled/
# If you have a clean copy:
# diff -u /root/known-good/site.conf /etc/nginx/sites-enabled/site.confUnexpected auto_prepend_file, odd rewrite targets, or extra server blocks deserve immediate review.
Step 3 — Network listeners you did not install
ss -tulpn
ss -tpn | grep -vE 'nginx|sshd|mysqld|redis|php-fpm'Unknown listening ports tied to binaries under /tmp are high priority for the same lsof/pstree workflow above.
When DIY is enough vs when to book Fixwebnode
DIY is reasonable when: you have working SSH/sudo, a single VPS, clear inotify events, one identifiable PID tree, and you can restore code from a known-good Git artefact or backup. Follow the numbered steps, keep quarantined samples, rotate passwords and keys, and keep a short watch window open after cleanup.
Book Fixwebnode when: reinfection returns within hours; you lack a clean baseline; multiple hosts or shared hosting panels are involved; SSH keys or billing emails suggest account takeover; or business uptime means you cannot afford a long live watch. Fixwebnode works as a direct remote specialist for Linux server incidents in Australia—diagnosis, containment, and hardening—not a bid board.
Soft scheduling note: remote sessions are often available the same day when you book early, depending on queue and severity.
Closing: contain the write, then lock the door
Ghost modifications stop being mysterious once inotify shows the path and lsof shows the PID. Kill the tree, purge cron and dropped shells, fix ownership so the web user cannot rewrite code, and re-check listeners and authorised keys. That sequence is the practical core of tracing and blocking unauthorised server backdoors under pressure.
If you want a specialist on the session with you—or you need the full host reviewed after a scare—start a conversation with Fixwebnode via Linux server support and bug fixing. For where we operate, see all service areas. Bring SSH access details and a short timeline of when files first went wrong; we will take it from the live watch through hardening.