Перейдём на страницу сайта Мегафон – Северный Кавказ. Отправка SMS - http://www.megafonkavkaz.ru/sms. Попробуем решить задачу, простую для человека, но не решаемую (а точнее почти не решаемую) для компьютера. Такого рода задача называется CAPTCHA.

CAPTCHA – это акроним, от выражения “Computer Aided Public Turing test to tell Computers and Humans Apart”. Собственно говоря, это Тест Тьюринга для различения компьютеров и людей. Иногда CAPTCHA называют обратным тестом Тьюринга. CAPTCHA может быть реализована различными способами. Иногда требуется ввести не одно слово, а несколько. Встречаются также задания, где надо найти общий элемент, присутствующий на 4-х изображениях или сказать о содержимом искаженного рисунка. Для людей с плохим зрением существуют звуковые тесты или задачи, требующие логического мышления. В нашем случае требуется распознать символы, размещенные на текстуре.

Из первичного анализа находим слабые стороны.

  1. Фиксированный шрифт, нет никаких искажений текста.
  2. Для отображения символов используются только 4 цвета.
  3. Символы легко отделяются от фона из-за хорошего контраста.

Распознавание сделать довольно легко путем прямого попиксельного сравнения каждого из символов со шрифтом.

Приступим.

/* Выдираем со страницы http://www.megafonkavkaz.ru/sms название картинки */

$Source = file_get_contents ('http://www.megafonkavkaz.ru/sms');
preg_match_all ('|svg-images/([^"]*)\?|is', $Source, $ImageName);

/* Создаём копию картинки у нас на диске */

$Image = ImageCreateFromPng ('http://www.megafonkavkaz.ru/svg-images/' . $ImageName[1][0]);

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

$Captcha = ImageCreateTrueColor (100, 20);
$CaptchaBackground = ImageColorAllocate ($Captcha, 255, 255, 255);
ImageFilledRectangle ($Captcha, 0, 0, 100, 20, $CaptchaBackground);

ImageCopyResampled ($Captcha, $Image, 0, 0, 0, 0, 100, 20, 100, 20);
ImageDestroy ($Image);
ImagePng ($Captcha, $ImageName[1][0]);
ImageDestroy ($Captcha);

/* В результате у нас на диске красуется такая картинка */

/* Далее получаем индекс цвета каждого пиксела этой картинки */

$Captcha = ImageCreateFromPng ($ImageName[1][0]);
list ($Width, $Height) = GetImageSize ($ImageName[1][0]);
for ($i = 0; $i < $Width; $i++) {
for ($j = 0; $j < $Height; $j++) {
$Pixels[$i][$j] = (ImageColorAt ($Captcha, $i, $j));
}
}

/* Для примера просмотреть значение индекса цвета каждого пиксела нашей картинки можно так */

for ($i = 0; $i < $Width; $i++) {
for ($j = 0; $j < $Height; $j++) {
echo $i . 'x' . $j . ' = ' . $Pixels[$i][$j] . '<br />';
}
}

Здесь 0 – черный, а 16777215 – белый. Из анализа captcha видно, что для отображения текста на картинке используются только 4 цвета, вот они:

1725025
1925170
4538477
6303773

Собираем черно-белую картинку путём отсеивания лишних цветов:

for ($i = 0; $i < $Width; $i++) {
for ($j = 0; $j < $Height; $j++) {

/* Если пиксель равен одному из цветов текста, присваиваем ему черный цвет (0) */

if ($Pixels[$i][$j] == '1725025' or $Pixels[$i][$j] == '1925170' or
$Pixels[$i][$j] == '4538477' or $Pixels[$i][$j] == '6303773') {
$Pixels[$i][$j] = 0;
}
else {

/* Если не равен, то белый (16777215) */

$Pixels[$i][$j] = 16777215;
}

/* Вновь собираем картинку */

ImageSetPixel ($Captcha, $i, $j, $Pixels[$i][$j]);
}
}
ImagePng ($Captcha, $ImageName[1][0]);
ImageDestroy ($Captcha);

После всех манипуляций получаем:

/* Далее ищем первый символ, т.е первый черный пиксель на картинке */

for ($i = 0; $i < $Width; $i++) {
for ($j = 0; $j < $Height; $j++) {

if ($Pixels[$i][$j] == 0) {

/* Его координаты записываем в переменные $IPX и $IPY */

$IPX = $i;
$IPY = $j;

/* Останавливаем поиск */

$j = $Height;
$i = $Width;

Теперь для каждого символа создаём условие. Например, для числа “1”:

/* От первой до последней точки символа */

if (
/* 1 */ $Pixels[$IPX][$IPY] == 0 &&
/* 2 */ $Pixels[$IPX + 1][$IPY - 1] == 0 &&
/* 3 */ $Pixels[$IPX + 1][$IPY + 10] == 0 &&
/* 4 */ $Pixels[$IPX + 2][$IPY - 2] == 0 &&
/* 5 */ $Pixels[$IPX + 2][$IPY + 2] == 0 &&
/* 6 */ $Pixels[$IPX + 2][$IPY + 10] == 0
)
{

/* Если условие выполняется, получаем 1-ый символ равный “1” */

$s1 = 1;

/* Задаём новую начальную координату для поиска 2-ого символа, $CX.
Координата последней точки “6”, $Pixels[$IPX + 2]
*/

$CX = $IPX + 2;

}

/* Далее для поиска второго символа будет правильным такое выражение */

for ($i = 0; $i < $Width; $i++) {
 for ($j = 0; $j < $Height; $j++) {
  if ($i > $CX) {
   if ($Pixels[$i][$j] == 0) {
     $IPX = $i;
     $IPY = $j;
     $i = $Width;
     $j = $Height;
     /*
Условие поиска */

}
}
}
}

/* Аналогично и для всех остальных символов */

Полную версию скрипта можно скачать здесь.

Данный вид взлома не был бы актуален, если бы при генерации изображения применялся какой-либо эффект, искажающий картинку. Например, волновое искажение по оси x и у.

Рекомендуем посетить сайт проекта по взлому CAPTCHA с примерами CAPTCHA-алгоритмов с разных сайтов и описанием их уязвимых мест.

Вроде бы всё, удачи.

 

Читай так же:

Оставить мнение