Website hacked or redirecting: clean it up
A hacked website usually shows one of three symptoms: visitors are redirected to spam or scam pages, search results show pages you never wrote, or browsers and Google warn that the site is dangerous. Cleaning it means removing every attacker file, replacing modified code with clean copies, and fixing the weakness that let them in, or they will be back within days.
Do this first.
- Take a full copy of the site files, database and web server logs before changing anything. You will need it to find the entry point.
- Put the site in maintenance mode or block public access if it is serving malware to visitors.
- Change the passwords for the hosting panel, SFTP/SSH, the database and every CMS admin account, from a computer you trust.
How to recognise it
- Visitors coming from Google or on mobile are redirected elsewhere, but you are not when you type the address directly. Attackers often target only search or mobile visitors so the owner does not notice.
- Searching
site:example.comshows pages in Japanese, pharmacy or casino spam that do not exist in your admin panel. - Google Search Console shows entries in the Security Issues report (hacked content, malware, social engineering).
- New admin users, unknown plugins, or PHP files in an uploads directory.
- Your host suspends the site, or the server starts sending spam (see IP blacklisted / spam).
To see what a search visitor sees, request your homepage with a Google referrer and a phone user agent and look for a Location: header pointing elsewhere:
curl -sI -e "https://www.google.com/" \
-A "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 Mobile Safari/537.36" \
https://example.com/
Back up the hacked site
Keep a copy of the infected state, outside the web root. The WordPress documentation also recommends this, so you can refer back to it if a clean-up step breaks something.
# Paths: Debian/Ubuntu often use /var/www/..., RHEL-family /var/www/html
sudo tar -czf /root/hacked-site-$(date +%F).tar.gz /var/www/example.com
# Add -u USER -p if the database root login needs a password
sudo mysqldump --single-transaction example_db | gzip | sudo tee /root/hacked-db-$(date +%F).sql.gz >/dev/null
# Web server logs: Debian/Ubuntu
sudo cp -a /var/log/apache2 /var/log/nginx /root/ 2>/dev/null
# RHEL-family
sudo cp -a /var/log/httpd /var/log/nginx /root/ 2>/dev/null
Find what was changed
Recently changed files
CISA’s web shell guidance lists files with timestamps newer than your last application update as a key sign. Attackers can fake the modification time (mtime) with touch, so also check the change time (ctime), which they cannot easily set:
# Files modified or changed in the last 14 days, newest first
sudo find /var/www -type f -mtime -14 -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort -r | head -50
sudo find /var/www -type f -ctime -14 -printf '%CY-%Cm-%Cd %CH:%CM %p\n' | sort -r | head -50
# PHP files where there should be none
sudo find /var/www -path '*/uploads/*' -name '*.php*'
sudo find /var/www -name '.htaccess' -ctime -30 -ls
Web shells and injected code
A web shell is a script an attacker uploads to control the server through the browser. They are usually PHP and often obfuscated. This search is noisy, because legitimate code also uses some of these functions, but it finds most crude shells:
sudo grep -rlE --include='*.php' \
'eval\(\s*(base64_decode|gzinflate|str_rot13|gzuncompress)|assert\(\s*\$_|preg_replace\(.*/e' \
/var/www | head -50
# Injected scripts in theme or core files
sudo grep -rlE --include='*.php' --include='*.js' 'String\.fromCharCode|atob\(|document\.write\(unescape' /var/www | head
Also look in the access log for POST requests to odd files. Web shells are usually visited only by their owner, so a PHP file requested by one or two IP addresses is suspicious:
# Debian/Ubuntu Apache: /var/log/apache2/access.log RHEL: /var/log/httpd/access_log
sudo grep '"POST ' /var/log/apache2/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -30
WordPress: compare with clean copies
WP-CLI can check every core file against official checksums, and plugins from the WordPress.org directory against theirs. Run it as the user that owns the site files, not as root (shown as www-data below):
cd /var/www/example.com
sudo -u www-data wp core verify-checksums --include-root
sudo -u www-data wp plugin verify-checksums --all
sudo -u www-data wp user list --role=administrator
sudo -u www-data wp db search '<script' --all-tables --format=table --fields=table,column,match
On RHEL-family systems the web server user is usually apache or nginx; if your files belong to a separate deploy user, use that account. --include-root also warns about extra files in the root directory. Commercial plugins and themes cannot be verified this way; compare them with a fresh download from the vendor.
Clean up
- Restore from a clean backup if you have one taken before the first signs of the hack, then update everything immediately. Check the backup is clean with the same searches.
- Replace core files. The WordPress FAQ says
wp-adminandwp-includescan be replaced safely, using the same version you run. Installers only overwrite existing files, so delete the old directories first so added backdoor files go too:sudo -u www-data wp core version # note the version, e.g. 6.x.y sudo mkdir -p /root/quarantine sudo mv wp-admin wp-includes /root/quarantine/ sudo -u www-data wp core download --version=6.x.y --skip-content --force - Reinstall plugins and themes from fresh downloads; delete the ones you do not use.
- Delete web shells and PHP files in upload directories, after copying them to your quarantine folder.
- Clean the database: remove injected scripts, unknown admin users and spam posts.
- Check
.htaccess,index.php,wp-config.phpand the theme’sheader.php,footer.phpandfunctions.php, which the WordPress FAQ names as common targets. - Check the server too: crontabs of the web user (
sudo crontab -l -u www-data), web server configuration, and the other backdoor locations. - Update everything to the latest versions (
wp core update,wp plugin update --all,wp theme update --all) and update PHP and the operating system. - Rotate secrets: new WordPress salts (
wp config shuffle-salts) log out every session; change the database password inwp-config.php; change all passwords again now that the site is clean.
Clear Google warnings
Add and verify the site in Google Search Console and open the Security Issues report. Google says to fix the problem across the whole site (a partial fix does not lift the warning), then choose Request Review and explain what you found, what you fixed, and the result. Reviews take several days or weeks; do not resubmit while one is pending. Also check Bing Webmaster Tools and any email blocklists.
Confirm it is fixed
wp core verify-checksumsandwp plugin verify-checksums --allreport success.- The
curltest above returns your own page, not a redirect. - No new files appear in
find /var/www -ctime -1over the next days. - A server scan is clean: see Malware scan.
Prevent it
- Update the CMS, plugins and themes promptly; enable automatic updates where safe. See Updating PHP.
- Add
define( 'DISALLOW_FILE_EDIT', true );towp-config.phpto disable the built-in code editor. - Files 644, directories 755,
wp-config.php400 or 440, and code not writable by the web server, as the WordPress hardening guide suggests. - Block PHP execution in upload directories and validate uploads as the OWASP File Upload Cheat Sheet describes.
- Use long unique passwords and two-factor login for all admins; use SFTP, not FTP.
- Keep dated off-server backups of files and database.
When to call a professional
Ask your host or a website security firm for help if the site processes payments or personal data, if the infection returns after cleaning, or if you find signs that the attacker reached the operating system (root-owned files, new system users, unknown services). In that case the server itself needs rebuilding, not just the site.
Sources
- FAQ My site was hacked, WordPress.org
- Hardening WordPress, WordPress Developer Resources
- wp core verify-checksums, WP-CLI
- wp plugin verify-checksums, WP-CLI
- wp core download, WP-CLI
- wp db search, WP-CLI
- wp config shuffle-salts, WP-CLI
- Security Issues report, Google Search Console Help
- Compromised Web Servers and Web Shells: Threat Awareness and Guidance, CISA
- File Upload Cheat Sheet, OWASP