TetCTF 2024

TetCTF 2024

CRYPTOGRAPHY WRITEUP

Author:

  • Pham Quoc Trung

Used Language:

  • Python3

Problem Solving:

flip

Chall name: flip Category: Crypto Author: ndh Description: You are allowed to inject a software fault. Server: nc 139.162.24.230 31339 Material: flip.zip

encrypt.c

// To compile:
// git clone https://github.com/kokke/tiny-AES-c
// gcc encrypt.c tiny-AES-c/aes.c
#include "tiny-AES-c/aes.h"
#include <unistd.h>

uint8_t plaintext[16] = {0x20, 0x24};
uint8_t key[16] = {0x20, 0x24};

int main() {
    struct AES_ctx ctx;
    AES_init_ctx(&ctx, key);
    AES_ECB_encrypt(&ctx, plaintext);
    write(STDOUT_FILENO, plaintext, 16);
    return 0;
}

main.py

Recon

Sau một hồi đọc code thì mình thấy được bài này sẽ cho người dùng nhập vào input dạng hex(plaintext) i j, với plaintext dài 16 bytes, i là một số từ 0 tới độ dài nội dung file binary checkj chạy từ 0 tới 7. Hệ thống sẽ tiến hành ghi plaintextkey (được gen từ hàm os.random(16)) vào offset của nó trong file check sau đó lưu thành một file tạm và khởi chạy. Kết quả sẽ trả về ciphertext của nó được mã hóa bằng AES_ECB. Yêu cầu của chúng ta là phải nhập đúng key và chương trình sẽ trả về flag.

Về 2 giá trị ij, nó được sử dụng ở đoạn code content[i] ^= (1 << j), có nghĩa rằng chúng ta được quyền sửa 1 byte bất kì ở trong đoạn file binary trước khi nó được khởi chạy. Hẳn sẽ có cách nào đó để ta có thể làm chương trình in ra key hoặc tạo ra ciphertext gì đó dễ dàng tính được key? Nghe vế đầu sẽ có vẻ khả thi hơn.

Lưu ý một điều nữa là ở đoạn code khởi chạy file binary tạm thời

Có thể thấy nếu có lỗi xảy ra trong quá trình khởi chạy, hàm ban_client() sẽ được thực thi. Ta không biết nó sẽ làm gì, cơ mà không nên chơi liều. Challenge có cho sẵn Dockerfile nên ta có thể dựng lại và xóa dòng đó đi cho an toàn để thử nghiệm payload.

Unintended solution

Vì ở bài này, ta chỉ được quyền sửa duy nhất 1 byte, và nội dung của file binary ngoài phần keyplaintext ra thì mọi thứ luôn không đổi vì nó được lấy từ file check. Chắc chắn sẽ có 1 byte khiến cho file binary này hoạt động không như mong muốn và giúp ta có được key. Nhưng để biết là byte nào thì mình không biết, cho nên mình đã nghĩ tới chuyện là sẽ thử thay đổi từng byte một và quan sát output trả về.

Mình sử dụng một đoạn code như sau:

Mình sử dụng rất nhiều hàm print() là do khi sửa đổi các bit của file binary có thể sẽ xảy ra lỗi khi thực thi (không phải lỗi từ python nên mình không chưa tìm ra cách bắt exception). In ra nhiều như vậy sẽ dễ dàng để nhận ra lúc nào có kết quả hơn.

Các kết quả mình thu được là

Tiếp theo mình sẽ dựng Docker để test xem khi nhập payload nó sẽ hiện ra như nào. Mình cũng sửa lại file main một chút để nó in ra key cho mình so sánh

Với payload đầu

Payload thứ hai

Payload thứ ba

Payload cuối

Có thể thấy các payload sau đều chỉ in ra key luôn chứ không in thêm những thứ không quan trọng như payload đầu. Mình sẽ thử dùng payload thứ hai để lấy flag

Flag: TetCTF{fr0m_0n3_b1t_fl1pp3d_t0_full_k3y_r3c0v3ry}

Thật ra là mình đã ăn may khi sử dụng plaintext = 00000000000000000000000000000000 để bruteforce. Khi phân tích kĩ trong intended solution, kết quả trả về từ server là key^plaintext. Điều này là do một số giai đoạn của mã hóa AES. Khi mình dùng plaintext là 00000000000000000000000000000000 thì khi XOR với key nó vẫn sẽ là key nên mình lấy được flag.

Faster bruteforce and some explain: Link

flip v2

Chall name: flip v2 Category: Crypto Author: ndh Description: Changing in main() is not allowed. Server: nc 139.162.24.230 31340 Material: main.py

main.py

Recon

Bài này thì code vẫn giống y nguyên bài trước chỉ khác là có thêm 2 trường OFFSET_MAIN_START = 0x1169OFFSET_MAIN_END = 0x11ed. Đây là đánh dấu cho offset của hàm main. Giờ đây thì i sẽ có điều kiện là assert not OFFSET_MAIN_START <= i < OFFSET_MAIN_END, nghĩa là i không được nằm trong main, hay ta không thể tác động tới byte nào ở trong main.

Unintended Solution

Như bài trước thì mình đã tìm ra 4 payload để có thể lấy được key. Ở đây với 0x1169 <= i < 0x11ed hay 4457 <= i < 4589 thì sẽ bị Exception. Vậy chỉ cần lấy payload có i nằm ngoài khoảng đó thôi, cụ thể là mình có i = 5463 j = 1i = 8871 j = 2

Code lấy flag:

Flag: TetCTF{fr0m_0n3_b1t_fl1pp3d_t0_full_k3y_r3c0v3ry_d043a7ff4cf6285a}

Last updated