Оперируем капчу на примере

66 комментариев

Здравствуйте!

В этой статье, пойдет речь, о еще нескольких приемах распознавания captcha защиты. Эти приемы я буду демонстрировать на подопытной капче. В качестве подопытной я выбрал капчу некоего Rafontes на которую я набрел когда искал материалы для предыдущей статьи Анализ алгоритмов генерации CAPTCHA.

Пример сгенерированной капчи:

Фон мне пришлось использовать другой, так как автор не выложил оригинальный (или я не нашел), но это не повлияет на результат.

Препроцесс

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

В первую очередь нам надо отделить фон от текста. Анализируем картинку и код генерации изображения. Налицо первые ошибки:

  • Используется один цвет для всего теста с кодом
  • Цвет для текста генерируется в диапазоне rand(0, 200), 0, rand(0, 200), для R G B соответственно (достаточно выделить цвета только в этом диапазоне)
  • Фон с большим количеством разных цветов (не сможет повлиять на статистику самого часто используемого цвета)

Теперь на основе этих фактов анализируем цвет каждого пикселя во всем изображении и выделяем самый часто-используемый. Получился 8C0074 (в hex-виде). Задаем от него небольшую погрешность и выделяем этот цвет и немного похожие на него с учетом погрешности. Все выделенные закрашиваем черным, остальные белым. Получается такая картинка:

Как видите, мы получили текст, практически без искажений. Правда осталась одна линия, но у нас хитрый алгоритм обрезки (о нем ниже), на который эта линия повлиять не сможет.

Теперь выделяем участок с кодом.
Так как наш текст это самое темное пятно, то и пытаемся алгоритмически найти это пятно. Сначала определяем границы по горизонтали:

Теперь определяем границы по вертикали:

Линия осталась тут потому что то тот участок до сих пор воспринимается функцией как очень темный участок. Но теперь на основе этих границ уточняем их по второму кругу, по горизонтали:

А почему теперь эта линия убралась спросите вы? Потому что теперь анализировалось меньше «столбцов пикселей» и при анализе алгоритмом выявилось что в данном участке слишком много столбцов с одним черным пикселем, а следовательно это шум. Теперь уточняем границу по вертикали:

Так как область определения стала меньше то, теперь тот та линия что была шумом стала недостаточно темным пятном и была удаленна  совсем. Вот мы и получили участок с текстом. Конечно этот алгоритм иногда не совсем верно выделяет нужную область. Но по моим тестам число НЕверных определений не превышает 5%, чем собственно можно пренебречь.

Сегментация

Теперь наша задача разбить полученное изображение на отдельные участки с символами.

Конечно можно расчитывать, искать границы символов, и тд. Но если опять проанализировать код генерации, то можно найти еще одну ошибку.

  • Отступ между каждым символом всегда равен 15 пикселям

Конечно иногда из за размера символов они выходять за рамки пятнадцати пикселей, тогда приходится откусывать от соседнего символа еще один-два пикселя. Но это не критично. Вообщем разбиваем картинку:

Теперь как мы видим вокруг некоторых символов есть пустая область. А нам все таки нужен именно сам символ. Применяем функцию обрезки для каждого символа, и полученные изображения вписываем в прямоугольники размером 17×27:

Именно такие изображения по отдельности будут подаваться на распознавание.

Распознавание

Распознавание мы будет производить БЕЗ всяких новомодных нейронных сетей. Почему? Решающую роль сыграло то что, нет ни одной достойной библиотеки под винду. Пользоваться будем обычным распознаванием по маскам символов.

Для этого мы, имея доступ к исходным кодам, нагенерируем кучу черно-белых картинок для каждого символа с разными углами поворотов (от двух до четырех градусов), и разными размерами шрифта (от 20pt до 30pt). Каждую полученную картинку, как вы догадались, вписываем в прямоугольник размером 17×27. Каждое полученное изображение называется маской.

Для каждой буквы я нагенерировал по 10-15 масок. Впринципе этого достаточно, но если увеличить количество масок, то можно увеличить процент распознавания.

Вообщем все изображения подающиеся на вход, сравниваются с масками, и алгоритм определяет какая маска больше всего соответствует нашему изображению, на основе этого делая вывод о том какой символ написан на картинке.

Результаты

Для теста я получил с помощью генерации картинки и ее разбиения на символы 200 зашумленных символов. И програмно запустил тест. И внимание!
Итог: Удачных: 172 Ошибок: 28 Процент: 86%
То есть каждый символ на капче будет распознан успешно с вероятностью в 86%!

Немного математики. Посчитаем процент вероятности успешного распознавания капчи:
Для 4-символьных капч: 0.86^4=54%
Для 5-символьных капч: 0.86^5=47%

В среднем каждая вторая капча будет успешно распознанна.

Если учесть что на каждую капчу приходится около 1 секунды, а 2 секунды в среднем будет приходится на успешное распознавание. То это очень отличный результат.

Исходники

Архив со скриптами (на php):
CaptchaBreaker_scripts
Архив масок (распаковать в папку ./masks/):
CaptchaBreaker_masks

Скрипт сам генерирует, и сам же распознает капчу. Пример работы скрипта на картинке приведенной в качестве примера автором капчи:

(Картинка кликабельна)

  1. Василий

    Сложной конечно назвать такую капчу нельзя, но и простой тоже. Поражает та легкость с которой вы описали ее взлом…
    Скажите сколько времени у вас ушло на разработку?

    1. Дмитрий Амиров Автор

      Не очень много около двух часов в сумме на код, и часа полтора на тесты для выявления оптимальных параметров. У меня имелись уже некоторые наработки по распознаванию капч, оставалось их немножко подточить под этот случай. =)

  2. Fenix

    50% это очень много. Этого хватит чтобы заспамить все что можно) Неплохо.

  3. Squanto

    Intellect, Вы гениальны, всё так просто, классно)
    Как думаете, если на сайте каптча стоит в виде ответов на вопросы (example: «Введите недостающий цвет флага РФ — белый, красный, ….?» — Ответ:»Синий»)
    И таких вопросов около 1000, это надежная защита? Или лучше использовать простые арифметические примеры (example: 3+4=? ответ — 7)
    ^P.S. вопрос из личного интереса^, т.к.
    есть сайт на Drupal, только начал этими вещами заниматься.

    1. Дмитрий Амиров Автор

      Сказать чесно, оба предложенных Вами варианта не выдерживают самой простейшей критики. К примеру для первого варианта достаточно один раз собрать полную базу вопросов-ответов и защита станет бесполезной. А для второго варианта достаточно написать наипростейший калькулятор.

      Но вообще из двух Ваших вариантов первый вариант защищенее, так как собрать базу вопрос-ответ все таки будет намного сложнее. Но при этом подумайте о конечном пользователе, не знаю как вам, но меня всегда раздражало подбирать что же имел ввиду автор защиты, так как часто встречаются неоднозначные вопросы.

  4. Евгений

    Intellect, могли бы вы мне написать, есть небольшое предложение, думаю вам будет интересно.

  5. Сэм

    Как создавать маски для остальных символов? Либо, если таковые есть, хотелось бы воспользоваться.

    1. Дмитрий Амиров Автор

      Берете ч/б изображение символа. В цикле проходите все пиксели этого изображения, если пиксель церный записываете единичку, если белый то записываете ноль. Полученная строка и будет маской символов.

  6. Pasha

    Здравствуйте. Добавил Вас в icq. Мой номер 3 восемь 09 четыре 2 девять. Есть предложение. Спасибо!

  7. Саша

    Intellect, пришлите и мне пожалуйста сообщение со своего адреса. Хочу заказать у вас маленькую разработку в этом направлении.

    1. Дмитрий Амиров Автор

      Да и какбы приходят) По 30-50 спам сообщений ежедневно. Благо хватает простенькой javascript защиты =)
      Ну и плюс ручная перемодерация, но за полгода существования этого блога, ни одно спам сообщение не прошло через javascript защиту…

  8. What!

    Решающую роль сыграло то что, нет ни одной достойной библиотеки под винду.

    Ха-ха, о да это не несомненно сыграла решающую роль. Какую не выбери библиотеку — нет никакой разницы что под *nix что под Win, они почти все на C/C++ — отсюда кроссплатформенность почти всех библиотек. Скорей решающую роль сыграла не знания нативных ЯП а не «достойной библиотеки под винду».

    1. Дмитрий Амиров Автор

      Уважаемый, зря вы так. Мне была интересна разработка именно на PHP, поскольку это проще чем реализовывать тоже самое на нативных языках. И для PHP есть только никсовые либы (и те кстати довольно убоги).

      Но вообще факторов в пользу отказа от нейронных сетей было множество:
      — В данном случае это тоже что стрелять из пушки по воробьям
      — Отсутствие нормальной либы для PHP
      — Больше гемора

      Но для меня решающим фактором стало именно отсутствие либы, а не «не знания нативных ЯП» так как некоторыми я все же владею на должном уровне.

  9. Дмитрий

    Что вы можете посоветовать с распознаванием этой капчи


    или вот еще:

    есть вообще варианты?

    1. Дмитрий Амиров Автор

      Чесно говоря посоветовать ничего не могу, капча довольно сложная. Но, как говорится варианты есть всегда, все упирается в ресурсы.

      PS: я подправил ваш пост, вместо ссылки на архив повесил пару изображений из него, надеюсь вы не против.

      1. Дмитрий

        Что вы имеете ввиду под ресурсами? Компьютерные мощности или финансы? Капчу я выбрал намеренно сложную для интереса. Сейчас думаю какой лучше алгоритм применить для сегментации данного образца.

        1. Дмитрий Амиров Автор

          Под «ресурсами» я подразумеваю все-таки затраченное время на разработку алгоритмов, то есть в итоге финансы)

          Любую капчу можно взломать наняв пару сотен программистов, десяток математиков и прочих специалистов, но вот стоит ли оно того. Это я утрирую, конечно. Для этой капчи хватит и одного программиста, но вот хватит ли у него терпения)

          Подсказать какую-то конкретику я не смогу, т.к., откровенно говоря, надо садится, анализировать и придумывать какой-то алгоритм, но я думаю у вас все получится и без моих подсказок.

  10. Гребень

    Автор, что за фигня :Warning: file(masks/CaptchaBreaker_masks/r) [function.file]: failed to open stream: Permission denied

    1. Гребень

      пришлось переписать функцию file на

  11. Имя

    Большое спасибо, Вам, Intellect. Легкость и адекватность Ваших статей, заслуживают уважения.

    1. Дмитрий Амиров Автор

      И Вам большое спасибо, мне очень приятно слышать такие слова =)

  12. Bagir

    Дмитрий,

    для такой капчи проще воспользоваться сервисом по разгадыванию капчей. Но если хочется помучаться…
    Шум отсюда не удалить, но он не изменяет геометрию букв, он накладывается, поэтому его можно просто проигнорировать.
    Не совсем понятно, но как я вижу, тут каждая буква либо дается курсивом, либо поворачивается без изменения геометрии.
    Соответственно, нарезаешь капчи с прямыми и курсивными буквами без шума.
    Анализируешь картинку по столбцам, нижние пики дадут границы букв.
    Разрезаешь по буквам, и вращаешь нарезанные куски. Анализируя опять их границы, и при минимальной ширине буквы ты получишь нужный градус вращения.
    Потом сопоставляешь с нарезанной капчей, анализируя только нули и игнорируя единицы, то есть игнорируя пустые области. Таким образом шум не будет тебе мешать, и с некоторой погрешностью сопоставления букв, которую предстоит вычислить экспериментально, капча будет разгадана.

  13. AK

    Intellect, сильно.
    Я использую код описанного генератора капчи на своем проекте, с доработками.
    Если не сложно, нельзя ли получить комметарии и замечания, как от специалиста?
    ЗЫ. дырка с редактированием куки закрыта — md5-хэш генерируется от строки с капчи + salt.

    1. Дмитрий Амиров Автор

      А какие именно вы хотите услышать комментарии и замечания?)

      1. AK

        ну не знаю…
        хвалебные или ругательные )
        примерную степень устойчивости к взлому по сравнению с прототипом.

        1. Дмитрий Амиров Автор

          Да так то я понял) Мне бы посмотреть, что именно хвалить или ругать…

          1. AK

            я то в кодинге — ламо патентованное. по образованию — биохимик )
            вот и интересно мнение спеца.

            1. Дмитрий Амиров Автор

              я то в кодинге — ламо патентованное

              интересное выражение :D повеселили… Но впринципе да — каждому свое) биохимик — это для меня звучит круто

              А касательно капчи — если не ошибаюсь то используется та же капча, что и в этой статье. Ваша немного сложнее за счет наложения символов, а также большего их колличества.

              Но главный минус остался — одинаковое расстояние между символами. Также используется несколько одних и тех же фоновых картинок. То есть если подкрутить уже имеющийся скрипт на очистку от фона, и подобрать коэфициенты, то я думаю можно будет получить процентов 10-20 успешных распознаваний особо не утруждаясь.

              Впрочем, мое мнение как «спеца» (только не обижайтесь): у вас не настолько популярный ресурс, чтобы ставить сложные капчи, и я бы вам посоветовал бы ее даже максимально упростить (всех обычных спам ботов это отсеит).

              1. AK

                понял, благодарю.

                только не обижайтесь

                да ну, вот еще… чего на правду обижаться? )
                он по умолчанию не может быть популярным — местный, ориентированный на одну кафедру одного ВУЗа.

  14. Free

    Доброго времени суток!!!
    Хотел использовать ваш скрипт в личных корысных целях но увы знаний не хватает.
    Не могли бы вы помочь в заполнении пробелов в знаниях.

    образец капчи которую охота пропускать

    1. Дмитрий Амиров Автор

      Да вобщем тут все просто…

      Цвет шрифта всегда один. Его оставляем черным, остальные пиксели которые другого цвета заменяем белым цветом. Выделяем участок с надписью. Между символами есть отступ, разбиваем по нему на символы. Искажений в надписи нет, поэтому распознать символы труда не составит (читайте: справится любой, даже начинающий, программист).

      Вы меня конечно извините, помочь в заполнении пробелов я могу, но, если чесно, реализовывать всю систему за вас просто так, тратя свое время, я не горю желанием.

      PS: подправил ваш комментарий, вставив картинку прямо в сообщение, надеюсь вы не против.

  15. Free

    А не могли бы вы выложить скрипт распознавания с комментариями внутри ибо 1 комментарий на 100 строк в виде //Определяем самые часто используемые цвета.

    Ставит в не то что затруднение в тупик прямо таки.
    C уважением к труду знающих людей!.

    1. Дмитрий Амиров Автор

      Гм… да вот ведь какая штука, я привык писать код так чтобы было все понятно. Например в этих скриптах вполне говорящие названия функций, да и сам алгоритм не вычисляет никаких гиперквантовых суперпозиций. Он достаточно прост. И если посидеть, покумекать пару часов, то можно разобраться в алгоритме более чем достаточно, только лишь надо иметь немного опыта.

      А чтобы выложить скрипт распознавания с комментариями, мне прийдется сесть и опять же тратить свое время, вписывая эти комментарии. Я человек не ленивый, но я не вижу в этом целесообразности. Просто, прошу, не обижайтесь, тому кто не понял алгоритм так, врятли помогут комментарии.

      Извините.

    2. Дмитрий Амиров Автор

      Но впрочем хорошо, сейчас добавлю общие комментарии к функциям.

      1. Дмитрий Амиров Автор

        Обновил архив.

        Боюсь что более понятнее прокомментировать не смогу. Но надеюсь вы сможете разобраться что к чему.

          1. Free

            Сталкнулся с новой делемой !

            можно записать код так что бы он был одним запросом а не двымя разными?

  16. edik

    интересная статья. спасибо!

    вопрос: хрумер когда качает картинку для раскодировки, в каком формате, аscii?

    1. Дмитрий Амиров Автор

      Чесно говоря не знаю, я хрумером не пользовался никогда)

  17. Дмитрий

    Здравствуйте, а возможно ли такую капчу расшифровать?
    Вот несколько примеров:


    1. Дмитрий Амиров Автор

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

      1. Дмитрий

        Спасибо за ответ, мне просто интересно было можно или нет. Буду пробовать, может что и получиться.

  18. Виктор

    А как вставить свою аналогичную картинку для распознавания. Вернее куда в какое место?

    1. Дмитрий Амиров Автор

      Боюсь что вам прийдется модифицировать исходники. А точнее — откройте index.php. Там есть такая строка:

      заменяете на это и вставляете свою картинку:

      1. Виктор

        Спасибо, но ошибку выдало, блин((
        Error: width=192
        И картинка не велика по сути

        1. Дмитрий Амиров Автор

          Ну так извиняйте, вы же сами сказали что хотите вставить «свою аналогичную картинку для распознавания» :) На деле — картинка у вас другая, а алгоритм же заточен под конкретную капчу описанную в статье.

          Боюсь что вам придется переработать большую часть всего кода. Но ваша капча довольно простая, а алгоритм из статьи чуть сложнее чем требуется вам. Я бы рекомендовал написать свой велосипед под это дело)

          1. Виктор

            Спасибо.
            Понял направление, куда копать.
            Исходники кода — самое главное.

  19. Максим

    Здравствуйте, Вы вручную генерировали маски?
    Для полноты скрипта не хватает пару функций по генерации масок на основе изображений, где:
    1. Ваш алгоритм распознал капчу;
    2. Создал из распознанного маски;
    3. Разложил «по полочкам».

    А нам, любителям халявы и Вашего блога, остается только пробежать по папкам и удостовериться в том, что там лежат соответствующие маски. Ну вы понимаете, что скрипт не положил в папку «1» маску от неверно распознанной буквы «l» ( маленькая L).

    Это был бы изи-то-юз вей)

  20. Solomon

    Спасибо вам огромное за такой код,но вопрос теперь возник в другом,как например взять капчу с вк или facebook,она же генерируется каждый раз новая и с новым id,сам веб-программист,сам делал так,а вот теперь не знаю,как скопировать такое изображение.Не подскажите,если вам не трудно?

Добавить комментарий

Прочли запись? Понравилась? Не стесняйтесь, оставьте, пожалуйста, свой комментарий. Мне очень интересно, что вы думаете об этом. Кстати в комментарии вы можете задать мне любой вопрос. Я обязательно отвечу.

Вы можете оставить коментарий анонимно, для этого можно не указывать Имя и email. Все комментарии проходят модерацию, поэтому ваш комментарий появится не сразу.