| Thies C. Arntzen, Stig Bakken, Shane Caraveo, Andi Gutmans, Rasmus Lerdorf, Sam Ruby, Sascha Schumann, Zeev Suraski, Jim Winstead, Andrei Zmievski |
42 |
43 |
48 | | PHP Authors |
49 | | Contribution | Authors |
50 | | Zend Scripting Language Engine | Andi Gutmans, Zeev Suraski, Stanislav Malyshev, Marcus Boerger, Dmitry Stogov, Xinchen Hui, Nikita Popov |
51 | | Extension Module API | Andi Gutmans, Zeev Suraski, Andrei Zmievski |
52 | | UNIX Build and Modularization | Stig Bakken, Sascha Schumann, Jani Taskinen, Peter Kokot |
53 | | Windows Support | Shane Caraveo, Zeev Suraski, Wez Furlong, Pierre-Alain Joye, Anatol Belski, Kalle Sommer Nielsen |
54 | | Server API (SAPI) Abstraction Layer | Andi Gutmans, Shane Caraveo, Zeev Suraski |
55 | """
56 |
57 | with requests_mock.Mocker() as m:
58 | m.get(
59 | f"https://localhost/AAAAAAAA",
60 | status_code=404,
61 | text="",
62 | )
63 |
64 | m.get(
65 | f"https://localhost/_fragment",
66 | status_code=403,
67 | text="",
68 | )
69 |
70 | m.get(
71 | f"https://localhost/_fragment?_path=_controller%3Dphpcredits&_hash=SrBMT/u6I0ylFIn/i6LYayCog21DnFMJ7yFBSnZpImA=",
72 | status_code=200,
73 | text=phpcredits_page,
74 | )
75 |
76 | monkeypatch.setattr(
77 | "sys.argv",
78 | ["python", "--url", "https://localhost/"],
79 | )
80 | symfony_knownkey.main()
81 | captured = capsys.readouterr()
82 | assert "Found Symfony Secret! [50c8215b436ebfcc1d568effb624a40e]" in captured.out
83 | print(captured)
84 |
--------------------------------------------------------------------------------
/badsecrets/examples/symfony_knownkey.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # badsecrets - Symfony _fragment known secret key brute-force tool
3 | # Black Lantern Security - https://www.blacklanternsecurity.com
4 | # @paulmmueller
5 |
6 | import re
7 | import os
8 | import sys
9 | import hashlib
10 | import argparse
11 | import requests
12 | from contextlib import suppress
13 | from requests.packages.urllib3.exceptions import InsecureRequestWarning
14 |
15 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
16 |
17 | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
18 | sys.path.append(os.path.dirname(SCRIPT_DIR))
19 |
20 | from badsecrets import modules_loaded
21 |
22 | Symfony_SignedURL = modules_loaded["symfony_signedurl"]
23 |
24 |
25 | def validate_url(
26 | arg_value,
27 | pattern=re.compile(
28 | r"^https?://((?:[A-Z0-9_]|[A-Z0-9_][A-Z0-9\-_]*[A-Z0-9_])[\.]?)+(?:[A-Z0-9_][A-Z0-9\-_]*[A-Z0-9_]|[A-Z0-9_])(?::[0-9]{1,5})?.*$",
29 | re.IGNORECASE,
30 | ),
31 | ):
32 | if not pattern.match(arg_value):
33 | raise argparse.ArgumentTypeError("URL is not formatted correctly")
34 | return arg_value
35 |
36 |
37 | def main():
38 | parser = argparse.ArgumentParser()
39 | parser.add_argument(
40 | "-u",
41 | "--url",
42 | type=validate_url,
43 | help="The URL of the page to access and attempt to pull viewstate and generator from",
44 | required=True,
45 | )
46 |
47 | parser.add_argument(
48 | "-p",
49 | "--proxy",
50 | help="Optionally specify an HTTP proxy",
51 | )
52 |
53 | parser.add_argument(
54 | "-a",
55 | "--user-agent",
56 | help="Optionally set a custom user-agent",
57 | )
58 |
59 | args = parser.parse_args()
60 |
61 | if not args.url:
62 | return
63 |
64 | proxies = None
65 | if args.proxy:
66 | proxies = {"http": args.proxy, "https": args.proxy}
67 |
68 | headers = {}
69 | if args.user_agent:
70 | headers["User-agent"] = args.user_agent
71 |
72 | fragment_test_url = f"{args.url.rstrip('/')}/_fragment"
73 | try:
74 | res_fragment = requests.get(f"{fragment_test_url}", proxies=proxies, headers=headers, verify=False)
75 | except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout):
76 | print(f"Error connecting to URL: [{args.url}]")
77 | return
78 |
79 | negative_test_url = f"{args.url.rstrip('/')}/AAAAAAAA"
80 | res_random = requests.get(f"{negative_test_url}", proxies=proxies, headers=headers, verify=False)
81 |
82 | if (res_fragment.status_code != 403) or not (res_random.status_code != res_fragment.status_code):
83 | print(f"Not a Symfony app, or _fragment functionality not enabled...")
84 | return
85 |
86 | print("Target appears to by a Symfony app with _fragment enabled. Brute forcing Symfony secret...")
87 |
88 | x = Symfony_SignedURL()
89 |
90 | phpinfo_test_url = f"{args.url.rstrip('/')}/_fragment?_path=_controller%3Dphpcredits"
91 |
92 | for l in x.load_resources(["symfony_appsecret.txt"]):
93 | with suppress(ValueError):
94 | secret = l.rstrip()
95 | for hash_algorithm in [hashlib.sha256, hashlib.sha1]:
96 | hash_value = x.symfonyHMAC(phpinfo_test_url, secret, hash_algorithm)
97 | test_url = f"{phpinfo_test_url}&_hash={hash_value.decode()}"
98 | test_res = requests.get(f"{test_url}", proxies=proxies, headers=headers, verify=False)
99 | if "PHP Authors" in test_res.text:
100 | print(test_url)
101 | print(f"Found Symfony Secret! [{secret}]")
102 | print(f"PoC URL: {test_url}")
103 | print(f"Hash Algorithm: {hash_algorithm.__name__.split('_')[1]}")
104 | return
105 |
106 |
107 | if __name__ == "__main__":
108 | print("badsecrets - Symfony _fragment known secret key brute-force tool\n")
109 | main()
110 |
--------------------------------------------------------------------------------
/badsecrets/modules/telerik_hashkey.py:
--------------------------------------------------------------------------------
1 | import re
2 | import hmac
3 | import base64
4 | import binascii
5 | import urllib.parse
6 | from contextlib import suppress
7 | from badsecrets.base import BadsecretsBase
8 |
9 |
10 | class Telerik_HashKey(BadsecretsBase):
11 | identify_regex = re.compile(r"^(?:[A-Za-z0-9+\/=%]{32,})$")
12 | description = {
13 | "product": "Telerik DialogParameters",
14 | "secret": "Telerik.Upload.ConfigurationHashKey",
15 | "severity": "HIGH",
16 | }
17 |
18 | def carve_regex(self):
19 | return re.compile(r"{\"SerializedParameters\":\"([^\"]*)\"")
20 |
21 | def prepare_keylist(self, include_machinekeys=True):
22 | if include_machinekeys:
23 | for l in self.load_resources(["aspnet_machinekeys.txt"]):
24 | try:
25 | vkey, ekey = l.rstrip().split(",")
26 | yield vkey
27 | except ValueError:
28 | continue
29 | for l in self.load_resources(["telerik_hash_keys.txt"]):
30 | vkey = l.strip()
31 | yield vkey
32 |
33 | @classmethod
34 | def telerik_hashkey_load(self, dialogParameters_raw):
35 | dialogParametersB64 = urllib.parse.unquote(dialogParameters_raw)
36 | return dialogParametersB64[:-44].encode(), dialogParametersB64[-44:].encode()
37 |
38 | def check_secret(self, dialogParameters_raw):
39 | if not self.identify(dialogParameters_raw):
40 | return None
41 |
42 | dp_enc, dp_hash = self.telerik_hashkey_load(dialogParameters_raw)
43 |
44 | for vkey in self.prepare_keylist():
45 | with suppress(binascii.Error):
46 | h = hmac.new(vkey.encode(), dp_enc, self.hash_algs["SHA256"])
47 | if base64.b64encode(h.digest()) == dp_hash:
48 | return {"secret": vkey, "details": None}
49 | return None
50 |
51 | def get_hashcat_commands(self, dialogParameters_raw, *args):
52 | dp_enc, dp_hash = self.telerik_hashkey_load(dialogParameters_raw)
53 | if not dp_enc or not dp_hash:
54 | return None
55 |
56 | try:
57 | dp_enc_decoded = base64.b64decode(dp_hash)
58 | dp_hash_decoded = base64.b64decode(dp_enc)
59 | except binascii.Error:
60 | return None
61 |
62 | return [
63 | {
64 | "command": f"hashcat -m 1450 -a 0 {dp_enc_decoded.hex()}:{dp_hash_decoded.hex()} --hex-salt ",
65 | "description": f"Telerik Hash Key Signature",
66 | }
67 | ]
68 |
69 | def hashkey_probe_generator(self, include_machinekeys=False, custom_keys=None):
70 | test_string = b"EnableAsyncUpload,False,3,True;DeletePaths,True,0,Zmk4dUx3PT0sZmk4dUx3PT0=;EnableEmbeddedBaseStylesheet,False,3,True;RenderMode,False,2,2;UploadPaths,True,0,Zmk4dUx3PT0sZmk4dUx3PT0=;SearchPatterns,True,0,S2k0cQ==;EnableEmbeddedSkins,False,3,True;MaxUploadFileSize,False,1,204800;LocalizationPath,False,0,;FileBrowserContentProviderTypeName,False,0,;ViewPaths,True,0,Zmk4dUx3PT0sZmk4dUx3PT0=;IsSkinTouch,False,3,False;ScriptManagerProperties,False,0,CgoKCkZhbHNlCjAKCgoK;ExternalDialogsPath,False,0,;Language,False,0,ZW4tVVM=;Telerik.DialogDefinition.DialogTypeName,False,0,VGVsZXJpay5XZWIuVUkuRWRpdG9yLkRpYWxvZ0NvbnRyb2xzLkRvY3VtZW50TWFuYWdlckRpYWxvZywgVGVsZXJpay5XZWIuVUksIFZlcnNpb249MjAxOC4xLjExNy40NSwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0xMjFmYWU3ODE2NWJhM2Q0;AllowMultipleSelection,False,3,False"
71 | dp_enc = base64.b64encode(test_string)
72 | for vkey in custom_keys if custom_keys else self.prepare_keylist(include_machinekeys=include_machinekeys):
73 | h = hmac.new(vkey.encode(), dp_enc, self.hash_algs["SHA256"])
74 | yield (f"{dp_enc.decode()}{base64.b64encode(h.digest()).decode()}", vkey)
75 |
76 | def sign_enc_dialog_params(self, hash_key, enc_dialog_params):
77 | dp_enc = enc_dialog_params.encode()
78 | h = hmac.new(hash_key.encode(), dp_enc, self.hash_algs["SHA256"])
79 | return f"{dp_enc.decode()}{base64.b64encode(h.digest()).decode()}"
80 |
--------------------------------------------------------------------------------
/badsecrets/modules/generic_jwt.py:
--------------------------------------------------------------------------------
1 | import re
2 | import jwt as j
3 | import json
4 | import base64
5 | from badsecrets.base import BadsecretsBase
6 |
7 | # XMLDSIG Translation Table
8 |
9 | XMLDSIG_table = {
10 | "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256": "HS256",
11 | "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384": "HS384",
12 | "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512": "HS512",
13 | "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256": "RS256",
14 | "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384": "RS384",
15 | "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512": "RS512",
16 | "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256": "ES256",
17 | "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384": "ES384",
18 | "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512": "ES512",
19 | "http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1": "PS256",
20 | "http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1": "PS384",
21 | "http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1": "PS512",
22 | }
23 |
24 |
25 | class Generic_JWT(BadsecretsBase):
26 | identify_regex = re.compile(r"eyJ(?:[\w-]*\.)(?:[\w-]*\.)[\w-]*")
27 | description = {"product": "JSON Web Token (JWT)", "secret": "HMAC/RSA Key", "severity": "HIGH"}
28 |
29 | @staticmethod
30 | def swap_algorithm(jwt, algorithm):
31 | header = j.get_unverified_header(jwt)
32 | header["alg"] = algorithm
33 | header_encoded = (
34 | base64.urlsafe_b64encode(json.dumps(header, separators=(",", ":")).encode()).rstrip(b"=").decode()
35 | )
36 | _, payload, signature = jwt.split(".")
37 | new_jwt = f"{header_encoded}.{payload}.{signature}"
38 | return new_jwt
39 |
40 | def carve_regex(self):
41 | return re.compile(r"(eyJ(?:[\w-]*\.)(?:[\w-]*\.)[\w-]*)")
42 |
43 | def jwtVerify(self, JWT, key, algorithm):
44 | try:
45 | r = j.decode(JWT, key, algorithms=[algorithm], options={"verify_exp": False})
46 | return r
47 | except j.exceptions.InvalidSignatureError:
48 | return None
49 |
50 | def jwtLoad(self, JWT):
51 | try:
52 | jwt_headers = j.get_unverified_header(JWT)
53 | # if the JWT is not well formed, stop here
54 | except j.exceptions.DecodeError:
55 | return (None, None, None)
56 | try:
57 | algorithm = jwt_headers["alg"]
58 |
59 | # It could be a JWT-like token that is actually a different format, for example a flask cookie
60 | except KeyError:
61 | return (None, None, None)
62 |
63 | if algorithm in XMLDSIG_table.keys():
64 | algorithm = XMLDSIG_table[algorithm]
65 | JWT = self.swap_algorithm(JWT, algorithm)
66 |
67 | return jwt_headers, algorithm, JWT
68 |
69 | def get_hashcat_commands(self, JWT, *args):
70 | jwt_headers, algorithm, JWT = self.jwtLoad(JWT)
71 | if jwt_headers and algorithm and JWT:
72 | if algorithm[0].lower() != "h":
73 | return None
74 |
75 | return [
76 | {
77 | "command": f"hashcat -m 16500 -a 0 {JWT} ",
78 | "description": f"JSON Web Token (JWT) Algorithm: {algorithm}",
79 | }
80 | ]
81 |
82 | def check_secret(self, JWT):
83 | if not self.identify(JWT):
84 | return None
85 |
86 | jwt_headers, algorithm, JWT = self.jwtLoad(JWT)
87 | if not jwt_headers or not algorithm or not JWT:
88 | return None
89 |
90 | if algorithm[0].lower() == "h":
91 | for l in self.load_resources(["jwt_secrets.txt", "top_100000_passwords.txt"]):
92 | key = l.strip()
93 |
94 | r = self.jwtVerify(JWT, key, algorithm)
95 | if r:
96 | r["jwt_headers"] = jwt_headers
97 | return {"secret": key, "details": r}
98 |
99 | elif algorithm[0].lower() == "r":
100 | for l in self.load_resources(["jwt_rsakeys_public.txt"]):
101 | private_key_name = l.split(":")[0]
102 | public_key = f"{l.split(':')[1]}".rstrip().encode().replace(b"\\n", b"\n")
103 | r = self.jwtVerify(JWT, public_key, algorithm)
104 | if r:
105 | r["jwt_headers"] = jwt_headers
106 | return {"secret": f"Private key Name: {private_key_name}", "details": r}
107 |
108 | return None
109 |
--------------------------------------------------------------------------------
/tests/rails_secretkeybase_test.py:
--------------------------------------------------------------------------------
1 | from badsecrets import modules_loaded
2 |
3 | Rails_SecretKeyBase = modules_loaded["rails_secretkeybase"]
4 |
5 | tests = [
6 | (
7 | "hash_algorithm",
8 | "SHA1",
9 | "4698bc5d99f3103ca76ab57f28a6b8f75f5f0768aab4f2e3f3743383594ad91f43e78c1b86138602f5859a811927698180ebfae7c490333f37b87521ca5a5f8c",
10 | "eyJfcmFpbHMiOnsibWVzc2FnZSI6IklraGxiR3h2TENCSklHRnRJR0VnYzJsbmJtVmtJSEpoYVd4ek5pQkRiMjlyYVdVaElnPT0iLCJleHAiOm51bGwsInB1ciI6ImNvb2tpZS5zaWduZWQifX0%3D--eb1ea3ddc55deb16ffc58ac165edfbb554067edc",
11 | ),
12 | (
13 | "encryption_algorithm",
14 | "AES_CBC",
15 | "6f9c2bdad527137950bd62e9688c6cd6a3f3ccc1bbd2972c2d9dbdc4bccbfeb38c2832804cfc62fc662ed54b15f8731083cc090b352168b335569cc4375a4696",
16 | "dUEvRldLekFNcklGZ3ZSbU1XaHJ0ZGxsLzhYTHlNTW43T3BVN05kZXE3WUhQOVVKbVA3Rm5WaSs5eG5QQ1VIRVBzeDFNTnNpZ0xCM1FKbzFZTEJISzhaNzFmVGYzME0waDFURVpCYm5TQlJFRmRFclYzNUZhR3VuN29PMmlkVHBrRi8wb3AwZWgvWmxObkFOYnpkeHR1YWpWZ3lnN0Y4ZW9xSk9LNVlQd0U4MmFsbWtLZUI5VzkzRkM4YXBFWXBWLS15L00xME1nVFp2ZTlmUWcxZVlpelpnPT0=--7efe7919a5210cfd1ac4c6228e3ff82c0600d841",
17 | ),
18 | (
19 | "encryption_algorithm",
20 | "AES_GCM",
21 | "4698bc5d99f3103ca76ab57f28a6b8f75f5f0768aab4f2e3f3743383594ad91f43e78c1b86138602f5859a811927698180ebfae7c490333f37b87521ca5a5f8c",
22 | "fuP54C4UxMudlZRR6j25zJfkevHVZ6IJR6Hp1B3rW6sAW5Aqc1j2Ri0XgcyLRvuSNVLwzq6cqeWlVhwU13xMS8scjU%2BSGGi%2Bta4jQU7oYujKdxynHSEiYOmeNFW4onXoF3KLlmr7ODmtIaHm1zIEP11TT%2FmRqZuxxecjz0VIxUDhvHYEFQ%3D%3D--ZclUs5zZFu3JPKnx--%2Fc0Q4ufTHqqmMxoin0mRtQ%3D%3D",
23 | ),
24 | ]
25 |
26 |
27 | negative_tests = [
28 | (
29 | "hash_algorithm",
30 | "SHA1",
31 | "4698bc5d99f3103ca76ab57f28a6b8f75f5f0768aab4f2e3f3743383594ad91f43e78c1b86138602f5859a811927698180ebfae7c490333f37b87521ca5a5f8c",
32 | "eyJfcmFpbHMiOnsibWVzc2FnZSI6IklraGxiR3h2TENCSklHRnRJR0VnYzJsbmJtVmtJSEpoYVd4ek5pQkRiMjlyYVdVaElnPT0iLCJleHAiOm51bGwsInB1ciI6ImNvb2tpZS5zaWduZWQifX0%3D--BADSECRETS5deb16ffc58ac165edfbb554067edc",
33 | ),
34 | (
35 | "encryption_algorithm",
36 | "AES_CBC",
37 | "6f9c2bdad527137950bd62e9688c6cd6a3f3ccc1bbd2972c2d9dbdc4bccbfeb38c2832804cfc62fc662ed54b15f8731083cc090b352168b335569cc4375a4696",
38 | "dUEvRldLekFNcklGZ3ZSbU1XaHJ0ZGxsLzhYTHlNTW43T3BVN05kZXE3WUhQOVVKbVA3Rm5WaSs5eG5QQ1VIRVBzeDFNTnNpZ0xCM1FKbzFZTEJISzhaNzFmVGYzME0waDFURVpCYm5TQlJFRmRFclYzNUZhR3VuN29PMmlkVHBrRi8wb3AwZWgvWmxObkFOYnpkeHR1YWpWZ3lnN0Y4ZW9xSk9LNVlQd0U4MmFsbWtLZUI5VzkzRkM4YXBFWXBWLS15$%^&&xME1nVFp2ZTlmUWcxZVlpelpnPT0=--7efe7919a5210cfd1ac4c6228e3ff82c0600d841",
39 | ),
40 | (
41 | "encryption_algorithm",
42 | "AES_CBC",
43 | "6f9c2bdad527137950bd62e9688c6cd6a3f3ccc1bbd2972c2d9dbdc4bccbfeb38c2832804cfc62fc662ed54b15f8731083cc090b352168b335569cc4375a4696",
44 | "UEvRldLekFNcklGZ3ZSbU1XaHJ0ZGxsLzhYTHlNTW43T3BVN05kZXE3WUhQOVVKbVA3Rm5WaSs5eG5QQ1VIRVBzeDFNTnNpZ0xCM1FKbzFZTEJISzhaNzFmVGYzME0waDFURVpCYm5TQlJFRmRFclYzNUZhR3VuN29PMmlkVHBrRi8wb3AwZWgvWmxObkFOYnpkeHR1YWpWZ3lnN0Y4ZW9xSk9LNVlQd0U4MmFsbWtLZUI5VzkzRkM4YXBFWXBWLS15$%^&&xME1nVFp2ZTlmUWcxZVlpelpnPT0=--7efe7919a5210cfd1ac4c6228e3ff82c0600d841",
45 | ),
46 | ]
47 |
48 |
49 | def test_rails():
50 | x = Rails_SecretKeyBase()
51 | for test in tests:
52 | print(test)
53 | found_key = x.check_secret(test[3])
54 | assert found_key
55 | assert found_key["secret"] == test[2]
56 | assert found_key["details"][test[0]] == test[1]
57 |
58 |
59 | def test_rails_negative():
60 | x = Rails_SecretKeyBase()
61 | for test in negative_tests:
62 | print(test)
63 | found_key = x.check_secret(test[3])
64 | assert not found_key
65 |
66 |
67 | def test_rails_malformed():
68 | x = Rails_SecretKeyBase()
69 | found_key = x.check_secret("AAECAwQF--AAECAwQF")
70 | assert not found_key
71 |
72 |
73 | def test_rails_error_unicode():
74 | x = Rails_SecretKeyBase()
75 | found_key = x.check_secret(
76 | "dUEvRldLekFNcklGZ3ZSbU1XaHJ0ZGxsLzhYTHlNTW43T3BVN05kZXE3WUhQOVVKbVA3Rm5WaSs5eG5QQ1VIRVBzeDFNTnNpZ0xCM1FKbzFZTEJISzhaNzFmVGYzME0waDFURVpCYm5TQlJFRmRFclYzNUZhR3VuN29PMmlkVHBrRi8wb3AwZWgvWmxObkFOYnpkeHR1YWpWZ3lnN0Y4ZW9xSk9LNVlQd0U4MmFsbWtLZUI5VzkzRkM4YXBFWXBWeS9NMTBNZ1RadmU5ZlFnMWVZaXpaZz09--7efe7919a5210cfd1ac4c6228e3ff82c0600d841"
77 | )
78 | assert not found_key
79 |
80 |
81 | def test_rails_error_binascii():
82 | x = Rails_SecretKeyBase()
83 | found_key = x.check_secret(
84 | "dUEvRldLekFNcklGZ3ZSbU1XaHJ0ZGxsLzhYTHlNTW43T3BVN05kZXE3WUhQOVVKbVA3Rm5WaSs5eG5QQ1VIRVBzeDFNTnNpZ0xCM1FKbzFZTEJISzhaNzFmVGYzME0waDFURVpCYm5TQlJFRmRFclYzNUZhR3VuN29PMmlkVHBrRi8wb3AwZWgvWmxObkFOYnpkeHR1YWpWZ3lnN0Y4ZW9xSk9LNVlQd0U4MmFsbWtLZUI5VzkzRkM4YXBFWXBWeS9NMTBNZ1RadmU5ZlFnMWV%20XpaZz09--7efe7919a5210cfd1ac4c6228e3ff82c0600d841"
85 | )
86 | assert not found_key
87 |
--------------------------------------------------------------------------------
/badsecrets/examples/blacklist3r.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # badsecrets - python 'blacklist3r' tool
3 | # Inspired by blacklist3r - https://github.com/NotSoSecure/Blacklist3r\n")
4 | # Black Lantern Security - https://www.blacklanternsecurity.com")
5 | # @paulmmueller
6 |
7 | import re
8 | import os
9 | import sys
10 | import argparse
11 | import requests
12 | import urllib.parse
13 | from requests.packages.urllib3.exceptions import InsecureRequestWarning
14 |
15 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
16 |
17 | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
18 | sys.path.append(os.path.dirname(SCRIPT_DIR))
19 |
20 | from badsecrets import modules_loaded
21 |
22 | ASPNET_Viewstate = modules_loaded["aspnet_viewstate"]
23 |
24 |
25 | def check_viewstate(viewstate, generator):
26 | bs_vs = ASPNET_Viewstate()
27 | r = bs_vs.check_secret(viewstate, generator)
28 | return r
29 |
30 |
31 | def print_result(r):
32 | print("Matching MachineKeys found!")
33 | print(r["secret"])
34 |
35 |
36 | def validate_viewstate(arg_value, pattern=re.compile(r"^(?:[A-Za-z0-9+\/=%]+)$")):
37 | if not pattern.match(arg_value):
38 | raise argparse.ArgumentTypeError("Viewstate is not formatted correctly")
39 | return arg_value
40 |
41 |
42 | def validate_generator(arg_value, pattern=re.compile(r"^(?:[A-Fa-f0-9]+)$")):
43 | if not pattern.match(arg_value):
44 | raise argparse.ArgumentTypeError("Generator is not formatted correctly")
45 | return arg_value
46 |
47 |
48 | def validate_url(
49 | arg_value,
50 | pattern=re.compile(
51 | r"^https?://((?:[A-Z0-9_]|[A-Z0-9_][A-Z0-9\-_]*[A-Z0-9_])[\.]?)+(?:[A-Z0-9_][A-Z0-9\-_]*[A-Z0-9_]|[A-Z0-9_])(?::[0-9]{1,5})?.*$",
52 | re.IGNORECASE,
53 | ),
54 | ):
55 | if not pattern.match(arg_value):
56 | raise argparse.ArgumentTypeError("URL is not formatted correctly")
57 | return arg_value
58 |
59 |
60 | def main():
61 | viewstate = None
62 | generator = "0000"
63 |
64 | generator_regex = re.compile(r'> $GITHUB_ENV
89 |
90 | - name: Fetch latest tag
91 | run: |
92 | git fetch --tags
93 | LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
94 | echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
95 |
96 | - name: Retrieve and strip "v" prefix if present
97 | run: |
98 | # Retrieve and strip "v" prefix if present
99 | CURRENT_VERSION="${{ env.VERSION }}"
100 | LATEST_VERSION="${{ env.LATEST_TAG }}"
101 | CURRENT_VERSION="${CURRENT_VERSION#v}"
102 | LATEST_VERSION="${LATEST_VERSION#v}"
103 |
104 | # Extract major.minor for comparison
105 | CURRENT_MAJOR_MINOR=$(echo "$CURRENT_VERSION" | cut -d '.' -f 1-2)
106 | LATEST_MAJOR_MINOR=$(echo "$LATEST_VERSION" | cut -d '.' -f 1-2)
107 |
108 | # Compare versions
109 | if [ "$CURRENT_MAJOR_MINOR" == "$LATEST_MAJOR_MINOR" ]; then
110 | echo "VERSION_CHANGE=false" >> $GITHUB_ENV
111 | else
112 | echo "VERSION_CHANGE=true" >> $GITHUB_ENV
113 | fi
114 | shell: bash
115 | env:
116 | VERSION: ${{ env.VERSION }} # dynamically passed VERSION variable
117 | LATEST_TAG: ${{ env.LATEST_TAG }} # dynamically passed LATEST_TAG variable
118 |
119 | - name: Build PyPi package
120 | if: github.ref == 'refs/heads/main' && env.VERSION_CHANGE == 'true'
121 | run: python -m build
122 |
123 | - name: Publish PyPi package
124 | if: github.ref == 'refs/heads/main' && env.VERSION_CHANGE == 'true'
125 | uses: pypa/gh-action-pypi-publish@release/v1.12
126 | with:
127 | password: ${{ secrets.PYPI_API_TOKEN }}
128 |
129 | - name: Tag the release if major or minor version changed
130 | if: github.ref == 'refs/heads/main' && env.VERSION_CHANGE == 'true'
131 | run: |
132 | git config user.name "github-actions[bot]"
133 | git config user.email "github-actions[bot]@users.noreply.github.com"
134 | git tag -a "${{ env.VERSION }}" -m "Release ${{ env.VERSION }}"
135 | git push origin "refs/tags/${{ env.VERSION }}"
136 |
--------------------------------------------------------------------------------
/badsecrets/modules/telerik_encryptionkey.py:
--------------------------------------------------------------------------------
1 | import re
2 | import hmac
3 | import base64
4 | import binascii
5 | import urllib.parse
6 | from Crypto.Cipher import AES
7 | from Crypto.Protocol import KDF
8 | from contextlib import suppress
9 | from Crypto.Util.Padding import pad
10 | from badsecrets.helpers import unpad
11 | from badsecrets.base import BadsecretsBase
12 | from badsecrets.helpers import Csharp_pbkdf1
13 | from badsecrets.errors import Telerik_EncryptionKey_Exception
14 |
15 | telerik_hardcoded_salt = [58, 84, 91, 25, 10, 34, 29, 68, 60, 88, 44, 51, 1]
16 |
17 |
18 | class Telerik_EncryptionKey(BadsecretsBase):
19 | identify_regex = re.compile(r"^(?:[A-Za-z0-9+\/=%]{32,})$")
20 | description = {
21 | "product": "Telerik DialogParameters",
22 | "secret": "Telerik.Web.UI.DialogParametersEncryptionKey",
23 | "severity": "MEDIUM",
24 | }
25 |
26 | def carve_regex(self):
27 | return re.compile(r"{\"SerializedParameters\":\"([^\"]*)\"")
28 |
29 | def prepare_keylist(self, include_machinekeys=False):
30 | if include_machinekeys:
31 | for l in self.load_resources(["aspnet_machinekeys.txt"]):
32 | with suppress(ValueError):
33 | vkey, ekey = l.rstrip().split(",")
34 | if ekey:
35 | yield ekey
36 | for l in self.load_resources(["telerik_encryption_keys.txt"]):
37 | ekey = l.strip()
38 | yield ekey
39 |
40 | def telerik_derivekeys(self, ekey, key_derive_mode):
41 | if key_derive_mode == "PBKDF1_MS":
42 | return self.telerik_derivekeys_PBKDF1_MS(ekey)
43 | elif key_derive_mode == "PBKDF2":
44 | return self.telerik_derivekeys_PBKDF2(ekey)
45 | else:
46 | raise Telerik_EncryptionKey_Exception("Invalid key_derive_mode")
47 |
48 | def telerik_derivekeys_PBKDF1_MS(self, ekey):
49 | csharp_pbkdf1 = Csharp_pbkdf1(ekey.encode(), bytes(telerik_hardcoded_salt), 100)
50 | derivedKey = csharp_pbkdf1.GetBytes(32)
51 | derivedIV = csharp_pbkdf1.GetBytes(16)
52 | return derivedKey, derivedIV
53 |
54 | def telerik_derivekeys_PBKDF2(self, ekey):
55 | pbkdf1 = KDF.PBKDF2(ekey.encode(), bytes(telerik_hardcoded_salt), dkLen=48)
56 | derivedKey = pbkdf1[:32]
57 | derivedIV = pbkdf1[32:]
58 | return derivedKey, derivedIV
59 |
60 | @classmethod
61 | def telerik_encrypt(self, derivedKey, derivedIV, dialog_parameters_pt):
62 | cipher = AES.new(derivedKey, AES.MODE_CBC, derivedIV)
63 | dialog_parameters_b64 = base64.b64encode(dialog_parameters_pt.encode()).decode().encode("utf-16le")
64 | dialog_parameters_raw = pad(dialog_parameters_b64, AES.block_size)
65 | encrypted_bytes = cipher.encrypt(dialog_parameters_raw)
66 | return base64.b64encode(encrypted_bytes).decode()
67 |
68 | @classmethod
69 | def telerik_decrypt(self, derivedKey, derivedIV, dp_enc):
70 | if not len(dp_enc) > 0:
71 | return None
72 |
73 | cipher = AES.new(derivedKey, AES.MODE_CBC, derivedIV)
74 | try:
75 | pt_raw = cipher.decrypt(dp_enc)
76 | except ValueError:
77 | return None
78 | original_bytes = unpad(pt_raw)
79 | try:
80 | decoded_bytes = original_bytes.decode("utf-16le")
81 | except UnicodeDecodeError:
82 | return None
83 | try:
84 | dialog_parameters = base64.b64decode(decoded_bytes).decode()
85 | except ValueError:
86 | return None
87 |
88 | return dialog_parameters
89 |
90 | def check_secret(self, dialogParameters_raw, key_derive_mode=None, include_machinekeys=False):
91 | if not key_derive_mode:
92 | key_derive_modes = ["PBKDF1_MS", "PBKDF2"]
93 | else:
94 | key_derive_modes = [key_derive_mode]
95 |
96 | if not self.identify(dialogParameters_raw):
97 | return None
98 |
99 | dialogParametersB64 = urllib.parse.unquote(dialogParameters_raw)
100 | try:
101 | dp_enc = base64.b64decode(dialogParametersB64[:-44])
102 | except binascii.Error:
103 | return None
104 | for key_derive_mode in key_derive_modes:
105 | for ekey in self.prepare_keylist(include_machinekeys=include_machinekeys):
106 | derivedKey, derivedIV = self.telerik_derivekeys(ekey, key_derive_mode)
107 | dialog_parameters = self.telerik_decrypt(derivedKey, derivedIV, dp_enc)
108 | if not dialog_parameters:
109 | continue
110 | if dialog_parameters.isascii():
111 | return {
112 | "secret": ekey,
113 | "details": {"DialogParameters": dialog_parameters},
114 | }
115 | return None
116 |
117 | def encryptionkey_probe_generator(self, hash_key, key_derive_mode, include_machinekeys=False, custom_keys=None):
118 | test_string = b"AAAAAAAAAAAAAAAAAAAA"
119 | dp_enc = base64.b64encode(test_string).decode()
120 |
121 | for ekey in custom_keys if custom_keys else self.prepare_keylist(include_machinekeys=include_machinekeys):
122 | derivedKey, derivedIV = self.telerik_derivekeys(ekey, key_derive_mode)
123 | ct = self.telerik_encrypt(derivedKey, derivedIV, dp_enc)
124 | h = hmac.new(hash_key.encode(), ct.encode(), self.hash_algs["SHA256"])
125 | yield (f"{ct}{base64.b64encode(h.digest()).decode()}", ekey)
126 |
--------------------------------------------------------------------------------
/badsecrets/helpers.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import hmac
3 | import struct
4 | import hashlib
5 | from colorama import Fore, Style, init
6 | from badsecrets.errors import BadsecretsException
7 |
8 | init(autoreset=True) # Automatically reset the color to default after each print statement
9 |
10 |
11 | def print_status(msg, passthru=False, color="white", colorenabled=True):
12 | color_dict = {"white": Fore.WHITE, "red": Fore.RED, "yellow": Fore.YELLOW, "blue": Fore.BLUE, "green": Fore.GREEN}
13 |
14 | colorama_color = color_dict.get(color.lower(), Fore.WHITE)
15 |
16 | if msg:
17 | if colorenabled:
18 | msg = f"{colorama_color}{msg}{Style.RESET_ALL}"
19 | if passthru:
20 | return msg
21 | else:
22 | print(msg)
23 |
24 |
25 | def _writeuint(v):
26 | return struct.pack(">I", v)
27 |
28 |
29 | def unpad(s):
30 | return s[: -ord(s[len(s) - 1 :])]
31 |
32 |
33 | def sp800_108_derivekey(key, label, context, keyLengthInBits):
34 | lblcnt = 0 if label is None else len(label)
35 | ctxcnt = 0 if context is None else len(context)
36 | buffer = b"\x00" * (4 + lblcnt + 1 + ctxcnt + 4)
37 | if lblcnt != 0:
38 | buffer = buffer[:4] + label + buffer[4 + lblcnt :]
39 | if ctxcnt != 0:
40 | buffer = buffer[: 5 + lblcnt] + context + buffer[5 + lblcnt + ctxcnt :]
41 | buffer = buffer[: 5 + lblcnt + ctxcnt] + _writeuint(keyLengthInBits) + buffer[5 + lblcnt + ctxcnt + 4 :]
42 | v = int(keyLengthInBits / 8)
43 | res = b"\x00" * v
44 | num = 1
45 | while v > 0:
46 | buffer = _writeuint(num) + buffer[4:]
47 | h = hmac.new(key, buffer, hashlib.sha512)
48 | hash = h.digest()
49 | cnt = min(v, len(hash))
50 | res = hash[:cnt] + res[cnt:]
51 | v -= cnt
52 | num += 1
53 | return res
54 |
55 |
56 | def write_vlq_string(string):
57 | encoded_string = string.encode("utf-8")
58 | length = len(encoded_string)
59 | length_vlq = bytearray()
60 | while length >= 0x80:
61 | length_vlq.append((length | 0x80) & 0xFF)
62 | length >>= 7
63 | length_vlq.append(length)
64 | return bytes(length_vlq) + encoded_string
65 |
66 |
67 | def sp800_108_get_key_derivation_parameters(primary_purpose, specific_purposes):
68 | derived_key_label = primary_purpose.encode("utf-8")
69 | derived_key_context = b"".join([write_vlq_string(purpose) for purpose in specific_purposes])
70 | return derived_key_label, derived_key_context
71 |
72 |
73 | class Csharp_pbkdf1_exception(BadsecretsException):
74 | pass
75 |
76 |
77 | class Csharp_pbkdf1:
78 | def __init__(self, passwordBytes, saltBytes, iterations):
79 | self.passwordBytes = passwordBytes
80 | self.saltBytes = saltBytes
81 | self.iterations = iterations
82 | self.extra = bytes([])
83 | self.extra_count = 0
84 | self.magic_number = 0
85 | if not iterations > 0:
86 | raise Csharp_pbkdf1_exception("Iterations must be greater than 0")
87 |
88 | try:
89 | self.lasthash = hashlib.sha1(passwordBytes + saltBytes).digest()
90 | except TypeError:
91 | raise Csharp_pbkdf1_exception("Password and Salt must be of type bytes")
92 |
93 | self.iterations -= 1
94 |
95 | for i in range(self.iterations - 1):
96 | self.lasthash = hashlib.sha1(self.lasthash).digest()
97 |
98 | self.derivedBytes = hashlib.sha1(self.lasthash).digest()
99 | self.ctrl = 1
100 |
101 | def GetBytes(self, keylen):
102 | if not isinstance(keylen, int):
103 | raise Csharp_pbkdf1_exception("GetBytes() must be called with an int")
104 |
105 | result = bytearray()
106 |
107 | if len(self.extra) > 0:
108 | self.magic_number = len(self.extra) - self.extra_count
109 | if self.magic_number >= keylen:
110 | result.extend(self.extra[self.extra_count : self.extra_count + keylen])
111 | if self.magic_number > keylen:
112 | self.extra_count += keylen
113 | else:
114 | self.extra = bytes([])
115 | self.derivedBytes = bytes([])
116 | return result
117 |
118 | result.extend(self.extra[self.magic_number : self.magic_number + self.magic_number])
119 | self.extra = bytes([])
120 |
121 | while len(self.derivedBytes) < keylen:
122 | self.derivedBytes += hashlib.sha1(bytes([ord(str(self.ctrl))]) + self.lasthash).digest()
123 | self.ctrl += 1
124 |
125 | result.extend(self.derivedBytes[: keylen - self.magic_number])
126 |
127 | if (len(self.derivedBytes) + self.magic_number) > keylen:
128 | self.extra = self.derivedBytes
129 | self.extra_count = keylen - self.magic_number
130 |
131 | self.derivedBytes = bytes([])
132 | return result
133 |
134 |
135 | def twos_compliment(unsigned):
136 | bs = bin(unsigned).replace("0b", "")
137 | val = int(bs, 2)
138 | b = val.to_bytes(1, byteorder=sys.byteorder, signed=False)
139 | return int.from_bytes(b, byteorder=sys.byteorder, signed=True)
140 |
141 |
142 | class Java_sha1prng:
143 | def __init__(self, key):
144 | keyBytes = key
145 | if not isinstance(key, bytes):
146 | keyBytes = key.encode()
147 |
148 | self.seed = hashlib.sha1(keyBytes).digest()
149 | self.state = None
150 | self.outBytes = b""
151 |
152 | # Simulate setseed()
153 | self.state = hashlib.sha1(self.seed).digest()
154 | self.outBytes = hashlib.sha1(self.state).digest()
155 | self.updateState(self.outBytes)
156 |
157 | def updateState(self, output):
158 | last = 1
159 | outputBytesArray = bytearray(output)
160 | newState = bytearray()
161 |
162 | for c, n in zip(self.state, outputBytesArray):
163 | v = twos_compliment(c) + twos_compliment(n) + last
164 | finalv = v & 255
165 | newState.append(finalv)
166 | last = v >> 8
167 | self.state = newState
168 |
169 | def get_sha1prng_key(self, outLen):
170 | while len(self.outBytes) < outLen:
171 | output = hashlib.sha1(self.state).digest()
172 | self.outBytes += output
173 | self.updateState(output)
174 | return self.outBytes[:outLen]
175 |
--------------------------------------------------------------------------------
/badsecrets/resources/jwt_rsakeys_private.txt:
--------------------------------------------------------------------------------
1 | 1:-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA6cs10W3XKnr1MDoO0NgfYEixdQy5e3m/E4POPC5t6yyc/eZZ\nayytrA6CfaZXBKnYU4YKD06sJULj30qw/TJJwphhb2a5s3sjXejL4KW2WTdP6F+D\nbSaokzvKVdaZ97GnLtiei8n6gnSE1xSsJ15+d9JHImekuW/ggksVbI26UTiXvfv7\nLUJ8ntt6wG1UQHWOvYbG81TTpZjItvZsYu1tpekjNpOwCsIbO//S1JOiSgpuKp7H\nwCnQwABNEWyMuIAMlymMyocbTdQHcClogZC9bwokxTPZGmD9xZ+meaeVD5HONqAS\nIJ1tOoFGsnwwwlEhwsul0FRs7qehuhJmKE5ZbwIDAQABAoIBAQCGiSKqJqwnzOPl\nYbN+6K99h7depPjjnhafkzyNkyY7q8uXrAOO0gIKvbrHtX3juB09Syfk0R/svUZG\nC0Q4H8UkTu3a3mFEcDrU4o7X8mQxiMvZ64TEvfdJ6qEvrjOhvsB3C76IsK0Qfx6m\nakX6zby3FPFMUhoPf9rQ/4YPlqs96tpybA6yYznHZaMGu8j+nNCeCb8xYh/jhon5\nCSOb5csOD2JQ1nUwcmMNpZn2xziZP0d+c5rlrX2IzB+Q2QZLM7C3rxGx2Q4YxMRZ\ndRLdoQs3cb4HOU2otrinrJ8+MBF+HKKXNN0u1x+VnLPdb6JX3hFylSZ5u0XdOCIG\n5dlvjFBpAoGBAPua8Whot8r6RolnaL8qMG+8t3pL9UpqR6ZLSsntMSudYrBSFVR4\noM4SFKymnusaHt6NvKwWUFW2NPgq03mekwX4wmZM1VXnKETmuoUcLL9kH/pwS2UT\n3ygtMMaBCyhSR0H2SLkNDpqmwFAQn83vVah+ouZYg5+GXfBp0qk7YDLzAoGBAO3g\nn31086MQiX7BT8vl9ddZT4g0e3XjUdt+mE3ym1KFyj017pzMZTMR7Mfq0D9OVOvG\n3fVJ0oH+fo/8FAwMAOpibLUOMdKHzD87n/3DWivHEV0NezTHzYTvufA5IUG1V2nQ\n+qrQZO4lPcsj0Nx/ZAdgsTxuYAVKYSTVVKnZJQaVAoGBAKlQPT/rqDL5dNomMoDi\nHTI0JqwvzWNEXe70H+H+seYNxUmuExiDDINf+3Wrsqm3LCrL6rlLUsg7Ey4lc6YW\nJg4QtpEtBysFoT2snrvQl/Q7pqFbTAE6/CMHNhl+4UlDBRzIZWvR84/ywtueNEva\n0SPQBENKMVj6jOCp9c9YW4YtAoGATXqWOCS5nmkqf5CzTvRNyKCcWP7PH6y04ssv\nDGRy1sQhBSLl30hrxeCWwN7oiVYYLtuNO/GZkSG1U2yFkw7t1WnNgoNnEu2MRyRC\njkLswcmLDEXx1VUmyZ/Tbj0NafuIxzx8CNrrpO2YXOwDgW40xHpoAAjrWY3KalbZ\nxqClgKkCgYEAoWexPasw32n1NNlUv+cPhsgoQyxQJcpdziN14KJOu7E2QrK7gT34\n8JOos1TTU/iuYYq+1vwrwtlSX1+avQuW61IZ+tCzGZhfXgSGQoldA+/iq/8bFQEb\n8nwdyxiI8DGcgpbqTDiLyZX2rSSk/tuovN7nxT4fK1iz/nvdimHt9tc=\n-----END RSA PRIVATE KEY-----
2 | 2:-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp\nwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5\n1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh\n3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2\npIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX\nGukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il\nAkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF\nL0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k\nX6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl\nU9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ\n37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=\n-----END RSA PRIVATE KEY-----
3 | 3:-----BEGIN RSA PRIVATE KEY-----\nMIIEoAIBAAKCAQEAnFWdIwBbLRw4xfFDXYFmlXKB4BpKeuAtfh1dcs5mhod0WTo/\ni/Z4DOpiiw/2H05luI4PzOZem8AlHI9hUhHq5p1+YHM68SyvBQ9OTl+O90nmLYOt\n2Jzquks11bf29nJh7KwGVHOv2nh3eL39BVsqHSt0O/rjSa0bV+QtUc2DP9U4WzZ3\n8RhT2bdiRcsDuMfI024u9JGG/O4iG3wDlXyS5j6G0NVw/KEJJtYYv8ruQVpvlKUd\nNtx7aE+u6F60SjJYQSfdjMoQNMDglBFwhY11RlHSmiJ/Ym8aE+Hj11JHhPcB1N+X\nRWaHV9ply4TnE13PsQtGWVKsLDNQNUeIUljKdQIDAQABAoIBAAa4d3owYxBcDOTA\nK7vdUDekezN9wy3nwozlXkW33G3JbOsDt1pLoiWL/eh/Kyl1XqdsaVQkTco28bbP\nQx5wFBUN4tzqlzdpoFcrV/EZPTV268+RFZbLnXDyGBez7N3zVNpZGtHj7JoLtmHD\nvm4jLnr1NJik1G3aZI6GtJwLpaocwtKWHB59hVwF5NinW6BXN0ALNfwKwU4vMWYo\nI65F2zvGMVl9rbfvU+E73DXK3TN5tLOAkqZMQ8+g/VnNd/XuZwh2ZADokEXV8aNR\n7zVm3MCCcaa8IKJMrgnb9q47tzfyaoIu5aRYGYKZ/8wuItv4Dal30MK1CQoCD8cD\n5uzorQECgYEA9+QTCXrVHzhJJm+QWQZrXu7ydk+tEix7WY9ZY702OHiTO2x9IT4d\n4lKFbLhQrQMAFhO3B31Hq5ODGS4jB3bFzATrtOR9eLCR7l+0Az2FcU1Zmqsdkyv8\nzlkD9oOYif6rICrVyLQ/lbQF7erVDRbxJUjeKqGAnvELrlzcr+rx+XECgYEAoXLQ\nMdR+OLsP5XbcoA//Z2pgwwKZVs282MfYjZLVqeEAAC8BB9+8HHrtMaJGvADI06OV\n7lTCDaE8UlqgzN2B55FmCTiLABjhk3fEDrhGVe4jhEZz1i8t0ArjsYTwXs/uXoUz\nYP2rcJtkybOQEzjbvM4s5+B8iht+dYaqwoW5/0UCgYAp68UYZlBiXjdoq5dCpuZD\ngK86ONEw8JrPk4Fvb5EazbFAbGFg3Mta+c+cijMCfy5ljWH3f0U+i8yw1m+QFJLw\npKhjx/w8C8gyArdDkQTfG1Ca6nMu71JqZv1Xk/uY4pt37iaHMYxLOc2C5aKv+wA+\n6OrBVNyWhHcQPp4Hlfjj0QJ/de5oJf4SNV5vPi6U+la1OdV62PgNCls+lxtkFAYu\nDOlOFtQ+7IGB50vj912STcJE8FOOMYm4NjyQ05df3kXvnjeXUST8ZBXIsO/LRvVU\na3CIgRb1hn7v+Af8Sq/Q5XD9rg2eejrSAG+CL9P6ahAecswoATj5v+hVd4PnODB2\nrQKBgAwe3pkQRFHjameLHip+xcHQ85aASiLjhTvFhFjRHDpJ+FoiJ2H4xi4/jd1F\nKGrhMpVnLXKwe1HaONFPV3yEFK2da1r66iIr/opcx1hyKmV1xvebcUxYYoRY6j/g\nJMsceBR10oGEath+43rS78LASIQG83PmTYhkcEkQNftxEGqC\n-----END RSA PRIVATE KEY-----
4 | 4:-----BEGIN RSA PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCKAIc+hqdKgcPb\n9XbR5Osbdeq1J14zxRG58CkrHZO0PMSf/smoCEyEcxhGsjrITl/sLv/q8iOVMKgY\nKdpOMIoPDGCF8KCXA4F9hM/WXJstprEeqPi7a1FnXzi3uwaf+jy2zUviDt09jm+g\nuu5TaZzTuzyoClEgfwIu2LwuHaJKtjceRKHWKvUqqxBQMXlq/s5lNXWajWSpLffP\n/5L0YfCK9uW1FJJXT4cP9fiNbcd6GiHGwVk/eJy4QYaR9lWNvnKKu1H52xgWkLC+\nTwfOtcqtjF9sWE5XIAjpdFVh5u64g/uOafKzEF/yVOTzPvYUWI3PhKjqSS3V3yhk\nTqoFG53hAgMBAAECggEALo0NEgdkCRsK0XjUsurQb/vvx1nXSglQ+HLNwFCC0Yqq\nHPpaVccu4ILejoJyl7zwWIBmLX+uhxXZrgT4MeXnvDnFmYjY8vfox0l0vm+QnO6c\n0qXW+Ymy9PbG8BszmeVUc6l+zmuLL8eLWiGUYSjAESAYzupkAV02hEzx9XBjnWWl\nifoWOXvO22ADtO8jRk1ODbOrqyt1Hz7UDLtQI6Vdw3QovadW/3hKCx+0a/WxgDhR\nVosPudbzIGYBzdnbOyT+ToVIyMBTJU/8muZbWsaaOXHhel9lD/CUjvCcivL5tcSU\n0KvEiHVCXWfojbuy/RksgSTvl/aFEOrmqRjyu2JEbQKBgQDt+B4r6NVuqOPus+Xb\nRHF8QpvtwzIWSxxAwbtAWxWDJSrMMlhAx1yZ4kefSxbxAkdNkv9vQoVabVAEiWdJ\nVzXB8W9tvcD57zrbiraHQI5hCn+t5GIsSTnbhg6CG2dxv58uWviDneeNEdDeki+b\nvwTTXuHIeyCnPdLI/vaMzO0clwKBgQCUdVm5IYxRd93ohYH14zIfty+7J301iB3t\nt/fccrg1qjx4WniLbhLweVYdL44XpzMZUzdAYFhyHUIyAWIR4yHC3b0+u34oshjv\nMD/gjWPiNTBBthYTy559todm3jyj+g9Z+gLLu2G93+wGl3u15igiTy0oMmh4bS3s\nxtFk1pLQRwKBgF8L+wEOvjC0xFVTBTvO2oUHFcChdh/xYBd9SY0q1CzNa4qjkRxO\nhG3yMykslL0ua8xQKjYGG71Ca/Nj7h0c+Bu+kwMCB1HMe3W0sbLT1gpsZxLNZWjK\n1pEXujO9PlPwdWPOcfQf3Zw6wXIkcV+DrCnAe+3XP/OMfeRJ8a/LKemBAoGAf46M\n9wqiO+WYH4+G6LS7fpCxTEdTx8kangQxzZIsQL/ykR568KI1V7WJji4sEpqwxxO/\nJ2sg03vcQob5spDLk1lenyYN8f2Eew+j8tbJebVlrzA6q+uKVE2e7X4J8IKM6ixs\ndoycIL7jV46U1ufYmBIbpKwbI0375bO2esP7BUUCgYBqmx7GJnyOapOYlR7wHhYL\nrXk0QWwE7j3d4zQCHGOqzFqWxyIi1hsQYCwgOeobmd0r5kULRRptYBKvflEiboVq\nRL3VeyR9ZIEDkbCUewwf2qn6EoOCfi7x6/36brhn8r3mWC9rvNiKB33iBJrkin1p
5 | f0aUgyrlhk1aMnDDBFFb8A==\n-----END RSA PRIVATE KEY-----
6 | 5:-----BEGIN RSA PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDWvChzPXBs9aA3\nVlCKSG5z/EaTgpXlSDqiBVmoUKVFTIvK+mj72QYZLIXwp8GimNJAK+atUdH5YfNN\nB8x2eQg2NLYigdnv5/lADI8gAcUVf1cKSwt9kgpLv2CURBBIlMh9eg3ofN9eCRm7\nrbsVULOtYjpMe2nbLNdmdBtuVcjpKfN8nC4uWcoogK0jJ4ijBNmsIqAFCcIFWMuG\nz2HENSFSbx+XOavsOaxrfsQpZI5IqiZMAR3GXCFkYu2nPrpUAhAElBql0TE/xr7l\ndxfm5wwTPMbcUvBvIskYUqMkhc+LeO1zC0GNYhJju2Y6Ur3MJf0ztewwj1HOqD2b\nQ3pAHjO9AgMBAAECggEATus8Go5cAU+MoInSc+AG6A2xiokVufx/wAgjWV66PuvQ\n/LpnVxf9y8a3OykMW0u7CeaYkt5dQ0AigQ76sBfvUqywu6HpjOg+jLGQ8Hx2CF6S\niK/n+zBvJEOjpRoWufYkcSkob2dlWFQT5wwEk+LjBjfxoSZCU1D5oSfO5RAWFMqv\nUWFQjlhpgtFWzBNtZIMBetWUeHuNJNYSCA2Gu2tv4yQqHgxcwScM596OXErduZc1\nOZQ9Kwxe9AE6pFryxcxyngJWOKky668JwUdc/IKDzsg4O5uodZabtR1aAsX6IMAQ\nylRZeCnV/BHSljoS0wAXvUNcC4KsuFUiROIoGNfCaQKBgQD+J5quLr+Exso1KvZZ\n3X4lK+hWx+7uSOr5j0No6Y+u5X98whbGqwXPFpjLFqQlcpx0DKbl4Od0FqeKBTdv\nqiL3b2CRp4w+AgHjfM2ENg5XgkQDZXwToQy8ZIQvL82QMnZMYYrVoV6PfCIs7+/t\nrWL+25IrP/NB9jGRKFCCBWz1ewKBgQDYS0jcaC11BvT4AfJfmZVZ8nPQuy5IB6Uq\nI++5PhtTRxOW/XS/kiblp5grVmD8ZgSyIgCBU3zcZ9AF5KyN2Xl7fM8oB1owxXmi\nSZgEA9b66elR7nnMRmPsDeeA0LBfasIIlifNdzEVyuy3BrI38zIuj/h1zs2WsLbX\ntQh4smoKJwKBgQCYmMTZsj3Rhd3g4GO7fy5/OQauHCsMLQHQR0FNG3bmpurNyGcO\nb570QPgKcBSsW00urG4E9e1iGTwMtaccR4XpFJlhuryMen4RzVxD9oTT6+XUODmw\nO3E/KAbpogUFgBbhM2u9ar8w3XJTkth21zTqGoF/sEzpHN2T7yWve3x5QwKBgQCB\nZJhT8qavCdhmvZNniZOFWbvbNP887AXsrc7tfLAQI8ceXsYHDMHkRVyNIIGovMc2\nYYz30SAzIo+Z1vE7csxwCXxMMAnOf3SCl5AvZrSnKmQANa/7emiwgKjrsOyySEWH\nqXxqOFHO/bSa0ZCwU/bDUDGNGIh5C4J2jMBipCk3pQKBgAfrM+zHmXxkTMUtFeZT\nOuZVv/4NEQYI0Sb243K/+PVw0c0VjIzp6SuDGvVhzcXV+0K8AhFaYBoAp4BSL11M\nfcmlSTMA1Zi6xOlgwuRDvsw03pRLBD8cJ7YzYau0UTqSWa+/ojXpuSdN4o5ZOsDJ\ntpl2RanF4WWFPPMrGYoPZ0f4\n-----END RSA PRIVATE KEY-----
--------------------------------------------------------------------------------
/tests/examples_blacklist3r_test.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import requests
4 | import requests_mock
5 | from mock import patch
6 |
7 | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
8 | sys.path.append(f"{os.path.dirname(SCRIPT_DIR)}/examples")
9 | from badsecrets.examples import blacklist3r
10 |
11 | base_viewstate_page = """
12 |
13 |
14 |
15 | Untitled Page
16 |
17 |
18 |
32 |
33 |
34 | """
35 |
36 | vulnerable_viewstate = (
37 | "o6oVz97xjF/9t1+trA4X4xBFcTnk9bFXqzCNksR5PszHkTScHA/onlBaTUX0tEiHyZX18kIGkuiNoJBmzaGmjEqNsiJuIxrBRjT52D+DEWM7n6d+"
38 | )
39 |
40 | non_vulnerable_viewstate = (
41 | "BADsecrets/9t1+trA4X4xBFcTnk9bFXqzCNksR5PszHkTScHA/onlBaTUX0tEiHyZX18kIGkuiNoJBmzaGmjEqNsiJuIxrBRjT52D+DEWM7n6d+"
42 | )
43 |
44 | no_viewstate_page = "Just a website"
45 |
46 |
47 | def test_examples_blacklist3r_manual(monkeypatch, capsys):
48 | # Valid Viewstate Unencrypted W/Generator
49 | monkeypatch.setattr(
50 | "sys.argv",
51 | [
52 | "python",
53 | "--viewstate",
54 | "/wEPDwUJODExMDE5NzY5ZGSglOSr1rG6xN5rzh/4C9UEuwa64w==",
55 | "--generator",
56 | "EDD8C9AE",
57 | ],
58 | )
59 | blacklist3r.main()
60 | captured = capsys.readouterr()
61 | assert "Matching MachineKeys found!" in captured.out
62 | assert (
63 | "F5144F1A581A57BA3B60311AF7562A855998F7DD203CD8A71405599B980D8694B5C986C888BE4FC0E6571C2CE600D58CE82B8FA13106B17D77EA4CECDDBBEC1B"
64 | in captured.out
65 | )
66 | assert "validationAlgo: SHA1" in captured.out
67 |
68 | # Valid Viewstate Encrypted
69 | monkeypatch.setattr(
70 | "sys.argv",
71 | [
72 | "python",
73 | "--viewstate",
74 | "dn/WEP+ogagnOcePgsXoPRe05wss0YIyAZdzFHJuWJejTRbDNDEqes7fBwNY4IqTmT7kTB0o9f8fRSpRXaMcyg==",
75 | ],
76 | )
77 | blacklist3r.main()
78 | captured = capsys.readouterr()
79 | assert "Matching MachineKeys found!" in captured.out
80 | assert (
81 | "F5144F1A581A57BA3B60311AF7562A855998F7DD203CD8A71405599B980D8694B5C986C888BE4FC0E6571C2CE600D58CE82B8FA13106B17D77EA4CECDDBBEC1B"
82 | in captured.out
83 | )
84 | assert "encryptionAlgo: DES" in captured.out
85 |
86 | # Invalid viewstate is Rejected
87 | monkeypatch.setattr(
88 | "sys.argv",
89 | [
90 | "python",
91 | "--viewstate",
92 | "/wEPDwUJODExMDE5NzY5ZGSglOSr1rG6xN4rzh/4C9UEuwa64w==",
93 | "--generator",
94 | "EDD8C9AE",
95 | ],
96 | )
97 | blacklist3r.main()
98 | captured = capsys.readouterr()
99 | assert "Matching MachineKeys NOT found" in captured.out
100 |
101 | # Invalid generator is rejected
102 | monkeypatch.setattr(
103 | "sys.argv",
104 | [
105 | "python",
106 | "--viewstate",
107 | "/wEPDwUJODExMDE5NzY5ZGSglOSr1rG6xN5rzh/4C9UEuwa64w==",
108 | "--generator",
109 | "^INVALID^",
110 | ],
111 | )
112 | with patch("sys.exit") as exit_mock:
113 | blacklist3r.main()
114 | assert exit_mock.called
115 | captured = capsys.readouterr()
116 | assert "Generator is not formatted correctly" in captured.err
117 |
118 | # Viewstate doesn't match pattern and is rejected
119 | with patch("sys.exit") as exit_mock:
120 | monkeypatch.setattr(
121 | "sys.argv",
122 | [
123 | "python",
124 | "--viewstate",
125 | "^INVALID^",
126 | "--generator",
127 | "EDD8C9AE",
128 | ],
129 | )
130 | blacklist3r.main()
131 | captured = capsys.readouterr()
132 | assert "Viewstate is not formatted correctly" in captured.err
133 |
134 |
135 | def test_examples_blacklist3r_offline(monkeypatch, capsys):
136 | with patch("sys.exit") as exit_mock:
137 | # Invalid URL is rejected
138 | monkeypatch.setattr("sys.argv", ["python", "--url", "hxxp://notaurl"])
139 | blacklist3r.main()
140 | assert exit_mock.called
141 | captured = capsys.readouterr()
142 | assert "error: One of --url or --viewstate is required" in captured.err
143 |
144 | with patch("sys.exit") as exit_mock:
145 | # Both URL and viewstate are supplied - rejected appropriately
146 | monkeypatch.setattr(
147 | "sys.argv",
148 | [
149 | "python",
150 | "--url",
151 | "http://example.com",
152 | "--viewstate",
153 | "dn/WEP+ogagnOcePgsXoPRe05wss0YIyAZdzFHJuWJejTRbDNDEqes7fBwNY4IqTmT7kTB0o9f8fRSpRXaMcyg==",
154 | ],
155 | )
156 | blacklist3r.main()
157 | assert exit_mock.called
158 | captured = capsys.readouterr()
159 | assert "error: --viewstate/--generator options and --url option are mutually exclusive" in captured.err
160 |
161 | with requests_mock.Mocker() as m:
162 | m.get(
163 | f"http://example.com/vulnerableviewstate.aspx",
164 | status_code=200,
165 | text=base_viewstate_page.replace("###viewstate###", vulnerable_viewstate),
166 | )
167 | m.get(
168 | f"http://example.com/nonvulnerableviewstate.aspx",
169 | status_code=200,
170 | text=base_viewstate_page.replace("###viewstate###", non_vulnerable_viewstate),
171 | )
172 | m.get(f"http://example.com/noviewstate.aspx", status_code=200, text=no_viewstate_page)
173 | m.get(f"http://notreal.com/", exc=requests.exceptions.ConnectTimeout)
174 | # URL Mode - Valid URL is visited, contains viewstate, viewstate is vulnerable
175 |
176 | monkeypatch.setattr("sys.argv", ["python", "--url", "http://example.com/vulnerableviewstate.aspx"])
177 | blacklist3r.main()
178 |
179 | # URL Mode - Valid URL is visited, contains viewstate, viewstate is vulnerable
180 | captured = capsys.readouterr()
181 | assert "Matching MachineKeys found!" in captured.out
182 | assert (
183 | "F4F0AC3A8889DFBB6FC9D24275A8F0E523C1FB1A2F3FA0C3F3B36320A80670E1D62D15A16A335F0CB14F8AECE7002A5BD8A980F677EA82666B49167947F0A669"
184 | in captured.out
185 | )
186 | assert "encryptionAlgo: AES" in captured.out
187 |
188 | # URL Mode - Valid URL is visited, contains viewstate, viewstate is NOT vulnerable
189 | monkeypatch.setattr("sys.argv", ["python", "--url", "http://example.com/nonvulnerableviewstate.aspx"])
190 | blacklist3r.main()
191 | captured2 = capsys.readouterr()
192 | assert "Matching MachineKeys NOT found" in captured2.out
193 |
194 | # URL Mode - Valid URL is visited, does not contain viewstate
195 | monkeypatch.setattr("sys.argv", ["python", "--url", "http://example.com/noviewstate.aspx"])
196 | blacklist3r.main()
197 | captured2 = capsys.readouterr()
198 | assert "Did not find viewstate in repsonse from URL" in captured2.out
199 |
200 | # URL Mode - Validly formatted URL is not responding
201 | monkeypatch.setattr("sys.argv", ["python", "--url", "http://notreal.com"])
202 | blacklist3r.main()
203 | captured2 = capsys.readouterr()
204 | assert "Error connecting to URL" in captured2.out
205 |
--------------------------------------------------------------------------------
/badsecrets/examples/cli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # badsecrets - command line interface
3 | # Black Lantern Security - https://www.blacklanternsecurity.com
4 | # @paulmmueller
5 |
6 | from badsecrets.base import check_all_modules, carve_all_modules, hashcat_all_modules
7 | from badsecrets.helpers import print_status
8 | import requests
9 | import argparse
10 | import sys
11 | import os
12 | import re
13 | from importlib.metadata import version, PackageNotFoundError
14 |
15 |
16 | from urllib3.exceptions import InsecureRequestWarning
17 |
18 | # Suppress only the single warning from urllib3 needed.
19 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
20 |
21 | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
22 | sys.path.append(os.path.dirname(SCRIPT_DIR))
23 |
24 | ascii_art_banner = r"""
25 | __ ) | |
26 | __ \ _` | _` | __| _ \ __| __| _ \ __| __|
27 | | | ( | ( | \__ \ __/ ( | __/ | \__ \
28 | ____/ \__,_| \__,_| ____/ \___| \___| _| \___| \__| ____/
29 | """
30 |
31 |
32 | def print_version():
33 | try:
34 | version_str = version("badsecrets")
35 | except PackageNotFoundError:
36 | version_str = "Unknown (Running w/poetry?)"
37 | print(f"Version - {version_str}\n")
38 |
39 |
40 | class CustomArgumentParser(argparse.ArgumentParser):
41 | def error(self, message):
42 | self.print_usage()
43 | self.exit(1)
44 |
45 |
46 | class BaseReport:
47 | def __init__(self, x):
48 | self.x = x
49 |
50 | def print_report(self, report_message):
51 | print(report_message)
52 | print(f"Detecting Module: {self.x['detecting_module']}\n")
53 | print(f"Product Type: {self.x['description']['product']}")
54 | print(f"Product: {self.x['product']}")
55 | print(f"Secret Type: {self.x['description']['secret']}")
56 | print(f"Location: {self.x['location']}")
57 |
58 |
59 | class ReportSecret(BaseReport):
60 | def report(self):
61 | self.print_report(print_status("Known Secret Found!\n", color="green", passthru=True))
62 | print_status(f"Secret: {self.x['secret']}", color="green")
63 | severity = self.x["description"]["severity"]
64 | if severity in ["CRITICAL", "HIGH"]:
65 | severity_color = "red"
66 | elif severity in ["LOW", "MEDIUM"]:
67 | severity_color = "yellow"
68 | elif severity == "INFO":
69 | severity_color = "blue"
70 | print_status(f"Severity: {self.x['description']['severity']}", color=severity_color)
71 | print(f"Details: {self.x['details']}\n")
72 |
73 |
74 | class ReportIdentify(BaseReport):
75 | def report(self):
76 | self.print_report(
77 | print_status("Cryptographic Product Identified (no vulnerability)\n", color="yellow", passthru=True)
78 | )
79 | if self.x["hashcat"] is not None:
80 | print_hashcat_results(self.x["hashcat"])
81 |
82 |
83 | def validate_url(
84 | arg_value,
85 | pattern=re.compile(
86 | r"^https?://((?:[A-Z0-9_]|[A-Z0-9_][A-Z0-9\-_]*[A-Z0-9_])[\.]?)+(?:[A-Z0-9_][A-Z0-9\-_]*[A-Z0-9_]|[A-Z0-9_])(?::[0-9]{1,5})?.*$",
87 | re.IGNORECASE,
88 | ),
89 | ):
90 | if not pattern.match(arg_value):
91 | raise argparse.ArgumentTypeError(print_status("URL is not formatted correctly", color="red"))
92 | return arg_value
93 |
94 |
95 | def validate_file(file):
96 | if not os.path.exists(file):
97 | raise argparse.ArgumentTypeError(print_status(f"The file {file} does not exist!", color="red"))
98 | if not os.path.isfile(file):
99 | raise argparse.ArgumentTypeError(print_status(f"{file} is not a valid file!", color="red"))
100 | if os.path.getsize(file) > 100 * 1024: # size in bytes
101 | raise argparse.ArgumentTypeError(
102 | print_status(f"The file {file} exceeds the maximum limit of 100KB!", color="red")
103 | )
104 | return file
105 |
106 |
107 | def print_hashcat_results(hashcat_candidates):
108 | if hashcat_candidates:
109 | print_status("\nPotential matching hashcat commands:\n", color="yellow")
110 | for hc in hashcat_candidates:
111 | print(
112 | f"Module: [{hc['detecting_module']}] {hc['hashcat_description']} Command: [{hc['hashcat_command']}]\n"
113 | )
114 |
115 |
116 | def main():
117 | global colorenabled
118 | colorenabled = False
119 | color_parser = argparse.ArgumentParser(add_help=False)
120 |
121 | color_parser.add_argument(
122 | "-nc",
123 | "--no-color",
124 | action="store_true",
125 | help="Disable color message in the console",
126 | )
127 |
128 | args, unknown_args = color_parser.parse_known_args()
129 | colorenabled = not args.no_color
130 |
131 | parser = CustomArgumentParser(
132 | description="Check cryptographic products against badsecrets library", parents=[color_parser]
133 | )
134 |
135 | if colorenabled:
136 | print_status(ascii_art_banner, color="green")
137 |
138 | else:
139 | print(ascii_art_banner)
140 | print_version()
141 |
142 | parser.add_argument(
143 | "-u",
144 | "--url",
145 | type=validate_url,
146 | help="Use URL Mode. Specified the URL of the page to access and attempt to check for secrets",
147 | )
148 |
149 | parser.add_argument(
150 | "-nh",
151 | "--no-hashcat",
152 | action="store_true",
153 | help="Skip the check for compatable hashcat commands when secret isn't found",
154 | )
155 |
156 | parser.add_argument(
157 | "-c",
158 | "--custom-secrets",
159 | type=validate_file,
160 | help="include a custom secrets file to load along with the default secrets",
161 | )
162 |
163 | parser.add_argument("product", nargs="*", type=str, help="Cryptographic product to check for known secrets")
164 |
165 | parser.add_argument(
166 | "-p",
167 | "--proxy",
168 | help="In URL mode, Optionally specify an HTTP proxy",
169 | )
170 |
171 | parser.add_argument(
172 | "-a",
173 | "--user-agent",
174 | help="In URL mode, Optionally set a custom user-agent",
175 | )
176 |
177 | parser.add_argument(
178 | "-r",
179 | "--allow-redirects",
180 | action="store_true",
181 | help="Optionally follow HTTP redirects. Off by default",
182 | )
183 |
184 | args = parser.parse_args(unknown_args)
185 |
186 | if not args.url and not args.product:
187 | parser.error(
188 | print_status(
189 | "Either supply the product as a positional argument (supply all products for multi-product modules), use --hashcat followed by the product as a positional argument, or use --url mode with a valid URL",
190 | color="red",
191 | )
192 | )
193 | return
194 |
195 | if args.url and args.product:
196 | parser.error(print_status("In --url mode, no positional arguments should be used", color="red"))
197 | return
198 |
199 | allow_redirects = False
200 | if args.allow_redirects:
201 | allow_redirects = True
202 |
203 | proxies = None
204 | if args.proxy:
205 | proxies = {"http": args.proxy, "https": args.proxy}
206 |
207 | custom_resource = None
208 | if args.custom_secrets:
209 | custom_resource = args.custom_secrets
210 | print_status(f"Including custom secrets list [{custom_resource}]\n", color="yellow")
211 |
212 | if args.url:
213 | headers = {}
214 | if args.user_agent:
215 | headers["User-agent"] = args.user_agent
216 |
217 | try:
218 | res = requests.get(
219 | args.url, proxies=proxies, headers=headers, verify=False, allow_redirects=allow_redirects
220 | )
221 | except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout):
222 | print_status(f"Error connecting to URL: [{args.url}]", color="red")
223 | return
224 |
225 | r_list = carve_all_modules(requests_response=res, custom_resource=custom_resource, url=args.url)
226 | if r_list:
227 | for r in r_list:
228 | if r["type"] == "SecretFound":
229 | report = ReportSecret(r)
230 | else:
231 | if not args.no_hashcat:
232 | hashcat_candidates = hashcat_all_modules(r["product"], detecting_module=r["detecting_module"])
233 | if hashcat_candidates:
234 | r["hashcat"] = hashcat_candidates
235 | report = ReportIdentify(r)
236 | report.report()
237 | else:
238 | print_status("No secrets found :(", color="red")
239 |
240 | else:
241 | x = check_all_modules(*args.product, custom_resource=custom_resource)
242 | if x:
243 | report = ReportSecret(x)
244 | report.report()
245 | else:
246 | print_status("No secrets found :(", color="red")
247 | if not args.no_hashcat:
248 | hashcat_candidates = hashcat_all_modules(*args.product)
249 | if hashcat_candidates:
250 | print_hashcat_results(hashcat_candidates)
251 |
252 |
253 | if __name__ == "__main__":
254 | main()
255 |
--------------------------------------------------------------------------------
/badsecrets/base.py:
--------------------------------------------------------------------------------
1 | import re
2 | import os
3 | import gzip
4 | import base64
5 | import hashlib
6 | import binascii
7 | import requests
8 | import badsecrets.errors
9 | from abc import abstractmethod
10 |
11 | generic_base64_regex = re.compile(
12 | r"^(?:[A-Za-z0-9+\/]{4}){8,}(?:[A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}={2})$"
13 | )
14 |
15 |
16 | class BadsecretsBase:
17 | identify_regex = re.compile(r".+")
18 | description = {"product": "Undefined", "secret": "Undefined", "severity": "Undefined"}
19 |
20 | hash_sizes = {"SHA1": 20, "MD5": 16, "SHA256": 32, "SHA384": 48, "SHA512": 64}
21 | hash_algs = {
22 | "SHA1": hashlib.sha1,
23 | "MD5": hashlib.md5,
24 | "SHA256": hashlib.sha256,
25 | "SHA384": hashlib.sha384,
26 | "SHA512": hashlib.sha512,
27 | "AES": hashlib.sha1,
28 | "3DES": hashlib.sha1,
29 | }
30 |
31 | check_secret_args = 1
32 | validate_carve = True
33 |
34 | def __init__(self, custom_resource=None, **kwargs):
35 | self.custom_resource = custom_resource
36 |
37 | if self.custom_resource:
38 | if not os.path.exists(self.custom_resource):
39 | raise badsecrets.errors.LoadResourceException(
40 | f"Custom resource [{self.custom_resource}] does not exist"
41 | )
42 |
43 | @abstractmethod
44 | def check_secret(self, secret):
45 | raise NotImplementedError
46 |
47 | @staticmethod
48 | def attempt_decompress(value):
49 | try:
50 | uncompressed = gzip.decompress(base64.b64decode(value))
51 | except (gzip.BadGzipFile, binascii.Error, ValueError):
52 | return False
53 | return uncompressed
54 |
55 | @classmethod
56 | def get_description(self):
57 | return self.description
58 |
59 | def get_product_from_carve(self, regex_search):
60 | return regex_search.groups()[0]
61 |
62 | def get_hashcat_commands(self, s):
63 | return None
64 |
65 | def load_resources(self, resource_list):
66 | filepaths = []
67 | if self.custom_resource:
68 | filepaths.append(self.custom_resource)
69 | for r in resource_list:
70 | filepaths.append(f"{os.path.dirname(os.path.abspath(__file__))}/resources/{r}")
71 | for filepath in filepaths:
72 | with open(filepath) as r:
73 | for l in r.readlines():
74 | if len(l) > 0:
75 | yield l
76 |
77 | def carve_to_check_secret(self, s, **kwargs):
78 | if s.groups():
79 | r = self.check_secret(s.groups()[0])
80 | return r
81 |
82 | @abstractmethod
83 | def carve_regex(self):
84 | return None
85 |
86 | def carve(self, body=None, cookies=None, headers=None, requests_response=None, **kwargs):
87 | results = []
88 |
89 | if not body and not cookies and not headers and requests_response == None:
90 | raise badsecrets.errors.CarveException("Either body/headers/cookies or requests_response required")
91 |
92 | if requests_response != None:
93 | if body or cookies or headers:
94 | raise badsecrets.errors.CarveException("Body/cookies/headers and requests_response cannot both be set")
95 |
96 | if type(requests_response) == requests.models.Response:
97 | if not cookies:
98 | cookies = (
99 | requests_response.cookies.get_dict() if hasattr(requests_response.cookies, "get_dict") else {}
100 | )
101 | if not headers:
102 | headers = requests_response.headers
103 | if not body and hasattr(requests_response, "text"):
104 | body = requests_response.text
105 | else:
106 | raise badsecrets.errors.CarveException("requests_response must be a requests.models.Response object")
107 |
108 | if cookies:
109 | if type(cookies) != dict:
110 | raise badsecrets.errors.CarveException("Header argument must be type dict")
111 | for k, v in cookies.items():
112 | r = self.check_secret(v)
113 | if r:
114 | r["type"] = "SecretFound"
115 | r["product"] = v
116 | r["location"] = "cookies"
117 | results.append(r)
118 |
119 | if headers:
120 | for header_value in headers.values():
121 |
122 | # Check if we have a match outright
123 | r = self.check_secret(header_value)
124 | if r:
125 | r["type"] = "SecretFound"
126 | r["product"] = header_value
127 | r["location"] = "headers"
128 | results.append(r)
129 | # If we dont, we will only be able to add context if we have a match with carve_regex()
130 | elif self.carve_regex():
131 | s = re.search(self.carve_regex(), header_value)
132 | if s:
133 | if not self.validate_carve or self.identify(s.groups()[0]):
134 | r = self.carve_to_check_secret(s)
135 | if r:
136 | r["type"] = "SecretFound"
137 | # the carve regex hit but no secret was found
138 | else:
139 | r = {"type": "IdentifyOnly"}
140 | r["hashcat"] = self.get_hashcat_commands(s.groups()[0])
141 | if "product" not in r.keys():
142 | r["product"] = self.get_product_from_carve(s)
143 | r["location"] = "headers"
144 | results.append(r)
145 |
146 | if body:
147 | if type(body) != str:
148 | raise badsecrets.errors.CarveException("Body argument must be type str")
149 | if self.carve_regex():
150 | s = re.search(self.carve_regex(), body)
151 | if s:
152 | if not self.validate_carve or self.identify(s.groups()[0]):
153 | r = self.carve_to_check_secret(
154 | s, url=kwargs.get("url", None), body=body, cookies=cookies, headers=headers
155 | )
156 | if r:
157 | r["type"] = "SecretFound"
158 | else:
159 | r = {"type": "IdentifyOnly"}
160 | r["hashcat"] = self.get_hashcat_commands(s.groups()[0])
161 | if "product" not in r.keys():
162 | r["product"] = self.get_product_from_carve(s)
163 | r["location"] = "body"
164 | results.append(r)
165 |
166 | for r in results:
167 | r["description"] = self.get_description()
168 |
169 | # Don't report an IdentifyOnly result if we have a SecretFound result for the same 'product'
170 | secret_found_results = set(d["product"] for d in results if d["type"] == "SecretFound")
171 | return [d for d in results if not (d["type"] == "IdentifyOnly" and d["product"] in secret_found_results)]
172 |
173 | @classmethod
174 | def identify(self, product):
175 | if re.match(self.identify_regex, product):
176 | return True
177 | return False
178 |
179 | @staticmethod
180 | def search_dict(d, query):
181 | items = [key for key, value in d.items() if query == value]
182 | if items:
183 | return items
184 |
185 |
186 | def hashcat_all_modules(product, detecting_module=None, *args):
187 | hashcat_candidates = []
188 | for m in BadsecretsBase.__subclasses__():
189 | if detecting_module == m.__name__ or detecting_module == None:
190 | x = m()
191 | if x.identify(product):
192 | hashcat_commands = x.get_hashcat_commands(product)
193 | if hashcat_commands:
194 | for hcc in hashcat_commands:
195 | z = {
196 | "detecting_module": m.__name__,
197 | "hashcat_command": hcc["command"],
198 | "hashcat_description": hcc["description"],
199 | }
200 | hashcat_candidates.append(z)
201 | return hashcat_candidates
202 |
203 |
204 | def check_all_modules(*args, **kwargs):
205 | for m in BadsecretsBase.__subclasses__():
206 | x = m(custom_resource=kwargs.get("custom_resource", None))
207 | r = x.check_secret(*args[0 : x.check_secret_args])
208 | if r:
209 | r["detecting_module"] = m.__name__
210 | r["description"] = x.get_description()
211 |
212 | # allow the module to provide an amended product, if needed
213 | if "product" not in r.keys():
214 | r["product"] = args[0]
215 | r["location"] = "manual"
216 | return r
217 | return None
218 |
219 |
220 | def carve_all_modules(**kwargs):
221 | results = []
222 | for m in BadsecretsBase.__subclasses__():
223 | x = m(custom_resource=kwargs.get("custom_resource", None))
224 | r_list = x.carve(**kwargs)
225 | if len(r_list) > 0:
226 | for r in r_list:
227 | r["detecting_module"] = m.__name__
228 | results.append(r)
229 | if results:
230 | return results
231 |
--------------------------------------------------------------------------------
/tests/telerik_hashkey_test.py:
--------------------------------------------------------------------------------
1 | import urllib.parse
2 | from badsecrets import modules_loaded
3 |
4 | Telerik_HashKey = modules_loaded["telerik_hashkey"]
5 |
6 |
7 | tests = [
8 | (
9 | "YOUR-SECOND-UNIQUE-STRONG-RANDOM-VALUE-UNIQUE-TO-YOUR-APP",
10 | "vpwClvnLODIx9te2vO%2F4e06KzbKkjtwmNnMx09D1Dmau0dPliYzgpqB9MnEqhPNe3fWemQyH25eLULJi8KiYHXeHvjfS1TZAL2o5Gku1gJbLuqusRXZQYTNlU2Aq4twXO0o0CgVUTfknU89iw0ceyaKjSteOhxGvaE3VEDfiKDd8%2B9j9vD3qso0mLMqn%2Btxirc%2FkIq5oBbzOCgMrJjkaPMa2SJpc5QI2amffBJ%2BsAN25VH%2BwabEJXrjRy%2B8NlYCoUQQKrI%2BEzRSdBsiMOxQTD4vz2TCjSKrK5JEeFMTyE7J39MhXFG38Bq%2FZMDO%2FETHHdsBtTTkqzJ2odVArcOzrce3Kt2%2FqgTUPW%2BCjFtkSNmh%2FzlB9BhbxB1kJt1NkNsjywvP9j7PvNoOBJsa8OwpEyrPTT3Gm%2BfhDwtjvwpvN7l7oIfbcERGExAFrAMENOOt4WGlYhF%2F8c9NcDv0Bv3YJrJoGq0rRurXSh9kcwum9nB%2FGWcjPikqTDm6p3Z48hEnQCVuJNkwJwIKEsYxJqCL95IEdX3PzR81zf36uXPlEa3YdeAgM1RD8YGlwlIXnrLhvMbRvQW0W9eoPzE%2FjP68JGUIZc1TwTQusIWjnuVubFTEUMDLfDNk12tMwM9mfnwT8lWFTMjv9pF70W5OtO7gVN%2BOmCxqAuQmScRVExNds%2FF%2FPli4oxRKfgI7FhAaC%2Fu1DopZ6vvBdUq1pBQE66fQ9SnxRTmIClCpULUhNO90ULTpUi9ga2UtBCTzI8z6Sb6qyQ52NopNZMFdrn9orzdP8oqFeyYpF%2BQEtbp%2F5AMENkFkWUxHZn8NoSlO8P6G6ubSyDdY4QJPaFS4FxNhhm85WlZC9xfEZ1AGSSBOu9JJVYiKxXnL1yYLqrlWp5mfBHZeUBwEa%2FMjGxZEVYDhXo4PiU0jxN7fYmjaobp3DSgA5H3BcFuNG5d8CUnOlQcEie5b%2BUHOpI9zAk7qcuEUXbaZ5Mvh0t2jXCRALRKYDyBdbHlWAFo10dTIM6L3aSTM5uEz9%2FalXLXoWlMo7dTDpuO5bBfTq7YkoPExL3g3JJX47UhuLq85i3%2Bzxfvd7r%2Fmid69kbD3PnX%2Bj0QxaiShhyOZg6jl1HMeRRXvZap3FPCIfxbCf7j2TRqB5gYefBIIdGYjrdiL6HS8SbjXcROMwh2Fxnt505X4jmkmDcGmneU3z%2B84TSSFewcSpxGEGvHVkkU4OaT6vyFwsxCmdrR187tQZ7gn3ZkAiTps%2FfOPcL5QWXja06Z%2FHT3zboq6Hj9v9NBHzpC1eAK0YN8r4V2UMI3P0%2FsIPQYXhovoeLjJwq6snKZTX37ulE1mbS1uOY%2BZrvFYbLN5DdNL%2B%2Bl%2F%2BcWIpc0RSYBLo19xHpKeoeLjU2sxaYzK%2B92D4zKANdPPvsHPqJD1Y%2FBwCL%2FfZKaJfRK9Bj09ez1Z1ixTEKjIRCwuxijnJGq33faZchbwpMPpTfv43jEriGwXwoqOo9Mbj9ggPAil7O81XZxNT4vv4RoxXTN93V100rt3ClXauL%2BlNID%2BseN2CEZZqnygpTDf2an%2FVsmJGJJcc0goW3l43mhx2U79zeuT94cFPGpvITEbMtjmuNsUbOBuw6nqm5rAs%2FxjIsDRqfQxGQWfS0kuwuU6RRmiME2Ps0NrBENIbZzcbgw6%2BRIwClWkvEG%2BK%2FPdcAdfmRkAPWUNadxnhjeU2jNnzI1yYNIOhziUBPxgFEcAT45E7rWvf8ghT08HZvphzytPmD%2FxuvJaDdRgb6a30TjSpa7i%2BEHkIMxM5eH1kiwhN6xkTcBsJ87epGdFRWKhTGKYwCbaYid1nRs7%2BvQEU7MRYghok8KMTueELipohm3otuKo8V4a7w4TgTSBvPE%2BLPLJRwhM8KcjGlcpzF1NowRo6zeJJhbdPpouUH2NJzDcp7P4uUuUB9Cxt9B986My6zDnz1eyBvRMzj7TABfmfPFPoY3RfzBUzDm%2FA9lOGsM6d9WZj2CH0WxqiLDGmP1Ts9DWX%2FsYyqEGK5R1Xpnp7kRIarPtYliecp50ZIH6nqSkoCBllMCCE6JN%2BdoXobTpulALdmQV0%2Bppv%2FAjzIJrTHgX7jwRGEAeRgAxTomtemmIaH5NtV7xt8XS%2BqwghdJl1D06%2FWhpMtJ1%2FoQGoJ0%2F7ChYyefyAfsiQNWsO66UNVyl71RVPwATnbRO5K5mtxn0M2wuXXpAARNh6pQTcVX%2FTJ4jmosyKwhI6I870NEOsSaWlKVyOdb97C3Bt0pvzq8BagV5FMsNtJKmqIIM0HRkMkalIyfow9iS%2B5xGN5eKM8NE4E6hO4CvmpG%2BH2xFHTSNzloV0FjLdDmj5UfMjhUuEb3rkKK1bGAVaaherp6Ai6N4YJQzh%2FDdpo6al95EZN2OYolzxitgDgsWVGhMvddyQTwnRqRY04hdVJTwdhi4TiCPbLJ1Wcty2ozy6VDs4w77EOAQ5JnxUmDVPA3vXmADJZR0hIJEsuxXfYg%2BRIdV4fzGunV4%2B9jpiyM9G11iiesURK82o%2BdcG7FaCkkun2K2bvD6qGcL61uhoxNeLVpAxjrRjaEBrXsexZ9rExpMlFD8e3NM%2B0K0LQJvdEvpWYS5UTG9cAbNAzBs%3Dz2r1wMUG5YT66qgXyvpZiSYBdpdh2nUvUhGephVuEok%3D",
11 | ),
12 | (
13 | "F5144F1A581A57BA3B60311AF7562A855998F7DD203CD8A71405599B980D8694B5C986C888BE4FC0E6571C2CE600D58CE82B8FA13106B17D77EA4CECDDBBEC1B",
14 | "vpwClvnLODIx9te2vO%2F4e06KzbKkjtwmNnMx09D1Dmau0dPliYzgpqB9MnEqhPNe3fWemQyH25eLULJi8KiYHXeHvjfS1TZAL2o5Gku1gJbLuqusRXZQYTNlU2Aq4twXO0o0CgVUTfknU89iw0ceyaKjSteOhxGvaE3VEDfiKDd8%2B9j9vD3qso0mLMqn%2Btxirc%2FkIq5oBbzOCgMrJjkaPMa2SJpc5QI2amffBJ%2BsAN25VH%2BwabEJXrjRy%2B8NlYCoUQQKrI%2BEzRSdBsiMOxQTD4vz2TCjSKrK5JEeFMTyE7J39MhXFG38Bq%2FZMDO%2FETHHdsBtTTkqzJ2odVArcOzrce3Kt2%2FqgTUPW%2BCjFtkSNmh%2FzlB9BhbxB1kJt1NkNsjywvP9j7PvNoOBJsa8OwpEyrPTT3Gm%2BfhDwtjvwpvN7l7oIfbcERGExAFrAMENOOt4WGlYhF%2F8c9NcDv0Bv3YJrJoGq0rRurXSh9kcwum9nB%2FGWcjPikqTDm6p3Z48hEnQCVuJNkwJwIKEsYxJqCL95IEdX3PzR81zf36uXPlEa3YdeAgM1RD8YGlwlIXnrLhvMbRvQW0W9eoPzE%2FjP68JGUIZc1TwTQusIWjnuVubFTEUMDLfDNk12tMwM9mfnwT8lWFTMjv9pF70W5OtO7gVN%2BOmCxqAuQmScRVExNds%2FF%2FPli4oxRKfgI7FhAaC%2Fu1DopZ6vvBdUq1pBQE66fQ9SnxRTmIClCpULUhNO90ULTpUi9ga2UtBCTzI8z6Sb6qyQ52NopNZMFdrn9orzdP8oqFeyYpF%2BQEtbp%2F5AMENkFkWUxHZn8NoSlO8P6G6ubSyDdY4QJPaFS4FxNhhm85WlZC9xfEZ1AGSSBOu9JJVYiKxXnL1yYLqrlWp5mfBHZeUBwEa%2FMjGxZEVYDhXo4PiU0jxN7fYmjaobp3DSgA5H3BcFuNG5d8CUnOlQcEie5b%2BUHOpI9zAk7qcuEUXbaZ5Mvh0t2jXCRALRKYDyBdbHlWAFo10dTIM6L3aSTM5uEz9%2FalXLXoWlMo7dTDpuO5bBfTq7YkoPExL3g3JJX47UhuLq85i3%2Bzxfvd7r%2Fmid69kbD3PnX%2Bj0QxaiShhyOZg6jl1HMeRRXvZap3FPCIfxbCf7j2TRqB5gYefBIIdGYjrdiL6HS8SbjXcROMwh2Fxnt505X4jmkmDcGmneU3z%2B84TSSFewcSpxGEGvHVkkU4OaT6vyFwsxCmdrR187tQZ7gn3ZkAiTps%2FfOPcL5QWXja06Z%2FHT3zboq6Hj9v9NBHzpC1eAK0YN8r4V2UMI3P0%2FsIPQYXhovoeLjJwq6snKZTX37ulE1mbS1uOY%2BZrvFYbLN5DdNL%2B%2Bl%2F%2BcWIpc0RSYBLo19xHpKeoeLjU2sxaYzK%2B92D4zKANdPPvsHPqJD1Y%2FBwCL%2FfZKaJfRK9Bj09ez1Z1ixTEKjIRCwuxijnJGq33faZchbwpMPpTfv43jEriGwXwoqOo9Mbj9ggPAil7O81XZxNT4vv4RoxXTN93V100rt3ClXauL%2BlNID%2BseN2CEZZqnygpTDf2an%2FVsmJGJJcc0goW3l43mhx2U79zeuT94cFPGpvITEbMtjmuNsUbOBuw6nqm5rAs%2FxjIsDRqfQxGQWfS0kuwuU6RRmiME2Ps0NrBENIbZzcbgw6%2BRIwClWkvEG%2BK%2FPdcAdfmRkAPWUNadxnhjeU2jNnzI1yYNIOhziUBPxgFEcAT45E7rWvf8ghT08HZvphzytPmD%2FxuvJaDdRgb6a30TjSpa7i%2BEHkIMxM5eH1kiwhN6xkTcBsJ87epGdFRWKhTGKYwCbaYid1nRs7%2BvQEU7MRYghok8KMTueELipohm3otuKo8V4a7w4TgTSBvPE%2BLPLJRwhM8KcjGlcpzF1NowRo6zeJJhbdPpouUH2NJzDcp7P4uUuUB9Cxt9B986My6zDnz1eyBvRMzj7TABfmfPFPoY3RfzBUzDm%2FA9lOGsM6d9WZj2CH0WxqiLDGmP1Ts9DWX%2FsYyqEGK5R1Xpnp7kRIarPtYliecp50ZIH6nqSkoCBllMCCE6JN%2BdoXobTpulALdmQV0%2Bppv%2FAjzIJrTHgX7jwRGEAeRgAxTomtemmIaH5NtV7xt8XS%2BqwghdJl1D06%2FWhpMtJ1%2FoQGoJ0%2F7ChYyefyAfsiQNWsO66UNVyl71RVPwATnbRO5K5mtxn0M2wuXXpAARNh6pQTcVX%2FTJ4jmosyKwhI6I870NEOsSaWlKVyOdb97C3Bt0pvzq8BagV5FMsNtJKmqIIM0HRkMkalIyfow9iS%2B5xGN5eKM8NE4E6hO4CvmpG%2BH2xFHTSNzloV0FjLdDmj5UfMjhUuEb3rkKK1bGAVaaherp6Ai6N4YJQzh%2FDdpo6al95EZN2OYolzxitgDgsWVGhMvddyQTwnRqRY04hdVJTwdhi4TiCPbLJ1Wcty2ozy6VDs4w77EOAQ5JnxUmDVPA3vXmADJZR0hIJEsuxXfYg%2BRIdV4fzGunV4%2B9jpiyM9G11iiesURK82o%2BdcG7FaCkkun2K2bvD6qGcL61uhoxNeLVpAxjrRjaEBrXsexZ9rExpMlFD8e3NM%2B0K0LQJvdEvpWYS5UTG9cAbNAzBs%3DpDsPXFGf2lEMcyGaK1ouARHUfqU0fzkeVwjXU9ORI%2Fs%3D",
15 | ),
16 | ]
17 |
18 |
19 | """
20 | Using the following test keys:
21 |
22 | YOUR-SECOND-UNIQUE-STRONG-RANDOM-VALUE-UNIQUE-TO-YOUR-APP (from telerik_hash_keys.txt)
23 | F5144F1A581A57BA3B60311AF7562A855998F7DD203CD8A71405599B980D8694B5C986C888BE4FC0E6571C2CE600D58CE82B8FA13106B17D77EA4CECDDBBEC1B (from aspnet_machinekeys.txt)
24 | """
25 |
26 |
27 | def test_hash_key():
28 | x = Telerik_HashKey()
29 | for test in tests:
30 | found_key = x.check_secret(test[1])
31 | assert found_key
32 | assert found_key["secret"] == test[0]
33 |
34 |
35 | def test_hashkey_probe_generator():
36 | x = Telerik_HashKey()
37 |
38 | # Ensure test probes generated with hashkey_probe_generator are solved with matching key
39 | # Try the first 100
40 | count = 0
41 | for y in x.hashkey_probe_generator(include_machinekeys=True):
42 | found_key = x.check_secret(y[0])
43 | assert found_key
44 | count += 1
45 | if count >= 100:
46 | break
47 |
48 |
49 | def test_sign_enc_dialog_params():
50 | test_hashkey = "6YXEG7IH4XYNKdt772p2ni6nbeDT772P2NI6NBE4@"
51 | sample_encrypted_dp_b64_encoded = "y1MPLyncErmvCfYRJDU72NLpEurHW6DfWxGJlfMGTH55vxb8V9m2vrkLDCkDm8%2F1PlVto%2FNCiuCR6ioagdVglig7fQjiAmlEMc7v5RWKx74f8v%2FXxMLhwqLzLkF5YbKbAJO7Rtmhqod1vAzINW2yo16gm7yNseksxi4dSIdiGKVIBuUYiA%2BJrhAlDYfmYrdSA0laWPsYjCyTLWwVipZnPb%2FmOJk%2BMnZC3WD2JLtJyiTTanExxyVsx8SKrKqighnPQCiCLEcBik9FoPNBElJLCIZqizM%2Fy8DYmvyC0bTH7rB6plNMYthd%2F%2FIr7DdRaoJJXHThVbra3BXybA7aiW4fRmuRD0vwiZUV%2BYWaClCgPpZ90YOfwXGlGpVhYfZJPNH%2BeCG2piS6oJPs2AjSUlQuzKn4uN%2F2OZYca8IP%2FkVE0jwU5EUq3uf%2FCmXJ8zNcgmcQXhhxejsn3dEygzw4zzyqR3LAnFQkk3BWtrhEmyNVjCL2y1MgsSTjClmTQzX0UicfQOBv4Vgg9E3EA6rqIdxj%2F7pq7N47X0f4wLByBROlgKj%2BhbuWNKAaZmXhjurQ5uu7WOGwKEmOpEnkTZzyoCFui8S6f3dtbrNw2rwGgo1oz8pD7gDXIXATx66hswuK7tfxjkMab%2FdXBQ3vQTSa5HYNpCWnJu3RunO3sb5OKT%2FtUe061%2BdO%2FcFDNwNiGXQvQ9yuY99w2BtNB7ZOazMl9vGG8lcL4s9yuSMdfG3tcgD4%2BrtHDEL7v0ub14dFxB8TOqY5JMRKdyd8D%2FP46%2BC3pWT61EYaddn3U548w%2FjHz1sXXx6b2lo7%2BYnG1DrRt%2Bk6%2BZt1Wa7UkfYC2b2n4OM2ro%2FqwHBU3FL0LOvBdXDDvlqqMSF4PtYUpO09GaE4TrzKlA%2FFN%2BZ9ibPj%2BmHyanK3GpdsR9S%2BavrhfnL%2BXrI26E5C2GPYOHTlR6u5dqvKJ71%2FCCF%2F%2FdYWbdzS5FVQ25WO6XREomBdvK2gP55Mh3byVUfoli%2F9pNkXytwYVo3yIIICReAuYdbteZN6%2BDJl4rJ5AKTbThpNk6co%2BG6Gl5rYKz1KqV80fqOF4TBlv6cm4kLvS%2FFk2JWD3L5kE8llElj9j4Bq7esFt1I%2Fvvo95guNdrBiiRfh2u7qENi1jfXYNlf1Npth8Vw11vztAq8jssrpMo3cVCKU2aTDkOQWvFBO6tN%2FvpYRCzRJHoy3e0sImQa3rN7wTNedxsadcL%2BHRXuYFFvQpcg5lfngY6lyVkjYPgxc5K4mRKZHDEXGWetFRl5af22wuNiEYmIERrh%2Fq25zBBCTfe2swAKb8hZLjoEywedeaQyZVveb4E0mTuMEQ259781fg727QoKnlu2m7Zh6gJINDk1a68Ap3t%2FCU1U8%2BL1haNZ5s7ywWl6vHM7dWvGffmqofBXoOKFhPdnSTc5xn6kgryFZJmnKwRyhOlPVCthRkgnANcLXEH1mtC1WQ8soXuVuMm6uAg44nwOt8BVZSNyJYYaEZCH4HPhtTo1F93W4PtXWJKIT6Mphf%2FWsIwJOKJzxgzCkCSwBB65kTL17LIQuyBqfmprPFtqEgTIRv4IFpJ8WuyeES08ti8QYwYM%2BPN2GZ1CTQu6kvlVlSBJxdTSvdf5IS%2BVje1pQqPJdYOIwwMTTpLfOno4qkHZVcM6OQnUNpvyIvRTuYJ5twYx8Rkty36P1%2BsKeaTMFgVWfMvpK5UNThjDxKMAsy7MgcMTxfZAeNi41gaQSbOFrdgtbkYMTALGiozY1NCcnHbXwr0qnHVKjVVDBuOPZeLL0lzBcm3hGjGYhOjrJLv4ZuRSLvCAe4UfHRhQcCjJd15vNpV8nbdcvEl2e7FUdoNlrPWxaglcEK0vu9WJxBzQVmzoNINhUvqnDZIrYOAGfzrDYrDAwMheLpr9OKHMvM2WHNHUecDK0781NXS%2FdoGGeheaTOe8DieXwcL%2FJlW2bBEwSUNDMuyD8RiukZHUQ4qcgDF%2FGLqUqkDesWIdQyj99wqKFfQNuwm41kCnzAN5uSt3IUiMiA7zsuDr%2BDg0Ro00K6Ap3wFLF1M3xtQobLnsRuCHZGwXSGxye%2Bmg8%2FxD%2BlTOs55IRwb3DDwi6eKdubRJMLN2o544FHYWL1UBAc%2BZcfz7vIqFeHUBMOc5htw%2BDPlXZRRnEzn%2F4qpV4ioEdZeQEv%2BhfXyUs9hF19JP%2BLJiWDJ3Ukdh7OdW2c6GtjOIiKeOcFcJi%2BYB8CP8ItWydzlt0IUaHufQ4ooPkkmmchlX7HV6%2BboKKGxaNWcOx%2BkAWPvP0IeYahPPff9PiSErWiFzc%2BOmFinwZu%2FXJsse%2BG1ndzbUJeMV%2B8jBdZtxiAewbNJxJZl%2Bgu6avfcLJqYjBfxFJ3%2B87%2B6AtI3JI93aCTEiLPVHMiMjsI6j8N1Nxn77BhCsXF3D9uXIqbqTsxp5je4xS4LHqrTTVnsKk3zqlc1PZvgVRGYVD3MRFUmFQfT%2Bnn9HhrDkuCfVdALWHnDOC%2BOOhHglnYm38GLFWA2Mo5VW4k3wM0ftFYVzaVVYYAEFmp8Uvup1sh6COO%2FZJJCSgBK1ZwjnLeWHM1j6Fo0f03YYC5Eghbzi2dBwR0WC2e0hHgtb2TY1K6Uc%3D"
52 | sample_encrypted_dp_bytes = urllib.parse.unquote(sample_encrypted_dp_b64_encoded)
53 |
54 | x = Telerik_HashKey(include_machinekeys=True)
55 | signed_encrypted_dp = x.sign_enc_dialog_params(test_hashkey, sample_encrypted_dp_bytes)
56 | r = x.check_secret(signed_encrypted_dp)
57 |
58 | assert r
59 | assert r["secret"] == test_hashkey
60 |
--------------------------------------------------------------------------------
/badsecrets/resources/yii2_cookieValidationKeys.txt:
--------------------------------------------------------------------------------
1 | ".$cookieValidationKey."
2 | %^&*()JH(**)H(JKLG&*(R%^(UJ()J()
3 | -3ffDUN7EtLddlOgyHFznuS64pR0a78Q
4 | -3o4E8YUQjnojIBI0ZWMA30eI1bxh5IQ
5 | -ab05p9ooDOXSQG4VENCQvupiYwBMOII
6 | -CHMxJ69ZZORr_aErVh0b4GnjCVrHQHc
7 | -gZ6AoxklSu1iy2mYvzmrS9NHFwEJsPV
8 | -sqOI0mlTYB8d2qDwkdnu-UudBJQaNwz
9 | -wvnuadHgBIriDedQwaDz25FmGsxTL6O
10 | 08d8b299f21c4dd0b81190972e9233d9
11 | 0_0w-naFBuT9NGxrkABFtAszJiouNl8s
12 | 0e5N415WTrIrcawM0vr4jineqKu7vzMx
13 | 0iOrv5YCnSBY2wAdt9z-8EK6nwuCPh2g
14 | 0Oh6j_0eKyKJ0d7bBsebS2QDPmsgZojk
15 | 0paU95BJBjgc8F00sz4JLZkn53I8MRTN
16 | 0QXciSd-hoCDCTd3bIGbNUlZzDOMTmpG
17 | 0wk1ayKHWC44MTmnYulIAT6c3MVUp2L1
18 | 0zlT5PU0aDhO5wuxfnOvilJCh4CNUXFu
19 | 1-mDz2sD92g-DpVK5NiLPb7QdYq_tHHh
20 | 11g-ICtiMpVx7WGB3SfQtUI56LVp9H09
21 | 1223456789
22 | 123
23 | 12345678
24 | 1348860441
25 | 1431414123190090990909
26 | 17O9JuhpSBcH4qYWnZrDS62NAYu7oAo1
27 | 1AKJyFLbfV50WohdwMuqpzwak9wH01T7
28 | 1D63Jwe1hiUtFH815xIi0Ixvuh6EqDwZ
29 | 2821868438
30 | 29234500
31 | 2923534000
32 | 2yzRNcm-CKfWteL1xqrBMDCfqud2u5eU
33 | 38838938936689
34 | 45ed697dtg8uhrg9eheg00j09
35 | 4hfR3NhwFDMJxrcchu_APBgTwrFSxXt-
36 | 4pZArirHMMzFjs2fP53IGsaF8bX82uEK
37 | 4V3hcVkYyPlfapn36JCGXUjzAzDyJhsy
38 | 66c957a65f4dfc0e6c2699f692ff17cd
39 | 6VehvOH_JIkJ7JymtY0Oel-dSUzzLRT7
40 | 6WIDi8V6ZoQYzJCfH8wgkO2nS_YQZOo-
41 | 6XZr8wRMUzI4hzSY5ynIj9da-aTpmT-l
42 | 6ZoDxNQWJLagz3dhQzchvQ1966rRhudE
43 | 7dkNyUW7ZqFWTT6IPiAYb6G2W3waiZ3X
44 | 7X0dtpvktsnbr3h2XhFKs7Asl7qagW3g
45 | 8soUA1VwjXbWEfzBEyD4K-1aeI2SutCV
46 | 91pFOhUmhJcKvasyPQZI-cOuiwrI_M-Y
47 | 9te1HJt3rRCqy9bQvMN2Ly5Z9f6t1Ouv
48 | 9uv54-uvETwGqEWbK-9qq9hjRiLISSdw
49 | =isset($cookieValidationKey)?$cookieValidationKey:
50 |
51 | @l#!/*W&+e5U-a%3IJnkC3|&nj^jpB#2.J2P
52 | [CSRF Key]
53 | [RANDOM KEY HERE]
54 | \
55 | _3VGWOfq8uWRZA-8ZEwF2UmNaPAloJjT
56 | _KrWQvmDJum_stF3vIO3MgXIyKn-rX28
57 | _pgCqvUirbYul8SQgXwSvms94dRKcEIX
58 | abcdefghijklmnopqrstuvwxyz012345
59 | alsdaf8*D(as8dasj
60 | ameBP_kz5IJ5-5mtQwp7lv2qj_1hDU9N
61 | api.application.www.b5net.com
62 | asd
63 | asdasAsadcSffgrd21aPleAerbhH
64 | asdasdsadadadada
65 | asdfsdfsdfs
66 | asdSb6orgFTiVXS05DS6TFqqLJQjf6ad
67 | asfsfdfdsfsd
68 | B5clhW-qqZndTv4tssQUE1WwDqrX3Bfo
69 | BCUm2SFBIThfY_CLwQaunfOFWPQwabp9
70 | bdgsddshfdbvgas14tds53tewu754edfv
71 | beNS_ukv8q7lGuGci0WrOg7Uy0qilYE_
72 | BjQnCuPZWKbjqV_HlQcgPuhuys3ihMKx
73 | bov4zECSN9LVaedRYS-xb5mxsnMNFqWI
74 | BqQTsu720MUOpioFJpJQVVyqS47PjjR8
75 | bWDbz9vyy-2hhGXg5oNHplSRZF-UD_Ij
76 | BYsZYK6GVFucxYv4cBuHD73Q8mRi5ZGD
77 | c3KxaQtedXAsvrUkULoiSDJ2gYPnidXf
78 | carsinsuranceindia
79 | chaide123
80 | cHsaFfPdkzswmgiXpZ2X_aLk8coW2fik
81 | citibus
82 | cMr2rLVvljIhN-CjvZi206hyFW7xZTdD
83 | CNsW2fQRoOgyYWSkFDY1uDfxpiPvbC01
84 | cookieValidationKey
85 | crouns
86 | CTNrckVh0Bwz2SVQUXEYkhbt0bxm1MoZ
87 | D6zCxJSFlWMPLSSAJKYwRY5CbrvBF7AJ
88 | dBjBzMTsoFsUtpIF4GAaAqtGVC3hjCfo
89 | DeuV44Ygufd363hHwV8uMZJSJyT9KXj4
90 | development
91 | dfg5y0dg-45sdg1v_dfg2rgh-ssWe0q
92 | DRvFtSLNf46sEEu7bbG9sj267a4XJlUq
93 | DuG6WXyJfk73xhCh8s3DdNr1uOn7GGM-
94 | DYuNUtMPNM3cFbeUbEY4m9Gu-qzALDHH
95 | eb9DFxpAUINo1bDhSyxLHnToTyUdtxlV
96 | Eg9MR1TYGf7PFT7-As63pT2GnVTXRbQS
97 | EJBy8WRohzpqJY7BTurjQaft2NV-g1cA
98 | enter your secret key here
99 | eSDNQqclPQoW1Zhkm6guPKQuVuMCIOJd
100 | f0J4-TdSBFyMpAXH3opRwQAGdDMGgtUt
101 | f763603732269fb75965b4a470455cf16b045326
102 | f9QDGuKYKutFihiE-1TRkqxJKmmY7N0q
103 | fCW-lf4bgT6kl7AX7q1_Z8nrB79T_cL0
104 | Fet2SHWdQQCJgh9dFkbF2RksZkU-pDOr
105 | fill in a secret key here
106 | Fssdf12d2s31raararararf2asdaZTq4GhB2W2QZqyierWmHWmFwAK
107 | Fxd2lkEPXhjmuPXi4ECR1M12HnnEq_kU
108 | gB_-zECp2elHU6gHSFAZc2pVozYEhEp8
109 | geetasksecret
110 | gfiLiZYgM8i39whlNHkOEow2TC6R0rXw
111 | ghsj&s_5{g#
112 | gn-9Ux0lv7wT4VcdfXvOTTQWveFQE2FP
113 | go9F70D1NY-VTtHV8GZU4EPV5F9snCbZ
114 | Gp9OXN6nMnp--YxgCYbNt6W9xew4k_By
115 | Gtwerwe34dvh90FArwre
116 | Gv0nHTwegb0Fa6bnWUUZOvxiqv10n03J
117 | H9faj5kCQM
118 | HAOcBYal0wqXg1kBwPZs5wStyqwQv_d4
119 | hC0PCZY3a5vLBxsCvfrvbwpQ7fZeez_o
120 | hh4tEcWT0KKLw$@157dKiUg7x~0Ad2*7d91#FJm1zb#9QCabq}hj}F7{57t2U8S#
121 | HjorQDlOMQXDRWcElFmX5iuVPfV1Pe9j
122 | hUqDYrJhdCFc6Qr6ppmXgSs8vTpKTLmc
123 | HVZrcUWNy4g1W_1yHDzNL4S09ScbhjDt
124 | hwdn8-iyIh5LylPLpD1PoplqjUka98Ba
125 | I-love-Yii2
126 | I2zaS-tiy069Mi6geizcZ3iAcA75GC2B
127 | I9twgjl1VHz2jm0Lh8XHd2AANJRq4RtH
128 | IeycYPYcVgCYNubf3oBvDJiBgivKMFoD
129 | IgAv5_z9pAJYj5XifBP5qHbABhGth_h4
130 | ihub
131 | iNgPOK8X4qFxJGxM7sDgXtQL1tnQNwJA
132 | iniadalahsecretkeyuntukcookie
133 | iQBKaQuqISOxZ84VO_EjqSINmUX51e1w
134 | iteazytest
135 | j5RVvxZIJQmqTlGpFzihajszp2gVuANO
136 | JDqkJaMgIITAKcsJY6yvLQdM9jf7WghX
137 | JH9hGZzjyaGctN8R_pfYArr_ZFgkIPv7
138 | jJqAbn3Mr0Cwx8VM_XaWnjDgdquq_vrr
139 | Jlwdg1TXsNyKBNypaXXl08_jXDEpPUVT
140 | JybFpZXMaQNoT9f0197C7xog0F4-NCqL
141 | Jylm1ld7qwzDt2nySXPFRSXsRvD3_cRu
142 | KaNMPF6oZegCr0bhED4JHYnhOse7UhrS
143 | KAwHQH1k3srx7iGs5Tg2L1bhdZ_nRjI-
144 | KBcetJwcWd5dIE1Z2BBjLx1pzxHwa6jy
145 | KCH-ljQL1txZIMEusHZgN8ECZs6GHHKD
146 | key
147 | KFBI6reenOjMCowgwXJCMlZGktelMYA7SyMexUGdyditoGber7siso
148 | ki4CcUDzXK3YJzm5X3jw-0Yiiwb5OsZN
149 | KMH2fE7EsGUMysHFAjxEcURe_q5rda59
150 | KS-GsRZNI5wnzWXgVc2dmQPqHvjg7dKd
151 | ksZ0900X9nvMMMyw37kRUILnrjltI7rj
152 | kt4gok1H6ISgQe1NlG0g92m9_RkYMgpo
153 | kZNDjIFgF1DJAZOTBW4umD4_WP2itjiw
154 | l63RbVH4rZYfXNn6JGWq88D41dc8cK00
155 | laeti
156 | LcFnSegZicgJpzBTArE6Qgjnf8nfHM6S
157 | letyii@!$(!&@
158 | Lf1hcz2i6_tj2d-i3-3ISd3B55_QKy71
159 | Lft6gEP2QuiCKdTInd7z0lhz__coAYCj
160 | LPNw88N93goOVcqVfJZb7yMZZRis_tTV
161 | lqNCkvEXt__5jLmIkUk6AUnRLj4K_qk8
162 | LrxOKUC-zXdQ40iBoXQWu3sljHRhbNXZ
163 | LyWC3tf2Bi8wUT6iJtdsgfIaZtc6CddY
164 | M-SQu6u6d-V5YinHtgifL6x2k1J6BwBb
165 | M0WYPF4CqWbMjHhucjMyqrf25xjNAk4j
166 | M48085L3F3Oy7cV4U01mWd1We7OtSiiG
167 | MDxAFCVHh8dfRfkSLtVDcjUCOIYa0CXV
168 | MeHYbcMs-njKgb2wDNXcZ-q7pI0xcy2o
169 | MERe0aSPDBmwt_3An7yqK6Y3VRnSEEKW
170 | mldcOhzqWMRgnEnGwqMKxIaiUJHiL_te
171 | mMSEH2PKbKevInuOsNvXh9_oPtNSC2et
172 | moon
173 | MsTEwas232
174 | mtAsnDCTuuZoahYt1ER838WsACPcmlV3
175 | Mx3-M-iXODDptssVYApG8WbGG9M4Dp5Q
176 | mySecretKey
177 | Nhập secret key tuỳ chọn vào đây
178 | NsB1f_FXBfgYOP1M1ErfscN-Kip98P6G
179 | nsFLiKiW5Kxk9xkeW85w4XYPICHU0J-Z
180 | nttN49BkYzUIiCrceNFctxIWK33-uLAF
181 | NXpMoQbj9pEXuBkd79DZJwptmv4biEQg
182 | O1d232trde1x-M97_7QvwPo-5QGdkLMp#@#@
183 | o1gTz_Q1NiFSctJ99SSYm56VdiTk8HKw
184 | oFwVN8ObxBLlQyJYGOp_go9EdyIgIY27
185 | OGCFiHwDQha84eYi8ajfsMJ8XEQ5ft4E
186 | OhLi2g92xO0Fj1r73_XIrO_60-F2xEdW
187 | ONIU4--N_7FIwD_-Y5OHWblw8dqU0PyB
188 | oXKrbycTet8CtdIWBW115vdNBOlphtjs
189 | oxTxC600X5DGRubG2mYdBMmC4MM0C-ZB
190 | pablo
191 | Pd8EdT0AfKjYucnwbnkjamdDJuzVHwxU
192 | PEi6ICsok3vWiJSJJtQV2JZ6D-jk5gkh
193 | pepe
194 | PFOqfTLbN9Nm03ChLMYmX5HGyXoTX7hA
195 | PvFIRI8b_yld0U496W_zjuCmwjDd6ism
196 | PXNfaJUXn3HwxUzNw-vONeHlJgVyxOQs
197 | q0ZHIeAhCBQb8s_8diYJvmC36OTA2QrG
198 | qbqVJnqfpI6YfTzPUdPL72mhYKRh74up
199 | QcLDLiX6AhSrCGBVGRi-HQIaPZ78gL6c
200 | Qh6AkAbY4alGAFda7k0FxE5zApCOlYF-
201 | Qq0fIK5vB6mseTKoYXX-dVdwHQFYrEXC
202 | qrbB052lggAyJEJCHd6HQuMTi8ilS4ps
203 | QTlcIizdBBGYyOLam2YuDWHKMhwAgSsB
204 | qwe
205 | qxOH-LMMrJJ_unqJzWsPO1eL39JF0cnK
206 | RADYvs43eCDoO5GLTEGXSs7GV0W_yDoU
207 | RAqSIDCpvJwUcmEAeuf7G0u5eT7rnLjr
208 | rg34123214
209 | rhANM0cj3sFb2Sy_0CHMNw-tsBf_vVyP
210 | RhLqcR79Fcg9GUBYSQa9R9BzTfo7htK-
211 | root
212 | RPGnD8bw1SmWBLQlv1XmZNvQ1BWx29z5
213 | RUR9jntbs4hk00D6Q-vf3nch3RdP9fai
214 | Rv43guZ-Gc791Yj_KpLgUen5O5Fmxs-I
215 | rVfcjiFtkMxVOsgsPhEI
216 | RYU8Zk8a6qn5N1bZvUaX3TM6LnRBnHpL
217 | S12Jkv6jtjLCCnqJKWLUfZ4QWXOFUb4J
218 | sBL6-t06ztw1QVjToSSvjrS_kc52b-fq
219 | schoolphone
220 | sdfjjksloeedf78789judd
221 | sdi8s#fnj98jwiqiw;qfh!fjgh0d8f
222 | sdifdbfshbsnstyrfedwety,mnbvcdsfe
223 | sdNsa23Ms
224 | secret
225 | SeNDCi8XHJrBSTZpujKp5D2xWtApuqej
226 | sewa_assessment
227 | sipedes123
228 | SjI1hMMp4bpIgU4_Tdke3W93EhpFghId
229 | sK8lASIoVVSFDKKRQ1LbN-jwlKjddGD2
230 | SlItZHuBitQn964GzOijvDz8AdkZgTlT
231 | SN4W4e4whReWuIJlSP4arZx-pfuTWpvy
232 | SNfuzgcfPdlc2LPHDbceW0qParv0YPk5
233 | some_pullr_key
234 | someValidationKey
235 | SVnVkT24CuHMpvpvZkiANzL6jR8xSNb0
236 | SYkjYFnYjkZgkNwhsvW7nU2Yb3X02SOF
237 | T-jnbpRXnB8GEesBosdfvcPvuqUtYQ5b
238 | test
239 | testkey
240 | TKe-3Bg1VWNFuy6MP0Z51ZF4nm6qoucR
241 | tmC8OAkIX2onr1DLBAF4IYtAL41Q_eEA
242 | token
243 | TRk9G1La5kvLFwqMEQTp6PmC1NHdjtkq
244 | TRss315QwFJIhelIv7Gnz1d5IDAlRPHX
245 | Tvs1WyzYBkqUs4nVKWdQ-Xp69NuszsRT
246 | TZ
247 | U-l3ZA7DXdK-2liZEZf-hy7PPQV91Cm3
248 | ubpqVTyRsPjbIHry6aSKZD10LLN9Zw9H
249 | uhU6aGtOWy7gDIm9AY3cawMuAAlrO8wp
250 | ujikomirsyad
251 | UML3Yaqcwpz-qs6C-GyC1Kz1oMRvMzGc
252 | UNIQUE_KEY_BACKEND
253 | UNIQUE_KEY_FRONTEND
254 | Uy4rVP6QGnQimM_S9avA2QZ0bwZiiYXI
255 | UZyP0w5IDbB3WQMCK8dnXLs8dziwrSs7
256 | Va1MpFBmItGc9uV6y2STcb-XHw0m0XPD
257 | VsmVgVFDUWvxnX-vGG5gvLYHJjrgUkn2
258 | vWLtvK9yeqtdvvEfP1l4snt8VEikNYEQ
259 | wefJDF8sfdsfSDefwqdxj9oq
260 | WEsRl7srQajvaDqry_TOmGbcgW08l-KP
261 | wg1VD6Hul8GQbNLD8PEYr7L2N67EYUnj
262 | wkHCswIPwLHSEEHaiN4P2nFCu6LDhKfX
263 | WMnTOZfa_D2CoMZj-U1WY11EwcNYETxg
264 | Wq72wxi1h7AJ42_DfoId8jSSSFWoUuL8
265 | wQrzC9luLQMCO1t5RDBEXU5HLQ9LWb0W
266 | WSw7dEwFY4jKDpb4tFlMSjT3g3351R0L
267 | wuqKYJyFRLfhuFbepB2aDTFiY30ZQ4X1
268 | WWAH9LZfwzvV4R-1RoZybEHJTagZa7KT
269 | X43fRCIn0tHvbWg0LXr8pD-TA_1iQKnH
270 | xHh6LpjrE6lnVB0E_Gipxai2dkvu_AKb
271 | XknlLjiyF9IbRBCXlAGxOGQ7CMqVudIf
272 | XLVFEHM1hG6t52DMKUeBUJkVDDDXigN0
273 | XS4TmK6AT3poEQ2NgGJij5zSPVsilCvs
274 | XsvslbQm64aqv_7yX9OASWzXTTlc75Ge
275 | xWZ35QUMzAprRApQdNFjcHkc87gwHhZV
276 | xxxx
277 | xxxxx......
278 | xxxxxxxx
279 | xyz
280 | Y0Sn7Ktyyk0l60_9yJiBkJfZ14Jqw_DeaA5pjNtPE4EuM-qvzietJ0a9OIT63dio4pW98ymEnLEhWAC0oyx55g==
281 | Y5CGAiG4SQeH5f7gtwoBP4_0leybu6Mp
282 | y66p--lh5kuVhVbWG8Na0UD6tTK2toqP
283 | Y8ifrez6YY1-r8Vo3Mv-rM_SFQAn_U5q
284 | YEagPq8_23qKZ3MIt1WgINQwqD3-HTwn
285 | yfyjsz
286 | yhHIxC8wBku2KRsFiTJWMkyz9DCMjr3d
287 | yii2belajar
288 | your secret key here
289 | your-validation-key
290 | your_validation_key
291 | YourProjectNameIdKEY
292 | yqCwgKwBKx9tmybEwgnH-GIplIuOJe8L
293 | Z7DybJgp8OLtbRXTJOYr3buTl1pIaQeG
294 | ziH_S4VhNJGkfb9h2wblvWjQTPwaQT9a
295 | zqv0r-fVImc4m9j1MEkmI-UIswX53tXG
296 | zR_vg9BEChcN34mow7RmJHToH_xeKFKt
297 | zvMfIt-ga4Y9vNmh2C-NjShC2N5_zMQd
298 | ZxlalSjI5PmXh7F02cQeGT17GYbOAQ_L
299 | {{secret}}
300 | 在此处输入你的密钥
301 | 秘密キーをここに入力
--------------------------------------------------------------------------------
/badsecrets/modules/aspnet_viewstate.py:
--------------------------------------------------------------------------------
1 | import re
2 | import hmac
3 | import struct
4 | import base64
5 | import hashlib
6 | import binascii
7 | from Crypto.Cipher import AES
8 | from Crypto.Cipher import DES
9 | from Crypto.Cipher import DES3
10 | from viewstate import ViewState
11 | from contextlib import suppress
12 | from urllib.parse import urlsplit, urlparse
13 | from badsecrets.helpers import unpad, sp800_108_derivekey, sp800_108_get_key_derivation_parameters
14 | from viewstate.exceptions import ViewStateException
15 | from badsecrets.base import BadsecretsBase, generic_base64_regex
16 |
17 |
18 | class ASPNET_Viewstate(BadsecretsBase):
19 | check_secret_args = 3
20 | identify_regex = generic_base64_regex
21 | description = {"product": "ASP.NET Viewstate", "secret": "ASP.NET MachineKey", "severity": "CRITICAL"}
22 |
23 | def carve_regex(self):
24 | return re.compile(
25 | r" 0
111 | with pytest.raises(Csharp_pbkdf1_exception):
112 | csharp_pbkdf1 = Csharp_pbkdf1(b"string", b"salt", -1)
113 |
114 | # try getting bytes with a non-int
115 |
116 | csharp_pbkdf1 = Csharp_pbkdf1(b"string", b"salt", 100)
117 | with pytest.raises(Csharp_pbkdf1_exception):
118 | csharp_pbkdf1.GetBytes("10")
119 |
120 |
121 | def test_csharp_ppkdf1_accuracy():
122 | testing_password = b"6YXEG7IH4XYNKdt772p2ni6nbeDT772P2NI6NBE4@"
123 | testing_salt = bytes([58, 84, 91, 25, 10, 34, 29, 68, 60, 88, 44, 51, 1])
124 |
125 | csharp_pbkdf1 = Csharp_pbkdf1(testing_password, testing_salt, 100)
126 |
127 | first32 = base64.b64encode(csharp_pbkdf1.GetBytes(32)).decode()
128 | second16 = base64.b64encode(csharp_pbkdf1.GetBytes(16)).decode()
129 | extra4 = base64.b64encode(csharp_pbkdf1.GetBytes(4)).decode()
130 |
131 | assert first32 == "0E96sqkdWxaKP6LiS51AZPiaf69vGRSrs5uQDKgTvHo="
132 | assert second16 == "ij+i4kudQGRbbIAdfNYc6A=="
133 | assert extra4 == "3dWedw=="
134 |
135 | csharp_pbkdf1_2 = Csharp_pbkdf1(testing_password, testing_salt, 100)
136 | multiblock = base64.b64encode(csharp_pbkdf1_2.GetBytes(61)).decode()
137 |
138 | assert multiblock == "0E96sqkdWxaKP6LiS51AZPiaf69vGRSrs5uQDKgTvHo3A4pO5Q425VtsgB181hzo3dWed76Wlpim4uhcRw=="
139 |
140 | csharp_pbkdf1_3 = Csharp_pbkdf1(testing_password, testing_salt, 100)
141 | halfblock1 = base64.b64encode(csharp_pbkdf1_3.GetBytes(10)).decode()
142 | halfblock2 = base64.b64encode(csharp_pbkdf1_3.GetBytes(10)).decode()
143 |
144 | assert halfblock1 == "0E96sqkdWxaKPw=="
145 | assert halfblock2 == "ouJLnUBk+Jp/rw=="
146 |
147 |
148 | def test_encryptionkey_probe_generator():
149 | x = Telerik_EncryptionKey()
150 |
151 | test_hashkey = "6YXEG7IH4XYNKdt772p2ni6nbeDT772P2NI6NBE4@"
152 |
153 | for key_derive_mode in ["PBKDF1_MS", "PBKDF2"]:
154 | for encryption_key_probe, encryption_key in x.encryptionkey_probe_generator(
155 | test_hashkey, key_derive_mode, include_machinekeys=False
156 | ):
157 | r = x.check_secret(encryption_key_probe, key_derive_mode, include_machinekeys=False)
158 | assert r
159 | assert r["details"] == {"DialogParameters": "QUFBQUFBQUFBQUFBQUFBQUFBQUE="}
160 |
161 |
162 | def test_malformed_dp():
163 | x = Telerik_EncryptionKey(include_machinekeys=False)
164 | r = x.check_secret("z2r1wMUG5YT66qgXyvpZiSYBdpdh2nUvUhGephVuEok=")
165 | assert not r
166 |
167 |
168 | def test_malformed_b64():
169 | x = Telerik_EncryptionKey(include_machinekeys=False)
170 | r = x.check_secret(
171 | "01e8fb7a2a67f5ef3efb27fb85276d927f295fbde6b3e4da378c646de18262f7634386432e3716a4bea164f4eb98e1e7721b82bb66"
172 | )
173 | assert not r
174 |
--------------------------------------------------------------------------------