For nørder: Incident response & hardening af et hacket WordPress-site

Denne artikel er til dig, der vil forstå hvor angribere gemmer sig, hvordan WordPress loader kode, og hvordan man rydder korrekt op uden at efterlade persistence.

Det er ikke en “scan & håb”-guide, men en praktisk gennemgang baseret på reelle kompromitteringer.

1. Hvor angribere oftest gemmer sig (og hvorfor)

wp-content/uploads/

Det mest misbrugte område.

Hvorfor

  • Skrivbar mappe
  • Fyldt med filer (støj)
  • Ofte overset


Røde flag

  • PHP-filer i uploads
  • Filer som image.php, wp.php, admin-ajax.php
  • jpg.php, png.php


Tjek

bash
Copy to clipboard
find wp-content/uploads -type f -name "*.php"

wp-content/mu-plugins/ (kritisk område)

MU-plugins indlæses automatisk og kan ikke deaktiveres i admin.

Hvorfor attraktivt for angribere

  • Kører altid
  • Overlever plugin-oprydning
  • Overlever tema-skift
  • Overses ofte

Tjek

bash
Copy to clipboard
ls -la wp-content/mu-plugins

Vigtigt: Ikke alle MU-plugins er malware

MU-plugins bruges legitimt i bl.a.:

  • hosting-setup
  • enterprise-setup
  • page builders (fx Elementor)


Eksempel: elementor-safe-mode.php

Denne fil:

  • er legitim
  • bruges af Elementor til fejlsøgning
  • ligger korrekt i mu-plugins/
  • indeholder læsbar kode uden obfuscation


Det er ikke et tegn på hack i sig selv.

Mistænkeligt hvis

  • sitet ikke bruger Elementor
  • koden er obfuskeret
  • filen loader eksterne scripts
  • den genskabes efter sletning uden forklaring

wp-includes/ (core manipulation)

Angribere ændrer kernefiler for dyb persistence.

Tjek altid

bash
Copy to clipboard
wp core verify-checksums

Hvis én fil ikke matcher, betragtes sitet som kompromitteret.

Aktivt tema (functions.php, footer.php)

Klassisk sted for injektion.

Tegn

  • Obfuskeret kode nederst
  • add_action(‘wp_footer’, …)
  • eval(base64_decode())


.htaccess

Bruges til:

  • redirects
  • cloaking
  • mobile-only infektioner


Røde flag

apache
Copy to clipboard
RewriteCond %{HTTP_USER_AGENT}
RewriteRule ^ https://spam.example [R,L]

wp-config.php

Sjældnere, men kritisk.

Tjek

  • kode efter /* That’s all, stop editing! */
  • require_once til ukendte paths


Databasen (ofte overset)

Malware findes i databasen i ca. 20–35 % af reelle hacks.

Bruges primært til

  • SEO-spam
  • JavaScript-injektion
  • persistence / reinfektion


Typiske tabeller

  • wp_options
  • wp_posts
  • wp_usermeta


Databasen bruges sjældent alene, men ofte som supplement til filbaseret malware.

2. Hvad er MU-plugins teknisk?

MU-plugin = Must-Use Plugin.

  • Ligger i wp-content/mu-plugins/
  • Indlæses automatisk af WordPress
  • Kræver ingen aktivering
  • Kræver ingen konfiguration i wp-config.php


Hvis en PHP-fil ligger direkte i mappen, bliver den eksekveret på hvert request.

Minimum

text
Copy to clipboard
wp-content/mu-plugins/test.php

php
Copy to clipboard
<?php
error_log('MU-plugin loaded');

Denne kode kører altid.

Vigtige MU-plugin-regler

  • Kun PHP-filer i roden indlæses automatisk
  • Undermapper kræver manuel require
  • Fejl i MU-plugin = fatal fejl for hele sitet
  • Kan kun fjernes via filsystemet

3. Hurtig teknisk triage

Find nyligt ændrede PHP-filer

bash
Copy to clipboard
find . -type f -name "*.php" -mtime -7

Scan for klassisk obfuscation

bash
Copy to clipboard
grep -RIn -E "eval\(|base64_decode\(|gzinflate\(|str_rot13\(|assert\(" .

4. Reparer WordPress core korrekt (wp-cli)

Tjek kernefiler

bash
Copy to clipboard
wp core verify-checksums

OK

text
Copy to clipboard
Success: WordPress installation verifies against checksums.

Kompromitteret

text
Copy to clipboard
Warning: File doesn't verify against checksum

Reparer

bash
Copy to clipboard
wp core download --force

Dette overskriver kun core-filer – ikke indhold.

5. Stop de mest almindelige angrebsveje

Blokér PHP i uploads

apache
Copy to clipboard
<FilesMatch "\.php$">
  Require all denied
</FilesMatch>

nginx
Copy to clipboard
location ~* /wp-content/uploads/.*\.php$ {
  deny all;
}

Luk xmlrpc.php (hvis muligt)

apache
Copy to clipboard
<Files xmlrpc.php>
  Require all denied
</Files>

Deaktiver filredigering i admin
php
Copy to clipboard
define('DISALLOW_FILE_EDIT', true);

6. Cron jobs – persistence-mekanismen

bash
Copy to clipboard
wp cron event list

Mistænkelige hooks:

  • tilfældige navne
  • kører hvert minut
  • loader eksterne scripts


Slet:

bash
Copy to clipboard
wp cron event delete suspicious_hook

7. Database-tjek (minimum)

SEO-spam:
bash
Copy to clipboard
wp db query "
SELECT ID FROM wp_posts
WHERE post_content LIKE '%casino%'
   OR post_content LIKE '%viagra%';
"
Tjek site hijack:
bash
Copy to clipboard
wp option get siteurl
wp option get home

8. MU-plugin til “incident mode” (hurtig lockdown)

php
Copy to clipboard
<?php
if (!defined('ABSPATH')) exit;

remove_action('wp_head', 'wp_generator');
add_filter('xmlrpc_enabled', '__return_false');

add_filter('rest_authentication_errors', function () {
    if (!is_user_logged_in()) {
        return new WP_Error(
            'rest_disabled',
            'REST API locked',
            ['status' => 401]
        );
    }
});
Bemærk: REST-blokering kan påvirke plugins og editors.

9. Den korte incident-checkliste

  • Skift alle adgangskoder
  • Force logout
bash
Copy to clipboard
wp user session destroy --all
  • Blokér PHP i uploads
  • Reparer WordPress core
  • Fjern og geninstallér plugins/temaer
  • Gennemgå MU-plugins
  • Tjek cron jobs
  • Tjek database
  • Aktivér WAF og file monitoring


Den vigtigste pointe

Oprydning uden forståelse for load order, MU-plugins og persistence er midlertidig. Hvis MU-plugins, cron og database ikke er gennemgået, er oprydningen ufuldstændig – også selvom scanneren siger “clean”.

For nørder: Incident response & hardening af et hacket WordPress-site