CRY302
Một bài liên quan tới hash, cách thực hiện khá dễ. Full source code bạn có thể xem tại đây
Bổ đề
Tóm tắt lại thì mình sẽ được đưa cho 1 số tiền ngẫu nhiên từ 1 tới 2000 và bị bắt phải mua 1 cái FLAG có giá tận 99,999. Kiểu gì cũng không đủ cho được.
Khi mình order 1 vật phẩm bất kỳ, order
của mình sẽ có cấu trúc dạng kiểu product=FLAG&price=99999&time=1633845957.70&sign=67df43a8c83ea4ee53ac7bb61cc9a51661f5b55b54153afb942246c11a3ab9a93cb7a1cecb235195eab957fceb3e3daaf3e97f484d29718aea8b0f63e1a3704a
(đã được decode từ chuỗi base64 encoded).
Khi nhập lại cái order
ở trên để xác nhận mua sản phẩm, order
này được kiểm tra các cấu trúc và tính toàn vẹn, cụ thể gồm:
Tồn tại cặp parameter-value
sign={sign_value}
Có signature hợp lệ
sha512(signkey+payment).hexdigest() == signature
Sau khi qua các bài check trên, payment
sẽ được truyền vào hàm parse_sql(self, query)
để tiến hành extract các parameter tương ứng.
1
2
3
4
5
6
7
def parse_qsl(self, query):
m = {}
parts = query.split(b'&')
for part in parts:
key, val = part.split(b'=')
m[key] = val
return m
Với cách hàm parse hoạt động như này, giả sử query có 2 cặp giá trị của price
(ví dụ như price=99999&price=0
) thì giá trị price
cuối cùng sẽ được quyết định bởi cái đằng sau. Điều đó đồng nghĩa với việc nếu mình có thể kéo dài cái payment
của mình bằng cách append thêm 1 đoạn &price=0
, mình có thể mua bất cứ thứ gì trong cửa hàng!
Ý tưởng kéo dài 1 đoạn payment được hash đã đưa mình đến hash length extension attack
Hash length extension attack
Hash length extension attack là gì?
Hash length extension attack cho phép mình kéo dài chuỗi văn bản được hash, đồng thời tính toán giá trị hash mới hợp lệ cho chuỗi văn bản được kéo dài ra từ hash của chuỗi văn bản ban đầu.
Nguồn đọc hiểu hash length extension attack
Trước hết, cần phải hiểu được sha512 hoạt động như thế nào đã. Bạn có thể xem tổng quan về hàm sha512 tại đây và xem chi tiết cách sha512 vận hành từng bước 1 tại đây. Thanks for Indian guys ❤️
Tiếp đó, mình đọc mô tả cách hash length extension attack hoạt động, và có bản demo tại đây. Thực ra trước có 1 bài blog bằng tiếng Việt cho họ hash SHA luôn, mà giờ trang đấy sập rồi 😢 Nên mình sẽ mô tả lại trong bài này để các bạn hiểu dưới góc độ python code, phòng trường hợp các bạn đọc demo trên mạng đều code bằng C và không hiểu gì =)))
Điều kiện để thực hiện hash length extension attack
Để thực hiện được hash length extension attack mà văn bản xác thực có dạng secret_value + public_value
, mình cần có đủ 3 dữ kiện:
Độ dài của
secret_value
, ở trong bài này chính là độ dài củasignkey
. Bài không cho cụ thể nhưng chỉ cho 24 giá trị khả năng, hoàn toàn có thể bruteforce. Mình không cần giá trị củasecret_value
!Giá trị của
public_value
, ở trong bài này chính làpayment
Giá trị hash của
secret_value + public_value
, ở trong bài này chính làsign
Vậy là bài này hội tụ đủ cả 3 yếu tố để tiến hành rồi.
Tiến hành tấn công thôi!
Mục tiêu của mình bao gồm:
Append thêm 1 đoạn
&price=0
vào cuốipayment
Tạo ra 1 giá trị
sign
mới sao chosha512(signkey+payment) = sign
vớipayment
mới
Sơ sơ cơ chế hoạt động của hash length extension attack sẽ như sau:
Cơ chế hoạt động của hàm hash: Hàm hash sha512 sẽ chia input đầu vào thành các khối 1024 bits, mỗi khối lại chia thành từng phần nhỏ
h[i]
gồm 128 bits. Một tuple(h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7])
được gọi làcurrent_state
của hàm hash hiện tại.current_state
sẽ được dùng để tính state cho khối 1024 bits tiếp theo. Hàm xử lý quá trình này gọi làround_function
hoặccompress
(tùy theo tài liệu). Kết quả cho khối 1024 bits cuối cùng chính là giá trị hash mình thu được.Cơ chế hoạt động của hash length extension attack: Từ cơ chế hoạt động trên của hàm hash, mình có thể thấy rằng chỉ cần biết được
current_state
và khối 1024 bits cuối cùng, mình hoàn toàn có thể tính toánstate
cho khối 1024 bits tiếp theo, trong đó, khối 1024 bits sẽ có giá trị tùy ý mình thích. Đó cũng chính là giá trị hash mới với chuỗi văn bản được kéo dài.
Khá là đơn giản phải không. Giờ mình sẽ đi vào cụ thể nhé:
Order FLAG, nhận giá trị
order
trả vềproduct=FLAG&price=99999&time=1633849486.36&sign=275e626950c677c05a669e4e9d73f015858ca2b477335b2e99f419f9f0bc860736e95bd87de1226764c70f8c59029edc10e6b2a514342bb85f0c29fe24b9d3e2
. Táchpayment
vàsign
riêng.Padding cho
payment
đểpayment
có dạngk ∗ 1024
, và lấy block cuối cùng, thu đượcproduct=FLAG&price=99999&time=1633849486.36\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02P
. Vốn chuỗi ban đầu không dài hơn 1024 bits nên cũng chỉ có block duy nhất. Trong phần ví dụ này, mình giả sử độ dài củasignkey
bằng 31. Cơ chế padding mình đính kèm nguồn ở trên.Append chuỗi
&price=0
vào chuỗi đã được padding ở trên. Lại tạo 1 khối 1024 bits có chứa&price=0
bằng cách padding, thu được&price=0\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x018
Extract
state
từ giá trịsign
, sau đó đưastate
cùng khối 1024 bits có chứa&price=0
ở trên vào hàmcompress
của sha512, thu được giá trị mới bằngad38b9ceecbdf41de6bb33970a473ecc1c500935e2cfd90007be639fa6754b6272c45340fca0f173090748722cc1e25e3440cc9975c3b712a8cabe7809cf6d7f
Nối chuỗi
payment
mới vàsign
mới vào với nhau, chuyển lên server và lấy flag. order mới sẽ làproduct=FLAG&price=99999&time=1633849486.36\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02P&price=0
Vậy là xong!
Full code exploit
Vì bài không cho giá trị cụ thể của độ dài signkey
, nên mình phải viết 1 đoạn code chạy tự động trong khoảng giá trị [8, 32]
. Full code exploit có thể xem ở đây. Trong code này, mình có sử dụng lại thư viện hlextend của stephenbradshaw trên github, với một chút chỉnh sửa để output ra có dạng byte thay vì string.
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
def solve():
[REDACTED]
#order
output = recvuntil(clientSock, b'Your choice:')
clientSock.sendall(b'2\n')
output = recvuntil(clientSock, b'ID:')
clientSock.sendall(b'6\n')
output = recvuntil(clientSock, b'Your choice:')
order = output.split(b'\n')[0][len('Your order:'):].strip()
order = b64decode(order).decode('latin-1')
sp = order.rfind('&sign=')
sign = order[sp+6:]
payment = order[:sp]
append_msg = '&price=0'
for i in range(8, 33):
sha = hlextend.new('sha512')
new_payment = sha.extend(append_msg, payment, i, sign)
new_sign = sha.hexdigest()
new_order = new_payment + b'&sign=' + new_sign.encode()
new_order = b64encode(new_order)
#confirm order
clientSock.sendall(b'3\n')
output = recvuntil(clientSock, b'Your order:')
clientSock.sendall(new_order + b'\n')
output = recvuntil(clientSock, b'Your choice:')
if b'FUSec{' in output:
flag = output.decode()[output.index(b'FUSec{'):output.index(b'}')+1]
print(flag)
break
Flag FUSec{th1s_1s_4n_0ld_vul_bUt...}
CRY303
Một bài siêu khó về Knapsack cipher sử dụng LLL (Lenstra–Lenstra–Lovász), hay còn gọi là Latice Reducation Technique, để giải.
Nói thật thì bài này mình cũng không tự làm được lúc tham gia giải CTF, nhưng search google được 1 bài giống tới 90%, nên chỉ đọc hiểu code rồi giải lại. Bởi vì bài cũng không có gì khác biệt mấy, nên mình để nguồn bài gốc ở đây để các bạn đọc vậy.
Đề bài này và code giải (đã sửa theo bài) mình để ở github của mình.
Thế là hết crypto rồi. Nếu mà kịp giải hết thì mình cũng mạnh dạn insert bomman meme gáy… nhưng không được nên gà không gáy nữa…