RSA Hard

Files

main.py

output.py

Phân tích

Giống như bài trước, main.py hoàn toàn không có lỗi nha, lỗi là nằm ở cái flag hư đốn kia 😗

Tuy nhiên, ở bài này file output.txt đã có sự khác biệt nhẹ, đó là từ l=43 chúng ta đã nâng cấp thành l=53. Áp dụng tư duy từ bài trước, ta có số bit của flag^5 phải là 53*8*5 = 2120 > n2048 bits. Vì vậy không thể dùng trick căn bậc 5 được rồi, rất tiếc :(

Có thể một số bạn cũng sẽ lập luận như sau:

c=flag5modn

nên ta có:

flag5=kn+c

và mò k từ 0 đến một số tít trời mây nào đó và căn bậc 5 để ra flag. Đây cũng là 1 cách suy nghĩ thú vị, tuy nhiên chỉ làm được nếu k bé mà thôi.

flag^52120 bit, và n chỉ có 2048 thôi, nên k phải có tầm 2120 - 2048 = 72 bits. Do vậy, số tít trời mây nào đó mà bạn muốn mò ra cũng phải bay đến tận 2**72, và mình khuyên là bạn không nên làm thế, vì nó to hơn bạn nghĩ nhiều đó 😗

Cách giải

thuật toán Coppersmith

Để giải được bài này, chúng ta cần biết đến 1 thuật toán rất hữu ích trong việc giải các phương trình dạng f(x) = 0 mod n với x < XX là một số mình cho trước. Và tên của nó chính là Coppersmith.

flag là nghiệm của phương trình x5=cmodn, nên sử dụng Coppersmith áp dụng cho hàm f(x) = x^5 - c để giải ra flag là một suy nghĩ hoàn toàn hợp lí.

Giới hạn

Tuy vậy, thuật toán Coppersmith có 1 giới hạn, đó chính là nếu degree của f(x)d, thì X phải bé hơn n^(1/d), và trong trường hợp này thì X < n^(1/5). Vì flag^5 to hơn n, nên flag to hơn n^(1/5), do vậy mà mình không thể dùng Coppersmith để giải ra flag ngay lập tức được.

Để tạo ra phương trình mà có nghiệm < n^(1/5) và giải = Coppersmith, mình sẽ phải sử dụng 1 thông tin khác rất quan trọng mà mọi người thường hay bỏ lỡ:

Đó là flag luôn có dạng BKSEC{...}.

Vì theo đề bài ta có l = 53, nên phần ... trong flag chỉ chiếm có 53 - 7 = 46 bytes mà thôi. Và vì con số đó tương đương với 46*8=368 bits, trong khi n^(1/5) sẽ xấp xỉ 2048/5 = 409.6 bits, chúng ta nên suy nghĩ theo hướng là cần tạo ra hàm để giải cho phần ... thay vì tìm cách giải cả cái flag.

(hoặc nếu bạn nào giải được cả flag thì bảo mình nhá :') mình cũng không biết có được không nữa hix, tại mò mãi mà không ra ý)

Tạo ra phương trình

May thay hàm bytes_to_long hoạt động cũng không phức tạp lắm. Nếu bạn dành thời gian đi thử nghiệm 1 chút thì bạn có thể nhận ra rằng hàm này có quy luật như sau:

Như vậy, ta có thể suy ra được:

Với x là một số có 368 bits.

 

Vì vậy, ta có thể đặt

f(x)=11218995871735093487161080956769118277607957494981887808631780963798464689101531164867880752334038264192570603194059857495851133+256xg(x)=f(x)5c

Và dùng Coppersmith để giải g(x)=0modn với X=2368.

Code giải

Tuy lí thuyết là vậy, nhưng khi thực hành sẽ khó khăn hơn 1 chút. May thay theo Wiki, thuật toán Coppersmith được thực hiện dưới dạng hàm small_roots trong sage. Với những ai chưa dùng sage, thì đại loại nó là 1 ngôn ngữ lập trình nhìn 99.999% giống Python.

Code mẫu

Phân tích code

Lưu ý

Khi giải bài này thì nhớ chú ý đến 3 arguments X, betaepsilon nha. Nếu chỉ dùng f.small_roots() không thì sẽ không giải được. Đặt X = 2^368 vì mình biết x luôn có ít hơn hoặc bằng 368 bits nên luôn nhỏ hơn 2^368, còn hai giá trị betaepsilon thì cứ mò đến khi nào ra nghiệm thì thôi :3

Nếu mà bạn nào cảm thấy bài này quá guessing phần betaepsilon, thì có thể dùng code Coppersmith của ông này. Code ở đây sẽ print chi tiết hơn về điều kiện để mà thuật toán chạy okela và in chi tiết những giá trị của điều kiện đó ra để mò biến và debug 1 cách dễ dàng hơn :)

tuy vẫn phải mò nhưng mà mò này có phương hướng hơn 1 tí :#

Flag