Presque OCR pour obtenir le mot de passe VPNBook. PHP + Mikrotik

Récemment, VPNBook a commencé à publier un mot de passe au lieu du texte brut en tant qu'image. "Eh bien, comment," pensai-je, et je commençai à chercher des moyens de résoudre ce problème. Nous reconnaissons le mot de passe "image" VPNBook en PHP. Et, bien sûr, un script pour Mikrotik.

Pendant longtemps, j'ai mis en place un tunnel VPN PPTP gratuit et automatique depuis VPNBook.com sur mon routeur (Mikrotik) et l'ai utilisé avec succès jusqu'à récemment. Je n'entrerai pas dans les détails, ils sont décrits dans l'article " Configurer la réception automatique d'un mot de passe pour VPN sur Mikrotik ". Avant le problème, le mot de passe du VPNBook pouvait simplement être extrait de la page html, par exemple, comme ceci:

preg_match('/Password: <strong>([^<]+)/', $homepage, $matches); print($matches[1]) 

Et plus récemment, le mot de passe est devenu une "image". Et la première pensée a été d'utiliser la reconnaissance optique de texte. J'ai commencé à essayer les services OCR en ligne et hors ligne, qui pouvaient reconnaître le mot de passe. J'adresse mes salutations à Winand , avec qui nous avons correspondu à ce sujet. En général, le dernier OCR avec lequel j'ai joué était Tesseract, qui, dès la sortie de la boîte, a déterminé le mot de passe, mais avec des erreurs. Mais on peut lui apprendre de nouvelles polices, ce que j'allais faire. Lorsque j'ai choisi une police qui ressemblait à une «police d'image», l'idée m'est venue que c'était quelque chose de simple, même si cela ressemblait à un teminal de Windows ou à une police terminale de Linux. Et le tour est joué - il s'est avéré qu'il s'agissait simplement d'une police PHP intégrée avec un nombre (taille) 5. Ensuite, j'ai abandonné l'OCR et écrit un script PHP qui recherche les caractères du mot de passe "image" dans le dictionnaire généré. Un dictionnaire est un ensemble d'images de caractères de mot de passe possibles de la même couleur et taille. La recherche se fait en faisant correspondre les images. Voici une ingénierie inverse si simple. Je suppose que la version actuelle de l'image sur le VPNBook ne durera pas longtemps, compte tenu de sa primitivité.

Script Vpnbook.php


Sprite renvoie une chaîne de mot de passe.

 <?php //   $wchar = 9; $hchar = 13; $strDict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '; $imgDict = imagecreatetruecolor(2 + strlen($strDict)* $wchar, $hchar); $bg = imagecolorallocate($imgDict, 0xF6, 0xF6, 0xF6); $textcolor = imagecolorallocate($imgDict, 0x4C, 0x4C, 0x4C); imagefill($imgDict, 0, 0, $bg); imagestring($imgDict, 5, 2, 0, $strDict, $textcolor); //  cURL $ch = curl_init(); //  url,      curl_setopt($ch, CURLOPT_URL, 'https://www.vpnbook.com/password.php'); //  ,      string curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); // also, this seems wise considering output is image. //   $output = curl_exec($ch); //  cURL curl_close($ch); $imgOCR = imagecreatefromstring($output); // $imgOCR = imageCreateFromPng('password.png'); //      10  . 2 + 10*9 = 92 < 100 $maxchar = floor((imagesx($imgOCR) - 2) / 9); $imgBox = imagecreatetruecolor($wchar, $hchar); $hashDict = Array(); //   for ($k = 0; $k < strlen($strDict) ; $k++) { imagecopy($imgBox, $imgDict, 0, 0, 2 + $k * $wchar, 0, $wchar, $hchar); $hashStr = ""; for($y = 0; $y < $hchar ; $y++) for($x = 0; $x < $wchar; $x++) $hashStr .= (imagecolorat($imgBox, $x, $y) != 0xF6F6F6)? '1': '0'; $hashDict[$hashStr] = $strDict[$k]; } //     for ($k = 0; $k < $maxchar ; $k++) { imagecopy($imgBox, $imgOCR, 0, 0, 2 + $k * $wchar, 0, $wchar, $hchar); $hashStr = ""; for($y = 0; $y < $hchar ; $y++) for($x = 0; $x < $wchar; $x++) $hashStr .= (imagecolorat($imgBox, $x, $y) != 0xF6F6F6)? '1': '0'; $tempchar = $hashDict[$hashStr]; if ($tempchar==' ') break; print($tempchar); } /*header('Content-type: image/png'); imagepng($imgOCR); */ //var_dump($hashDict); imagedestroy($imgDict); imagedestroy($imgOCR); imagedestroy($imgBox); ?> 


Plan B. Mot de passe de twitter


Avec l'invite vvsvic , je propose une implémentation simple d'un script alternatif pour récupérer un mot de passe à partir d'un twitter VPNBook (https://twitter.com/vpnbook/)
 <?php function url_get_html($url) { //  cURL $ch = curl_init(); //  url      curl_setopt($ch, CURLOPT_URL, $url); //        string curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //   $output = curl_exec($ch); //  cURL curl_close($ch); //   return $output; } $homepage = url_get_html('https://twitter.com/vpnbook'); preg_match('/Password: ([^<]+)/', $homepage, $matches); // Print the entire match result // var_dump($matches); print($matches[1]) // print_r($matches); ?> 


Script Mikrotik VPNBook


Le script doit être appelé toutes les minutes depuis le sheduler. Le script surveille l'état de la connexion PPTP et, lors de la déconnexion, appelle toute la procédure pour demander un nouveau mot de passe, donc Mikrotik n'inondera pas les tentatives d'ouverture de la connexion pendant plusieurs heures avec le mauvais mot de passe, et la reconnexion se fait en 1 minute. Il surveille également les erreurs d'erreur lors de la récupération et de l'obtention de fichiers pour déterminer plus précisément qu'un mot de passe a été reçu.

 # VPNBookScript v2 :global VPNBookpIfName "pptp-out1" :global VPNBookServerAddresses {"euro217.vpnbook.com";"euro214.vpnbook.com";"us1.vpnbook.com";"us2.vpnbook.com";"ca1.vpnbook.com";"de233.vpnbook.com";"fr1.vpnbook.com"} #:if ([:typeof $VPNBookServerAddresses] != "array") do={ # :set VPNBookServerAddresses {"euro217.vpnbook.com";"euro214.vpnbook.com";"us1.vpnbook.com";"us2.vpnbook.com";"ca1.vpnbook.com";"de233.vpnbook.com"} #} :global VPNBookErr false :global VPNBookPassFile "VPNBookPass.txt" :global VPNBookPass :global VPNBookRun #:global TToken "4.....................2" #:global TChatId "2342432...9" :global VPNBookServerIndex :if ([:typeof $VPNBookServerIndex] != "num") do={:set VPNBookServerIndex 0} :if ([/interface pptp-client get $VPNBookpIfName running]) do={ :set VPNBookRun true } else { :if (!$VPNBookRun) do={ :set VPNBookServerIndex ($VPNBookServerIndex + 1) :if ($VPNBookServerIndex>=[:len $VPNBookServerAddresses]) do={:set VPNBookServerIndex 0} } else { :set VPNBookRun false } :if (![/interface pptp-client get $VPNBookpIfName disabled]) do={/interface pptp-client set $VPNBookpIfName disabled=yes} :do {/tool fetch url="http://server/vpnbookpass.php" dst-path=$VPNBookPassFile} on-error={:set VPNBookErr true} :delay 2 :do {:set VPNBookPass [/file get $VPNBookPassFile contents]} on-error={:set VPNBookErr true} :if (!$VPNBookErr) do={ :if ([/interface pptp-client get $VPNBookpIfName password] != $VPNBookPass) do={/interface pptp-client set $VPNBookpIfName password=$VPNBookPass} :if ([/interface pptp-client get $VPNBookpIfName connect-to] != $VPNBookServerAddresses->$VPNBookServerIndex) do={/interface pptp-client set $VPNBookpIfName connect-to=($VPNBookServerAddresses->$VPNBookServerIndex)} :log info ("VPNBook: Attempt to connect to: ".($VPNBookServerAddresses->$VPNBookServerIndex).". Password: $VPNBookPass") # /tool fetch url=("https://api.telegram.org/bot$TToken/sendmessage\?chat_id=$TChatId&text=VPNBook: Attempt to connect to: ".($VPNBookServerAddresses->$VPNBookServerIndex).". Password: $VPNBookPass") keep-result=no /interface pptp-client set $VPNBookpIfName disabled=no } } 

Je recommande également d'ajouter la déconnexion de l'interface PPTP pour la déconnexion (événement on-down) dans le profil PPP afin que la reconnexion n'inonde pas du tout, même en 1 minute.

En conséquence, le script principal en 1 minute en cas de réception réussie d'un nouveau mot de passe augmentera la connexion pptp-out1.

 add change-tcp-mss=yes name=VPNBook on-down=\ ":if (![/interface pptp-client get pptp-out1 disabled]) do={\r\ \n /interface pptp-client set pptp-out1 disabled=yes\r\ \n}" only-one=yes use-compression=yes use-encryption=required use-ipv6=no use-mpls=no use-upnp=no 

Source: https://habr.com/ru/post/fr420373/


All Articles