
Turbo Intruder용 Python 라이브러리로, 페이로드 위치 지원과 Sniper/Clusterbomb/Pitchfork 공격 유형을 추가하며 태그 기반 테스트 생성을 통해 HTTP 퍼징을 수행합니다.

Haptyc는 Turbo Intruder에 페이로드 위치 지원과 Sniper/Clusterbomb/Batteringram/Pitchfork 공격 유형을 추가하기 위해 만들어진 Python 라이브러리입니다. Haptyc는 이러한 목표를 상당히 잘 달성하면서도 일반적으로 테스트 시퀀스를 더 간단하게 표현하는 방법을 제공합니다. 이 라이브러리는 Turbo Intruder를 대상으로 설계되었지만 Turbo Intruder에 대한 하드 의존성이 없으며 Python 컨텍스트에서 테스트 생성이 필요한 모든 곳에서 사용할 수 있습니다. 아쉽게도 현재 Haptyc는 Jython 인터프리터용으로 제작되었기 때문에 Python 2.7만 지원합니다(그러나 향후 변경 사항에서 이를 수정할 예정입니다).
Haptyc 태그는 테스터가 원본 입력 페이로드에 주석을 달기 위해 사용할 수 있는 태그입니다. 테스터는 여러 태그를 사용하여 HTTP 요청의 주요 데이터 조각을 감싸서 위치 기반 페이로드로 래핑할 수 있습니다. 테스트가 생성될 때 Haptyc는 원본 페이로드의 모든 태그를 파싱하고 태그 이름과 연관된 함수에 따라 테스트를 생성합니다. Haptyc가 Haptyc 태그를 평가할 때, 요청에서 해당 태그 위치에 배치할 테스트 페이로드를 위해 연관된 태그 함수(이를 Haptyc 변환이라고 함)를 실행합니다. 모든 태그 함수는 data 인수와 state 인수를 받습니다. data 인수에는 태그의 내부 데이터나 다른 테스트 페이로드 시퀀스가 포함될 수 있습니다. state 인수는 태그와 연관된 상태 객체로, 테스트 반복 간에 상태를 저장할 수 있습니다. 예제를 살펴보겠습니다.
원본 페이로드:
GET /animal/[+GuessAnimal]dog[+end] HTTP/1.1
Haptyc 클래스 및 Haptyc 변환:
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)를 연결한 다음 state 객체의 iter 값을 연결한 것입니다. 마지막으로 나머지 Python 코드는 TestFactory 객체를 생성하고 for 루프 반복기에서 모든 테스트를 생성하는 것을 보여줍니다. 이것은 단일 페이로드 위치를 대상으로 하는 표준 Sniper 스타일 공격의 예입니다. 이제 다른 스타일의 공격을 살펴보겠습니다.
원본 페이로드:
GET /animal?type=[%type]dog[%end]&name=[%name]fido[%end] HTTP/1.1
Haptyc 클래스 및 Haptyc 변환:
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은 태그에서 '+' 기호 표기법([+tag][+end])을 사용하여 변환을 Sniper 스타일로 평가하는 방법을 보여주었습니다. 예제 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 변환:
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
영구 변환은 '@' 기호로 표시되며 변환 함수는 항상 per_로 시작합니다. 이는 이러한 변환이 반복적이지 않고 테스트를 생성하지도 상태를 유지하지도 않기 때문입니다. 이러한 변환은 단순한 변환으로, 상태를 유지하는 변환에 영향을 주지 않고 페이로드의 어느 곳에나 적용할 수 있는 상태 비저장 변환입니다. 자체적으로 테스트를 지정하지 않으므로 영구 변환만으로는 테스트를 생성할 수 없습니다. 이는 반복 변환과 혼합하여 사용하기 위한 것입니다. 위 예제에서는 증가하는 id를 배치하는 10개 테스트의 Sniper 스타일 변환이 있습니다. 또한 해당 위치에 무작위 부울을 배치하는 영구 변환이 있습니다.
테스트 시퀀스가 시작되기 전에 테스터가 일부 처리/초기화를 수행하려는 경우가 있을 수 있습니다. 이를 지원하기 위해 Haptyc는 테스트 생성을 위한 변환을 실행하기 전에 초기화 단계에서 관련된 모든 변환을 실행합니다. 이 초기화 단계는 테스터가 필요한 초기화를 수행하고 그 결과를 state 객체에 저장하는 데 사용할 수 있습니다. 이를 위해 테스터는 state.init을 부울 값으로 사용하여 실행이 초기화 단계인지 확인할 수 있습니다. 초기화 단계에서 반환된 모든 데이터는 무시됩니다.
원본 페이로드:
GET /animal?data=[+b64mutate]SGVsbG8gSGFja2VyIQ==[+end] HTTP/1.1
Haptyc 클래스 및 Haptyc 변환:
from haptyc import *
import base64
original = "GET /animal?data=[+b64mutate]SGVsbG8gSGFja2VyIQ==[+end] HTTP/1.1"
class TestLogic(Transform):
@ApplyIteration(10)
def test_b64mutate(self, data, state):
if state.init:
state.decoded = base64.b64decode(data)
return
return base64.b64encode(random_insert(state.decoded, ["'"]))
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
생성된 테스트:
GET /animal?data=SGVsbG8gSCdhY2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFja2VyISc= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjaydlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGEnY2tlciE= HTTP/1.1
GET /animal?data=SCdlbGxvIEhhY2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjaydlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFja2VyISc= HTTP/1.1
GET /animal?data=SCdlbGxvIEhhY2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjJ2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjJ2tlciE= HTTP/1.1
위 예제에서 테스트는 state.init을 사용하여 래핑된 내부 페이로드를 테스트 시퀀스 시작 시 한 번만 base64 디코딩하고 그 결과를 state.decoded에 저장합니다. 그런 다음 모든 일반 테스트 생성 실행에서 state.decoded는 처리할 디코딩된 내부 데이터로 사용됩니다. 이 유형의 패턴은 초기에 한 번만 디코딩이 발생하므로(모든 테스트 생성 시 동일한 페이로드를 디코딩하는 것과 비교하여) 변환 성능을 향상시키는 데 유용합니다.
[+tag]inner[+end] - Sniper 스타일 반복 변환[%tag]inner[%end] - Clusterbomb 스타일 반복 변환[#tag]inner[#end] - Batteringram/Pitchfork 스타일 반복 변환[@tag]inner[@end] - 상태 비저장 영구 변환| 이름 | 인수 | 설명 |
|---|---|---|
| @CloneTransform(srcname, destname) | srcname=복사할 변환 메서드의 문자열 이름, destname=복사할 대상의 존재하지 않는 변환 메서드의 문자열 이름 | CloneTransform은 복사/붙여넣기 없이 한 변환의 구현을 다른 네임스페이스로 복사하는 데 사용됩니다. 이는 여러 위치에서 동일한 변환 구현을 재사용해야 하는 '%' 및 '#' 스타일 공격에서 유용합니다. |
| 이름 | 설명 |
|---|---|
| self.inner() | 태그의 내부 페이로드를 검색합니다. |
| self.stop() | 해당 변환의 테스트 생성을 즉시 중지합니다. |
| self.me() | 현재 변환 컨텍스트의 이름을 반환합니다. |
| 이름 | 설명 |
|---|---|
| state.iter | 변환의 현재 반복 횟수(0부터 시작) |
| state.init | 초기화 단계에 있는지 나타내는 부울 값 |
| 이름 | 설명 |
|---|---|
| radamsa(data) | 이 함수는 입력 데이터에 대해 radamsa를 실행하고 결과를 반환합니다(radamsa가 설치되어 있어야 함). |
| index_insert(data, list, index) | 이 함수는 제공된 인덱스에서 제공된 데이터에 리스트의 페이로드를 삽입합니다. |
| random_insert(data, list) | 이 함수는 무작위 인덱스에서 제공된 데이터에 리스트의 페이로드를 삽입합니다. |
Haptyc를 설치하는 방법은 2가지가 있습니다.
turbo-intruder-all_w_haptyc.jar를 사용하는 쉬운 방법어느 방법을 선택하든 이러한 릴리스에는 radamsa가 포함되어 있지 않으며 radamsa 지원을 원하면 이 저장소에서 설치해야 합니다. (선택 사항) radamsa를 https://gitlab.com/akihe/radamsa를 통해 설치하세요.
turbo-intruder-all_w_haptyc.jar를 확인합니다.Add 버튼을 클릭합니다.Select File ... 버튼을 클릭하고 turbo-intruder-all_w_haptyc.jar를 선택합니다../install.sh <turbo-intruder-all.jar가 있는 절대 디렉터리>를 실행합니다.| 이름 | 인수 | data 입력 | 설명 |
|---|
| @ApplyIteration(n) | n= 반복 횟수 | haptyc 태그의 내부 값 | inner를 data로 사용하여 N개의 테스트를 생성하는 로직 |
| @ApplyRange(b,e,s=1) | b= 시작 값, e= 최대 값, s= 단계 | 범위에서 생성된 값 | 주어진 값을 data로 사용하여 단계별로 모든 값에 대해 테스트를 생성하는 로직 |
| @ApplyList(L) | L = Python 리스트 | 리스트의 항목 | 리스트의 모든 값에 대해 data로 주어진 값을 사용하여 테스트를 생성하는 로직 |
| @ApplyFilelist(path) | path = 파일 시스템 경로 | 리스트의 항목 | 파일 리스트의 모든 값에 대해 data로 주어진 값을 사용하여 테스트를 생성하는 로직 |
| @ApplyPayloads(name) | name = 내장 리스트 이름 | 리스트의 항목 | 내장 리스트의 모든 값에 대해 data로 주어진 값을 사용하여 테스트를 생성하는 로직 |
| self.set_label(label) | 이 현재 테스트의 레이블을 설정합니다. |
| self.get_label(label) | 이 현재 테스트의 레이블을 가져옵니다. |