Outils d'utilisateurs

Outils du Site


29c3:misc:jsux

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

29c3:misc:jsux [2012/12/30 13:26]
mooh
29c3:misc:jsux [2017/04/09 15:33] (Version actuelle)
Ligne 10: Ligne 10:
 On ouvre le fichier html et on essaie de voir ce qui se passe On ouvre le fichier html et on essaie de voir ce qui se passe
  
-{{:29c3:misc:screen_shot_2012-12-30_at_1.19.18_pm.png?200|}}+{{:29c3:misc:screen_shot_2012-12-30_at_1.19.18_pm.png?400|}} 
 + 
 +On remarque que les champs de saisie ont des [[http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#the-pattern-attribute|patterns]] qui verifient que les donnees entrees ont le bon format:
  
-On remarque que les champs de saisie ont des patterns qui verifient que les donnees entrees ont le bon format: 
 pour le username: <code html> pattern="^(?:[\uFFFE\uFEFF\uFFFF]|[\u202A-\u202E])+$" maxlength="3" </code> pour le username: <code html> pattern="^(?:[\uFFFE\uFEFF\uFFFF]|[\u202A-\u202E])+$" maxlength="3" </code>
 +ce qui correspond a des caracteres [[http://www.charbase.com/fffe-unicode-invalid-character|bizarres]]
 +
 pour le pass: <code html> pattern="^\d+$" maxlength="6" </code> pour le pass: <code html> pattern="^\d+$" maxlength="6" </code>
 +
  
 En regardant le code source, on voit aussi des commentaires (interessant pour la suite) En regardant le code source, on voit aussi des commentaires (interessant pour la suite)
Ligne 25: Ligne 29:
 Le formulaire est ensuite envoye a google! <code html> <form action="http://google.com" method="POST" onsubmit="return false;"> </code> Le formulaire est ensuite envoye a google! <code html> <form action="http://google.com" method="POST" onsubmit="return false;"> </code>
  
-On remarque que le script main.js n'est pas appele <code html> <script src="main_readable.js"></script> </code>, on modifie donc le fichier html.+On remarque que le script main.js n'est pas appele<code html> <script src="main_readable.js"></script> </code> On modifie donc le fichier html. 
 + 
 +Analysons maintenant le javascript. 
 +Le code est obfusque, on remarque des appels de la forme  
 +<code>  
 +window[b[0]] = 65534; /*b*/ 
 +window[b[31]](b[1], function () {  
 +</code> 
 + 
 +et a la fin du script  
 +<code javascript> 
 +("262626263O1G3S3C3F31343S3L3J35103J3K3I39333K3S3S3C353E373K383S3J3L323J3K3I393E373S3338313I233F3435213K3S3J3G3C393K3S1G1H1I1J1K1L1M1N1O1P3132333435363S3A3F393E3S351P1J1O1O331P341K31311G3232311P1G1N1N341J1I1P1L1O1P1J1M1L1P1K1P3S3J3L323D393K3S333835333B2G353I3D393J3J393F3E3S3N35323B393K2E3F3K39363933313K393F3E3J3S3N35323B393K27353K2L3J353I2D353439313S3E313M3937313K3F3I3S37353F3C3F33313K393F3E3S3L3J353I2137353E3K3S393S3C3F33313K393F3E3S3M313C3L353S393E3G3L3K3S37353K253C353D353E3K3J223P2K31372E313D353S31343D393E3S1M31311N1O31361J1N1I1K1I331J331K1M1O361L1H1P35331G341M1O1M311G353S3J383F3N3S1I1P231J3S1I1P231J2V3S3J3L323J3K3I3S3K3F2L3G3G353I23313J353S333I35313K352E3F3K39363933313K393F3E3S313434253M353E3K2C393J3K353E353I3S363F3I3D3J".replace(/\w{2}/g, function (a) { 
 +    return String.fromCharCode(parseInt(a, 32)); /*b*/ 
 +    /*b*/ 
 +}).split("|")); 
 +</code> 
 +Si on l'execute, on obtient l'array suivant: 
 +<code> 
 +["FFFFx0", "load", "use strict", "", "length", "substring", "charCodeAt", "split", "0123456789abcdef", "join", "e9388c9d4aa0bba9077d329589365949", "submit", "checkPermission", "webkitNotifications", "webkitGetUserMedia", "navigator", "geolocation", "userAgent", "i", "location", "value", "input", "getElementsByTagName", "admin", "6aa78af37242c3c468f519ec0d686a0e", "show", "29C3", "29C3_", "substr", "toUpperCase", "createNotification", "addEventListener", "forms"] 
 +</code> 
 + 
 +On remplace maintenant les b[] par leurs valeurs 
 +<code javascript> 
 +"use strict"; /*b*/ 
 +var a = "0123456789abcdef".split(); /*b*/ 
 +var p = "e9388c9d4aa0bba9077d329589365949", 
 +    d; /*b*/ 
 +document.forms[0].addEventListener("submit", function () { 
 +    for (; /*b*/ (d = !! window.webkitNotifications.checkPermission + !window.webkitNotifications.checkPermission() + !! window.navigator.webkitGetUserMedia + !! window.navigator.geolocation + (p === c(window.navigator.userAgent)) + !! window.location.i) == 6; /*b*/ ) { 
 +        if (!~ (d - 7) === !! window && document.getElementsByTagName("input")[0].value === "admin" && c(document.getElementsByTagName("input")[1].value, 5e3) == "6aa78af37242c3c468f519ec0d686a0e" /*\d{1,4}*/ ) { 
 +            window.webkitNotifications.createNotification(false, "29C3", "29C3_" + c(window.webkitNotifications.checkPermission() + window.navigator.userAgent + d + document.getElementsByTagName("input")[0].value + typeof window.navigator.webkitGetUserMedia + window.location.i + document.getElementsByTagName("input")[1].value).toUpperCase().substr(0, 4)).show() 
 +</code> 
 +et on remarque que le script ajoute un eventListener au bouton submit de index.html 
 +Il y a une boucle for de la forme **for (;(exp) == 6;)** La boucle ne sera execute seulement si exp == 6 (on remarque egalement le break pour sortir de la boucle, ce qui revient en fait a faire un if exp == 6) 
 + 
 +Le script utilise les [[http://www.html5rocks.com/en/tutorials/notifications/quick/?ModPagespeed=noscript|webkitNotifications]] et si les conditions sont remplies, va afficher une notification 
 + 
 +On analyse la boucle for: 
 +<code> 
 +(d = !! window.webkitNotifications.checkPermission +  
 +!window.webkitNotifications.checkPermission() +  
 +!! window.navigator.webkitGetUserMedia +  
 +!! window.navigator.geolocation +  
 +(p === c(window.navigator.userAgent)) +  
 +!! window.location.i) == 6 
 +</code> 
 + 
 +si on utilise chrome par exemple et on lance la page html depuis un serveur web (pas en local), les notifications sont activees et on obtient 4 true pour les premiers tests. Il ne reste plus qu'a trouver  
 +<code> 
 +(p === c(window.navigator.userAgent)) +  
 +!! window.location.i 
 +</code> 
 +pour obtenir 6. 
 +La fonction c calcule un hash de l'user Agent. On va donc bruteforcer tous les user agents possibles pour trouver celui qui retourne le bon hash. On commence par [[http://www.useragentstring.com/pages/Chrome/|Chrome]] (on utilise beautifulsoup pour recuperer tous les noms des liens) puis Firefox comme ce sont les 2 browsers qui supportent les notifications. Mais aucun ne marche... Puis il y a eu un hint, "it's a IE ua"... lol et la on trouve le bon user agent "Mozilla/1.22 (compatible; MSIE 2.0; Windows 3.1)" 
 + 
 +pour **!! window.location.i** j'obtenais toujours False car window.location.i est "Undefined"... 
 +Si on se rappelle le contenu du fichier html, il y avait une ligne commentee:  
 +<code html> 
 +<!--[if IE]> 
 +            <script>window.location.i=!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~(FFFFx0-0xFFFF);</script> 
 +</code> 
 +On va donc enlever les commentaires et cela va definir window.location.i 
 + 
 +Maintenant on est dans la boucle, il ne reste plus que ce test 
 +<code html> 
 +if (!~ (d - 7) === !! window &&  
 +document.getElementsByTagName("input")[0].value === "admin" &&  
 +c(document.getElementsByTagName("input")[1].value, 5e3) == "6aa78af37242c3c468f519ec0d686a0e" /*\d{1,4}*/ ) 
 +</code> 
 + 
 +Le !~ (d - 7) === !! window est True car d = 6 (de la boucle), ensuite le user doit etre admin et la encore une fois la fonction c est appellee sur le pass. On va bruteforcer le pass (il est de la forme **pattern="^\d+$"** ie un nombre et on trouve pass = 593 
 + 
 +On teste tout ca (en enlevant les patterns et length pour le username pour qu'il accepte "admin") et on obtient une belle notification avec le flag{{:29c3:misc:screen_shot_2012-12-30_at_2.07.36_pm.png?400|}} 
  
 ==== Source ==== ==== Source ====
29c3/misc/jsux.1356870368.txt.gz · Dernière modification: 2017/04/09 15:33 (modification externe)