
Biblioteca Python para Turbo Intruder que adiciona suporte a posições de payload e tipos de ataque Sniper/Clusterbomb/Pitchfork com geração de testes baseada em tags para fuzzing HTTP.

Haptyc é uma biblioteca Python criada para adicionar suporte a posições de carga útil e tipos de ataque Sniper/Clusterbomb/Batteringram/Pitchfork no Turbo Intruder. Embora o Haptyc atinja esses objetivos razoavelmente bem, também introduz uma maneira mais simples de expressar sequências de teste em geral. Embora esta biblioteca tenha sido feita para o Turbo Intruder, ela não possui dependências rígidas com ele e pode ser usada em qualquer lugar onde seja necessária a geração de testes em um contexto Python. Infelizmente, por enquanto, como o Haptyc foi construído para um interpretador Jython, ele só suporta Python 2.7 (no entanto, alterações futuras corrigirão isso).
Tags Haptyc são tags que um testador pode usar para anotar uma carga útil de entrada original. Um testador pode usar várias tags para envolver partes importantes de dados em uma requisição HTTP, transformando-a em uma carga útil posicional. Quando os testes estão sendo gerados, o Haptyc analisará todas as tags na carga útil original e gerará testes de acordo com as funções associadas aos nomes das tags. Quando o Haptyc avalia uma tag Haptyc, ele executa a função de tag associada (chamada de Haptyc Transform) para uma carga útil de teste a ser colocada na posição da tag correspondente na requisição. Cada função de tag recebe um argumento data e um argumento state. O argumento data pode conter os dados internos da tag ou alguma outra sequência de carga útil de teste. O argumento state é um objeto de estado associado à tag, onde o estado pode ser armazenado entre iterações de teste. Vamos revisar um exemplo.
Carga útil original:
GET /animal/[+GuessAnimal]dog[+end] HTTP/1.1
Classe Haptyc e 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)
Testes gerados:
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
No exemplo acima, vemos como é possível expressar testes de forma simples usando Haptyc. Primeiro, a biblioteca Haptyc é importada. Em segundo lugar, definimos os dados originais com nossas anotações de tag Haptyc (GuessAnimal). Em seguida, a classe TestLogic é definida e estendida como uma classe Transform. Dentro desta classe, todo método que começa com test_ será registrado como uma tag Haptyc para avaliação na carga útil original. Usamos um decorador de lógica para aplicar a lógica de estado para este Haptyc Transform. Neste caso, usamos o decorador @ApplyList(list) para instruir o Haptyc a gerar um teste para cada item na lista especificada e colocar esse item no Haptyc Transform como argumento data. Dentro do transform, retornamos uma versão mutada dos dados para inserir de volta na posição da tag. Neste caso, a mutação é o item da lista como data concatenado com os dados envolvidos pela tag (dog) e depois concatenado com o valor iter no objeto state. Por fim, o restante do Python mostra o objeto TestFactory sendo criado e todos os testes sendo gerados em um loop for. Este é um exemplo de um ataque padrão do tipo sniper que ataca uma única posição de carga útil. A seguir, vejamos outros estilos de ataque.
Carga útil original:
GET /animal?type=[%type]dog[%end]&name=[%name]fido[%end] HTTP/1.1
Classe Haptyc e 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)
Testes gerados:
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
O Exemplo 1 mostrou como avaliar transforms no estilo sniper usando a anotação '+' na tag [+tag][+end]. O Exemplo 2 mostra como podemos usar 2 transforms/posições para conduzir um ataque no estilo clusterbomb. Como podemos ver, usamos duas tags de transform separadas chamadas [%type][%end] e [%name][%end]. O sinal '%' indica ao Haptyc para avaliar esses transforms no estilo clusterbomb: para cada carga útil no primeiro transform, crie um teste com a carga útil do segundo transform. O número de testes é a multiplicação do número de testes de cada transform envolvido.
Usando exatamente o mesmo código Python, podemos mudar o estilo de ataque de clusterbomb para pitchfork alterando '%' para '#'. Os ataques estilo pitchfork colocam as cargas úteis de posição todas em paralelo. O número de testes é o menor número de testes entre todos os transforms envolvidos.
Carga útil original:
GET /animal?type=[#type]dog[#end]&name=[#name]fido[#end] HTTP/1.1
Testes gerados:
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
Carga útil original:
GET /animal?type=dog&id=[+idor]0[+end]&process=[@randbool]False[@end] HTTP/1.1
Classe Haptyc e 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)
Testes gerados:
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