Đây là Writeups của giải CTF được tổ chức bởi Đại Học Bách khoa Hà Nội vào 20/8. Lời nói đầu thì mình thấy đây là giải ở Việt Nam từ hồi TetCTF 2023 đầu năm tới giờ mà mình ưng phần cryptography nhất (không guessy, không quá khó, không quá nhiều), nói chung là đọc đề là có hướng ngay chứ cũng không bị lan man
Để ý có dạng đặc biệt là , ngoài ra để dễ dàng tính dlog của ta sẽ tính dlog trên 2 trường con và .
Đây là các trường đặc biệt hay nói cách khác là bài toán logarithm rời rạc trên các số p-adic là rất dễ dàng: Tham khảo
Tuy nhiên , nên mà để tính dlog cho các số p-adic trên chỉ trả về 1 số nằm trong trường con trên , tương tự với . Do đó ta cần tính thêm dlog trên 2 trường con và , sau đó dùng định lý số dư Trung hoa để khôi phục lại
Vì mình đang cần tìm dlog trên subgroup nên cần phải mũ cho 2 số để đưa về cùng subgroup (), tương tự với
key
và giải mã flag
thôi:encrypt
, ta sẽ thấy mối quan hệ toán học của leak
và các block trong enc
:=> Vector bé nhất trong Lattice sẽ là:
flag
:Đoạn text đọc hơi cấn nha :v
Source không quá dài nên ta có thể nắm bắt được một số đặc điểm của challenge dễ dàng:
Đầu tiên là server sử dung libfaketime với khoảng thời gian được random từ faketime.py
(Khá lớn để bruteforce)
Để lấy được flag thì ta cần phải dự đoán đúng (ít nhất là tới xấp xỉ giờ) để có thể tìm được seed mà giải mà flag vì thời gian lấy tới microsecond ()
Với cả 2 điều kiện trên việc bruteforce thẳng seed mà không có thông tin là quá lâu trong 1 giải CTF 8 tiếng. Đây là lúc có thể khẳng định chức năng 1. Get encrypted datas.
sẽ là mục tiêu hàng đầu để exploit
Chức năng 1. Get encrypted datas.
sẽ cho chúng ta biết vô hạn dữ liệu đầu ra của module random
=> Khôi phục được state ban đầu ngay khi khởi tạo object Random
Ngoài ra có 1 đoạn code rất quan trọng ngay đầu file server.py, tí mình sẽ nói tại sao.
Việc khởi tạo object Random
mặc định ko có tham số thì đoạn call lên object sẽ được truyền None
. _random.pyi
:
Tới đây sẽ không còn code để đọc do đó ta sẽ lên github tìm và xem các bước tiếp theo và đây là code mình tìm được: _randommodule.c
Đây là hàm seed
sẽ được call tiếp theo: _randommodule.c#L283. Với arg
là None
thì đây là điều xảy ra bên trong hàm:
Như vậy random_seed_urandom
sẽ được gọi để khởi tạo state
trước, nếu lỗi thì sẽ gọi hàm random_seed_time_pid
để thay thế khởi tạo. Tiếp tục trace random_seed_urandom
thì mình thấy đoạn này:
Đây là lý do tại sao lại có đoạn code mà mình nói quan trọng lúc đầu. Đoạn code lúc đầu sẽ gây xảy ra lỗi ngay khi có bất kỳ syscall getrandom
nào, do đó hàm random_seed_urandom
sẽ luôn luôn xày ra lỗi và hàm random_seed_time_pid
sẽ luôn là hàm được sử dụng để khởi tạo thay thế
Code của hàm random_seed_time_pid
_randommodule.c#L257:
Code của hàm init_by_array
_randommodule.c#L213:
=> Để có thể giải mã flag, ta cần phải khôi phục lại mảng key
được dùng để khởi tạo cho object
Tóm lại toàn bộ quá trình khởi tạo state sẽ là như này:
Với việc module random trong python sử dụng thuật toán MT19937, cái được biết tới không an toàn, thì ta hoàn toàn khôi phục được lại được state
nếu chúng ta có đủ 624 output được random ra (mỗi output 32 bits).
Đầu tiên thì mình sẽ kết nối lên server và lấy đủ số lượng output cần thiết. Tối ưu nhất sẽ là lấy flag đã bị mã hoá rồi hãy lấy output từ server vì quá trình lấy output có thể khá lâu, nên việc làm như trên sẽ giúp thời gian chênh lệch sẽ không quá lớn sau khi khôi phục lại được thời gian từ state
Để khôi phục state
thì có nhiều cách nhưng được biết tới nhiều và đơn giản thì là z3. Tuy nhiên mình sẽ dùng repository này từ github vì nó sử dụng cách solve hệ phương trình bằng ma trận trên với ma trận hệ số đã được dump lại từ trước nên hiệu suất là vượt trội so với z3
Tiếp theo để khôi phục key
thì ta chỉ cần dùng z3 để symbolic lại toàn bộ quá trình trong init_by_array
và dùng Solver()
để giải là xong:
Hehe, tới đây thì cần tính lại time và brute 6 chữ số thập phân là được:
Writeups chỉ tới đây thôi, câu shuffle
thì vì mình tham câu It's time
nên cũng chưa kịp đọc đề trong thời gian diễn ra. Với lại cũng khá đáng tiếc khi mình bận hầu hết thời gian của giải CTF và chỉ có khoảng 3 tiếng cuối để làm nên đã không kịp blood câu It's time
(ra lúc 16h39