# Back To The Past Bài cho ta 1 file Binary và 1 file flag.enc: ![image](https://hackmd.io/_uploads/HkilvBUi1e.png) file flag.enc chỉ là flag đã bị mã hóa ![image](https://hackmd.io/_uploads/rkgYCwSUjyl.png) phân tích file binary: ![image](https://hackmd.io/_uploads/BJGbFSIi1l.png) chương trình lấy unix timestamp hiện tại để làm seed random \- srand đọc file mà ta truyền vào (kiểu rb+) qua vòng lặp mỗi bytes, xor với rand() (mod 127) và ghi lại vào file bằng fputc đổi tên file thành flag.enc Tuy nhiên vấn đề là hàm srand(seed) và rand() đã bị custom: ![image](https://hackmd.io/_uploads/H1FLiHIiJl.png) ![image](https://hackmd.io/_uploads/HkQOiBLske.png) Dù đã bị custom nhưng mã hóa chính vẫn là xor nên ta chỉ cần dựng lại code và xor với file flag.enc là được seed là unix timestamp lúc mã hóa file nên ta lấy luôn hoặc cũng có thể bruteforce Script solve (by [Zupp](https://hackmd.io/@Zupp)): ```python= import ctypes from tqdm import tqdm def rand(): global seed seed = ctypes.c_uint64(6364136223846793005 * seed + 1).value return seed >> 33 seed = 1715198477 f = open("flag.enc", "rb").read() msg = "" seed = seed - 1 for i in range(len(f)): v11 = ctypes.c_int(rand()).value msg += chr(f[i] ^ (v11 % 127)) print(msg) ``` # C4 License ![image](https://hackmd.io/_uploads/SyQd_-fikx.png) kết nối server ta thấy bài yêu cầu nhập vào license cho 100 user có tên khác nhau dựa trên license mẫu của user Noa ![image](https://hackmd.io/_uploads/HknzY-Gjkl.png) đề cho ta 1 file binary và 1 file license như sau: ![image](https://hackmd.io/_uploads/rJhSBWMjkg.png) nội dung file license-Noa là một đoạn Json bị mã hóa base64: ``` eyJ1c2VyIjogIk5vYSIsICJzZXJpYWwiOiAiZTNiZmJkZjE2MzE0ZWJlZDdiZDJjNjA4YWU1MzA2OTI3MjRjYzNhNSJ9 ``` ![image](https://hackmd.io/_uploads/BJ51Ibfoye.png) file binary: ![image](https://hackmd.io/_uploads/Hksc8-Mi1e.png) bài được viết bằng ngôn ngữ khá lạ và hơi khó đọc chạy file binary: ![image](https://hackmd.io/_uploads/BkWjY-MiJl.png) ![image](https://hackmd.io/_uploads/ByG75bGoJl.png) có một số hàm để gọi UI nhưng ta chỉ quan tâm hàm check license: ![image](https://hackmd.io/_uploads/HkS63bfoJl.png) ![image](https://hackmd.io/_uploads/HJ3Fp-Gjkg.png) sơ qua ta có thể thấy chương trình decode base64 được Json, lấy thông tin "user" và "serial" từ đoạn Json đó đưa vào hàm checker Nội dung hàm checker: ![image](https://hackmd.io/_uploads/BkjzC-zoJl.png) ![image](https://hackmd.io/_uploads/rJwUCWfskl.png) `crc32`: tính crc32 từ user `srand(v5)`: khởi tạo seed random từ `crc32` tiếp theo tạo key rc4 qua `_byteswap_ulong(rand() % 0xFFFF * (v6 % 0xFFFF));` rồi decrypt "serial" bằng key đã tạo cuối cùng là tạo hash SHA-1 và so sánh với `b039d6daea04c40874f80459bff40142bd25b995` Ý tưởng giải bài: ta có thể thấy chương trình tạo key từ tên user và decrypt serial, vì RC4 là mã dòng nên ta sẽ đảo ngược lại lấy giá trị trước khi bị hash đó rồi encrypt bằng key để lấy serial là xong Tuy nhiên có 1 vấn đề là hash SHA-1 `b039d6daea04c40874f80459bff40142bd25b995` không thể bị decrypt nên mình sẽ debug để lấy giá trị trước khi hash v13 chứa địa chỉ: ![image](https://hackmd.io/_uploads/rkCGQGfjyg.png) ![image](https://hackmd.io/_uploads/BkkvXMGs1x.png) ta trỏ tới địa chỉ đó: ![image](https://hackmd.io/_uploads/BJ707GGjJl.png) vậy ta có plaintext là `'PwNmE_c4_message!137'` Vì `srand(seed)` và `rand()` trong C nó khác với python cũng như khác nhau giữa Windows và Linux nên mình sẽ viết chương trình tạo key bằng C trước, compile ra file binary và dùng pwntools để tạo process kết nối với file đó code C khởi tạo key: ```c= #include <stdio.h> #include <stdint.h> #define POLY 0xEDB88320L uint32_t byteswap_ulong(uint32_t value) { return ((value >> 24) & 0x000000FF) | ((value >> 8) & 0x0000FF00) | ((value << 8) & 0x00FF0000) | ((value << 24) & 0xFF000000); } uint32_t crc32_table[256]; void crc32_init() { uint32_t crc; for (int i = 0; i < 256; i++) { crc = i; for (int j = 8; j > 0; j--) { if (crc & 1) crc = (crc >> 1) ^ POLY; else crc = crc >> 1; } crc32_table[i] = crc; } } uint32_t crc32(uint32_t crc, const unsigned char *buf, size_t len) { crc = ~crc; for (size_t i = 0; i < len; i++) { uint8_t byte = buf[i]; crc = crc32_table[(crc ^ byte) & 0xFF] ^ (crc >> 8); } return ~crc; } int main() { char data[256]; fgets(data, sizeof(data), stdin); data[strcspn(data, "\n")] = 0; size_t len = strlen(data); crc32_init(); uint32_t crc = crc32(0, (const unsigned char *)data, len); //printf("CRC32: %08X\n", crc); srand(crc); int v3; v3=rand(); uint32_t v14; v14 =byteswap_ulong(rand() % 0xFFFF * (v3 % 0xFFFF)); printf("%u\n", v14); return 0; } ``` code pwntools: ```python= from Crypto.Cipher import ARC4 from Crypto.Util.number import* import re from pwn import * import base64 host = "c4license-3fed2c5bfcd688ee.deploy.phreaks.fr" port = 443 pp = remote(host, port, ssl=True) res = pp.recvline() print(res) for i in range(100): res = pp.recvuntil(b': ') print(res) match = re.search(b'for\s+(.+?)\s+user', res) name=match.group(1) print(name) p = process('./pwnme') #file C đã compile p.sendline(name) rrr = p.recvline() p.close() print(rrr) key = long_to_bytes(int(rrr))[::-1] data = b'PwNmE_c4_message!137' cipher = ARC4.new(key) encrypted_data = cipher.encrypt(data) print(encrypted_data.hex()) se=encrypted_data.hex() #name=b'Noa' t=b'{"user": "'+name+b'", "serial": "'+se.encode()+b'"}' #tạo lại cấu trúc Json print(t) tt=base64.b64encode(t) print(tt) pp.sendline(tt) print(i) print(pp.recv(20)) print(pp.recvline()) ``` # Super secure network Bài cho ta 1 file pcap và 1 file binary: ![image](https://hackmd.io/_uploads/HybcuGfo1x.png) Nội dung file binary: ![image](https://hackmd.io/_uploads/HkaRLGzjJg.png) vì tên hàm đặt tên khá mù mắt nên rất khó để hiểu chương trình đang làm gì Tuy nhiên mentor [SonVH](https://github.com/SonVH2511) đã rename lại kha khá và thêm một chút chỉnh sửa của mình thì code đã chuẩn chỉnh và dễ đọc hơn: ![image](https://hackmd.io/_uploads/HytmOMfsyl.png) Trước tiên ta cần hiểu chương trình làm gì: ![image](https://hackmd.io/_uploads/r18utGMjke.png) nhìn qua ta có thể thấy chương trình tạo kênh an toàn để trao đổi khóa bằng Diffie-Hellman ta có thể hiểu đơn giản Diffie-Hellman như sau: ``` 2 người Alice và Bob trao đổi khóa -tạo khóa công khai chung là số nguyên tố p và căn nguyên thủy là g -Alice tạo khóa bí mật a, Bob tạo khóa bí mật b -Alice tính A= g**a (mod p), Bob tính B= g**b (mod p) -Alice gửi A cho Bob, Bob gửi B cho Alice -Alice tính B**a (mod p) = g**(a*b) (mod p) -Bob tính A**b (mod p) = g**(a*b) (mod p) ->2 người sử dụng khóa bí mật chung g**(a*b) (mod p) để mã hóa các loại khóa đối xứng ``` Về lại với file binary: chương trình tạo khóa công khai `p` là số nguyên tố 8 bytes lấy random 8 bytes để tạo khóa bí mật `a` lấy căn nguyên thủy `g` = 2 tính `A` = `pow_mod(2,a,p)` = `g**a (mod p)` gói lại bằng: ``` v1[5] = 2LL; v1[4] = 1LL; v1[1] = &p; v1[2] = &v1[5]; v2 = pow_mod(2uLL, a, p); // tmp_rand = a v1[0] = &v2; v1[3] = 0x800000008LL; ``` và tương tác với `192 168 1 60 port 3333` mở wireshark: ![image](https://hackmd.io/_uploads/rJaj1mGoJl.png) ta thấy gói tin chứa data `010021000800000008000000010000005c4f31a50c2d980c6b152f4845212e1502` được gửi đi bóc tách ra ta được các giá trị sau: ``` A=0x0c982d0ca5314f5c p=0x152e2145482f156b g=0x02 ``` Nếu không biết p nằm ở đâu trong packet thì ta có thể viết script sau để tìm p dựa trên tính chất p là số nguyên tố: ```python= from Crypto.Util.number import* n=(long_to_bytes(0x010021000800000008000000010000005c4f31a50c2d980c6b152f4845212e1502)[::-1]).hex() print(n) for i in range(len(n)-16): hex_string = n[i:i+16] hex_string = hex_string.replace(" ", "").replace("\n", "") byte_array = bytes.fromhex(hex_string) o=bytes_to_long(byte_array) if isPrime(o)==1: print('p= ',hex(o)) ``` chỉ lấy được các khóa công khai `A`, `p`, `g`, theo thông thường attacker sẽ không thể lấy được khóa bí mật `a` tuy nhiên các giá trị trong trường hợp này khá nhỏ và dễ dàng crack được bằng logarith rời rạc. ta có thể dùng https://www.alpertron.com.ar/DILOG.HTM ta tính được: `a` = `1330218279148611220` = `0x1275e27a22626694` ta vào hàm `decrypt_and_forward_packet`: ![image](https://hackmd.io/_uploads/BJ-FfmMskx.png) Hàm kiểm tra 4 bytes cuối của packet được nhận về, nếu bằng `0x86E35DE5` thì nhảy vào hàm `decrypt_somthing(a1)`, nếu bằng `0x89E35DE5` thì thực hiện decrypt aes_ctr data của packet gói tin chứa `0x86E35DE5`: ![image](https://hackmd.io/_uploads/B1LbOmzsyl.png) lấy được `65027c9877d09804e55de386` bỏ 4 bytes cuối ta lấy được khóa công khai `B` = `0x0498d077987c0265` Xem hàm `decrypt_something`: ![image](https://hackmd.io/_uploads/Bkzh8XGs1l.png) ta có thể thấy hàm này thực hiện tính khóa bí mật chung và tạo key cho cho mã hóa aes tính `v2 = pow_mod(B,a,p) = B**a (mod p) = g**(a*b) (mod p)` tính SHA-256 của `v2` để làm key aes Đã có các giá trị `B`, `a`, `p`, viết script python tính `v2` ```python= A=0x0c982d0ca5314f5c#g**a (mod p) B=0x0498d077987c0265#g**b (mod p) p=0x152e2145482f156b #prime number b=0x131654790612f1a4 a=0x1275e27a22626694 key=pow(B,a,p) #0x3b3edf533b6434 ``` tiếp theo là bước tính hash, do mình không để ý key chỉ có 7 bytes trong khi `result = hash_sha256(&v2, 8u, s);` lại tính hash của 8 bytes, lại còn là kiểu LEndian nên sẽ phải tính hash của `0x3b3edf533b643400` (chỗ này anh [Bình](https://github.com/noobmannn) chỉ ra mới biết) https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')SHA2('256',64,160)&input=MzQ2NDNCNTNERjNFM0IwMA&oeol=CRLF ![image](https://hackmd.io/_uploads/SkN7i7fokx.png) vậy ta lấy được key aes là `bf98795c03cdbce091b8986cc599628ea6ba2d91b8e50443c4bb144477ce982b` Tiếp tục: ![image](https://hackmd.io/_uploads/B1k1hmGoJe.png) phần này ta có thể hiểu là bỏ 4 bytes cuối của packet, lấy 16 bytes cuối làm IV cho aes\_ctr và phần còn lại là data để decrypt/encrypt Phần còn lại của chương trình chủ yếu là việc decrypt/encrypt data và gửi qua lại Cuối cùng là việc decrypt toàn bộ packet đã được anh [Bình](https://github.com/noobmannn) giải quyết: ```python= from scapy.all import * from Crypto.Cipher import AES from Crypto.Util import Counter from Crypto.Util.Padding import * pp = PcapNgReader("capture.pcapng") for p in pp: if TCP in p: payload = raw(p[TCP].payload) if len(payload) < 36: continue print(payload) sig = payload[-4:] IV = payload[-20:-4] enc = payload[:-20] print(sig.hex()) print(enc.hex()) print(IV.hex()) print() key = bytes.fromhex('bf98795c03cdbce091b8986cc599628ea6ba2d91b8e50443c4bb144477ce982b') ctr = Counter.new(128, initial_value=int.from_bytes(IV, byteorder='big')) cipher = AES.new(key, AES.MODE_CTR, counter=ctr) plaintext = cipher.decrypt(enc) print(plaintext.hex()) print(plaintext) print() #PWNME{Crypt0_&_B4ndwidth_m4k3s_m3_f33l_UN83474813!!!} ``` Flag: ~~PWNME{Crypt0_&_B4ndwidth_m4k3s_m3_f33l_UN83474813!!!}~~