Решение MintEye CAPTCHA в 23 строки кода

http://www.jwandrews.co.uk/2013/01/breaking-the-minteye-image-captcha-in-23-lines-of-python/
  • Перевод
Как заядлый читатель HAD я был заинтересован этим постом, описывающим способ взлома аудиокапчи MintEye. Графическая версия также выглядела довольно интересно, так что я подумал, что будет забавно взломать и её.

Вот один из примеров графической капчи MintEye:



Для решения нужно всего лишь подвигать слайдер и выбрать неискажённый вариант изображения. В комментариях на HAD было несколько довольно наивных на мой взгляд предложений решения капчи, основанных на поиске прямых линий. Однако, подобные варианты не сработают с примерами, подобными указанному выше (т. е. содержащим малое количество прямых линий).

После некоторых раздумий я нашёл хороший, надёжный и, на удивление, простой способ разгадывания капчи. Вот вся его реализация на Python:

import cv2
import sys
import numpy as np
import os
import matplotlib.pyplot as plt
 
if __name__ == '__main__':
 
    for dir in range(1,14):
        dir = str(dir)
 
        total_images = len(os.listdir(dir))+1
        points_sob = []
 
        for i in range(1,total_images):
            img = cv2.imread(dir+'/'+str(i)+'.jpg')
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
            sob = cv2.Sobel(gray, -1, 1, 1)
            points_sob.append(np.sum(sob))
 
        x = range(1,total_images)
        res = np.argmin(points_sob)+1
        print res
        plt.plot(res,points_sob[res-1], marker='o', color='r', ls='')
        plt.plot(x, points_sob)
 
        plt.savefig(dir+'.png')
        plt.show()


(Обратите внимание, что большая часть кода относится к открытию изображения и построению графика. Такие функции, как автоматический разбор изображений и возврат готового результата оставим спаммерам как домашнее задание).

Суть метода в следующем: чем больше изображение «скручено», тем длинее границы. Это можно заметить на картинке, представленной выше, но есть и более наглядный пример:



Обратите внимание на увеличение длины чёрного прямоугольника. Для того, чтобы использовать это, нам нужно посчитать сумму длин границ изображения. Простейший способ сделать это — взять производную изображения (в предложенной выше реализации используется оператор Собеля) и сложить результаты (рекомендуется к прочтению статья о том, как работает оператор Собеля). Затем мы просто выбираем изображение с наименьшей «длиной границ» — оно и будет верным ответом.

Результаты впечатляют, 13 из 13 мною скачанных капч были решены верно этим способом. Эти графики показывают номер изображения на оси Х и «длину границ» на оси Y. Красной точкой отмечен верный ответ.


Интересно, что зачастую абсолютно неискажённое изображение на графике отображается как пик. Это обычно значит, что мы промахнулись с верным ответом на одну картинку влево или вправо (что, впрочем, принимается MintEye как корректный ответ). Происходит это обычно потому, что неискажённое изображение кое-где выглядит чётче и границы выделяются точнее, что влияет на конечную сумму длин.

В завершении хотелось бы сказать, что данная CAPTCHA по своей архитектуре не устойчива ко взлому. Простое «скручивание» изображения всегда может быть легко замечено вышеописанным методом вне зависимости от исходного изображения.
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 51
  • +5
    Спросили бы «Какое изображение скручено по часовой?».
    • +29
      «Какое изображение забавнее выглядит?»
      • +17
        «Какое изображение я загадал?»
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          А смысл подсовывать капчу ботам, если они её всё равно обойдут? Имхо, намного удобнее и действеннее ловушки ставить.
          • НЛО прилетело и опубликовало эту надпись здесь
            • НЛО прилетело и опубликовало эту надпись здесь
              • +1
                Человек не будет, а «шпана и неадекват» с деньгами, заплативший за скрипт взлома каптчи — увы, будет =).
                • НЛО прилетело и опубликовало эту надпись здесь
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              Можно было бы сделать такую штуку: если вы бот, то введите капчу с картинки. :)
              • +12
                Вы недооцениваете невнимательность и глупость некоторых пользователей) Потом сотнями посыпятся вопросы «ПАЧИМУ НИРАБОТАЕТ????? Я ВСЁ ПРАЛЬНО ВЫБИРАЮ, А МЕНЯ НИПУСКАЕТ!!!!» :)
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Если каптчу будут распознавать только боты, это тоже хорошо: не распознал белый текст на белом же фоне — значит, человек ты, проходи, милейший!
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • 0
                      Любая общая каптча очень легко ломается хотя бы одним из этих способов:
                      а) Аутсорсом живым индусам/китайцам (которые только и делают, что целый день разгадывают присылаемые им каптчи за копейки)
                      б) Пробросом каптч по схеме: держим какой-нибудь популярный порносайт, на котором крутим каптчу, но не свою, а с ломаемого ресурса. Живой человек ради контента разгадывает, а мы для валидации отправляем его ввод на целевой сервер. Сервер сказал: «свой, проходи» — говорим то же самое на своём ресурсе.
                      Имхо эта борьба щита и меча никогда не закончится, сколь бы искусно изощрённые методы защиты ни придумывали. До сих пор нет 100% защиты от взлома реальных банковско-денежных систем (включая фальшивомонетчество), хотя что-что, а деньги защищать есть огромный стимул и имеются средства.
                      Кажись, Митник ещё сказал, что если в системе есть человеческий фактор — она ломается проще простого =).
                      • НЛО прилетело и опубликовало эту надпись здесь
              • 0
                а как быть, если на картинке изначально будет что-то вроде спирали, да еще и с нечеткими линиями? :)
                • 0
                  Самое страшное если оно еще и скручиваться в противоположную сторону будет.
                  • 0
                    В результате скручивания они станут сильно чётче и Собель их надетектит чуть более чем дофига.
                    И к стати сказать далеко не только Собель, но и любой другой оператор выделения края.
                    • +10
                    • +2
                      В демо проверил неправильный ввод.
                      «No, Mr. Robot, you shall not pass!»
                      Убило.
                      • 0
                        hashcash кажется поможет
                        • 0
                          Вообще, скручивание плодит края, так что задачу можно решать анализом спектра пространственных частот.
                          Или использовать оператор выделения края оптимизированный вообще не находить краёв в нормальном изображении, а только когда скрутка их наплодит, и решение принимать на основании суммы всех пикселов после детектора, которую можно посчитать и в самом детекторе. Минимальное значение, суть не искаженное изображение.
                          • 0
                            Идея — шикарна.

                            Вместо слэша при сборке пути до картинки нужно использовать os.sep
                            • +5
                              os.path.join лучше
                              • 0
                                Чем лучше? В конкретном коде.
                                • +1
                                  os.path.join лучше, потому что:
                                  * умеет правильно работать с абсолютными и относительными путями
                                  * не добавит дублирующих слешей
                                  * эта функция предназначена для формирования путей

                                  Потренируйтесь, и напишите свою функцию которая будет работать аналогично os.path.join
                                  Вот примеры для тестов

                                  os.path.join('/home','usr')
                                  os.path.join('/home/','usr')
                                  os.path.join('/home/','/usr')
                                  


                                  • 0
                                    Зачем мне писать уже готовую функцию?
                                    Зачем рассуждать о преимуществах использования данной функции в отрыве от конкретной ситуации?

                                    Я предлагаю исправить код на:
                                    img = cv2.imread(dir + os.sep + str(i) + '.jpg')

                                    Вы на:
                                    img = cv2.imread(os.path.join(dir, str(i) + '.jpg'))

                                    Весь спор — не более чем мнение каждого из нас о том, что такое «pythonic way».
                                    Мне нравится мой вариант.

                                    Кто-то может и вместо оставшегося плюса в вашем варианте какой-нибудь «более правильный» способ формирования строки обосновать. Добавив этим (с моей точки зрения) нечитаемости и наколбасив символов, которые можно не колбасить.
                                    • 0
                                      Я не говорю, что вашем варианте есть изьян.

                                      Как и pawnhearts я утверждаю, что os.path.join — правильнее использовать как в общем так и в данном кокнретном случае. Правильнее — потому что всегда для склейки пути стоит использовать os.path.join и забыть о проблеме переносимости, дубликатов слешей, относительности путей,… Даже на секунду не надо задумываться, питоник/непитоник, больше символов/меньше, для склейки путей надо использовать os.path.join

                                      По поводу читабельности и «наколбасить» символов тоже не соглашусь. Код

                                      img = cv2.imread(os.path.join(dir, '%s.jpg'%i)) 
                                      

                                      отлично читается, тут дословно написано: «объединиться путь к файлам»

                                      Как только в коде вы увидите os.path.join — значит формируется путь к файлу, когда в коде используются знакомые общепринятые конктрукции — такой код всегд будет читаться лучше.
                                      • 0
                                        Мне нравится.

                                        Я к стыду своему думал, что минимальный код для форматирования строки:
                                        '%s.jpg' % (i)
                            • +1
                              Есть еще такой вариант решения капчи MintEye с использованием голосовых подсказок и гуглового text2speech API — gist.github.com/4520930
                              Демо: www.youtube.com/watch?v=u0M7gmS5Eg0
                              • 0
                                Интересно, будет ли работать такой подход — покрутить на разные углы и прокоррелировать с исходным изображением? Предположительно, наиболее закрученные изображения должны давать более высокие значения корреляции при одинаковых углах поворота.
                                • +1
                                  Просто выводить 3 разных картинки, 1 из которых не скручена.
                                  • +2


                                    Возможно, немного сложнее оригинала, но всяко проще рекапчи. Как такое разгадывать будете?)
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • +2
                                          А, извиняюсь, вижу слайдер. Хм, в любом случае, если вместо морфинга там будет даваться несколько различных изображений, одно из которых не искажено, то разгадать капчу станет сложнее.
                                          • 0
                                            А потом капчу спросит гугл.
                                          • 0
                                            Неужто нет алгоритма, который определит, что большинство линий изогнуты по одинаковому алгоритму? :) В скрученном изображении не бывает прямых, каждая линия — спиралевидна.
                                            • 0
                                              Можно использовать разные алгоритмы искажения. Например, как в эффектах Photo Booth:



                                              Но, как было сказано выше, даже если разместить 6 картинок с одной правильной, то при случайном тыке — будет 30% правильных распознаваний, что вполне себе нормальный результат.

                                              • +2
                                                9 картинок, 3 правильные
                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                  • 0
                                                    c(9,3)=84, все равно большая вероятность угадать
                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                      • 0
                                                        Я уже не помню комбинаторику, разве не 1/9*1/8*1/7? В любом случае этот шанс достаточно низок, чтобы при разумном количестве попыток блокировать ip на часов 6 :).
                                                        • НЛО прилетело и опубликовало эту надпись здесь
                                            • 0
                                              А если скручивание будет относительно нескольких центров вместо одного — сработает?
                                              • 0
                                                А вы сами-то такое решите, с несколькими слайдерами? :)

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.