TrNam
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Hack.<span>lu CTF 2022</span> [![hackmd-github-sync-badge](https://hackmd.io/qkA1CGJpTtCgetw1dY3SIg/badge)](https://hackmd.io/qkA1CGJpTtCgetw1dY3SIg) ## Crypto - Linear Starter - 166 solves ~~Bạn mình solve lúc mình đang ngủ rồi =)))~~ ## Crypto - Deltawings Delivery Time - 33 solves > At Deltawings we like do deploy our own crypto and we like fast delivery times. We have this new blazingly fast hmac scheme and thought of a brilliant idea: Let our customers test the implementation to win a free food coupon. Of course we've limited the amount of traffic that can be send to our server - we don't want it burning as our chicken wings are already spicy enough! [Attachments](https://github.com/m1dm4n/HackluCTF2022/tree/main/deltawings_delivery_time/public) Sau khi test trên server 1 chút và đọc source thì mình thấy server sẽ cho ta 2 lựa chọn là: 1. Tính hmac của đoạn text chúng ta nhập vào và debug cho xem chúng ta thời gian hoàn thành của mỗi block và mỗi vị trí. Chỉ cho phép 1 session tính `hmac` của tối đa 250 bytes 2. Kiểm tra nếu text chúng ta nhập vào trùng với `key` hiện tại của server thì trả về `FLAG` Phân tích kĩ hàm `hmac` thì mình thấy đây là các bước để tính ra kết quả: 1. Nếu độ dài văn bản không chia hết cho 16 thì sẽ chạy hàm `pad` để lấp đủ độ dài thỏa mãn yêu cầu 2. Tạo giá trị khởi đầu `state = 0000000000000000ffffffffffffffff` 3. Chia văn bản thành các block 16 bytes 4. Với mỗi block sẽ chạy 16 rounds tương đương với mỗi bytes trong block 5. Nếu byte tại vị trí đó `xor` với byte tại cùng vị trí trong `key` ra 1 byte mà có số lượng bit 1 lớn hơn 3 thì sẽ sự dụng hàm `hash1` để hash hàm hiện tại ngược lại sẽ sử dụng hàm hash2 6. Quay lại bước 4 với block tiếp theo. Nếu không còn sẽ kết thúc và in ra kết quả cuối cùng Ngoài ra sau khi thực hiện xong bước 5 chương trình sẽ cho chúng ta biết thời gian hiện tại. Tới đây thì mình thấy có mùi **side channel attack**. Và khi đọc hàm `hash1` và `hash2` thì nó đúng là vậy thật :smiley: `hash1`: ```cpp= void hash1(struct Bytearray *input){ SHA256_CTX ctx; byte outbuf[32]; sha256_init(&ctx); sha256_update(&ctx,input->data,input->sz); sha256_final(&ctx,outbuf); memcpy(input->data,outbuf,16); } ``` `hash2`: ```cpp= void hash2(struct Bytearray *input){ for (int i=0;i<50;i++){ blake2b(input->data,16,input->data,input->sz,0,0); } } ``` Hàm `hash2` thực hiện lâu hơn hàm `hash1` rất nhiều lần, do đó ta dựa vào thời gian ta có thể xác định được hàm nào đã được thực thi. Từ đó ta có thể biết $x$ ($x=block_i\oplus key_i$) có số lượng bit $1$ lớn hơn $3$ hay không Vậy làm sao để tìm được key? Lấy vị dụ $block_1$ là $5$ và chương trình cho ta biết tại vị trí đó chạy hàm `hash1` thì có tới $163$ số mà `xor` với $5$ có số lượng bit $1$ lớn hơn $3$. Tuy nhiên nếu chúng ta chạy với $1$ mẫu khác có $block_1$ là $199$ và chương trình chạy hàm `hash2` thì lúc này từ $163$ số đó ta chỉ còn $55$ số thỏa cả 2 yêu cầu. Như vậy càng nhiều điều kiện thì số lượng đáp án sẽ càng giảm Nếu để ý thì `input` chúng ta nhập và lúc nào cũng được `pad` nên ta có thể lợi dụng điểm này để debug được tối đa 250 đoạn `text`. Sau khi có đủ số lượng mẫu thì ta sẽ xem ở vị trí thứ $i$ của `key`, từ 0 tới 255 có số nào thỏa được nhiều điều kiện nhất thì đó có thể là byte tại vị trí $i$ của `key` (Vì mình sẽ chọn 1 mức thời gian cố định để xác định liệu đó là `hash1` hay `hash2` do đó không phải lúc nào cũng chính xác nên có thể bị nhiễu) Mình thấy sử dụng khoảng 100 mẫu thử là đủ và mốc thời gian để phân biệt là $100000$nanosecond. [Script solve.py](https://github.com/m1dm4n/HackluCTF2022/blob/main/deltawings_delivery_time/solve.py) Output: ``` [+] Opening connection to ddt.flu.xxx on port 10201: Done [+] Trying byte: Got enough 100 payloads. [*] Good byte for index 0: 247 (95.0%) [*] Good byte for index 1: 119 (98.0%) [*] Good byte for index 2: 182 (95.0%) [*] Good byte for index 3: 133 (96.0%) [*] Good byte for index 4: 67 (96.0%) [*] Good byte for index 5: 45 (95.0%) [*] Good byte for index 6: 235 (96.0%) [*] Good byte for index 7: 139 (96.0%) [*] Good byte for index 8: 186 (96.0%) [*] Good byte for index 9: 38 (95.0%) [*] Good byte for index 10: 122 (98.0%) [*] Good byte for index 11: 74 (94.0%) [*] Good byte for index 12: 54 (98.0%) [*] Good byte for index 13: 4 (96.0%) [*] Good byte for index 14: 7 (96.0%) [*] Good byte for index 15: 154 (95.0%) [+] Found session Key: f777b685432deb8bba267a4a3604079a [+] FLAG: Correct! Enjoy your coupon :) flag{now_its_time_to_grab_your_free_food!_?v=8Dax_Ex5Rt0} [*] Closed connection to ddt.flu.xxx port 10201 ``` ## Crypto - Recipe Vault - 17 solves > We have an extra secure encryption system for our recipes.<br>It uses organic, locally sourced crypto from the 90s! Sadly, there is no decryption routine, and we stored the key on a machine to which we forgot the password. BUT: We have the source code and you can connect to the encryption routine via TCP. Could you please decrypt this for us:<br> 184aed743987e240d2715d41fa0d450aa3ac24aecce9dbc5e86d5f69aa1677d2 [Attachments](https://github.com/m1dm4n/HackluCTF2022/tree/main/Recipe_Vault) Câu này thì mình cũng không biết phân tích sao =)) Mình gửi lên sever `plaintext` và server sẽ trả về `ciphertext` thôi. Còn đoạn hex trong mô tả là `FLAG` đã bị mã hóa Sau khi osint 1 hồi thì mình biết nó là mã hóa **MAGENTA**. Osint thêm xíu thì mình tìm được tài liệu về [Cryptanalysis of Magenta](https://www.schneier.com/wp-content/uploads/2016/02/paper-magenta.pdf). Và có 1 đoạn mình thấy hứng thú > We would also wish to note that due to the symmetry of the key scheduling, encryption and decryption are identical except for the order of the two halves of the plaintexts and ciphertexts. Therefore, given a ciphertext, one can decrypt it by swapping its two halves, reencrypting the result, and swapping again. Note that this attack uses an adaptive access to an encryption device and cannot be used to recover the key Check lại hàm mã hóa: ```python= def encrypt(blk, something_key): blk = np.copy(blk) blk[0:2] = combination_magic(blk[0:2], blk[2:4], something_key[0:2]) blk[2:4] = combination_magic(blk[2:4], blk[0:2], something_key[2:4]) blk[0:2] = combination_magic(blk[0:2], blk[2:4], something_key[4:6]) blk[2:4] = combination_magic(blk[2:4], blk[0:2], something_key[6:8]) blk[0:2] = combination_magic(blk[0:2], blk[2:4], something_key[8:10]) blk[2:4] = combination_magic(blk[2:4], blk[0:2], something_key[10:12]) return blk ``` Tóm là là ta không cần **cryptanalysis** để khôi phục key mà chỉ cần lấy cái ciphertest đã bị mã hóa, và gửi lên sever để mã hóa lần nữa nhưng lúc này ta hoán nửa đầu và cuối của `ciphertext` và bùm.... Giải mã thành công =)))))) Thật ra thì lý do tại sao lại giải mã đơn giản như trên mà không cần `key` thì các bạn có thể để ý hàm `combination_magic` có tính chất đối xứng (tức là cùng 1 `key` thì mã hóa bằng hàm này và giải mã cũng bằng hàm này luôn). Hàm giải mã sẽ trông như sau: ```python= def decrypt(blk, something_key): blk = np.copy(blk) blk[2:4] = combination_magic(blk[2:4], blk[0:2], something_key[2:4]) blk[0:2] = combination_magic(blk[0:2], blk[2:4], something_key[0:2]) blk[2:4] = combination_magic(blk[2:4], blk[0:2], something_key[6:8]) blk[0:2] = combination_magic(blk[0:2], blk[2:4], something_key[4:6]) blk[2:4] = combination_magic(blk[2:4], blk[0:2], something_key[10:12]) blk[0:2] = combination_magic(blk[0:2], blk[2:4], something_key[8:10]) return blk ``` Mỗi block là 16 bytes và `FLAG` gồm 2 block do đó ta chỉ cần gửi cho server payload như sau (`FLAG` đang ở dạng hex): ```python flag = flag[16:32] + flag[:16] + flag[48:] + flag[32:48] ``` Swap lại như ban đầu và `unhex` là ra flag: ``` d2715d41fa0d450a184aed743987e240e86d5f69aa1677d2a3ac24aecce9dbc5 [x] Opening connection to flu.xxx on port 12001 [x] Opening connection to flu.xxx on port 12001: Trying 31.22.123.45 [+] Opening connection to flu.xxx on port 12001: Done [*] Closed connection to flu.xxx port 12001 666c61677b786372697370796770756361626c65776974686761726c6963787d flag{xcrispygpucablewithgarlicx} ``` ## Crypto - Faulty Ingredient - 25 solves > My boss said, that we should better encrypt the secret ingredient of our delicious sauce. But when I used my own AES, I noticed that sometimes, I got totally wrong values. Since I had a great crypto class at my evening school, I managed to nail the error down to the input of the Mix Columns in Round 9. I can't say how, but when the error occurs, exactly one random byte in every column of the state changes. I ran some tests, solely for myself, but my dumb intern posted them on Fluxstagram when making one of his stupid selfies. Well anyway, I hope nobody can use this to recover the main key and decrypt our secret ingredient! [Attachments](https://github.com/m1dm4n/HackluCTF2022/tree/main/Faulty_Ingredient/public) Theo mình thấy thì đây là câu hay nhất và mình học được nhiều nhất. Tuy nhiên để phân tích toàn bộ câu này một cách chi tiết nhất thì mất rất nhiều thời gian :crying_cat_face: nên mình sẽ nói một cách khái quát nhất vậy. Còn bạn nào muốn tìm hiểu sâu hơn thì có thể tham khảo blog này: [Differential Fault Analysis on White-box AES Implementations](https://blog.quarkslab.com/differential-fault-analysis-on-white-box-aes-implementations.html) Trong source code người ta cho mình thì cũng chỉ có 1 file AES tự code của tác giả y chang AES gốc tuy nhiên có thêm 1 hàm mã hóa và ở round thứ 9 thì cứ 1 byte bất kì mỗi 4 bytes sẽ bị lỗi (xor với 1 số random) Vậy thì tại sao điều này lại làm 1 hệ mã hóa đạt chuẩn của **NIST** về mọi mặt lại gãy ? Đầu tiên mọi người cần hiểu AES hoặc động trên một trường hữu hạn đặc biệt GF($2^8$). Nên phép xor được hiểu là phép cộng trên trường này Bây giờ mình sẽ biểu diễn block AES trước khi trải qua `mixcolumn` ở round thứ 9 của cả `ciphertext` gốc $C_i$ và cái bị lỗi $F_i$ như sau: \begin{equation*} \begin{pmatrix} A & E & I & M \\ B & F & J & N \\ C & G & K & O \\ D & H & L & P \end{pmatrix} \text{and} \begin{pmatrix} A+X & E & I & M \\ B & F & J & N \\ C & G & K & O \\ D & H & L & P \end{pmatrix} \end{equation*} Lưu ý là mình sẽ chỉ biểu diễn duy nhất 1 việc bị lỗi trên 1 cột để dễ hình dung (Đề bài bị lỗi trên cả 4 cột và cứ 4 bytes của 1 block là 1 cột). Sau khi `mixcolumn` ở round 9: \begin{equation*} \begin{pmatrix} 2A+3B+C+D & \cdots & \cdots & \cdots \\ A+2B+3C+D & \cdots & \cdots & \cdots \\ A+B+2C+3D & \cdots & \cdots & \cdots \\ 3A+B+C+2D & \cdots & \cdots & \cdots \end{pmatrix} \text{and} \begin{pmatrix} 2A+2X+3B+C+D & \cdots & \cdots & \cdots \\ A+X+2B+3C+D & \cdots & \cdots & \cdots \\ A+X+B+2C+3D & \cdots & \cdots & \cdots \\ 3A+3X+B+C+2D & \cdots & \cdots & \cdots \end{pmatrix} \end{equation*} Sau khi `add_roundkey` $K_9$ ở round 9 và kết thúc round: $$ \begin{pmatrix} 2A+3B+C+D+K_{9,0} & \cdots & \cdots & \cdots \\ A+2B+3C+D+K_{9,1} & \cdots & \cdots & \cdots \\ A+B+2C+3D+K_{9,2} & \cdots & \cdots & \cdots \\ 3A+B+C+2D+K_{9,3} & \cdots & \cdots & \cdots \end{pmatrix} \text{and} \begin{pmatrix} 2A+2X+3B+C+D+K_{9,0} & \cdots & \cdots & \cdots \\ A+X+2B+3C+D+K_{9,1} & \cdots & \cdots & \cdots \\ A+X+B+2C+3D+K_{9,2} & \cdots & \cdots & \cdots \\ 3A+3X+B+C+2D+K_{9,3} & \cdots & \cdots & \cdots \end{pmatrix} $$ Sau khi trải qua `SubBytes`(viết tắt là `S`), `ShiftRows` và `AddRoundKey` $K_{10}$: \begin{pmatrix} S(2A+3B+C+D+K_{9,0})+K_{10,0} \qquad \cdots \qquad \cdots \qquad \cdots \\ \cdots \qquad \cdots \qquad \cdots \qquad S(A+2B+3C+D+K_{9,1})+K_{10,13}\\ \cdots \qquad \cdots \qquad S(A+B+2C+3D+K_{9,2})+K_{10,10} \qquad \cdots \\ \cdots \qquad S(3A+B+C+2D+K_{9,3})+K_{10,7} \qquad \cdots \qquad \cdots \end{pmatrix} <p style="text-align:center"> and </p> \begin{pmatrix} S(2A+2X+3B+C+D+K_{9,0})+K_{10,0} \qquad \cdots \qquad \cdots \qquad \cdots \\ \cdots \qquad \cdots \qquad \cdots \qquad S(A+X+2B+3C+D+K_{9,1})+K_{10,13}\\ \cdots \qquad \cdots \qquad S(A+X+B+2C+3D+K_{9,2})+K_{10,10} \qquad \cdots \\ \cdots \qquad S(3A+3X+B+C+2D+K_{9,3})+K_{10,7} \qquad \cdots \qquad \cdots \end{pmatrix} Ta có: \begin{align} O_0 &= S(2A+3B+C+D+K_{9,0})+K_{10,0} \\ O_7 &= S(A+2B+3C+D+K_{9,1})+K_{10,7} \\ O_{10} &= S(A+B+2C+3D+K_{9,2})+K_{10,10} \\ O_{13} &= S(3A+B+C+2D+K_{9,3})+K_{10,13} \\ \end{align} \begin{align} O'_0 &= S(2A+3B+C+D+K_{9,0})+K_{10,0} \\ O'_7 &= S(A+2B+3C+D+K_{9,1})+K_{10,7} \\ O'_{10} &= S(A+B+2C+3D+K_{9,2})+K_{10,10} \\ O'_{13} &= S(3A+B+C+2D+K_{9,3})+K_{10,13} \\ \end{align} \begin{align} =>O_0 + O'_0 &= S(2A+3B+C+D+K_{9,0}) +K_{10,0} + S(2A+2X+3B+C+D+K_{9,0}) +K_{10,0} \\ &= S(2A+3B+C+D+K_{9,0}) + S(2A+2X+3B+C+D+K_{9,0}) \end{align} Tương tự: \begin{align} O_7 + O'_7 &= S(A+2B+3C+D+K_{9,1}) + S(A+X+2B+3C+D+K_{9,1}) \\ O_{10} + O'_{10} &= S(A+B+2C+3D+K_{9,2}) + S(A+X+B+2C+3D+K_{9,2}) \\ O_{13} + O'_{13} &= S(3A+B+C+2D+K_{9,3}) + S(3A+3X+B+C+2D+K_{9,3}) \\ \end{align} Nếu ta đặt $Y_i$ là giá trị thứ i của cột đầu tiên của `block` sau khi kết thúc round 9 (trong hàm mã hóa bình thường) thì ta có 4 phương trình sau: \begin{align} O_0 + O'_0 &= S(Y_0) + S(Y_0+2X) \\ O_7 + O'_7 &= S(Y_1) + S(Y_1+X) \\ O_{10} + O'_{10} &= S(Y_2) + S(Y_2+X) \\ O_{13} + O'_{13} &= S(Y_3) + S(Y_3+3X) \\ \end{align} $O_i$ và $O'_i$ đều là các giá trị ta đã biết và với mỗi thằng `X` từ trong 256 giá trị của GF($2^8$) và 4 vị trị bất kì trên cột ```python= for fault_ind in range(4): for j in range(256): e = [0]*fault_ind + [j] + [0]*(3 - fault_ind) state_e = [0, 0, 0, 0] state_e[0] = gf_mul123(e[0], 2) ^ gf_mul123(e[1], 3) ^ gf_mul123(e[2], 1) ^ gf_mul123(e[3], 1) state_e[1] = gf_mul123(e[0], 1) ^ gf_mul123(e[1], 2) ^ gf_mul123(e[2], 3) ^ gf_mul123(e[3], 1) state_e[2] = gf_mul123(e[0], 1) ^ gf_mul123(e[1], 1) ^ gf_mul123(e[2], 2) ^ gf_mul123(e[3], 3) state_e[3] = gf_mul123(e[0], 3) ^ gf_mul123(e[1], 1) ^ gf_mul123(e[2], 1) ^ gf_mul123(e[3], 2) # print(state_e) Xs.add(tuple(state_e)) ``` Ta sẽ tìm giá trị $Y_0$ tương ứng thỏa phương trình thứ nhất, từ những thẳng thỏa trước đó ta sẽ tìm tiếp những giá trị $Y_1$ thỏa tiếp phương trình thứ 2... Cứ như vậy ta sẽ tìm được các tập 4 giá trị $Y_i$ thỏa đc 4 phương trình trên với thằng $X$ tương ứng (vì $X$ là random nên ta sẽ lấy toàn bộ nghiệm). ```python= idxs = [0, 13, 10, 7] # inverse shift rows for col 1 Ys = set() needs = [ft[ind] ^ ct[ind] for ind in idxs] def dfs(X, cur, l): if l == 4: Ys.add(tuple(cur)) return for y in range(256): if sbox[y] ^ sbox[y ^ X[l]] == needs[l]: cur.append(y) dfs(X, cur, l+1) cur.pop(-1) for X in Xs: dfs(X, [], 0) print(len(Ys)) ``` Output: ``` 976 ``` Chạy rất nhanh dù nghe thì có vẻ là vét cạn tìm tất cả 5 bytes thỏa mãn chưa kể ta còn không biết vị trí chính xác của bytes bị lỗi trong 4 bytes trên cột đó. Tuy nhiên thực tế thì với mỗi thẳng $X$ tương ứng chỉ có số lượng rất nhỏ các giá trị $Y_i$ trong miền $[0,255]$ thỏa mãn được phương trình thứ $i$ tương ứng thôi. Ngoài ra việc chúng ta có nhiều hơn 1 cặp `ciphertext` và `faulttext` sẽ giúp chúng ta giao thoa các tập kết quả lại với nhau làm giảm bớt các trường hợp lại. Sau khi có được các thằng $Y_i$ thì nhớ lại 4 phương trình ta có ở trước đó: \begin{align} O_0 &= S(2A+3B+C+D+K_{9,0})+K_{10,0} = S(Y_0) + K_{10,0}\\ O_7 &= S(2A+3B+C+D+K_{9,1})+K_{10,7} = S(Y_7) + K_{10,7}\\ O_{10} &= S(2A+3B+C+D+K_{9,2})+K_{10,10} = S(Y_{10}) + K_{10,10}\\ O_{13} &= S(2A+3B+C+D+K_{9,3})+K_{10,13} = S(Y_{13}) + K_{10,13}\\ \end{align} Như vậy là chúng ta sẽ kiếm được những thằng có thể là $K_{10,0}, K_{10,7}, K_{10,10}, K_{10,13}$ và 1 trong các thằng đó sẽ là đáp án đúng. Đề bài cũng cho chúng ta bị lỗi ở cả 4 cột do đó ta có thể hoàn toàn khôi phục hoàn toàn $K_{10}$ dùng ở `add_roundkey` thứ 10. Vì hàm để mở rộng `key` (hay `key_schedule_128`) là hàm 2 chiều nên ta có thể khôi phục lại `key` bí mật ban đầu 1 cách dễ dàng ```python= def reverse_key_schedule(round_key: bytes, aes_round: int): assert len(round_key) * 8 == 128 def xor_bytes(aa, bb) -> bytes: return bytes(a ^ b for a, b in zip(aa, bb)) for i in range(aes_round - 1, -1, -1): a2 = round_key[0:4] b2 = round_key[4:8] c2 = round_key[8:12] d2 = round_key[12:16] d1 = xor_bytes(d2, c2) c1 = xor_bytes(c2, b2) b1 = xor_bytes(b2, a2) a1 = xor_bytes(a2, g(d1, i)) round_key = a1 + b1 + c1 + d1 return round_key ``` Script hoàn chỉnh: [Link](https://github.com/m1dm4n/HackluCTF2022/blob/main/Faulty_Ingredient/dfa.py) Mình thậm chí chỉ cẩn 2 cặp `ciphertext` và `faultext` là đủ để tìm được 1 đáp án duy nhất. Output: ``` 976 992 1232 1024 1328 1008 1008 976 key at round 10: [178, 54, 86, 62, 78, 61, 224, 159, 86, 231, 247, 114, 96, 170, 82, 188] key: 25acfc955fa52864657da3c67384eef8 flag{Th3_s3cr3t_inGreDient_is_oni0n_powd3r_h3h3} ``` Write up của giải này chỉ có vậy thôi. Dù được đánh giá là giải top nhưng mình thấy có vẻ nhìn chung Crypto không ác như những giải top mình chơi trước đó :crying_cat_face:. Tóm lại thì mình ấn tượng nhất vẫn là câu **Faulty Ingredient** thôi vì mình khá non trong cryptanalyst. Hy vọng là mình cũng truyền được xíu kiến thức của bản thân. Bye!

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully