Bài dễ thì mình làm chậm mà bài khó thì không làm được :(( Do mình làm bài chưa được tốt nên sẽ cố gắng viết WU chi tiết và đầy đủ ý nhất # REVERSE ## HIDDEN ![image](https://hackmd.io/_uploads/ByTm-9cD1e.png) mở ida dễ dàng thấy flag ![image](https://hackmd.io/_uploads/HyLNG9cv1g.png) submit thử thì báo incorrect, rõ ràng là fakeflag vào functions thấy hàm printFlag khả nghi ![image](https://hackmd.io/_uploads/H1G0K9qDkg.png) Xem mã giả ta dễ dàng thấy đây chỉ là mã hóa xor từng byte của v2 với \x88 ![image](https://hackmd.io/_uploads/H1Qtc5qwJg.png) bài này warmup nên có thể giải nhanh bằng cách debug và nhảy RIP đến hàm printFlag ![image](https://hackmd.io/_uploads/ByLjpcqDkx.png) Flag: ~~KCSC{you_can't_see_me:v}~~ ![image](https://hackmd.io/_uploads/HynMA9qwye.png) ## easyre ![image](https://hackmd.io/_uploads/r1GGkj9vkl.png) chạy thử: ![image](https://hackmd.io/_uploads/SkEEliqvyx.png) pseudo code: ```C= int __cdecl sub_7FF78B081280(int argc, const char **argv, const char **envp) { FILE *v3; // rax size_t v4; // rax __int64 v5; // rdx __int64 v6; // rcx __int64 v7; // r8 __int64 v8; // r9 __int64 v9; // rax unsigned int v10; // edx unsigned int v11; // r8d unsigned __int64 v12; // rax __m128 v13; // xmm0 __m128 v14; // xmm1 __int64 v15; // rcx __int64 v16; // rax char *v17; // rcx char Buffer[16]; // [rsp+20h] [rbp-68h] BYREF __int128 v20; // [rsp+30h] [rbp-58h] BYREF int v21; // [rsp+40h] [rbp-48h] __int128 v22[2]; // [rsp+48h] [rbp-40h] BYREF __int64 v23; // [rsp+68h] [rbp-20h] int v24; // [rsp+70h] [rbp-18h] char v25; // [rsp+74h] [rbp-14h] LOBYTE(v21) = 0; v23 = 0i64; *(_OWORD *)Buffer = 0i64; v24 = 0; v20 = 0i64; v25 = 0; memset(v22, 0, sizeof(v22)); sub_7FF78B081010("Enter flag: "); v3 = _acrt_iob_func(0); fgets(Buffer, 33, v3); v4 = strcspn(Buffer, "\n"); if ( v4 >= 0x21 ) { sub_7FF78B081558( v6, v5, v7, v8, *(_QWORD *)Buffer, *(_QWORD *)&Buffer[8], v20, *((_QWORD *)&v20 + 1), v21, *(_QWORD *)&v22[0], *((_QWORD *)&v22[0] + 1)); JUMPOUT(0x7FF78B08141Ei64); } Buffer[v4] = 0; v9 = -1i64; do ++v9; while ( Buffer[v9] ); if ( v9 == 32 ) { sub_7FF78B081070(Buffer, v22); v10 = 0; v11 = 0; v12 = 0i64; do { v13 = (__m128)_mm_loadu_si128((const __m128i *)&byte_7FF78B085078[v12]); v11 += 32; v14 = (__m128)_mm_loadu_si128((const __m128i *)&v22[v12 / 0x10]); v12 += 32i64; *(__m128 *)&dword_7FF78B085058[v12 / 4] = _mm_xor_ps(v14, v13); *(__m128 *)&qword_7FF78B085068[v12 / 8] = _mm_xor_ps( (__m128)_mm_loadu_si128((const __m128i *)((char *)&v20 + v12 + 8)), (__m128)_mm_loadu_si128((const __m128i *)&qword_7FF78B085068[v12 / 8])); } while ( v11 < 0x20 ); v15 = (int)v11; if ( (unsigned __int64)(int)v11 < 0x2C ) { do { ++v11; byte_7FF78B085078[v15] ^= *((_BYTE *)v22 + v15); ++v15; } while ( v11 < 0x2C ); } v16 = 0i64; while ( byte_7FF78B0832F0[v16] == byte_7FF78B085078[v16] ) { ++v10; ++v16; if ( v10 >= 0x2C ) { v17 = "Correct!\n"; goto LABEL_13; } } } v17 = "Incorrect!\n"; LABEL_13: sub_7FF78B081010(v17); return 0; } ``` xem qua ta có thể thấy chương trình gọi một số hàm mã hóa và cuối cùng là check để kiểm tra flag có đúng không ![image](https://hackmd.io/_uploads/ryTM-jqP1e.png) tuy code khá dài tuy nhiên ta có thể chú ý một số hàm mã hóa chính như sau lần 1: ![image](https://hackmd.io/_uploads/B1qEwo9vyx.png) chương trình kiểm tra xem đầu vào mà ta nhập có phải là 32 ký tự hay không nếu đúng thì sẽ gọi hàm ```sub_7FF7EEA81070``` để mã hóa nội dung hàm khá dài và khó nhìn tuy nhiên ta có thể check output để xem hàm làm gì với input output: ![image](https://hackmd.io/_uploads/H1Tgtscw1x.png) ![image](https://hackmd.io/_uploads/SJ38KocPJe.png) ta có thể dễ dàng nhận ra đây là mã hóa base64 của input ```aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``` mà ta đã nhập vào trước đó lần 2: ![image](https://hackmd.io/_uploads/rJCEcjqwJe.png) xor từng bytes của ```v18``` (output của base64 trước đó) với từng bytes của ```byte_7FF6E4DF5078``` và lưu trữ kết quả luôn vào ```byte_7FF6E4DF5078``` cuối cùng là check: ```byte_7FF6E4DF5078``` với ```byte_7FF6E4DF32F0``` ![image](https://hackmd.io/_uploads/BJbWoi5DJx.png) nếu tất cả các bytes ```byte_7FF6E4DF5078``` và ```byte_7FF6E4DF32F0``` đều giống nhau thì báo ```Correct!``` nếu không thì báo ```Incorrect!``` Tổng kết: \- nhận vào chuỗi 32 ký tự \- mã hóa base64 \- xor với ```byte_7FF6E4DF5078``` \- kiểm tra Ta dễ dàng viết script decrypt: ```python= import base64 byte_7FF6E4DF32F0=[0xC1, 0x91, 0x69, 0xB4, 0x66, 0xF9, 0x04, 0x12, 0xB2, 0xD3, 0x7D, 0x6B, 0x0F, 0xB9, 0x7F, 0xF5, 0xD2, 0x1C, 0xBF, 0x32, 0x0B, 0x32, 0x34, 0x9C, 0x98, 0xA4, 0x14, 0x37, 0x86, 0xC9, 0xAF, 0xE2, 0x9C, 0x46, 0x2B, 0xEC, 0x9F, 0x63, 0x38, 0x23, 0x54, 0x78, 0xCD, 0xF2] byte_7FF6E4DF5078=[0x92, 0xA1, 0x27, 0xE0, 0x37, 0xCA, 0x70, 0x7E, 0xE6, 0xBE, 0x33, 0x1D, 0x5D, 0xFE, 0x29, 0x93, 0xB6, 0x66, 0xF9, 0x02, 0x6A, 0x74, 0x0D, 0xDF, 0xD6, 0xEC, 0x5A, 0x71, 0xC8, 0xA3, 0xFD, 0x84, 0xC5, 0x13, 0x1E, 0x87, 0xC7, 0x52, 0x50, 0x55, 0x01, 0x16, 0xFD, 0xCF] a='' for i in range(len(byte_7FF6E4DF5078)): a+=chr(byte_7FF6E4DF5078[i]^byte_7FF6E4DF32F0[i]) p=base64.b64decode(a.encode()) print(p.decode()) #KCSC{eNcoDe_w1th_B4sE64_aNd_XoR} ``` Flag: ~~KCSC{eNcoDe_w1th_B4sE64_aNd_XoR}~~ ## Spy Room ![image](https://hackmd.io/_uploads/BkdCyh5Dkl.png) đây là 1 bài dotnet đơn giản, không có gì phức tạp, chủ yếu là kiểm tra khả năng xài dnspy và cryptography cơ bản mở dnspy: ![image](https://hackmd.io/_uploads/rJ3Dencwyl.png) bài flagchecker gọi khá nhiều hàm xor ta có thể dùng GPT gen chương trình decode :\(\( ```python= def xor(a, b): num = max(len(a), len(b)) result = [] for i in range(num): if len(a) >= len(b): result.append(chr(ord(a[i]) ^ ord(b[i % len(b)]))) else: result.append(chr(ord(a[i % len(a)]) ^ ord(b[i]))) return result def reverse_xor(source, url): source_chars = [chr(e) for e in source] array6 = xor(source_chars, list(url)) num = len(array6) array2 = array6[:num // 4] array3 = array6[num // 4:num // 2] array4 = array6[num // 2:3 * num // 4] array5 = array6[3 * num // 4:] array5 = xor(array5, array2) array4 = xor(array4, array5) array3 = xor(array3, array4) array2 = xor(array2, array3) decoded_array = array2 + array3 + array4 + array5 return ''.join(decoded_array) def main(): source = [ 85, 122, 105, 71, 17, 94, 71, 24, 114, 78, 107, 11, 108, 106, 107, 113, 121, 51, 91, 117, 86, 110, 100, 18, 124, 104, 71, 66, 123, 3, 111, 99, 74, 107, 69, 77, 111, 2, 120, 125, 83, 99, 62, 99, 109, 76, 119, 111, 59, 32, 1, 93, 69, 117, 84, 106, 73, 85, 112, 66, 114, 92, 61, 80, 80, 104, 111, 72, 98, 28, 88, 94, 27, 120, 15, 76, 15, 67, 86, 117, 81, 108, 18, 37, 34, 101, 104, 109, 23, 30, 62, 78, 88, 10, 2, 63, 43, 72, 102, 38, 76, 23, 34, 62, 21, 97, 1, 97 ] url = "https://www.youtube.com/watch?v=L8XbI9aJOXk" decoded_text = reverse_xor(source, url) print(decoded_text) if __name__ == "__main__": main() #VXpCT1ZGRXpkRVpaV0U0MVdEQldkVmt6U2pWalNGSndZakkxWmxZeWJEQmhSamxGWWpOU1QxSldVbVpWU0VwMldqTkthR0pVYjNwbVVUMDk= ``` output là chuỗi đã bị mã hóa base64 nhiều lần ![image](https://hackmd.io/_uploads/Bkpn7h5PJx.png) Flag : ~~KCSC{Easy_Encryption_With_DotNET_Program:3}~~ ## EzRev ![image](https://hackmd.io/_uploads/rypoEn9Pyg.png) Pseudocode IDA: ```C= int __cdecl main(int argc, const char **argv, const char **envp) { __int64 v3; // rdx unsigned int *v4; // r8 int i; // [rsp+20h] [rbp-28h] __int64 v7; // [rsp+28h] [rbp-20h] sub_140001200("Enter Something: ", argv, envp); sub_1400012D0("%s", byte_1400047A8); if ( (unsigned int)sub_140001100(byte_1400047A8) == -1982483102 ) { v7 = -1i64; do ++v7; while ( byte_1400047A8[v7] ); if ( v7 == 40 ) { sub_140001000(byte_1400047A8); dword_1400047A0 = 1; for ( i = 0; i < 40; ++i ) { v4 = dword_140004700; v3 = dword_140004700[i]; if ( dword_140004080[i] != (_DWORD)v3 ) dword_1400047A0 = 0; } } } if ( dword_1400047A0 ) sub_140001200("Excellent!! Here is your flag: KCSC{%s}", byte_1400047A8); else sub_140001200("You're chicken!!!", v3, v4); return 0; } ``` phân tích sơ qua thì đây có thể là 1 bài flagchecker với một số hàm mã hóa cơ bản lần 1: ![image](https://hackmd.io/_uploads/rJW5H25Pkx.png) chương trình nhận vào input và kiểm tra 1 điều kiện gì đấy ![image](https://hackmd.io/_uploads/Bks0HhqvJe.png) qua kiểm tra thì đây có thể là một loại hash nào đấy vì không thể dịch ngược được và không ảnh hưởng quá nhiều đến chương trình nên mình sẽ patch luôn tại đây để bỏ qua bước kiểm tra điều kiện này ![image](https://hackmd.io/_uploads/BkuPP2qPyx.png) lần 2: ![image](https://hackmd.io/_uploads/H12m_35Pkl.png) đếm số phần tử có trong ```byte_7FF64BE347A8``` (là input ta nhập vào) và kiểm tra xem có đủ 40 ký tự không gọi hàm ```sub_7FF64BE31000``` để mã hóa ![image](https://hackmd.io/_uploads/HJjlY2cvJe.png) hàm ```sub_7FF64BE31000``` lấy từng bytes của input rồi xor với các phép toán dịch bit ROR, ROL nhiều lần rồi lưu các giá trị đó vào ```dword_7FF64BE34700``` Cuối cùng là kiểm tra từng phần tử (dword) trong mảng ```dword_7FF64BE34700``` và ```dword_7FF64BE34080``` với nhau: ![image](https://hackmd.io/_uploads/BkfI9hcP1e.png) Tổng kết: \- kiểm tra hash (bỏ qua) \- mã hóa qua hàm ```sub_7FF64BE31000``` \- kiểm tra do mã hóa từng bytes một nên mình sẽ bruteforce luôn để tiết kiệm thời gian dịch ngược Script solve: ```python= def _rol(val, bits, bit_size=32): return (val << bits % bit_size) & (2 ** bit_size - 1) | ((val & (2 ** bit_size - 1)) >> (bit_size - (bits % bit_size))) def _ror(val, bits, bit_size=32): return ((val & (2 ** bit_size - 1)) >> bits % bit_size) | (val << (bit_size - (bits % bit_size)) & (2 ** bit_size - 1)) def sub_7FF765091000(a1): for i in range(len(a1)): v2 = a1[i] v5 = 4 v6 = 6 for j in range(5): v2 ^= _rol(v2, v5) ^ _ror(v2, v6) v5 *= 2 v6 *= 2 return (v2) enc=[ 0x0F30C0330, 0x340DDE9D, 0x750D9AC9, 0x391FBC2A, 0x9F16AF5B, 0x0E6180661, 0x6C1AAC6B, 0x340DDE9D, 0x0B60D5635, 0x9F16AF5B, 0x0A3195364, 0x681BBD3A, 0x0F30C0330, 0x0A3195364, 0x0AB1B71C6, 0x0F30C0330, 0x0F21D5274, 0x9F16AF5B, 0x0E6180661, 0x300CCFCC, 0x0F21D5274, 0x9F16AF5B, 0x0AB1B71C6, 0x0A3195364, 0x750D9AC9, 0x0A3195364, 0x9F16AF5B, 0x0F21D5274, 0x0F30C0330, 0x0A3195364, 0x0F21D5274, 0x351C8FD9, 0x710C8B98, 0x0F70D1261, 0x2D1AE83F, 0x0F30C0330, 0x0EE1A24C3, 0x0F70D1261, 0x6108CEDC, 0x6108CEDC ] flag='' for e in enc: for i in range(33,127): a=sub_7FF765091000((flag+chr(i)).encode()) if a==e: flag=flag+chr(i) print(flag) break #345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!! ``` Mình có tham khảo script chuyển ROR,ROL sang python tại: https://github.com/tandasat/scripts_for_RE/blob/master/rotate.py Flag: ~~KCSC{345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!!}~~ Thông thường mình sẽ không quá để ý việc dịch ngược hay chuyển code sang python cho những bài flagchecker như này mà sẽ hay xài gdb để bruteforce nhanh flag. Tuy nhiên lần này gdb không decompile được nên mình đã không thể xài lại trick cũ, đây cũng là bài học cho mình để thay đổi tư duy làm bài và nghiên cứu nghiêm túc hơn trong tương lai! có thể tham khảo 1 số bài mình đã giải bằng gdb tại: https://hackmd.io/@robertowen/rkXtc16N1l ## Reverse me ![image](https://hackmd.io/_uploads/rkoFZpqv1g.png) Pseudocode (khá dễ nhìn): ```C= __int64 __fastcall main(int a1, char **a2, char **a3) { int i; // [rsp+18h] [rbp-58h] int j; // [rsp+1Ch] [rbp-54h] char s[56]; // [rsp+30h] [rbp-40h] BYREF unsigned __int64 v7; // [rsp+68h] [rbp-8h] v7 = __readfsqword(0x28u); memset(s, 0, 0x31uLL); printf("FLAG: "); __isoc99_scanf("%48s", s); for ( i = 0; i <= 47; i += 8 ) sub_12D4(&s[i], &s[i + 4]); for ( j = 0; ; ++j ) { if ( j > 47 ) { puts("Correct!"); return 0LL; } if ( s[j] != byte_4040[j] ) break; } puts("Incorrect!"); return 0LL; } ``` Vì mình không cài IDA lên WSL nên mình sẽ debug remote như này ![image](https://hackmd.io/_uploads/Byopza9vkl.png) ![image](https://hackmd.io/_uploads/r1mQXTcDkg.png) Do chương trình cũng đơn giản nên ta chỉ phân tích nhanh ![image](https://hackmd.io/_uploads/BkGpQa9Dyg.png) \- chương trình nhận vào 48 bytes từ input và mã hóa thông qua hàm ```sub_5555555552D4```, lưu trữ luôn vào s \- kiểm tra với ```byte_555555558040```, nếu đúng thì trả về Correct, sai thì Incorrect Hàm mã hóa ```sub_5555555552D4```: ![image](https://hackmd.io/_uploads/SkCfSacvJl.png) ta có thể nhận ra đây là mã hóa XTEA khá quen thuộc Mình có tham khảo chương trình decrypt XTEA bằng python tại: https://github.com/niklasb/ctf-tools/blob/master/crypto/xtea.py Script: ```python= from Crypto.Util.number import* dword_5555555580C0=[0x126575B, 0x51903231, 0x8AAB8F5E, 0x0CA51930F] byte_555555558040=[473413356, 2967692918, 1094173039, 1162692205, 2047540795, 593189689, 3392237974, 2109325366, 3133376540, 144254372, 4264188329, 2498107430] rounds = 32 mask = 0xffffffff delta = 0x9E3779B9 def decrypt(v, key): v=list(v) sum=(delta*rounds)&mask for _ in range(rounds): v[1] -= (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ (sum + key[(sum>>11) & 3]) v[1] &= mask sum = (sum-delta)&mask v[0] -= (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ (sum + key[sum & 3]) v[0] &= mask return v if __name__ == "__main__": n=b'' for j in range(0,len(byte_555555558040),2): a=(decrypt(byte_555555558040[j:j+2], dword_5555555580C0)) for i in range(2): n+=(long_to_bytes(a[i])[::-1]) print(n) #b'\xec\xb0LNQ\xa7r\xdd}\x1d\x0c\x9c\x0f\x9e\x93\x8ez\xb6\x1d\xedC\xea{H\xa93\x9f\x1a\rj\xa9\xc9m\xb5\xbc\xf1%\xc6\xb6.\x80,II\x1e\xb3\x103' ``` đến đây mình mới phát hiện ra điều gì đấy không đúng, ngồi fix lại chương trình decrypt khá lâu vì nghĩ chắc là sai ở đâu đấy, cuối cùng mình đã phải xem xét lại kỹ file binary ![image](https://hackmd.io/_uploads/r1bbKaqPyl.png) trong functions mình thấy chương trình có gọi ```ptrace``` \- là syscall chống debug trong Linux do đây không phải là file Windows excutable nên sẽ không có các WinAPI như ```IsDebuggerPresent()``` hay ```NtQueryInformationProcess()``` nên ta cần lưu ý khi làm bài ta trỏ đến địa chỉ gọi ptrace: ![image](https://hackmd.io/_uploads/SyZOjTqv1g.png) Nếu ta debug thì chương trình sẽ chuyển sang luồng fake, dẫn đến key decrypt XTEA bị sai xem pseudo code để có cái nhìn trực quan hơn: ![image](https://hackmd.io/_uploads/rJBOna9PJe.png) ta có thể nhận thấy khác nhau ở ```off_555555558080``` và ```off_555555558090``` giữa luồng fake và luồng real dẫn đến chương trình trả về 2 key khác nhau cần sửa ZF hoặc patch để chương trình đưa vào luồng đúng lúc này ta có thể lấy ```dword_5555555580C0``` chuẩn ra và bỏ vào script solve: ```python= from Crypto.Util.number import* #dword_5555555580C0=[0x126575B, 0x51903231, 0x8AAB8F5E, 0x0CA51930F] dword_5555555580C0=[ 0x3AB27278, 0x0A840805B, 0x0E864925B, 0x0B7B1EEDE] byte_555555558040=[473413356, 2967692918, 1094173039, 1162692205, 2047540795, 593189689, 3392237974, 2109325366, 3133376540, 144254372, 4264188329, 2498107430] #dword rounds = 32 mask = 0xffffffff delta = 0x9E3779B9 def decrypt(v, key): v=list(v) sum=(delta*rounds)&mask for _ in range(rounds): v[1] -= (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ (sum + key[(sum>>11) & 3]) v[1] &= mask sum = (sum-delta)&mask v[0] -= (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ (sum + key[sum & 3]) v[0] &= mask return v if __name__ == "__main__": n=b'' for j in range(0,len(byte_555555558040),2): a=(decrypt(byte_555555558040[j:j+2], dword_5555555580C0)) for i in range(2): n+=(long_to_bytes(a[i])[::-1]) print(n) #b'KCSC{XTEA_encryption_and_debugger_detection_:>>}' ``` Flag: ~~KCSC{XTEA_encryption_and_debugger_detection_:>>}~~ ## ChaChaCha ![image](https://hackmd.io/_uploads/rJfjf09Dkl.png) Bài này mình tốn cả chiều để viết script decrypt tuy nhiên cuối cùng mình lại giải được mà không cần decrypt \:\(\( làm mình khá đuối sức và buồn ngủ ![image](https://hackmd.io/_uploads/Bkf4N09vyl.png) Để cho ta 3 file, 1 file dump, 1 file txt và 1 file exe mở important_note.txt bằng hex editor và nhìn kích thước file thì ta có thể đoán rằng đây là 1 file đã bị mã hóa: ![image](https://hackmd.io/_uploads/rJrCEC9P1e.png) mở file ChaChaCha.exe bằng IDA ta có pseudo code như sau: ```C= int __cdecl main(int argc, const char **argv, const char **envp) { HMODULE LibraryA; // eax BOOLEAN (__stdcall *SystemFunction036)(PVOID, ULONG); // eax HMODULE v5; // eax BOOLEAN (__stdcall *ProcAddress)(PVOID, ULONG); // eax HANDLE FileW; // eax void *v8; // ebx signed int FileSize; // edi _BYTE *v11; // ebx int v12; // ecx _BYTE *v13; // ecx signed int v14; // esi signed int v15; // ebx _BYTE *v16; // eax char v17; // al char v18; // [esp+0h] [ebp-D8h] HANDLE hFile; // [esp+Ch] [ebp-CCh] signed int v20; // [esp+10h] [ebp-C8h] char *v21; // [esp+14h] [ebp-C4h] _BYTE *v22; // [esp+18h] [ebp-C0h] char *v23; // [esp+1Ch] [ebp-BCh] DWORD NumberOfBytesWritten; // [esp+20h] [ebp-B8h] BYREF DWORD NumberOfBytesRead; // [esp+24h] [ebp-B4h] BYREF char v26[48]; // [esp+28h] [ebp-B0h] BYREF int v27; // [esp+58h] [ebp-80h] char v28[64]; // [esp+68h] [ebp-70h] BYREF char v29[32]; // [esp+A8h] [ebp-30h] BYREF char v30[12]; // [esp+C8h] [ebp-10h] BYREF LibraryA = LoadLibraryA("advapi32.dll"); SystemFunction036 = (BOOLEAN (__stdcall *)(PVOID, ULONG))GetProcAddress(LibraryA, "SystemFunction036"); SystemFunction036(v29, 32); v5 = LoadLibraryA("advapi32.dll"); ProcAddress = (BOOLEAN (__stdcall *)(PVOID, ULONG))GetProcAddress(v5, "SystemFunction036"); ProcAddress(v30, 12); FileW = CreateFileW(FileName, 0xC0000000, 0, 0, 3u, 0x80u, 0); v8 = FileW; hFile = FileW; if ( FileW == (HANDLE)-1 ) { sub_401590("Cannot Open File", v18); CloseHandle((HANDLE)0xFFFFFFFF); return 1; } else { FileSize = GetFileSize(FileW, 0); v20 = FileSize; v21 = (char *)malloc(FileSize); if ( ReadFile(v8, v21, FileSize, &NumberOfBytesRead, 0) ) { v11 = malloc(FileSize); v22 = v11; sub_4013D0(v12, v30); v14 = 0; if ( FileSize > 0 ) { v23 = v28; do { sub_401000(v26, v28, v13); ++v27; v15 = v14 + 64; if ( !__OFSUB__(v14, v14 + 64) ) { v16 = v22; do { if ( v14 >= FileSize ) break; v13 = &v16[v14]; v17 = v23[v14] ^ v16[v14 + v21 - v22]; ++v14; FileSize = v20; *v13 = v17; v16 = v22; } while ( v14 < v15 ); } v23 -= 64; v14 = v15; } while ( v15 < FileSize ); v11 = v22; } SetFilePointer(hFile, 0, 0, 0); if ( WriteFile(hFile, v11, FileSize, &NumberOfBytesWritten, 0) ) { CloseHandle(hFile); sub_401590("Some important file has been encrypted!!!\n", (char)FileName); return 0; } else { sub_401590("Cannot Write File", v18); CloseHandle(hFile); return 1; } } else { sub_401590("Cannot Read File", v18); CloseHandle(v8); return 1; } } } ``` phân tích: Đầu tiên chương trình tạo 1 Buffer ngẫu nhiên 32 bytes và 1 Buffer 12 bytes: ![image](https://hackmd.io/_uploads/rJaHU0qwkx.png) tiếp đến là các bước mở file, đọc file gì đấy tuy nhiên mình sẽ không đi phân tích phần này: ![image](https://hackmd.io/_uploads/BkFyvCqD1e.png) tiếp đến gọi hàm ```sub_8913D0```: ![image](https://hackmd.io/_uploads/S15Uw0qvJx.png) Bên trong có khá nhiều phép toán bitwise, có thể là thuật toán tạo khóa nào đấy: ![image](https://hackmd.io/_uploads/SkdiwR9vkx.png) ta để ý: ```python! qmemcpy(a2, "expand 32-byte k", 16); ``` đây có thể là gọi sig của mã hóa salsa20 hoặc chacha20, tuy nhiên đề bài là ChaChaCha nên khả năng cao là chacha20 Ta có thể hiểu là tạo ma trận 4x4, hàng 1 là chuỗi “expand 32-byte k”, 2 hàng tiếp theo là 32 bytes key, 4 bytes đầu tiên của hàng cuối là counter = 1129530187 = 'KCSC' và 12 bytes cuối là nonce ![image](https://hackmd.io/_uploads/ByOGqCcvyl.png) tìm hiểu thêm tại https://xilinx.github.io/Vitis_Libraries/security/2019.2/guide_L1/internals/chacha20.html đặt breakpoint như sau và mở hexview, ta có thể thấy key và nonce đã được lưu trữ: ![image](https://hackmd.io/_uploads/ryH1JysD1x.png) tiếp theo: ![image](https://hackmd.io/_uploads/BJdLo0cvyg.png) gọi hàm ```sub_891000``` là mã hóa file bằng thuật toán chacha20 sau đó là xor gì đấy mình không hiểu lắm, có lẽ đây là nguyên nhân khiến mình viết chương trình decrypt cả chiều không được (sau khi tham khảo các WU khác thì thấy mọi người sử dụng CyberChef để decrypt) Tạm dừng ở đây, ta sẽ phân tích file dump: search strings "expand 32-byte k" trong IDA: ![image](https://hackmd.io/_uploads/Sy5UkyoDJx.png) click vào để tìm địa chỉ lưu nó: ![image](https://hackmd.io/_uploads/BJLt1yiwJl.png) Do file dump này trích được memory lúc file bị mã hóa thành important_note.txt nên đây sẽ là key và nonce để decrypt file dump lấy bytes: ``` [0x65, 0x78, 0x70, 0x61, 0x6E, 0x64, 0x20, 0x33, 0x32, 0x2D, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6B, 0xD9, 0xFA, 0xBB, 0x42, 0x0C, 0x2D, 0xB8, 0x08, 0xD1, 0xF8, 0xBF, 0xA5, 0x89, 0x0A, 0xC3, 0xB3, 0x84, 0x9F, 0x69, 0xE2, 0xF3, 0x30, 0xD4, 0xA9, 0x0D, 0xB1, 0x19, 0xBD, 0x4E, 0xA0, 0xB8, 0x30, 0x4B, 0x43, 0x53, 0x43, 0xDB, 0x7B, 0xE6, 0x93, 0xEE, 0x9B, 0xC1, 0xA4, 0x70, 0x73, 0xCA, 0x4B] ``` Do chacha20 có thể dùng chương trình mã hóa để giải mã(mã dòng), nên mình sẽ patch luôn bộ nhớ tại key hiện tại thành key lấy từ file dump để giải mã file important_note.txt đặt breakpoint tại: ![image](https://hackmd.io/_uploads/ryH1JysD1x.png) ta chạy script sau để thay đổi thay đổi bộ nhớ (không thấy ai xài cách này nên tâm đắc vl 😈) ```python= import idaapi import idc start_addr = 0x00AFFAA0#địa chỉ sẽ khác nhau mỗi lần debug, cần thay đổi khi thử chạy end_addr = start_addr+63 new_data = [ 0x65, 0x78, 0x70, 0x61, 0x6E, 0x64, 0x20, 0x33, 0x32, 0x2D, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6B, 0xD9, 0xFA, 0xBB, 0x42, 0x0C, 0x2D, 0xB8, 0x08, 0xD1, 0xF8, 0xBF, 0xA5, 0x89, 0x0A, 0xC3, 0xB3, 0x84, 0x9F, 0x69, 0xE2, 0xF3, 0x30, 0xD4, 0xA9, 0x0D, 0xB1, 0x19, 0xBD, 0x4E, 0xA0, 0xB8, 0x30, 0x4B, 0x43, 0x53, 0x43, 0xDB, 0x7B, 0xE6, 0x93, 0xEE, 0x9B, 0xC1, 0xA4, 0x70, 0x73, 0xCA, 0x4B ] for i in range(len(new_data)): addr = start_addr + i idc.patch_byte(addr, new_data[i]) print(f"Thay đổi bộ nhớ thành công từ {hex(start_addr)} đến {hex(end_addr)}") ``` sau khi thay đổi bộ nhớ, tiếp tục chạy hết chương trình để mã hóa lại file mở lại file important_note.txt lúc nãy ra, ta thấy file đã được decrypt thành công ![image](https://hackmd.io/_uploads/Syo07Jiwkl.png) Nhìn header ta có thể thấy đây là một file Windows excutable chạy file exe, ta được: ![image](https://hackmd.io/_uploads/BJs4rkov1g.png) ![image](https://hackmd.io/_uploads/HJQcryjPkl.png) ## WaiterFall ![image](https://hackmd.io/_uploads/rkcIRYoPkl.png) Mở IDA: ![image](https://hackmd.io/_uploads/rk7OCFjvJx.png) nhìn có vẻ rất khủng bố :O Tuy nhiên đây chỉ là 1 dạng bài sử dụng Z3 rất kinh điển solve Script: (byClaude) ```python= from z3 import * def solve_challenge(): s = Solver() chars = [BitVec(f'char_{i}', 8) for i in range(62)] v3 = 0 v5 = 0x1000008020020 v7 = 0x60010020000100 v8 = 0x100020080408000 v9 = 0x844000044000 for i, char in enumerate(chars): s.add(char >= 32) # Space s.add(char <= 126) # ~ conditions = [] conditions.append(If(char == ord('C'), If((i - 1) & 0xFFFFFFFD == 0, 1, 0), 0)) conditions.append(If(char == ord('K'), If(i == 0, 1, 0), 0)) conditions.append(If(char == ord('S'), If(i == 2, 1, 0), 0)) conditions.append(If(char == ord('c'), If(i == 37, 1, 0), 0)) conditions.append(If(char == ord('d'), If(i == 20, 1, 0), 0)) conditions.append(If(char == ord('g'), If(Or(i == 11, i == 60), 1, 0), 0)) conditions.append(If(char == ord('u'), If(i == 24, 1, 0), 0)) conditions.append(If(char == ord('{'), If(i == 4, 1, 0), 0)) conditions.append(If(char == ord('}'), If(i == 61, 1, 0), 0)) if i <= 0x31: # For '_' if (0x2101004011000 >> i) & 1: conditions.append(If(char == ord('_'), 1, 0)) if i <= 0x34: # For 'a' if (0x10000210000040 >> i) & 1: conditions.append(If(char == ord('a'), 1, 0)) if i <= 0x37: # For 'e' if (0x80000040200000 >> i) & 1: conditions.append(If(char == ord('e'), 1, 0)) if i <= 0x32: # For 'f' if (0x4200100802000 >> i) & 1: conditions.append(If(char == ord('f'), 1, 0)) if i <= 0x3A: # For 'i' if (0x400000000000280 >> i) & 1: conditions.append(If(char == ord('i'), 1, 0)) if i <= 0x33: # For 'l' if (0x8480C02000000 >> i) & 1: conditions.append(If(char == ord('l'), 1, 0)) if i <= 0x3B: # For 'n' if (0xA00008000080400 >> i) & 1: conditions.append(If(char == ord('n'), 1, 0)) if i <= 0x2F: # For 'o' if (v9 >> i) & 1: conditions.append(If(char == ord('o'), 1, 0)) if i <= 0x38: # For 'r' if (v8 >> i) & 1: conditions.append(If(char == ord('r'), 1, 0)) if i <= 0x36: # For 't' if (v7 >> i) & 1: conditions.append(If(char == ord('t'), 1, 0)) if i <= 0x30: # For 'w' if (v5 >> i) & 1: conditions.append(If(char == ord('w'), 1, 0)) v3 = v3 + Sum(conditions) s.add(v3 == 62) if s.check() == sat: m = s.model() result = '' for i in range(62): c = m[chars[i]].as_long() result += chr(c) return result return None result = solve_challenge() if result: print("Flag:", result) else: print("No solution found") #Flag: KCSC{waiting_for_wonderful_waterfall_control_flow_flatterning} ``` Flag: ~~KCSC{waiting_for_wonderful_waterfall_control_flow_flatterning}~~ ## STEAL # Crypto :((