Home
Explore
Contact
Sign in
Emergency Fixes & Security

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.

Fixwebnode Support
Fixwebnode Support
10 min read 18 views
Trace Ghost File Changes & Kill Server Backdoors with inotifywait

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.

SymptomQuick fixWhen to call Fixwebnode
Files rewrite with no deployinotifywait on web root + lsof on the pathWriter returns after kill or hides in kernel/module space
CPU loop, same script respawnsps/pstree, kill parent, purge cron/@rebootMultiple hosts or unknown persistence mechanisms
New PHP/shell in uploads or /tmpQuarantine file, block PHP execution in upload dirsLateral 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
whoami

Work 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 psmisc

inotifywait 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/null

Note 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/tmp

Leave 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.log

Background 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>&1

Note 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
done

When 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 20

Confirm 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 80

Kill 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/null

Remove 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-binary

Step 5 — Confirm the loop is dead

sleep 30
ps aux | grep -E 'suspicious-name|/tmp/' | grep -v grep
tail -n 20 /root/inotify-www.log

No 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 | head

Step 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 nginx

Apache 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/uploads

Adjust 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-pager

When 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_config

Remove unknown keys, keep a known-good backup offline, then:

systemctl reload sshd || systemctl reload ssh

Step 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.conf

Unexpected 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.

Share this article
Fixwebnode Support
Fixwebnode Support

Hey there!
I am your assistant for Fixwebnode. Ask about our services, quotes, packages, orders, or how to get support.
While you wait
What’s your name and best email? We’ll reply even if you leave.