Погружаюсь в SQLMAP

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор petrinh1988
Источник https://xss.is


Всем привет!

Больше всего хочется сейчас написать «это моя первая статья, я новичок - не судите строго». Но давайте по факту, взялся писать - постарайся хотя бы приложить усилия, чтобы заглянуть за рамки уже 10000 раз описанного. Самого бесит, когда открываешь статью по XSS, в которой тебе обещают, что не будут писать про банальный <img src=x onerror=alert`1`>.... а пофакту именно это и делают. Поэтому пинайте смело, но по делу. Обратная связь это наиболее прямой путь в обучении.

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

Коварный первый таргет
Я очень везучий человек… и конечно же, первая моя цель оказалась не самой простой. Вернее, выглядит все достаточно элементарно:

Код: Скопировать в буфер обмена
GET /sitemap1.xml'%2b(select*from(select(if(1=1',sleep(5),sleep(0))))a)%2b' HTTP/1.1

Инъекция прямо в URL, без каких-либо параметров. Просто подставляй time-based и будет тебе счастье. Но реальность оказалась не такой радужной. SQLMAP в упор не хотел видеть место инъекции. Я уже и звездочкой ему показывал:

Код: Скопировать в буфер обмена
GET sitemap.xm* HTTP/1.1

И альтернативный стиль написания использовал:

Код: Скопировать в буфер обмена
GET sitemap.xml%INJECT HERE% HTTP/1.1

Как же обидно было просматривать десятки статей, где авторы упирались в элементарное указание места инъекции, через аргумент “p” или ?id=*. Во всех видео и инструкциях, sqlmap бодро подхватывал место инъекции.

В поисках ответа, я начал шерстить xss.is и наткнулся на тему “Вопрос про БД и sqlmap”, в которой у меня удачно завязался диалог с c0d3x, а после к нам присоединился xargs. Спасибо вам огромное!

Повторяться не вижу смысла, кому интересно подробно решение смотрите здесь: https://xss.is/threads/111836/#post-787043

Если коротко, то вот:
Решающим было сочетание параметров:

--technique=TQ --prefix="'%2b(" --suffix=")%2b'"

T - инъекция основанная на времени, Q - инлайн режим инъекции, ну и prefix с suffix, как открытие и закрытие инъекции.
Нажмите, чтобы раскрыть...

82268



И вот, я вижу этот шикарный скрин!!! Наконец-то! SQLMAP увидел место для инъекции. К слову сказать, есть предположение, что скрин сыграл со мной злую шутку. Когда первый раз выложил его здесь на форуме, забыл спрятать цель… сутки цель была в статусе 504… но, может быть, это просто совпадение. Если же кто-то расковырял мой сладенький кусочек пирога, очень прошу в личку написать каким образом и с какого бока. На момент написания статьи, я так и не добрался до админ-панели или сколь-нибудь интересного доступа к недрам сайта.

Казалось бы, очевидная вещь - параметры крайне важны, но иногда подобные выводы накрывают, как озарение или манна небесная.

Ключевым оказалось значение Q параметра technique. Чтобы понять в чем вся соль, полезем в набор пэйлоадов sqlmap. Для этого переходим по следующему пути: /usr/share/sqlmap/data/xml/payloads
Оговорюсь, что это путь для предустановленного в Kali sqlmap. Возможно есть какие-то экзотические способы установки и путь может отличаться.

В папке нас ждут шесть файлов:
  1. boolean_blind.xml
  2. error_based.xml
  3. inline_query.xml
  4. stacked_queries.xml
  5. time_blind.xml
  6. union_query.xml

Собственно, эти файлы и указываются параметром technique:
  • B: Boolean-based blind
  • E: Error-based
  • Q: Inline queries
  • S: Stacked queries
  • T: Time-based blind
  • U: Union query-based

И здесь мы видим простой первый вывод: подходящий нагрузки просто нет в иных пэйлоадах, кроме как в Q - inline_query.xml. Если говорить точнее, нет нагрузки, у которой тип T, а субтип Q. Или наоборот, это не главное, важно сочетание пэйлоадов TQ. Чтобы было понятнее, вот структура пэйлоада:

XML: Скопировать в буфер обмена
Код:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <!-- Boolean-based blind tests - WHERE/HAVING clause -->
<test>
        <title></title>
        <stype></stype>
        <level></level>
        <risk></risk>
        <clause></clause>
        <where></where>
        <vector></vector>
        <request>
            <payload></payload>
            <comment></comment>
            <char></char>
            <columns></columns>
        </request>
        <response>
            <comparison></comparison>
            <grep></grep>
            <time></time>
            <union></union>
        </response>
        <details>
            <dbms></dbms>
            <dbms_version></dbms_version>
            <os></os>
        </details>
</test>
    <!-- End of boolean-based blind tests - Stacked queries -->
</root>

Полное описание каждого ключа скрыл под спойлер, чтобы не загромождать статью:

Спойлер: Посмотреть описание формата payload xml
Tag: <test>
SQL injection test definition.

Sub-tag: <title>
Title of the test.

Sub-tag: <stype>
SQL injection family type.

Valid values:
1: Boolean-based blind SQL injection
2: Error-based queries SQL injection
3: Inline queries SQL injection
4: Stacked queries SQL injection
5: Time-based blind SQL injection
6: UNION query SQL injection

Sub-tag: <level>
From which level check for this test.

Valid values:
1: Always (<100 requests)
2: Try a bit harder (100-200 requests)
3: Good number of requests (200-500 requests)
4: Extensive test (500-1000 requests)
5: You have plenty of time (>1000 requests)

Sub-tag: <risk>
Likelihood of a payload to damage the data integrity.

Valid values:
1: Low risk
2: Medium risk
3: High risk

Sub-tag: <clause>
In which clause the payload can work.

NOTE: for instance, there are some payload that do not have to be
tested as soon as it has been identified whether or not the
injection is within a WHERE clause condition.

Valid values:
0: Always
1: WHERE / HAVING
2: GROUP BY
3: ORDER BY
4: LIMIT
5: OFFSET
6: TOP
7: Table name
8: Column name
9: Pre-WHERE (non-query)

A comma separated list of these values is also possible.

Sub-tag: <where>
Where to add our '<prefix> <payload><comment> <suffix>' string.

Valid values:
1: Append the string to the parameter original value
2: Replace the parameter original value with a negative random
integer value and append our string
3: Replace the parameter original value with our string

Sub-tag: <vector>
The payload that will be used to exploit the injection point.

Sub-tag: <request>
What to inject for this test.

Sub-tag: <payload>
The payload to test for.

Sub-tag: <comment>
Comment to append to the payload, before the suffix.

Sub-tag: <char>
Character to use to bruteforce number of columns in UNION
query SQL injection tests.

Sub-tag: <columns>
Range of columns to test for in UNION query SQL injection
tests.

Sub-tag: <response>
How to identify if the injected payload succeeded.

Sub-tag: <comparison>
Perform a request with this string as the payload and compare
the response with the <payload> response. Apply the comparison
algorithm.

NOTE: useful to test for boolean-based blind SQL injections.

Sub-tag: <grep>
Regular expression to grep for in the response body.

NOTE: useful to test for error-based SQL injection.

Sub-tag: <time>
Time in seconds to wait before the response is returned.

NOTE: useful to test for time-based blind and stacked queries
SQL injections.

Sub-tag: <union>
Calls unionTest() function.

NOTE: useful to test for UNION query (inband) SQL injection.

Sub-tag: <details>
Which details can be infered if the payload succeed.

Sub-tags: <dbms>
What is the database management system (e.g. MySQL).

Sub-tags: <dbms_version>
What is the database management system version (e.g. 5.0.51).

Sub-tags: <os>
What is the database management system underlying operating
System.

Как видно из описания, вот оно сочетание параметров, которое определяет, какие пэйлоады будут использоваться на тесте, какие нет. Проходит по устанновленому типу и субтипу нагрузки? Окей, идем дальше. Что там с risk и level? И т.д.

Можно, конечно, рубить с плеча - запустить все возможные нагрузки, но есть нюанс… с дуру можно и хером гвозди забивать. Но, во-первых, подобная проверка может занять безумное количество времени. Во-вторых, так называемая “команда синих” может очень заинтересоваться возросшей нагрузкой. Далеко не все забывают о существовании сайта, после приемки его у фрилансеров.

xargs. очень рекомендовал обратить внимание на такие параметры, как –risk и –level. Собственно, давайте в них и попробуем углубиться. После перейти к не менее интересному –tamper

LEVEL

Для начала, стоит посмотреть на описание параметра в контексте xml-файлов с пэйлоадами:
  1. По умолчанию(<100 запросов)
  2. Попробуйте немного больше (100–200 запросов).
  3. Хорошее количество запросов (200–500 запросов).
  4. Расширенное тестирование (500–1000 запросов)
  5. У вас много времени (>1000 запросов)
Выходит, level напрямую виляет, какое количество запросов будет отправлено. Причем! Ключ level используется для каждого объекта test. Т.е. каждый пэйлоад будет использован от <100 до >1000, в зависимости от указанного level.

Я может и душный, но повторю по другом: если указать значение три, то sqlmap использует все пэйлоады со значением от 1 до 3. При этом у каждого пйэлоада будет выполнено соответствующее левелу количество запросов: каждый первый меньше 100 раз, каждый третий в пределах 250-500.

Но из чего складывается это количество запросов? Из справки мы узнаем, что помимо разного рода динамических параметров шаблона пэйлоад, и количества запросов для подтверждения или опровержения каждого пэйлоада (нам ведь нужно убедиться, что это не случайное совпадение, что сработала или не сработала нагрузка), level влияет на места для тестирования инъекций.

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

При значении “по умолчанию”, а это “1”, sqlmap пытается выполнить инъекции исключительно во все параметры GET и POST. К слову, поэтому моя инъекция и не находилась, т.к. она подставлялась к URL, а не к параметру.

Для самых маленьких поясню, что под параметрами имеются ввиду переменные в URL идущие после знакак “?”: ?id=&sort= - в данном случае, параметры это id и sort. В случае POST добавляется тело запроса со своими данными, которые могут выглядеть так:
Код: Скопировать в буфер обмена
id=1&sort=asc
Или так
Код: Скопировать в буфер обмена
Код:
{
    “Id”:1,
    “sort”:”asc”
}

При указании уровня 2, мы получаем тестирование Cookie.
Уровень три добавляет сразу две точки инъекции: HTTP User-Agent и HTTP Referer
Уровень четыре остается загадкой….
Уровень пять добавляет проверку значения Host, как точки инъекции.

При этом, работу параметра level можно корректировать, используя параметры:
--skip= Пропустить тестирование для заданных параметров.
--skip-static Пропустить параметры тестирования, которые не кажутся динамическими. --param-exclude=.. Регулярное выражение для исключения параметров из тестирования (например, "ses")
--param-filter=.Выбрать проверяемые параметры по месту (например, «POST»)
Нажмите, чтобы раскрыть...

Кроме того, никто не мешает четко указывать место инъекции, используя параметр -p, если есть такая возможность. Другой вариант, это использование “*” или %INJECT HERE%. Например, вот один из моих запросов:
1712924229184.png



Можно его сохранить из Burp и скормить sqlmap через параметр r. Либо, прописав в командной строке:

Код: Скопировать в буфер обмена
sqlmap … -d ‘{"id":0,"clave":"GAT_INV%INJECT HERE%"}’

Но опять же, нужно учитывать “применяемость” инъекции. Как было в моем первом случае - обязательно нужен был инлайн Q.

RISK
Не менее интересный параметр. Интересен он тем, что при слепом использовании высоких значений можно получить совершенно неожиданный результат. Например, похерить базу данных сайту. Значение три позволяет sqlmap использовать нагрузки начинающиеся с OR. Теперь прикиньте, если ваша инъекция влетит в какой-нибудь UPDATE или, еще веселее, DELETE

DELETE FROM users WHERE id=1 OR 1=1….

Но поправлюсь - установка значения три, позволяет sqlmap использовать пэйлоады со значением risk равным 3 или меньше. Если вы запихнете кастомный пайлоад с OR, но укажете ключ риск равный 1…. sqlmap будет пофиг на наличие OR, главное, что ключ с параметром совпали.

Правильнее написать, что при создании пэйлоадов стоит учитывать следующие рекомендации, а при использовании sqlmap отталкиваться от следующих значений:

  1. Безвредные запросы: без OR и тяжелых временных инъекций
  2. Запросы, который могут включать тяжелые time-based инъекции
  3. Запросы включающие OR.

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

Например, моя инъекция в чистом виде выглядит следующим образом

SQL: Скопировать в буфер обмена
select * from( select if(1=1,sleep(5),sleep(0)) a

Обычный sql-запрос, который всегда будет ставить выполнение на паузу. Но вот незадача, таргет не хочет принимать его в таком виде. Как минимум, ему не нравятся пробелы. Чтобы привести итоговый запрос к нужному виду, sqlmap передает его функции, которую пользователь указал через параметр tamper. После, уже обработанный тампером SQL-запрос с префиксом и суфиксом, добавляется в запрос к серверу:

SQL: Скопировать в буфер обмена
(select*from(select(if(1=1,sleep(5),sleep(0))))a)

Причем, в рамках tamper мы можем спокойно добавить нужные нам суффиксы и префиксы, но это история больше для какого-то индивидуального тампера под конкретный сайт. В любом случае, смысл простой: получили строку, что-то с ней поделали - вернули строку. Вот шаблон тампера:

Python: Скопировать в буфер обмена
Код:
from lib.core.compat import xrange
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass

def tamper(payload, **kwargs):
    return payload


Тамперы доступные по умолчанию лежат в /usr/share/sqlmap/tamper. Я обязательно вернусь к теме написания собственных тамперов, тема безумно интересная, но пока не буду углубляться.

Спойлер: Код тампера space2plus.py
Python: Скопировать в буфер обмена
Код:
from lib.core.compat import xrange
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with plus ('+')

    Notes:
        * Is this any useful? The plus get's url-encoded by sqlmap engine invalidating the query afterwards
        * This tamper script works against all databases

    >>> tamper('SELECT id FROM users')
    'SELECT+id+FROM+users'
    """

    retVal = payload

    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += "+"
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == " " and not doublequote and not quote:
                retVal += "+"
                continue

            retVal += payload[i]

    return retVal

Есть еще много чего интересного в sqlmap, но пихать в одну статью было бы слишком. Разбор одного ключа в xml-файле пэйлоадов может занять не одну тысячу знаков. Поэтому, считаю правильным продолжить в том случае, если уважаемым форумчанам статья зайдет.
 
Сверху Снизу