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 31339Material: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 check và j chạy từ 0 tới 7. Hệ thống sẽ tiến hành ghi plaintext và key (đượ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ị i và j, 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 key và plaintext 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 31340Material: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 = 0x1169 và OFFSET_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 = 1 và i = 8871 j = 2
Code lấy flag:
Flag: TetCTF{fr0m_0n3_b1t_fl1pp3d_t0_full_k3y_r3c0v3ry_d043a7ff4cf6285a}
Last updated