Repository navigation
Expand file tree
/
Copy pathbruteforce.py
More file actions
91 lines (80 loc) · 3.66 KB
/
Copy pathbruteforce.py
File metadata and controls
91 lines (80 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
from __future__ import annotations
import itertools
import re
from refinery.lib.meta import metavars
from refinery.lib.types import Param, bounds, buf
from refinery.units import Arg, Unit
class bruteforce(Unit):
"""
Generates all possible combinations of letters in a given alphabet.
For each generated string, one copy of each input chunk is generated and populated with a
meta variable containing that string. This can be used for simple brute forcing checks.
"""
def __init__(
self,
name: Param[str, Arg.String(help='Name of the meta variable to be populated.')],
length: Param[int | slice, Arg.Bounds(metavar='length', intok=True, help=(
'Specifies the interval of characters to brute force, default is {default}.'
))] = slice(1, None),
format: Param[str | None, Arg.String(help=(
'Optional format expression for the output string. The format sequence "{0}" is the '
'current brute force string, the sequence "{1}" represents the input data.'
))] = None,
alphabet: Param[buf | None, Arg.Binary('-a', group='ALPH', help=(
'The alphabet from which to choose the letters. Entire byte range by default.'
))] = None,
pattern: Param[str | None, Arg.RegExp('-r', group='ALPH',
help='Provide a regular expression pattern to define the alphabet.')] = None,
printable: Param[bool, Arg.Switch('-p', group='ALPH',
help='Equivalent to --pattern=[\\s\\x20-\\x7E]')] = False,
digits: Param[bool, Arg.Switch('-d', group='ALPH',
help='Equivalent to --pattern=\\d')] = False,
identifier: Param[bool, Arg.Switch('-i', group='ALPH',
help='Equivalent to --pattern=\\w')] = False,
letters: Param[bool, Arg.Switch('-l', group='ALPH',
help='Equivalent to --pattern=[a-zA-Z]')] = False,
):
options = sum(1 for x in [printable, digits, identifier, letters] if x)
if options > 1 or options and pattern:
raise ValueError('Invalid selection.')
if printable:
pattern = '[\\s\\x20-\\x7E]'
if digits:
pattern = '\\d'
if identifier:
pattern = '\\w'
if letters:
pattern = '[a-zA-Z]'
super().__init__(
name=name,
length=length,
format=format,
alphabet=alphabet,
pattern=pattern,
)
def _alphabet(self) -> bytes:
if (alphabet := self.args.alphabet):
return alphabet
else:
alphabet = bytes(range(0x100))
if not (pattern := self.args.pattern):
return alphabet
if isinstance((regex := Arg.AsRegExp(self.codec, pattern, flags=re.DOTALL)), re.Pattern):
if (alphabet := B''.join(regex.findall(alphabet))):
return alphabet
raise ValueError(F'Invalid regular expression: {pattern}')
def process(self, data: bytearray):
format_spec: str = self.args.format
meta = metavars(data)
name = self.args.name
kwargs: dict[str, buf | None] = {name: None}
for length in bounds[self.args.length]:
self.log_info(F'generating {length} digits')
if not isinstance(length, int) or length < 0:
raise ValueError(F'Unable to brute force {length} characters.')
for string in itertools.product(self._alphabet(), repeat=length):
string = bytes(string)
if format_spec:
string = meta.format_bin(format_spec, self.codec, [string, data])
kwargs[name] = string
yield self.labelled(data, **kwargs)