Enjoy the good Javascript User Xperience!
On ouvre le fichier html et on essaie de voir ce qui se passe
On remarque que les champs de saisie ont des patterns qui verifient que les donnees entrees ont le bon format:
pour le username:
pattern="^(?:[\uFFFE\uFEFF\uFFFF]|[\u202A-\u202E])+$" maxlength="3"
ce qui correspond a des caracteres bizarres
pour le pass:
pattern="^\d+$" maxlength="6"
En regardant le code source, on voit aussi des commentaires (interessant pour la suite)
<!--[if IE]> <script>window.location.i=!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~(FFFFx0-0xFFFF);</script>
le if IE m'a fait ignorer cette ligne, grave erreur
Le formulaire est ensuite envoye a google!
<form action="http://google.com" method="POST" onsubmit="return false;">
On remarque que le script main.js n'est pas appele:
<script src="main_readable.js"></script>
On modifie donc le fichier html.
Analysons maintenant le javascript. Le code est obfusque, on remarque des appels de la forme
window[b[0]] = 65534; /*b*/ window[b[31]](b[1], function () {
et a la fin du script
("262626263O1G3S3C3F31343S3L3J35103J3K3I39333K3S3S3C353E373K383S3J3L323J3K3I393E373S3338313I233F3435213K3S3J3G3C393K3S1G1H1I1J1K1L1M1N1O1P3132333435363S3A3F393E3S351P1J1O1O331P341K31311G3232311P1G1N1N341J1I1P1L1O1P1J1M1L1P1K1P3S3J3L323D393K3S333835333B2G353I3D393J3J393F3E3S3N35323B393K2E3F3K39363933313K393F3E3J3S3N35323B393K27353K2L3J353I2D353439313S3E313M3937313K3F3I3S37353F3C3F33313K393F3E3S3L3J353I2137353E3K3S393S3C3F33313K393F3E3S3M313C3L353S393E3G3L3K3S37353K253C353D353E3K3J223P2K31372E313D353S31343D393E3S1M31311N1O31361J1N1I1K1I331J331K1M1O361L1H1P35331G341M1O1M311G353S3J383F3N3S1I1P231J3S1I1P231J2V3S3J3L323J3K3I3S3K3F2L3G3G353I23313J353S333I35313K352E3F3K39363933313K393F3E3S313434253M353E3K2C393J3K353E353I3S363F3I3D3J".replace(/\w{2}/g, function (a) { return String.fromCharCode(parseInt(a, 32)); /*b*/ /*b*/ }).split("|"));
Si on l'execute, on obtient l'array suivant:
["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"]
On remplace maintenant les b[] par leurs valeurs
"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()
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 webkitNotifications et si les conditions sont remplies, va afficher une notification
On analyse la boucle for:
(d = !! window.webkitNotifications.checkPermission + !window.webkitNotifications.checkPermission() + !! window.navigator.webkitGetUserMedia + !! window.navigator.geolocation + (p === c(window.navigator.userAgent)) + !! window.location.i) == 6
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
(p === c(window.navigator.userAgent)) + !! window.location.i
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 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:
<!--[if IE]> <script>window.location.i=!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~(FFFFx0-0xFFFF);</script>
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
if (!~ (d - 7) === !! window && document.getElementsByTagName("input")[0].value === "admin" && c(document.getElementsByTagName("input")[1].value, 5e3) == "6aa78af37242c3c468f519ec0d686a0e" /*\d{1,4}*/ )
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
index.html
<!DOCTYPE html> <html> <head> <title>Gain Access</title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <script src="main_readable.js"></script> </head> <body> <!--[if IE]> <script>window.location.i=!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~(FFFFx0-0xFFFF);</script> <blink>คุณกำลังทำอะไร?</blink> <![endif]--> <!--[if !IE]> --> <form action="http://google.com" method="POST" onsubmit="return false;"> <input type="text" placeholder="User" required="true" pattern="^(?:[\uFFFE\uFEFF\uFFFF]|[\u202A-\u202E])+$" maxlength="3" /> <input type="password" placeholder="Password" required="true" pattern="^\d+$" maxlength="6" /> <input type="submit" value="Gain Access!" /> </form> <!-- <![endif]--> </body> </html>
main.js (apres un coup de http://jsbeautifier.org/)
! function (b) { delete b; window[b[0]] = 65534; /*b*/ window[b[31]](b[1], function () { function e(e, t) { var o = e[0], u = e[1], a = e[2], f = e[3]; /*b*/ o = n(o, u, a, f, t[0], 7, -680876936); /*b*/ f = n(f, o, u, a, t[1], 12, -389564586); /*b*/ a = n(a, f, o, u, t[2], 17, 606105819); /*b*/ u = n(u, a, f, o, t[3], 22, -1044525330); /*b*/ o = n(o, u, a, f, t[4], 7, -176418897); /*b*/ f = n(f, o, u, a, t[5], 12, 1200080426); /*b*/ a = n(a, f, o, u, t[6], 17, -1473231341); /*b*/ u = n(u, a, f, o, t[7], 22, -45705983); /*b*/ o = n(o, u, a, f, t[8], 7, 1770035416); /*b*/ f = n(f, o, u, a, t[9], 12, -1958414417); /*b*/ a = n(a, f, o, u, t[10], 17, -42063); /*b*/ u = n(u, a, f, o, t[11], 22, -1990404162); /*b*/ o = n(o, u, a, f, t[12], 7, 1804603682); /*b*/ f = n(f, o, u, a, t[13], 12, -40341101); /*b*/ a = n(a, f, o, u, t[14], 17, -1502002290); /*b*/ u = n(u, a, f, o, t[15], 22, 1236535329); /*b*/ o = r(o, u, a, f, t[1], 5, -165796510); /*b*/ f = r(f, o, u, a, t[6], 9, -1069501632); /*b*/ a = r(a, f, o, u, t[11], 14, 643717713); /*b*/ u = r(u, a, f, o, t[0], 20, -373897302); /*b*/ o = r(o, u, a, f, t[5], 5, -701558691); /*b*/ f = r(f, o, u, a, t[10], 9, 38016083); /*b*/ a = r(a, f, o, u, t[15], 14, -660478335); /*b*/ u = r(u, a, f, o, t[4], 20, -405537848); /*b*/ o = r(o, u, a, f, t[9], 5, 568446438); /*b*/ f = r(f, o, u, a, t[14], 9, -1019803690); /*b*/ a = r(a, f, o, u, t[3], 14, -187363961); /*b*/ u = r(u, a, f, o, t[8], 20, 1163531501); /*b*/ o = r(o, u, a, f, t[13], 5, -1444681467); /*b*/ f = r(f, o, u, a, t[2], 9, -51403784); /*b*/ a = r(a, f, o, u, t[7], 14, 1735328473); /*b*/ u = r(u, a, f, o, t[12], 20, -1926607734); /*b*/ o = i(o, u, a, f, t[5], 4, -378558); /*b*/ f = i(f, o, u, a, t[8], 11, -2022574463); /*b*/ a = i(a, f, o, u, t[11], 16, 1839030562); /*b*/ u = i(u, a, f, o, t[14], 23, -35309556); /*b*/ o = i(o, u, a, f, t[1], 4, -1530992060); /*b*/ f = i(f, o, u, a, t[4], 11, 1272893353); /*b*/ a = i(a, f, o, u, t[7], 16, -155497632); /*b*/ u = i(u, a, f, o, t[10], 23, -1094730640); /*b*/ o = i(o, u, a, f, t[13], 4, 681279174); /*b*/ f = i(f, o, u, a, t[0], 11, -358537222); /*b*/ a = i(a, f, o, u, t[3], 16, -722521979); /*b*/ u = i(u, a, f, o, t[6], 23, 76029189); /*b*/ o = i(o, u, a, f, t[9], 4, -640364487); /*b*/ f = i(f, o, u, a, t[12], 11, -421815835); /*b*/ a = i(a, f, o, u, t[15], 16, 530742520); /*b*/ u = i(u, a, f, o, t[2], 23, -995338651); /*b*/ o = s(o, u, a, f, t[0], 6, -198630844); /*b*/ f = s(f, o, u, a, t[7], 10, 1126891415); /*b*/ a = s(a, f, o, u, t[14], 15, -1416354905); /*b*/ u = s(u, a, f, o, t[5], 21, -57434055); /*b*/ o = s(o, u, a, f, t[12], 6, 1700485571); /*b*/ f = s(f, o, u, a, t[3], 10, -1894986606); /*b*/ a = s(a, f, o, u, t[10], 15, -1051523); /*b*/ u = s(u, a, f, o, t[1], 21, -2054922799); /*b*/ o = s(o, u, a, f, t[8], 6, 1873313359); /*b*/ f = s(f, o, u, a, t[15], 10, -30611744); /*b*/ a = s(a, f, o, u, t[6], 15, -1560198380); /*b*/ u = s(u, a, f, o, t[13], 21, 1309151649); /*b*/ o = s(o, u, a, f, t[4], 6, -145523070); /*b*/ f = s(f, o, u, a, t[11], 10, -1120210379); /*b*/ a = s(a, f, o, u, t[2], 15, 718787259); /*b*/ u = s(u, a, f, o, t[9], 21, -343485551); /*b*/ e[0] = h(o, e[0]); /*b*/ e[1] = h(u, e[1]); /*b*/ e[2] = h(a, e[2]); /*b*/ e[3] = h(f, e[3]) } function t(e, t, n, r, i, s) { t = h(h(t, e), h(r, s)); /*b*/ return h(t << i | t >>> 32 - i, n) } function n(e, n, r, i, s, o, u) { return t(n & r | ~n & i, e, n, s, o, u) } function r(e, n, r, i, s, o, u) { return t(n & i | r & ~i, e, n, s, o, u) } function i(e, n, r, i, s, o, u) { return t(n ^ r ^ i, e, n, s, o, u) } function s(e, n, r, i, s, o, u) { return t(r ^ (n | ~i), e, n, s, o, u) } function o(t) { var n = b[3]; /*b*/ var r = t[b[4]], i = [1732584193, -271733879, -1732584194, 271733878], s; /*b*/ for (s = 64; /*b*/ s <= t[b[4]]; /*b*/ s += 64) { e(i, u(t[b[5]](s - 64, s))) } t = t[b[5]](s - 64); /*b*/ var o = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; /*b*/ for (s = 0; /*b*/ s < t[b[4]]; /*b*/ s++) { o[s >> 2] |= t[b[6]](s) << (s % 4 << 3) } o[s >> 2] |= 128 << (s % 4 << 3); /*b*/ if (s > 55) { e(i, o); /*b*/ for (s = 0; /*b*/ s < 16; /*b*/ s++) { o[s] = 0 } } o[14] = r * 8; /*b*/ e(i, o); /*b*/ return i } function u(e) { var t = [], n; /*b*/ for (n = 0; /*b*/ n < 64; /*b*/ n += 4) { t[n >> 2] = e[b[6]](n) + (e[b[6]](n + 1) << 8) + (e[b[6]](n + 2) << 16) + (e[b[6]](n + 3) << 24) } return t } function f(e) { var t = b[3], n = 0; /*b*/ for (; /*b*/ n < 4; /*b*/ n++) { t += a[e >> n * 8 + 4 & 15] + a[e >> n * 8 & 15] } return t } function l(e) { for (var t = 0; /*b*/ t < e[b[4]]; /*b*/ t++) { e[t] = f(e[t]) } return e[b[9]](b[3]) } function c(e, t) { if (!t) { t = 1 } var n = e; /*b*/ for (var r = 0; /*b*/ r < t; /*b*/ r++) { n = l(o(n)) } return n } function h(e, t) { return e + t & 4294967295 } b[2]; /*b*/ var a = b[8][b[7]](b[3]); /*b*/ var p = b[10], d; /*b*/ document[b[32]][0][b[31]](b[11], function () { for (; /*b*/ (d = !! window[b[13]][b[12]] + !window[b[13]][b[12]]() + !! window[b[15]][b[14]] + !! window[b[15]][b[16]] + (p === c(window[b[15]][b[17]])) + !! window[b[19]][b[18]]) == 6; /*b*/ ) { if (!~ (d - 7) === !! window && document[b[22]](b[21])[0][b[20]] === b[23] && c(document[b[22]](b[21])[1][b[20]], 5e3) == b[24] /*\d{1,4}*/ ) { window[b[13]][b[30]](false, b[26], b[27] + c(window[b[13]][b[12]]() + window[b[15]][b[17]] + d + document[b[22]](b[21])[0][b[20]] + typeof window[b[15]][b[14]] + window[b[19]][b[18]] + document[b[22]](b[21])[1][b[20]])[b[29]]()[b[28]](0, 4))[b[25]]() } break } return false }, false) }, false) }("262626263O1G3S3C3F31343S3L3J35103J3K3I39333K3S3S3C353E373K383S3J3L323J3K3I393E373S3338313I233F3435213K3S3J3G3C393K3S1G1H1I1J1K1L1M1N1O1P3132333435363S3A3F393E3S351P1J1O1O331P341K31311G3232311P1G1N1N341J1I1P1L1O1P1J1M1L1P1K1P3S3J3L323D393K3S333835333B2G353I3D393J3J393F3E3S3N35323B393K2E3F3K39363933313K393F3E3J3S3N35323B393K27353K2L3J353I2D353439313S3E313M3937313K3F3I3S37353F3C3F33313K393F3E3S3L3J353I2137353E3K3S393S3C3F33313K393F3E3S3M313C3L353S393E3G3L3K3S37353K253C353D353E3K3J223P2K31372E313D353S31343D393E3S1M31311N1O31361J1N1I1K1I331J331K1M1O361L1H1P35331G341M1O1M311G353S3J383F3N3S1I1P231J3S1I1P231J2V3S3J3L323J3K3I3S3K3F2L3G3G353I23313J353S333I35313K352E3F3K39363933313K393F3E3S313434253M353E3K2C393J3K353E353I3S363F3I3D3J".replace(/\w{2}/g, function (a) { return String.fromCharCode(parseInt(a, 32)); /*b*/ /*b*/ }).split("|"));