How to detect and fix a hacked PHP website

Regain control and kick evildoers out. Actionable tips for web developers on how to clean a compromised website. This is the human-to-human edition.
# Common patterns
It happens often. Script kiddies chasing quick wins and a few bucks. Automated attacks usually leverage known vulnerabilities in unpatched software. Targeted attacks are much less common.
- Phishing sites for banks and crypto wallets
- Crypto mining
- Fake e-commerce stores
- SEO spam - sneaky links to shady sites
- Malware distribution to your visitors
- Backdoor installation for later use
- DDoS participation
# Target systems
Hackers love PHP‑based websites. Server‑side rendering lets them execute code; with weak isolation they may even escalate privileges. These are the systems we most often see targeted:
- WordPress
- WordPress
- WordPress
- Craft CMS
- Laravel
- Others
# Detect
In our experience, the average time to detection is about three months. Some catch it quickly, others snooze. This is how website owners usually discover they've been hacked:
- Performance problems
- Website errors (500, 504 …)
- Strange Google results
- Unexpected content on the website
- Google blocklist warnings
- Phishing warning on the website
- Weird new users in your admin panel
- Your friendly web hosting service notifies you
- A CVE is discussed online
# Implications
- SEO ranking downgrade
- Cached search engine results with spammy content
- Higher hosting costs
# Investigate
Check the access logs to see which files have been accessed how and by whom (by IP) to get a better picture.
# Fix
The fix depends on how deep the intruders got in. Sometimes it helps to investigate recent breaches. The more you know about the attack, the easier it is to find a cure.
# Is the hosting runtime compromised?
VPS hosting systems are at risk of full compromise. Many hosting providers, such as ourselves, provide a jailed environment where it's unlikely that hackers can escalate access beyond the website owner. If in doubt, rebuild the hosting resources (after creating fresh backups) and redeploy to a clean instance, or reinstall the OS.
fortrabbit users run in tightly jailed environment making it extra hard to escape.
# Restore from backup
Preferred path if you have recent, trustworthy backups. Backups can be local copies of your development environment, a hosted Git repository, or the backups provided by your hosting platform. For classical LAMP‑stack applications, backups usually include the code, runtime files like uploads, possibly build artifacts, and a database dump.
Restoring from backup means redeploying the code and importing the database dump.
# Cleanup
No backups? Clean up manually. Download all online code to your local environment so you can work faster and make safe mistakes. Use grep and friends to hunt for trouble. Your AI can probably help you detect obfuscated PHP. You can also compare your framework or CMS core files with clean upstream versions to spot modifications.
- Run
composer auditin Composer driven projects - Clean files
- Look deeply, backdoors can be hard to detect
- Search for obfuscated code between normal code
- Look in usual locations
- Files with weird timestamps
- Hidden files with names like
.htacces(missing s) - Obfuscated PHP, base64 blobs, eval and assert scattered around
- Clean database
- Check users and roles for unknown accounts
- Scan posts/pages/options tables for injected links or iframes
- Look for serialized payloads hiding scripts
- Export to SQL and grep for suspicious keywords
# Example files
Here are some files from a recent Craft CMS CVE that we found to be affected.
.well-known/* .widgets.php accesson.php autoload_classmap.php cgi-bin/* CoreCheck.php craftt-api.php envcraft.php m.php memberfuns.php mn.php mnb.php wp-blogs.php # Some files might be deeply hidden with existing folder structure like so: assets/_120x78_crop_center-center_none/-vwugcm.php assets/_240x122_crop_center-center_none/-gqpmnb.php assets/_68x56_crop_center-center_none/-yuobgf.php cpresources/4c4d6e37/d3-format/-rfihgs.php cpresources/718fe862/mode/cypher/-nswipf.php cpresources/718fe862/mode/swift/-oxtkip.php cpresources/926d5982/js/captchas/-wtfbav.php cpresources/d87ff9ec/-npcqfu.php migrations/... templates/... vendor/...bash
# Example code
Obfuscated code is meant to be unreadable for humans. It's usually encoded. Luckily, the code of your CMS or PHP framework is not obfuscated, so identifying malicious code is not that hard.
// Harmful code sometimes is hidden between other code. <?php error_reporting(0); header('Content-Type: text/html; charset=utf-8'); $OooO0 = 'fgs1075'; date_default_timezone_set($O{35}.$O{22}.$O{12}); $OOooO="%31%73%65%71%71%69%75%69%6f%70%61%73%64%66%67%68%6a%6b%6c%7a%78%63%76%62%6e%6d%51%57%45%52%54%59%55%49%4f%50%41%53%44%46%47%48%4a%4b%4c%5a%58%43%56%42%4e%4d%5f%2d%22%3f%3e%20%3c%2e%2d%3d%3a%2f%31%32%33%30%36%35%34%38%37%39%27%3b%28%29%26%5e%24%5b%5d%5c%5c%25%7b%7d%21%2a%7c"; $O=urldecode($OOooO);php
# Aftermath
Once all malicous code and all potential back doors are removed, make sure to reset all related passwords.
- Reset all acces credentials
- Database passwords
- Admin user login creds
- FTP passwords
- SSH keys
- API tokens
- ( Hosting control panel passwords )
- Get on a regular update schedule
- Remove unused plugins/themes
- Fix file permissions
# Appendix
Still reading? Here is the desert.
# Liability
Who is actually to blame for the damage done? In most cases the website owner. We, as hosting provider, practice separation of concerns. We take care of the infrastructure and OS layer. Customers are responsible for the code they install and write.
# Security audits
We sometimes help clients with security audits. Wet think that many offerings are snake oil.
# White hat hackers
White‑hat hackers can be useful to identify real security issues.
# Security plugins
We have little experience with security plugins and are in general sceptical. Our advice is to use as few plugins as possible. Use small well maintained plugins.
# Forensics
You can try to figure out how the hackers gained access and maybe even uncover the hackers. In most cases this will lead nowhere.
- Find a Telegram chat group ID where stolen credentials are sent
- Find a generic email address
- Get the geo location from origin IPs
- See bash history (unlikely since most hacks are done with web shells)
# Prevention
- Update software regularly
- Update software regularly
- Update software regularly
- Use a web application firewall