New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Way to break 100% VisualCaptcha via checksum #24

Open
yanncam opened this Issue May 24, 2016 · 4 comments

Comments

Projects
None yet
3 participants
@yanncam

yanncam commented May 24, 2016

Hello VisualCaptcha team,

I have worked with VisualCaptcha solution for several month, on my projects and during security audits.
As penetration tester, I encountered recently an old VisualCaptcha solution (branch 5.x with API endpoints /start and /image) integrated into a CMS. I worked on this to find a way to break it, and it was successfull with this methodology :

  1. List all text-label solution for the VisualCaptcha
  2. Download all the image database used by VisualCaptcha
  3. Calculate checksum of each PNG downloaded
  4. Making an map with text-label corresponding to the right image's checksum
  5. Automatized with a Python script a call to "/start/1" ("1" to force a minimum number of image choice in the user session, that was 2 images in this old implementation of VisualCaptcha)
  6. Then download each "/image/0" and "/image/1"
  7. Calculate their PNG-checksum and search these values in the "map"
  8. Send the right "value" to the final page (100% captcha bypass)

After this successfull scenario I tried my script on the latest VisualCaptcha versoin (available on demo.visualcaptcha.com) and it doesn't work...

I dig again to understand "why it doesn't work on the latest version, and what security mecanism was added ?", then I found this issue : #2

Random bytes are added to each PNG (and audio) file delivered to the client's browser. This is the reason why my PNG checksum calculation failed (two same PNG visualy are not the same with checksum comparison).

So I updated my script to convert each PNG downloaded to JPG. These conversion delete all additionnal random data to make a comparable JPG file with the same checksum any time.

Via this mecanism, the final script works on all VisualCaptcha 5.x version, with random bytes added or not and with a 100% success rate (because the captcha solution is based on limited image database).

I encountered several times this kind of captcha (that are really appreciated for equipment like smartphone or tablet), so I decided to create a generic "VisualCaptchaBreaker" script to demonstrate the feasability of breaking this solution.

You can find the full script, default database and sample here:
https://github.com/yanncam/VisualCaptchaBreaker

Demonstration video against the demo.visualcaptcha.net page :
https://www.youtube.com/watch?v=fkfeDQqXNdk

I know that VisualCaptcha has already been broken by the past (describe in issues), but no generic script was created (usable with BurpSuite, proxy, custom configuration, etc.).
And other methods are OCR-based or need image-analysis library (slower). None of them seems to exploit the "simple checksum" method with JPG-conversion.

I think VisualCaptcha can be updated to add more randomization in image/audio to produce different checksum in PNG and after JPG conversion.
It's not a long-term solution, VisualCaptcha will be broken again via OCR or image-analysis method, but it will take more time for a potential attacker.
Plus, what do you think about the idea to add a "timer" (several second) between the "/start" call (captcha initialization) and the form submit with the captcha verification? For a simple "contact form" a user doesn't need to send the form with less than 1sec after it was displayed, so scripting attack against the form (and the captcha) will be slower.

VisualCaptcha is a good and well designed solution, but as all other "limited static-image database captcha solution", it can be broken.

Thanks for your reading and your interest,

Do not hesitate to contact me for more information,

Sincerely,

@BrunoBernardino

This comment has been minimized.

Collaborator

BrunoBernardino commented May 25, 2016

Wow, this is great! Thanks for the thorough exposition and explanation here (and for doing your research and understanding why certain things happen the way they do).

  1. What do you mean with "add more randomization in image/audio to produce different checksum in PNG and after JPG conversion"? Do you mean visually degrade the images? I know that would solve this issue, but would also cripple the UX, which is more important for this captcha, if we can only choose one of them.
  2. I like the idea of a timer, as an optional backend setting, though. Imagine there's a captcha for a login where the user gets it auto-filled. They'll take a second or two only to submit that form, and we want to allow that, right?

I'm currently focused on Oikon, and very open to taking in and reviewing PRs for visualCaptcha!

Thanks again.

@yanncam

This comment has been minimized.

yanncam commented May 25, 2016

Hello Bruno, thanks for your feedback and your comment.

Yes, I meant "degrade the images". I well understand that the UX is more important for VisualCaptcha than solve this kind of security issue, but there are some solutions to not degrade too much pictures and add some security features, like :

  • Doing LSB (less significant bit) modification on random pixel of each image dynamically : for visual experience and UX, there is no difference. But with few pixel changed a little, checksum breaking as demonstrated in this issue will not be able to work (even if PNG are converted to JPG, because pixel color will be kept after conversion, so each "same visually" PNG and JPG will have a unique checksum).
  • Timer integrated as backend option is the better idea to mitigate (or reduce) the number of form-capctha-protected-submission. This timer needs to be optional as you said, depending on the kind of form (login / contact / etc.).
  • With another timer and a counter, you can add another security mecanism : store in session the current IP address of the client's request, and the timestamp of the first captcha request. Then, increment a session-counter to count how many captcha are submited. If a same client (identified via his IP address) has submited more than X captchas in less than Y secondes, minutes or hours, then doesn't accept any captcha from this IP source during Z minutes (even if there are valid).
  • Other idea : to add significant security to a visual captcha, the implementation needs to use a very huge picture-database, so huge that this database can be compared to the "infinite". Via a such db, a potential attacker will not be able to enumerate all image and create his own dictionary to resolve VisualCaptcha. I know, it's unrealistic even if Google has created by the past a captcha with this approach (based on house-number or car-number dynamically found on GoogleStreetView).

So, how to increase the VisualCaptcha's picture-database without adding thousands images ? Some ideas :

  • Deliver image in protected web page with random MIME/accept-type (image/jpg, image/png, svg, gif, etc.). Each image will have different checksum because they are in different format.
  • Increase the "visible image database" (default 37 images) via several dynamic modification. For example, image of "the cat" is by default "a black cat with white background". It's possible to change the "cat color" (blue for example) and/or the background color (grey) then provide this dynamic picture to the client's browser and display the message "Click or touch the blue cat on the grey background". So a simple static image will have infinite variation with different color and each of these variation will come with unique checksum.
  • Modifying the image size (1 or 2px) dynamically. If the original image is intergrated into a "div" bigger than the image size, and if the image size have transparent background, the UX isn't altered. Checksum are unique too with this process.

These are just few ideas, but they could improve the solution I think.
Some more complex than others, I agreed.

In any case, if UX is the goal of VisualCaptcha, there will always be an opportunity to "break" this solution relying on security through obscurity.

Sincerely,

@BrunoBernardino

This comment has been minimized.

Collaborator

BrunoBernardino commented May 25, 2016

I love you've documented these here for others to take ideas from (to improve their own implementations of visualCaptcha).

These are all things people can do on their own implementations. Some become to hard to circumvent if we implement a "generic" solution, like the IP one, maybe even the timer one.

Different types of colors also start getting in the way of people with color blindness.

Increasing the image database is definitely something that could be easily done. The LSB is also an interesting technique.

@CrazyPython

This comment has been minimized.

CrazyPython commented Jul 12, 2016

@BrunoBernardino You need to change random pixels to mess up basic attackers. It won't prevent sophisticated attacks, but it's a start. Implementing IP-based blocking is a bad idea - two many Wi-Fi networks are plagued by this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment