This library automates a specific category of "simplified" brute-force searches, exploiting a vulnerability by which a string can be determined to start with an initial substring, without providing the entire string.
Three conditions are necessary for this library to be applicable to deducing a secret string (faster than a regular brute-force search):
- No rate limiting is in place
- The permitted character set, from which the secret string was formed, is known (e.g. ASCII-printable)
- A vulnerability exists that permits an attacker to determine if the secret string starts with an arbitrary guess
- this must also be scriptable as a boolean "test-function" in python
A secret string can be exfiltrated by repeated tests of whether it starts with an arbitrary guess, given knowledge of the character set from which it was built.
- Simply try each character in the legal character set until one tests positive for being the first.
- Then try that character repeatedly suffixed with 1 different character from the legal subset until a 2-length string tests positive
- Repeat by adding 1 different character to an n-length string from the legal subset, while positive tests still occur.
- If an iteration does not produce a positive test, this is the reversed secret string
From the root directory (ideally in a virtual environment), install locally with the following command:
python3 -m pip install -e .
Create a python function that takes a candidate string, performs a test (e.g. a blind SQL injection), and returns:
True
if the secret string starts with the candiate stringFalse
otherwise
Then decorate it with the repeat
method from the repeat package, giving the following arguments:
- the legal characters that the secret string may be formed from (as a string)
- the maximum length of the secret string attempts, before an iteration is halted
This produces a function, that when called, performs this attack. An optional initial string may be provided
as the keyword argument initial
, e.g. HTB{ . If parallelism is desired, it is supported by specifying the number of
parallel threads (as an integer) as the keyword argument parallelism
(though see the health warning below!)
import string
from wheatear_repeat import repeat
@repeat
def get_flag(candidate_string: str) -> bool:
FLAG = 'HTB{fl4gs-4r3_fun}'
# this is a silly example
return FLAG.startswith(candidate_string)
get_flag.characters = string.ascii_letters + string.digits + '-_}', # the permitted character set
get_flag.max_length = 30 # the maximum length of guess before giving up
get_flag.initial = 'HTB{' # the flag must start like all other HTB flags
get_flag.parallelism = 5 # use 5 parallel threads
flag = get_flag()
print(flag)
A better example will follow.
Parallelism can give wrong results on certain servers, especially for higher numbers of parallel threads against servers with low resources.
Obviously incorrect behaviour includes:
- giving different results each time it is run.
- giving a very short string (just 1 or 2 characters)
- giving a long string very fast, usually containing the same character over and over
See the example folder in this repository, containing a totally unrealistic blind-SQL injection vulnerability.
First install the testing requirements:
python3 -m pip install -r test/requirements.txt
Then run the tests:
python3 -m pytest test
- Make PyPI package
- Support parallel brute-forcing