
Библиотека Python для Turbo Intruder, которая добавляет поддержку позиций полезной нагрузки и типы атак Sniper/Clusterbomb/Pitchfork с генерацией тестов на основе тегов для HTTP-фаззинга.

Haptyc — это библиотека на Python, созданная для добавления поддержки позиций полезной нагрузки и типов атак Sniper/Clusterbomb/Batteringram/Pitchfork в Turbo Intruder. Haptyc достаточно хорошо справляется с этими задачами, а также предлагает более простой способ описания тестовых последовательностей в целом. Хотя эта библиотека предназначена для Turbo Intruder, у неё нет жёстких зависимостей от него, и её можно использовать везде, где требуется генерация тестов в контексте Python. К сожалению, на данный момент, поскольку Haptyc создавался для интерпретатора Jython, он поддерживает только Python 2.7 (однако будущие изменения исправят это).
Теги Haptyc — это теги, с помощью которых тестировщик может аннотировать исходную входную полезную нагрузку. Можно использовать несколько тегов, чтобы окружить ключевые фрагменты данных в HTTP-запросе, превратив их в позиционные нагрузки. При генерации тестов Haptyc разберёт все теги в исходной нагрузке и сгенерирует тесты в соответствии с функциями, связанными с именами тегов. Когда Haptyc вычисляет тег Haptyc, он выполняет связанную с ним функцию (называемую Haptyc Transform) для тестовой нагрузки, помещая результат на место соответствующего тега в запросе. Каждая функция тега получает аргументы data и state. Аргумент data может содержать внутренние данные тега или другую последовательность тестовой нагрузки. Аргумент state — это объект состояния, связанный с тегом, в котором можно хранить состояние между итерациями теста. Рассмотрим пример.
Исходная нагрузка:
GET /animal/[+GuessAnimal]dog[+end] HTTP/1.1
Класс Haptyc и Haptyc Transform:
from haptyc import *
original = "GET /animal/[+GuessAnimal]dog[+end] HTTP/1.1"
class TestLogic(Transform):
@ApplyList(["snake","cat","owl","lion"])
def test_GuessAnimal(self, data, state):
return data + "?original=" + self.inner() + "&attempt=" + str(state.iter)
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
Сгенерированные тесты:
GET /animal/snake?original=dog&attempt=0 HTTP/1.1
GET /animal/cat?original=dog&attempt=1 HTTP/1.1
GET /animal/owl?original=dog&attempt=2 HTTP/1.1
GET /animal/lion?original=dog&attempt=3 HTTP/1.1
В примере выше показано, как можно просто выразить тесты с помощью Haptyc. Сначала импортируется библиотека Haptyc. Затем определяются исходные данные с аннотациями тегов Haptyc (GuessAnimal). Далее объявляется класс TestLogic, наследующий Transform. Внутри этого класса каждый метод, начинающийся с test_, регистрируется как тег Haptyc для вычисления в исходной нагрузке. Мы используем декоратор логики для применения логики состояния к этому преобразованию Haptyc. В данном случае мы используем декоратор @ApplyList(list), чтобы указать Haptyc генерировать тест для каждого элемента указанного списка и передавать этот элемент в преобразование Haptyc в качестве аргумента data. Внутри преобразования мы возвращаем мутированную версию data для вставки обратно на место тега. В данном случае мутация представляет собой элемент списка как data, объединённый с данными, окружёнными тегом (dog), и затем объединённый со значением iter из объекта state. Наконец, оставшаяся часть кода Python показывает создание объекта TestFactory и генерацию всех тестов в цикле for. Это пример стандартной атаки типа Sniper, нацеленной на одну позицию нагрузки. Далее рассмотрим другие типы атак.
Исходная нагрузка:
GET /animal?type=[%type]dog[%end]&name=[%name]fido[%end] HTTP/1.1
Класс Haptyc и Haptyc Transform:
from haptyc import *
original = "GET /animal?type=[%type]dog[%end]&name=[%name]fido[%end] HTTP/1.1"
class TestLogic(Transform):
@ApplyList("snake","cat","owl","lion")
def test_type(self, data, state):
return data
@ApplyList("Frank", "Lisa", "Jin", "Tooth")
def test_name(self, data, state):
return data
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
Сгенерированные тесты:
GET /animal?type=snake&name=Frank HTTP/1.1
GET /animal?type=snake&name=Lisa HTTP/1.1
GET /animal?type=snake&name=Jin HTTP/1.1
GET /animal?type=snake&name=Tooth HTTP/1.1
GET /animal?type=cat&name=Frank HTTP/1.1
GET /animal?type=cat&name=Lisa HTTP/1.1
GET /animal?type=cat&name=Jin HTTP/1.1
GET /animal?type=cat&name=Tooth HTTP/1.1
GET /animal?type=owl&name=Frank HTTP/1.1
GET /animal?type=owl&name=Lisa HTTP/1.1
GET /animal?type=owl&name=Jin HTTP/1.1
GET /animal?type=owl&name=Tooth HTTP/1.1
GET /animal?type=lion&name=Frank HTTP/1.1
GET /animal?type=lion&name=Lisa HTTP/1.1
GET /animal?type=lion&name=Jin HTTP/1.1
GET /animal?type=lion&name=Tooth HTTP/1.1
Пример 1 показал, как вычислять преобразования в стиле Sniper, используя знак '+' в теге [+tag][+end]. Пример 2 показывает, как можно использовать 2 преобразования/позиции для проведения атаки в стиле Clusterbomb. Как видите, мы используем два отдельных тега преобразования: [%type][%end] и [%name][%end]. Знак '%' сообщает Haptyc, что эти преобразования должны вычисляться в стиле Clusterbomb: для каждой нагрузки из первого преобразования создаётся тест с нагрузкой из второго преобразования. Количество тестов равно количеству тестов каждого участвующего преобразования, умноженному друг на друга.
Используя тот же самый код Python, можно переключить стиль атаки с Clusterbomb на Pitchfork, заменив '%' на '#'. Атаки в стиле Pitchfork размещают позиционные нагрузки параллельно. Количество тестов равно наименьшему количеству тестов среди всех участвующих преобразований.
Исходная нагрузка:
GET /animal?type=[#type]dog[#end]&name=[#name]fido[#end] HTTP/1.1
Сгенерированные тесты:
GET /animal?type=snake&name=Frank HTTP/1.1
GET /animal?type=cat&name=Lisa HTTP/1.1
GET /animal?type=owl&name=Jin HTTP/1.1
GET /animal?type=lion&name=Tooth HTTP/1.1
Исходная нагрузка:
GET /animal?type=dog&id=[+idor]0[+end]&process=[@randbool]False[@end] HTTP/1.1
Класс Haptyc и Haptyc Transform:
from haptyc import *
import random
original = "GET /animal?type=dog&id=[+idor]0[+end]&process=[@randbool]False[@end] HTTP/1.1"
class TestLogic(Transform):
@ApplyIteration(10)
def test_idor(self, data, state):
return str(state.iter)
def per_randbool(self, data):
return random.choice(["True", "False"])
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
Сгенерированные тесты:
GET /animal?type=dog&id=0&process=False HTTP/1.1
GET /animal?type=dog&id=1&process=True HTTP/1.1
GET /animal?type=dog&id=2&process=False HTTP/1.1
GET /animal?type=dog&id=3&process=True HTTP/1.1
GET /animal?type=dog&id=4&process=False HTTP/1.1
GET /animal?type=dog&id=5&process=True HTTP/1.1
GET /animal?type=dog&id=6&process=False HTTP/1.1
GET /animal?type=dog&id=7&process=True HTTP/1.1
GET /animal?type=dog&id=8&process=False HTTP/1.1
GET /animal?type=dog&id=9&process=False HTTP/1.1