Здравствуйте. Поставил DVWA, тренируюсь. На 2-х уровнях безопасности провел инъекцию, на 3-м стоит сабж. Как я понял обойти его можно, даже нужно. Только как? PHP: <?php if (isset($_GET['Submit'])) { // Retrieve data $id = $_GET['id']; $id = stripslashes($id); $id = mysql_real_escape_string($id); if (is_numeric($id)){ $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'"; $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' ); $num = mysql_numrows($result); $i=0; while ($i < $num) { $first = mysql_result($result,$i,"first_name"); $last = mysql_result($result,$i,"last_name"); echo '<pre>'; echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last; echo '</pre>'; $i++; } } } ?>
http://php.net/manual/en/function.mysql-real-escape-string.php Если magic_quotes_gpc ON и сначала stripslashes, то получается 2-ой эскейп magic_quotes_gpc - это единственная проблема у mysql-real-escape-string и она уходит в прошлое, потому что никто не включает эту опцию
phpdreamer Если ты считаешь что этот код уязвим, покажи реализацию плз. Та цитата, которую ты привёл, говорит о том, что при MQ=on НАДО убирать слеши, и тут они убираются. Но это не секурити проблема. Да, данные заэскейпяться дважды, но скуль ты не проведёшь, т.к. бекслеши тоже заэскейпятся. Это можно было-бы проделать при mysql_escape_string которая не учитывает кодировку, но тут... Да и это вобщем-то не всё. Даже если мы прорываем mysql_real_escape_string дальше идёт is_numeric, так что... Вобщем у кого есть реальзация баги, было-бы интересно взглянуть, но я склоняюсь к тому, что разрабы курнули
http://www.dvwa.co.uk/ Тренировачная площадка для хакера. 3 уровня сложности. Легкий и средний прошел, но тяжелый не выходит...
stripslashes и mysql_real_escape_string тут вообще никакой роли не играют, проверка входных данных осуществляется функцией is_numeric, а его ты не пройдешь никак
Навряд ли конечно, но может будет полезно, is_numeric() пропускает хекс PHP: $test = is_numeric('0x3a'); var_dump($test); возвращает bool(true), хз как это можно использовать тут, но может наведет кого на мысли.
PHP: <?php //hex('union+select') -> 0x756e696f6e2b73656c656374 $test = is_numeric('0x756e696f6e2073656c656374'); var_dump($test); ?> bool(false) откуда такая инфа ?
У меня 0x756e696f6e2073656c656374 возвращает true. Тестилось на Apache/2.2.8 (Win32) PHP/5.2.6 -------- инфа взята с бложека разора, http://raz0r.name/mysli/phpids-za-i-protiv/ вычитано в коментах
0x3a пропускает потому что оно число в hex (13) 0011 (2^0 + 2^1) + 1010 (2^1+2^3) а текст пропускать не может
Konqi, почему тогда 0x756e696f6e2073656c656374 у меня тоже возвращает true ? --------- Протестировал еще на PHP Version 5.2.17 (linux) тоже вернуло true
Windows NT/ php 5.1.6 - false Linux / 5.2.6 - true Linux / 5.2.17 - true хм =\ p.s если вернемся к теме, то ясно становится, если даже is_numeric Поможет обойти фильтр, то вес запрос все равно в hex виде не отправишь в бд, база операторы в хекс виде не поймет, так что с этим все равно облом, но тему is_numeric стоит исследовать..
PHP: <?php function conv($string, $hex='') { for ($i=0;$i<strlen($string);$i++)$hex .= dechex(ord($string[$i])); return '0x'.$hex; } $data = array('union select 1 from table#', '$%^&*(Jkabhsdf', 'test', 'UniON/**/SELECT/**/1', '-1/*!UnioN SELEct*/1,2,3'); foreach($data as $str) { ob_start(); var_dump(is_numeric(conv($str))); $dump = ob_get_contents(); ob_end_clean(); print "Str: {$str}\nHex value:".conv($str)."\nis_numeric? - ".trim($dump)."\n"; print "\n--------------------\n\n"; } ?> Code: Str: union select 1 from table# Hex value:0x756e696f6e2073656c65637420312066726f6d207461626c6523 is_numeric? - bool(true) -------------------- Str: $%^&*(Jkabhsdf Hex value:0x24255e262a284a6b616268736466 is_numeric? - bool(true) -------------------- Str: test Hex value:0x74657374 is_numeric? - bool(true) -------------------- Str: UniON/**/SELECT/**/1 Hex value:0x556e694f4e2f2a2a2f53454c4543542f2a2a2f31 is_numeric? - bool(true) -------------------- Str: -1/*!UnioN SELEct*/1,2,3 Hex value:0x2d312f2a21556e696f4e2053454c4563742a2f312c322c33 is_numeric? - bool(true) Если же убрать 0x в хекс значении: PHP: <?php function conv($string, $hex='') { for ($i=0;$i<strlen($string);$i++)$hex .= dechex(ord($string[$i])); return $hex; } $data = array('union select 1 from table#', '$%^&*(Jkabhsdf', 'test', 'UniON/**/SELECT/**/1', '-1/*!UnioN SELEct*/1,2,3'); foreach($data as $str) { ob_start(); var_dump(is_numeric(conv($str))); $dump = ob_get_contents(); ob_end_clean(); print "Str: {$str}\nHex value:".conv($str)."\nis_numeric? - ".trim($dump)."\n"; print "\n--------------------\n\n"; } ?> Code: Str: union select 1 from table# Hex value:756e696f6e2073656c65637420312066726f6d207461626c6523 is_numeric? - bool(false) -------------------- Str: $%^&*(Jkabhsdf Hex value:24255e262a284a6b616268736466 is_numeric? - bool(false) -------------------- Str: test Hex value:74657374 is_numeric? - bool(true) -------------------- Str: UniON/**/SELECT/**/1 Hex value:556e694f4e2f2a2a2f53454c4543542f2a2a2f31 is_numeric? - bool(false) -------------------- Str: -1/*!UnioN SELEct*/1,2,3 Hex value:2d312f2a21556e696f4e2053454c4563742a2f312c322c33 is_numeric? - bool(false) Хотя это понятно, он воспринимает хек значение без 0x как обычную строку.
а вообще если разобрать код из первого поста: PHP: <?php if (isset($_GET['Submit'])) { // Retrieve data $id = $_GET['id']; $id = stripslashes($id); // в случае если MQ=ON, то убирается экранирование $id = mysql_real_escape_string($id); // тут происходит экранирование по правилам функции mysql_real_escape_string, которая добавляет обратную косую черту к следующим символам: \x00, \n, \r, \, ', " и \x1a. // тут проходит проверка содержимого переменной $id, число это или нет, если нет, то ничего не происходит // если же в $id число (а именно функция is_numeric пропускает строки, содержащие числа, состоят из необязательного знака, любого количества цифр, // необязательной десятичной части и необязательной экспоненциальной части. Так, +0123.45e6 является верным числовым значением. // Шестнадцатеричная запись (0xFF) также допускается, но только без знака, десятичной и экспоненциальной части.) // то происходит запрос к БД if (is_numeric($id)){ // переменная $id обрамлена одинарной кавычкой, что заставляет соблюсти правильный синтаксис скул запроса, для проведения инъекции // и прибегнуть к использованию одинарной кавычки на примере: 1' and false union select 1,2,3# // но так как, во-первых функция mysql_real_escape_string заэкранирует нашу кавычку // а is_numeric вообще не выполнит условие, то все попытки четны. $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'"; $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' ); $num = mysql_numrows($result); $i=0; while ($i < $num) { $first = mysql_result($result,$i,"first_name"); $last = mysql_result($result,$i,"last_name"); echo '<pre>'; echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last; echo '</pre>'; $i++; } } } ?> Я так полагаю автор привел не полный код уязвимого скрипта. В данном коде, лично я, уязвимостей не наблюдаю.
is_numeric() разумеется пропускает 0xlalala, потому что это ЧИСЛО. И даже если переменная в запросе не будет обрамлена кавычками (id=$id) то всё равно инъекции не будет, база такое гавно не схавает А если бы это было возможно, то все WAFы сосали бы сразу, т.к. по этой логике можно сразу весь запрос переводить в HEX и не парится ) PS Об этом свойстве is_numeric примерно раз в год все вспоминают\открывают заново и начинаются движения и исследования, которые ничем не кончаются, и снова забвение на год )