---
# System prepended metadata

title: PWNME QUALS

---

# 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!!!}~~