Перейдём на страницу сайта Мегафон – Северный Кавказ. Отправка SMS - http://www.megafonkavkaz.ru/sms. Попробуем решить задачу, простую для человека, но не решаемую (а точнее почти не решаемую) для компьютера. Такого рода задача называется CAPTCHA.
CAPTCHA – это акроним, от выражения “Computer Aided Public Turing test to tell Computers and Humans Apart”. Собственно говоря, это Тест Тьюринга для различения компьютеров и людей. Иногда CAPTCHA называют обратным тестом Тьюринга. CAPTCHA может быть реализована различными способами. Иногда требуется ввести не одно слово, а несколько. Встречаются также задания, где надо найти общий элемент, присутствующий на 4-х изображениях или сказать о содержимом искаженного рисунка. Для людей с плохим зрением существуют звуковые тесты или задачи, требующие логического мышления. В нашем случае требуется распознать символы, размещенные на текстуре.
Из первичного анализа находим слабые стороны.
- Фиксированный шрифт, нет никаких искажений текста.
- Для отображения символов используются только 4 цвета.
- Символы легко отделяются от фона из-за хорошего контраста.
Распознавание сделать довольно легко путем прямого попиксельного сравнения каждого из символов со шрифтом.
Приступим.
/* Выдираем со страницы 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-алгоритмов с разных сайтов и описанием их уязвимых мест.
Вроде бы всё, удачи.
Читай так же: