⬆️ ⬇️

Almost OCR to get VPNBook password. PHP + Mikrotik

Recently, VPNBook began to publish a password instead of direct text as an image. “Well, how is that?” - I thought and began to look for ways to solve this problem. We recognize the "picture" password VPNBook for PHP. And, of course, the script for Mikrotik.



I have already set up an automatic free PPTP VPN tunnel from VPNBook.com on my router (Mikrotik) and used it until recently successfully. I will not go into details, they are described in the article " Configuring automatic password retrieval for VPN on Mikrotik ". Before the problem, the password for the VPNBook could be simply extracted from the html page, for example, like this:



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


And more recently, the password has become a "picture". And the first thought was to use optical text recognition. I began to try online and offline services OCR, which could recognize the password. I say hello to Winand , with whom we have correspondence on this topic. In general, the last OCR I fumbled with was Tesseract, which “out of the box” defined the password, but with errors. But it can be taught new fonts, which I was going to do. When I selected a font that looked like a “picture” font, the thought arose that it was something simple, although it looked like a teminal from Windows or a terminus font from Linux. And voila - it turned out to be just a built-in PHP font with the number (size) 5. Next, I abandoned OCR and wrote a PHP script that looks for characters of the “picture” password using the generated dictionary. A dictionary is a set of images of possible password characters of the same color and size. The search is done by matching the images. Here is a simple reverse engineering. I assume that the current version of the image in the VPNBook will not last long, given its primitiveness.



Script vpnbook.php



Sprint returns a string-password.

')

 <?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. Password from twitter



From the vvsvic hint, I ’ll quote a simple alternative script implementation for extracting the password from the VPNBook twitter (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



The script needs to be called every minute from the scheduler. The script monitors the status of the PPTP connection and, when the connection is broken, calls the whole procedure for requesting a new password, so the microtic does not “flood attempts to open the connection for several hours with the wrong password, and reconnection is done in 1 minute. Also, on-error errors for fetch and file get are tracked here to more accurately determine that a password has been received.



 # 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 } } 


I also recommend adding the disconnection of the PPTP interface by breaking the connection (on-down event) in the PPP profile so that the reconnection does not flood at all even for 1 minute.



Accordingly, the main script will, within 1 minute in case of a successful receipt of a new password, raise the pptp-out1 connection.



 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/420373/



All Articles