-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_32.py
124 lines (93 loc) · 3.01 KB
/
test_32.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
import unittest
import time
import requests
import random
import http.server
import socketserver
from urllib.parse import urlparse
from urllib.parse import parse_qsl
from http import HTTPStatus
from multiprocessing import Process
from crypto.hmac import hmac_sha1
from util.bettercode import random_word
HOST = '127.0.0.1'
PORT = random.randint(7000, 9000)
URL = "http://" + HOST + ":" + str(PORT)
SECRET = random_word()
ARTIFICIAL_DELAY = 0.005
def insecure_compare(hmac: bytes, signature: bytes):
if len(hmac) != len(signature):
return False
for a, b in zip(hmac, signature):
if a != b:
return False
time.sleep(ARTIFICIAL_DELAY)
return True
class RequestHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
parsed = urlparse(self.path)
params = dict(parse_qsl(parsed.query))
filename = params.get('file', None)
signature = params.get('signature', None)
if not filename or not signature:
self.send_response(HTTPStatus.BAD_REQUEST, "No filename or signature")
h = hmac_sha1(SECRET, filename.encode())
if insecure_compare(h, signature.encode()):
self.send_response(HTTPStatus.OK, "You got it!")
else:
self.send_response(HTTPStatus.INTERNAL_SERVER_ERROR, "Incorrect signature")
self.end_headers()
return True
def run_server():
with socketserver.TCPServer(("", PORT), RequestHandler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()
def time_f(f) -> int:
start = time.time_ns()
f()
return int(time.time_ns() - start)
def attack_next_byte(signature, filename, sig_length) -> bytes:
lows = {}
observations = {}
sample_size = 11 # Should be odd to make mean easier
def f():
attack_s = (signature + s.encode()).ljust(sig_length, b"\x00")
requests.get(URL, params={'file': filename, 'signature': attack_s})
for s in 'abcdefgh0123456789':
for o in range(sample_size):
t = time_f(f)
observations.setdefault(s, []).append(t)
for c, timings in observations.items():
s_timings = list(sorted(timings))
lows[str(c)] = s_timings[0]
lowest = list(reversed(sorted(lows.items(), key=lambda x: x[1])))[0][0]
return lowest.encode()
class TestChallenge32(unittest.TestCase):
p = None
@classmethod
def setUpClass(cls) -> None:
cls.p = Process(target = run_server)
cls.p.start()
time.sleep(1)
pass
@classmethod
def tearDownClass(cls) -> None:
cls.p.terminate()
@unittest.skip
def test_run_server_make_requests(self):
filename = 'root.exe'
print(hmac_sha1(SECRET, filename.encode()))
# First guess the length
sig_length = len(hmac_sha1(b'dummy', b'dummy'))
signature = b''
for i in range(sig_length):
# Attacking the ith byte
b = attack_next_byte(signature, filename, sig_length)
signature += b
r = requests.get(URL, params={'file': filename, 'signature': signature})
print(signature)
print(hmac_sha1(SECRET, filename.encode()))
self.assertEqual(r.status_code, 200)
def test_hmac(self):
h = hmac_sha1(b"key", b"The quick brown fox jumps over the lazy dog")
self.assertEqual(h, b'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9')