Skip to content

Commit 69a638f

Browse files
committed
feat: add xss, cmdi, and path traversal fuzzers
1 parent 47db816 commit 69a638f

File tree

65 files changed

+1294
-48
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1294
-48
lines changed

pirebok/fuzzers/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1+
from .cmdi.guided_random_cmdi_fuzzer import GuidedRandomCmdiFuzzer
2+
from .cmdi.random_cmdi_fuzzer import RandomCmdiFuzzer
3+
from .cmdi_fuzzer import CmdiFuzzer
14
from .fuzzer import Fuzzer
25
from .fuzzer_builder import FuzzerBuilder
36
from .fuzzer_transformer_resolver_visitor import FuzzerTransformerResolverVisitor
47
from .fuzzer_visitor import FuzzerVisitor
58
from .generic.random_generic_fuzzer import RandomGenericFuzzer
69
from .generic_fuzzer import GenericFuzzer
10+
from .guided_fuzzer_mixin import GuidedFuzzerMixin
11+
from .path_traversal.guided_random_path_traversal_fuzzer import GuidedRandomPathTraversalFuzzer
12+
from .path_traversal.random_path_traversal_fuzzer import RandomPathTraversalFuzzer
13+
from .path_traversal_fuzzer import PathTraversalFuzzer
714
from .payload_pool import PayloadPool
815
from .sql.guided_random_sql_fuzzer import GuidedRandomSqlFuzzer
916
from .sql.random_sql_fuzzer import RandomSqlFuzzer
1017
from .sql_fuzzer import SqlFuzzer
18+
from .xss.guided_random_xss_fuzzer import GuidedRandomXssFuzzer
19+
from .xss.random_xss_fuzzer import RandomXssFuzzer
20+
from .xss_fuzzer import XssFuzzer

pirebok/fuzzers/cmdi/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from typing import Sequence
2+
3+
from pirebok.fuzzers.cmdi_fuzzer import CmdiFuzzer
4+
from pirebok.fuzzers.fuzzer_visitor import FuzzerVisitor
5+
from pirebok.fuzzers.guided_fuzzer_mixin import GuidedFuzzerMixin
6+
from pirebok.transformers import Transformer
7+
8+
9+
class GuidedRandomCmdiFuzzer(GuidedFuzzerMixin, CmdiFuzzer):
10+
_target_class = "cmdi"
11+
12+
def __init__(self, transformers: Sequence[Transformer]) -> None:
13+
super().__init__(transformers)
14+
self.threshold: float
15+
self.max_rounds: int = 100
16+
self.round_size: int = 20
17+
self.timeout: int = 0
18+
19+
def accept(self, visitor: FuzzerVisitor) -> None:
20+
visitor.visit_cmdi(self)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import random
2+
3+
from pirebok.fuzzers.cmdi_fuzzer import CmdiFuzzer
4+
from pirebok.fuzzers.fuzzer_visitor import FuzzerVisitor
5+
6+
7+
class RandomCmdiFuzzer(CmdiFuzzer):
8+
def fuzz(self, payload: str) -> str:
9+
return random.choice(self.transformers).transform(payload)
10+
11+
def accept(self, visitor: FuzzerVisitor) -> None:
12+
visitor.visit_cmdi(self)

pirebok/fuzzers/cmdi_fuzzer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from pirebok.fuzzers.fuzzer import Fuzzer
2+
3+
4+
class CmdiFuzzer(Fuzzer):
5+
pass

pirebok/fuzzers/fuzzer_transformer_resolver_visitor.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@
22
from operator import iconcat
33
from typing import Sequence
44

5+
from pirebok.fuzzers.cmdi_fuzzer import CmdiFuzzer
56
from pirebok.fuzzers.fuzzer_visitor import FuzzerVisitor
67
from pirebok.fuzzers.generic_fuzzer import GenericFuzzer
8+
from pirebok.fuzzers.path_traversal_fuzzer import PathTraversalFuzzer
79
from pirebok.fuzzers.sql_fuzzer import SqlFuzzer
8-
from pirebok.transformers import GenericTransformer, SqlTransformer, Transformer
10+
from pirebok.fuzzers.xss_fuzzer import XssFuzzer
11+
from pirebok.transformers import (
12+
CmdiTransformer,
13+
GenericTransformer,
14+
PathTraversalTransformer,
15+
SqlTransformer,
16+
Transformer,
17+
XssTransformer,
18+
)
919

1020

1121
class FuzzerTransformerResolverVisitor(FuzzerVisitor):
@@ -23,3 +33,33 @@ def visit_sql(self, fuzzer: SqlFuzzer) -> None:
2333
],
2434
[],
2535
)
36+
37+
def visit_xss(self, fuzzer: XssFuzzer) -> None:
38+
self.transformers = reduce(
39+
iconcat,
40+
[
41+
list(map(lambda x: x(), XssTransformer.__subclasses__())), # type: ignore
42+
list(map(lambda x: x(), GenericTransformer.__subclasses__())), # type: ignore
43+
],
44+
[],
45+
)
46+
47+
def visit_cmdi(self, fuzzer: CmdiFuzzer) -> None:
48+
self.transformers = reduce(
49+
iconcat,
50+
[
51+
list(map(lambda x: x(), CmdiTransformer.__subclasses__())), # type: ignore
52+
list(map(lambda x: x(), GenericTransformer.__subclasses__())), # type: ignore
53+
],
54+
[],
55+
)
56+
57+
def visit_path_traversal(self, fuzzer: PathTraversalFuzzer) -> None:
58+
self.transformers = reduce(
59+
iconcat,
60+
[
61+
list(map(lambda x: x(), PathTraversalTransformer.__subclasses__())), # type: ignore
62+
list(map(lambda x: x(), GenericTransformer.__subclasses__())), # type: ignore
63+
],
64+
[],
65+
)

pirebok/fuzzers/fuzzer_visitor.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from abc import ABC, abstractmethod
22

3+
from pirebok.fuzzers.cmdi_fuzzer import CmdiFuzzer
34
from pirebok.fuzzers.generic_fuzzer import GenericFuzzer
5+
from pirebok.fuzzers.path_traversal_fuzzer import PathTraversalFuzzer
46
from pirebok.fuzzers.sql_fuzzer import SqlFuzzer
7+
from pirebok.fuzzers.xss_fuzzer import XssFuzzer
58

69

710
class FuzzerVisitor(ABC):
@@ -12,3 +15,15 @@ def visit_generic(self, fuzzer: GenericFuzzer) -> None:
1215
@abstractmethod
1316
def visit_sql(self, fuzzer: SqlFuzzer) -> None:
1417
pass
18+
19+
@abstractmethod
20+
def visit_xss(self, fuzzer: XssFuzzer) -> None:
21+
pass
22+
23+
@abstractmethod
24+
def visit_cmdi(self, fuzzer: CmdiFuzzer) -> None:
25+
pass
26+
27+
@abstractmethod
28+
def visit_path_traversal(self, fuzzer: PathTraversalFuzzer) -> None:
29+
pass
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import random
2+
import time
3+
from typing import Sequence
4+
5+
from pirebok.fuzzers.payload_pool import PayloadPool
6+
from pirebok.transformers import Transformer
7+
8+
9+
class GuidedFuzzerMixin:
10+
_target_class: str
11+
transformers: Sequence[Transformer]
12+
threshold: float
13+
max_rounds: int
14+
round_size: int
15+
timeout: int
16+
17+
def _mutation_round(self, payload: str, round_size: int) -> set[str]:
18+
return {random.choice(self.transformers).transform(payload) for _ in range(round_size)}
19+
20+
def fuzz(self, payload: str) -> str:
21+
from metamaska.metamaska import Metamaska
22+
23+
metamask = Metamaska()
24+
pool = PayloadPool()
25+
26+
cls, proba = metamask.form(payload, True)
27+
confidence = proba if cls == self._target_class else 0.0
28+
pool.push(confidence, payload)
29+
30+
best_confidence = confidence
31+
best_payload = payload
32+
33+
deadline = (time.monotonic() + self.timeout) if self.timeout > 0 else 0.0
34+
35+
for _ in range(self.max_rounds):
36+
if deadline and time.monotonic() >= deadline:
37+
break
38+
if best_confidence < self.threshold:
39+
break
40+
if not pool:
41+
break
42+
43+
candidate_confidence, candidate = pool.pop()
44+
mutations = self._mutation_round(candidate, self.round_size)
45+
46+
for mutated in mutations:
47+
cls, proba = metamask.form(mutated, True)
48+
mutation_confidence = proba if cls == self._target_class else 0.0
49+
pool.push(mutation_confidence, mutated)
50+
51+
if mutation_confidence < best_confidence:
52+
best_confidence = mutation_confidence
53+
best_payload = mutated
54+
55+
pool.push(candidate_confidence, candidate)
56+
57+
return best_payload
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from typing import Sequence
2+
3+
from pirebok.fuzzers.fuzzer_visitor import FuzzerVisitor
4+
from pirebok.fuzzers.guided_fuzzer_mixin import GuidedFuzzerMixin
5+
from pirebok.fuzzers.path_traversal_fuzzer import PathTraversalFuzzer
6+
from pirebok.transformers import Transformer
7+
8+
9+
class GuidedRandomPathTraversalFuzzer(GuidedFuzzerMixin, PathTraversalFuzzer):
10+
_target_class = "path-traversal"
11+
12+
def __init__(self, transformers: Sequence[Transformer]) -> None:
13+
super().__init__(transformers)
14+
self.threshold: float
15+
self.max_rounds: int = 100
16+
self.round_size: int = 20
17+
self.timeout: int = 0
18+
19+
def accept(self, visitor: FuzzerVisitor) -> None:
20+
visitor.visit_path_traversal(self)

0 commit comments

Comments
 (0)