Joomla site hacked: what to do in the first hour
Block the site at server level, copy files, database and logs, then find the planted PHP and the way in. Clean up first, change every password after.
Google shows a warning, visitors on phones land on a casino page, or the host mails you about outgoing spam. Most of the damage after a hack comes from the next few hours: someone restores a backup, deletes the odd files and goes back to work, and the same hole is used again two days later. Work in the order below.
Check that it is real
Hacks often hide from the site owner. The redirect only fires for visitors coming from Google, or only on mobile, and never for a logged-in administrator. Test from a private window on your phone's data connection, and search Google for site:example.com to look for pages you never wrote. Google Search Console lists what it found under Security & Manual Actions > Security Issues.
Copy everything before you change anything
Make a full copy of the files and the database and store it outside the web root, labelled as infected. Download the web server access logs as well, because many hosts keep them for only a few days. You need all of this later to find out how they got in, and cleaning destroys the evidence.
Keep your older backups out of reach while you work, so nothing overwrites the last clean one. If the only backups are the ones your host rotates, read why those are not really yours once this is over.
Close the site properly
The Site Offline switch in Global Configuration is not enough. It only stops pages that Joomla renders, and a backdoor in images/ is a PHP file called directly, so it keeps running. Block the site at server level instead. On Apache, put this at the top of the root .htaccess with your own IP address:
Require ip 203.0.113.10
Visitors get a 403 for now, which is better than malware, and you can work on the live site undisturbed. On nginx ask the host to do the same.
Look for what was added
Accounts
Open Users > Manage, filter on the Super Users group and check every name. Look at registration date and last visit. Then read the user actions log for that period, keeping in mind that an attacker with database access can empty it.
Files
Connect over SSH if you have it and run these from the site root:
# images and tmp should hold no PHP at all
find images tmp -type f -name '*.ph*'
# PHP changed in the last 30 days, cache excluded
find . -name '*.php' -mtime -30 -not -path './cache/*' | sort
# the usual obfuscation
grep -rlE 'eval\(base64_decode|gzinflate\(|str_rot13\(|assert\(\$_' --include='*.php' .
Dates can be forged and the grep will flag a few innocent files, so treat these as leads. The reliable test is a comparison with a clean copy. Download the full package of your exact Joomla version from downloads.joomla.org, unpack it next to the site and run:
diff -rq joomla-clean/ public_html/
Every "differ" line is a core file that was modified. Every "Only in public_html" line is an extension, your own file or something planted. Pay extra attention to index.php, .htaccess, configuration.php and your template's index.php, because injected code usually lands there.
Database and extensions
Search #__content for <script and <iframe in introtext and fulltext, using your real table prefix. Check System > Manage > Extensions for plugins nobody remembers installing, and System > Scheduled Tasks plus the cron jobs in your hosting panel for anything that restores the infection.
Find the way in
Take the date of the oldest planted file and search the access log around it for POST requests to odd URLs. On most sites the cause turns out to be an outdated extension, a reused administrator password or an old Joomla version. Compare your extension list with the Vulnerable Extensions List and look at System > Update > Extensions. Without an answer here, assume it will happen again and plan for that: remove every extension you do not need.
Clean up
You have two routes. If you have a backup from before the oldest planted file, restore it and update Joomla and all extensions before anyone else can reach the site. If you don't, clean the live site:
- Overwrite the core with the clean package of the same version, keeping
configuration.phpafter you have checked it. - Delete the files you identified as planted.
- Reinstall each extension from a fresh download from its developer.
- Update Joomla and every extension to the current release.
The "Reinstall Joomla core files" option under System > Update > Joomla overwrites core files but leaves added files where they are, and it runs on an installation you can't trust yet. Unpacking the package yourself is safer.
Change every secret
Assume the attacker has read configuration.php. Change these after the cleanup, because a backdoor still in place would hand them over again:
- All administrator passwords, and the hosting panel, FTP and SSH logins.
- The database password, then the same value in
configuration.php. - The
$secretvalue inconfiguration.php. This also invalidates existing API tokens. - The SMTP password and any keys for external services stored in extensions.
Then empty the session table to log everyone out, stolen sessions included:
TRUNCATE TABLE jos_session;
Turn on two-factor login for every administrator while you are at it.
Go back online
Remove the Require ip line, test as an anonymous visitor on a phone and clear all caches, including the host's. If Google flagged the site, request a review on the Security Issues page. Watch the access log and the list of changed files for at least a week.
If the site holds customer data and that data may have been read, the matter does not end with the cleanup. Under the GDPR you have 72 hours from the moment you become aware of a breach to report it to your data protection authority, unless it is unlikely to pose a risk to the people involved.
Doctor Joomla is a project of Cloudfaction, a Dutch agency building and maintaining Joomla sites since 1999. The articles are made with the help of AI, so tell us if something does not match your screen. Mail info@cloudfaction.nl if you want someone to look at yours.