Vous êtes ici

Bypass du script antibot "testcookie"

Portrait de ivan
J'ai constaté il y a quelques jours que l'application Android sur laquelle je travaille à mes heures perdues, ApkTrack, ne parvenait plus à lire l'un des sites sur lesquelles elle récupère habituellement des informations.
Pour résumer, ApkTrack fait principalement du web scraping pour collecter des informations de version, et il arrive régulièrement que les sites consultés mettent en place des mesures pour empêcher les robots, même non-malveillants, d'accéder à leur contenu. Ce post décrit l'une de ces contremesures à laquelle j'ai été confronté ce week-end, et comment elle a pu être contournée.

Tout d'abord, le constat : j'ai remarqué que le script suivant était servi sur un site qu'on ne nommera pas en lieu et place des données attendues.

<html>
 
<body>
    <script type="text/javascript" src="/aes.min.js"></script>
    <script>
        function toNumbers(d) {
            var e = [];
            d.replace(/(..)/g, function(d) {
                e.push(parseInt(d, 16))
            });
            return e
        }
 
        function toHex() {
            for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16);
            return e.toLowerCase()
        }
        var a = toNumbers("5d026cff5942d1ab28e3757e4b2e2f87"),
            b = toNumbers("845dd1e672b840c246aa8cfe9b5d3632"),
            c = toNumbers("e48176221e1325e09b9a959370446f05");
        var now = new Date(),
            time = now.getTime();
        time += 3600 * 1000 * 24;
        now.setTime(time);
        document.cookie = "BKS=" + toHex(slowAES.decrypt(c, 2, a, b)) + "; expires=" + now.toUTCString() + "; path=/";
        location.href = "http://site.com/page/?ckattempt=1";
    </script>
</body>
 
</html>

On comprend assez vite que le script a pour but d'effectuer un calcul (de l'AES, et lentement en plus) pour générer un cookie qui sert de sésame pour afficher les pages du site. J'observe que la valeur obtenue ressemble à un MD5, tout comme les variables a, b et c du code ci-dessus qui sont d'ailleurs régénérées à chaque nouvelle tentative. Je ne parviens à casser aucun de ces hashes rapidement : il va donc falloir creuser un peu.
Idéalement, j'aimerais lire le code source qui génère ces valeurs et par chance, on le retrouve assez facilement via une recherche bien sentie : c'est un module nginx intitulé testcookie.

La lecture des quelques 2000 lignes de code est rendue pénible par l'omniprésence de macros issues de nginx, mais les éléments suivants finissent par émerger :

  • a et b sont respectivement la clé et le vecteur d'initialisation utilisés par l'algorithme AES-CBC ; c est la valeur à déchiffrer.
  • Cette valeur est calculée de la manière suivante : c = AES(MD5($testcookie_session + $testcookie_secret)), ces deux variables étant définies dans la configuration nginx. Plus précisément :
    • Selon la documentation, testcookie_session peut-être soit l'adresse IP du visiteur (ex : 127.0.0.1), soit l'adresse IP concaténée à l'user-agent du navigateur (ex : 127.0.0.1Mozilla/5.0 (X11; Ubuntu; Linux x86_64; [...]). Cette partie est connue, et on peut la générer facilement.
    • testcookie_secret en revanche est une valeur fixe mais inconnue. Elle est soit prédéterminée, soit aléatoire (auquel cas elle change à chaque redémarrage du serveur web).

A partir d'ici, deux voies sont possibles pour contourner ce script. Soit se débrouiller pour exécuter le javascript comme le ferait un navigateur légitime, soit trouver un moyen de deviner la valeur que prendra le cookie. La première option me parait trop lourde, je commence donc par étudier la seconde. Il faut en premier lieu déterminer comment la valeur testcookie_session est générée. Pour cela, rien de plus facile : je change de navigateur et me connecte au site, puis compare les deux cookies. Ils sont identiques : cela signifie que cette variable ne contient que mon adresse IP.
La seconde étape est a priori plus délicate : arriver à trouver la valeur de testcookie_secret qui a été paramétrée sur le site cible. L'équation est la suivante :

  • Je connais un cookie valide (il suffit de se connecter au site) : 64534e58cbc178830089d06de12c00ed.
  • Je sais que mon adresse IP pour cette connexion était 95.130.11.147.
  • Enfin, on a établi que 64534e58cbc178830089d06de12c00ed = MD5("95.130.11.147" + testcookie_secret).

Nous nous retrouvons donc dans un cas de bruteforce classique. Je sors l'artillerie lourde, Hashcat :

PS C:\Users\Ivan\oclHashcat-1.33> .\oclHashcat64.exe -m0 .\targets\site.txt -a7 95.130.11.147 .\dicts\wordlist.txt
oclHashcat v1.33 starting...
[...]
64534e58cbc178830089d06de12c00ed:95.130.11.147keepmesecret

L'option a7 correspond à une attaque hybride, c'est à dire que chaque mot du dictionnaire est préfixé par une chaine de caractères. Après un certain temps passé à mouliner, l'outil crache glorieusement le résultat : testcookie_secret = keepmesecret.
En réalité, j'avais découvert cette valeur avant que le bruteforce ne soit terminé pour une raison amusante : keepmesecret est la valeur donnée en exemple dans la documentation du script, et dans le doute, je l'avais testée manuellement. Parier sur le fait que l'admin système est paresseux et va copier/coller la configuration donnée en exemple paye toujours.

Tous les ingrédients sont à présent réunis et il n'y a plus qu'à calculer un MD5 avant chaque requête afin de pouvoir accéder aux pages souhaitées.

EDIT : Suite à ce post, la taille minimale de testcookie_secret a été portée à 32 caractères dans la dernière version du script.

Commentaires

I made a promise to tell my testimony all over the globe once my man come back to me and my husband came just as Great Mother told me when she helped me. I made the right choice to have contacted Great Mother the great spell caster who is capable of helping you solve your problems. My man left me to suffer and i never believed that he will come back to me again but when i contacted Great Mother she assured me that my man will come again. She gave me some list of items to buy but i could not get them in my country and so i sent her the money and she bought the items and prepared the perfect love spell. My husband ran back to me in 3 days time begging for forgiveness THIS IS SO REAL AND GENUINE. NO SCAMS. I was so surprise that the spell worked just as she told me. This is so amazing and i want you to believe because Great Mother is so real and i urge you contact her now on her email so that she can also help you the way she helped me. Her email is Greatmotherofsolutiontemple@yahoo.com and you can also contact her with her phone number on whats app +2348078359876 you can also check and contact her on
Greatmotherofpowers.blogspot.com
Greatmotherofsolution.blogspot.com

I made a promise to tell my testimony all over the globe once my man come back to me and my husband came just as Great Mother told me when she helped me. I made the right choice to have contacted Great Mother the great spell caster who is capable of helping you solve your problems. My man left me to suffer and i never believed that he will come back to me again but when i contacted Great Mother she assured me that my man will come again. She gave me some list of items to buy but i could not get them in my country and so i sent her the money and she bought the items and prepared the perfect love spell. My husband ran back to me in 3 days time begging for forgiveness THIS IS SO REAL AND GENUINE. NO SCAMS. I was so surprise that the spell worked just as she told me. This is so amazing and i want you to believe because Great Mother is so real and i urge you contact her now on her email so that she can also help you the way she helped me. Her email is Greatmotherofsolutiontemple@yahoo.com and you can also contact her with her phone number on whats app +2348078359876 you can also check and contact her on
Greatmotherofpowers.blogspot.com
Greatmotherofsolution.blogspot.com

Ajouter un commentaire

(If you're a human, don't change the following field)
Your first name.
(If you're a human, don't change the following field)
Your first name.
(If you're a human, don't change the following field)
Your first name.

Plain text

  • Aucune balise HTML autorisée.
  • Les adresses de pages web et de courriels sont transformées en liens automatiquement.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
To prevent automated spam submissions leave this field empty.
CAPTCHA
Prouve que tu n'es pas un script en résolvant l'énigme suivante :