SQL-инъекции

d0ppl4r

Старшина
Сообщения
49
Реакции
33
Здравствуйте. Мы приступаем к изучению одной из самых распространенных веб-атак - SQL-инъекции.


  • Введение.
  • Что такое SQL-инъекция?
  • Виды SQL-инъекций.
  • Материалы по уязвимостям.
  • Как можно использовать SQL-инъекции? - как-то глянем и сюда
  • Практика. и сюда
  • Автоматизация. - ну там sqlmap та и всё

Введение.

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


Если вы до сих пор не разобрались с языком SQL, то дальнейшее чтение для вас бессмысленно.




Ну а теперь, когда меньшиство посетителей уже закрыло вкладку (большинство и не открывало), мы с вами перейдем к делу.




Что такое SQL-инъекция?

Существует два вида приложений. Первый вид - приложение, которое ведет себя именно так, как задумал программист. Второй - приложение, которое ведет себя не совсем так, как задумал программист.


И вся суть SQL-инъекции (а также php-инъекций, xml-инъекций и т.д.) состоит в том, чтобы найти приложение второго вида и заставить его выполнить некоторое полезное нам действие, возможность которого не планировалась программистом.


К примеру, есть некий скрипт articles.php. И туда методом Get передается значение параметра id. Кодер когда писал свое приложение думал примерно так:


"Кроче, берем id из адресной строки. Пихаем иво в скуль-запрос. Если в базе есть такой id, то выводим страницу, которая к энтому Id прикручена, а ежеле нету, то тохда ибись оно в рот и ничово не выводем."
Код:
    <?php
//articles.php

include("db_config");
$id = $_GET['id'];
$sql = "SELECT * FROM articles WHERE id = '$id' ";
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result) or die("НИЧЕВО НЕТУ!!!");

//...

В зависимости от того, что мы будем передавать в параметр id, приложение будет возвращать разный результат. Но любой результат можно свести к одному из трех вариантов:


  • Пустой ответ
  • Нормальный ответ
  • Ошибка

Теперь давайте посмотрим, что получится, если мы будем пихать разные значения в параметр id:

Параметр/значениеОжидания кодераСуровая действительность
id=1Страница 1Страница 1
id=2Страница 2Страница 2
id=3Страница 3Страница 3
id=4000000Пустой ответПустой ответ
id=0Пустой ответПустой ответ
id=1kkdkaПустой ответПустой ответ
id=asdfПустой ответПустой ответ
id=-1Пустой ответПустой ответ
id=9999.9Пустой ответПустой ответ
id=2-1Пустой ответПустой ответ
id=-1'Пустой ответОшибка
id=-1\Пустой ответОшибка
id=9999.9' or id='2Пустой ответСтраница 2


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


Остается дело за малым - раскрутить эту самую инъекцию (попробовать вывести данные из бд, прочитать файлы, залить шелл и т.д.)


Стоит сразу отметить 2 нюанса:


  1. Если ошибки не выводятся, это совсем не значит, что в приложении нет SQL-инъекции.
  2. Помните, что есть существенная разница между выводом ошибок от интерпретатора и выводом ошибок от СУБД.

Если вы ни черта не поняли из того что было написано в этой части статьи - либо я очень херово все описал (и это ведь только начало!), либо ты ещё не закрыл вкладку.


Виды SQL-инъекций.

SQL-инъекции разделяют на множество видов


1) По типу переменной:


Integer (целочисленная). Параметр не обрамлен кавычками:

Код:
SELECT * FROM articles WHERE id = $id ;
String (строковая). Параметр обрамлен кавычками:
Код:
SELECT * FROM articles WHERE id = ' $id ';
SELECT * FROM `$articles` WHERE id = 123 ;
SELECT * FROM articles WHERE id = " $id ";


2) По типу SQL-запроса и месту инъекции в запросе. В теории, инъекция может быть в абсолютно любом месте абсолютно любого SQL-запроса, если туда попадают недостаточно фильтруемые данные. Чаще всего инъекции находят в SELECT (отдельно выделяют инъекции после order by, потому как их реализация чуть сложнее), реже в UPDATE, INSERT, DELETE. Поэтому можно встретить разделение - Update based, Insert based и т.д.


3) Данные в SQL-запрос могут попадать через Get, Post, Cookie, HTTP заголовки (реферрер, юзерагент, или еще что-то, на что хватит фантазии у программиста).


Также стоит отметить такой класс инъекций как Second order injection. Это когда данные попадают в SQL-запрос не напрямую от пользователя (get, post, cookie, http headers), а из БД, из файла, от самого Аллаха или еще из какого места куда мы могли ранее ввести данные.


К примеру, есть форма регистрации (все очень условно):

Код:
<?php
//Форма регистрации
$username = mysql_real_escape_string($_POST['username']);
$pass = mysql_real_escape_string($_POST['pass']);
$sql = "INSERT INTO users (username, pass) VALUES ('$username','$pass') ";
mysql_query($query) or die('Люк, игрой в доту и меня возьми!');

Данные экранируются, SQL-инъекции нет. Далее, форма авторизации:


Код:
<?php
//Форма аутентификации. Логин попадает в сессию
$username = mysql_real_escape_string($_POST['username']);
$pass = mysql_real_escape_string($_POST['pass']);
$sql = "SELECT * FROM users WHERE username='$username' AND pass='$pass'";
$result = mysql_query($query) or die('Блэчер, учи уроке!');
$row = mysql_fetch_row($result);
$_SESSION['username'] = $row['username'];

И наконец форма для смены пароля:


Код:
<?php
//Форма смены пароля.
$username=$_SESSION['username'];
$password = mysql_real_escape_string($_POST['pass']);
$new_pass = mysql_real_escape_string($_POST['new_pass']);
$sql = "UPDATE users SET PASSWORD='$new_pass' where username='$username' and password='$password' ";
$result = mysql_query($query) or die('Катафалк выехал...');


Тут тоже нет SQL-инъекции. Но! Если зарегистрировать пользователя с логином "admin' #", то можно сменить пароль для пользователя "admin", не зная его действующий пароль (проверьте на досуге). Это и будет Second order SQL-injection.


4) По типу SQL-инъекции:


4.1) Union-based. Инъекция в SELECT запросе, вывод данных из БД производится с помощью оператора UNION. Этот метод работает, когда веб-приложение напрямую возвращает результат вывода команды SELECT на страницу (поэтому без разницы, включен вывод ошибок или нет).



В начале стоит 9999.9 (хотя могло быть и 0, -1 и т.д.) для того, чтобы первый запрос вернул пустой результат, а второй (уже внедренный нами), вернул то, что нам нужно.

да, прибудет кроба!

4.2) Error-based (double query). Если использовать UNION не получается (нет колонки для вывода или инъекция в UPDATE, INSERT или DELETE), то можно вывести данные из базы искусственно вызывая ошибки.


Например такой запрос:
SELECT COUNT(*) FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)x GROUP BY MID(user(), FLOOR(RAND(0)*2), 64)
Вызовет ошибку, в отчете о которой мы увидим данные, которые нам были нужны:
Duplicate entry '[email protected]' for key 1



Представьте, что чекист спрашивает еврея:
- Правда, что самый жадный еврей украл завтра шекель у старушки?
- Вы непгавильно задали вопгос, нельзя навегняка сказать, Изя завтга укгадет что-то или таки-нет.


4.3) Blind-based (boolean based). Если данные нельзя вывести через union, а ошибки никак не выводятся, то скорее всего мы имеем дело со слепой инъекцией.


Как вы помните, приложение может вернуть либо нормальный результат, либо пустой, либо ошибку. Ошибки в данном случае подавляются. Поэтому мы можем использовать только, что пустой ответ это false, а нормальный ответ - true.

Параметр/значениеРезультат
id=1' and Ascii(substring((Select user()),1,1))>97 --+True
id=1' and Ascii(substring((Select user()),1,1))>120 --+False
id=1' and Ascii(substring((Select user()),1,1))>110 --+True
id=1' and Ascii(substring((Select user()),1,1))>115 --+False
id=1' and Ascii(substring((Select user()),1,1))<113 --+False
id=1' and Ascii(substring((Select user()),1,1))=114 --+True
И это только чтобы узнать, что первый символ в имени пользователя базы данных это "r" (114 это ascii-код этого символа).

Представьте что вы общаетесь с суперкомпьютером, который говорит "да" в случае правильного утверждения и молчит в случае неправильного утверждения:
- Бог есть?
- (молчание)
- У люка есть тянка?
- (молчание)
- Мир захватят огромные человекоподобные роботы которых напишут люк и сола?
- Да.

4.4) Time-based (double blind). А теперь представьте, что SQL-инъекция есть, но результат отдаваемый веб-приложением, не меняется вообще никак. Нельзя как-то выделить, что будет false, а что будет true? Что делать тогда? Использовать временные задержки.

Параметр/значениеРезультат
id=1' and if (Ascii(substring((Select user()),1,1))>97, sleep(10),0) --+True
id=1' and if (Ascii(substring((Select user()),1,1))>120, sleep(10),0) --+False
id=1' and if (Ascii(substring((Select user()),1,1))>110, sleep(10),0) --+True
id=1' and if (Ascii(substring((Select user()),1,1))>115, sleep(10),0) --+False
id=1' and if (Ascii(substring((Select user()),1,1))<113, sleep(10),0) --+False
id=1' and if (Ascii(substring((Select user()),1,1))=114, sleep(10),0) --+True

Там где будет True, сервак будет тупить 10 секунд, прежде чем вернуть страницу. В остальном все идентично обычным слепым (boolean based) инъекциям.

Чтобы как-то уложилось в голове (вывод ошибок - от СУБД!):
1649427694940.png


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

Материалы.

SQL.
Как говорит сола, книжки эта долга
для более лучшей практики, советую самому поднять какую-нить бд
вскоре дополню ещё курсами какими-та


SQL-инъекции.
https://portswigger.net/web-security/sql-injection совет самого Люквана
https://tryhackme.com/room/sqlinjectionlm на этом же сайте есть овермного комнат по скулям

если будут ещё какие-то прикольные штучки, подкидывайте
 
Последнее редактирование модератором:

lukeone

Магистр
Администратор
hackerville
Сообщения
20
Реакции
16
xD мне понравились аналогии) Теперь давайте про xss reflected, stored, lfi, path traversal, rfi, xxe, и можешь попробовать про дессереализацию джава.
 
  • Like
Реакции: d0ppl4r