<h1 id="Hack-The-Box">Hack The Box - Reversing (Medium 3)</h1> ![image](https://hackmd.io/_uploads/HyCWL9bl0.png) Ghi chú: <ul> <li>Medium: 13-18 challenge</li> <ul> <li><a href="#Debugme">13. Debugme</a></li> <li><a href="#Iterative Virus">14. Iterative Virus</a></li> <li><a href="#Coffee Invocation">15. Coffee Invocation</a></li> <li><a href="#FFModule">16. FFModule</a></li> <li><a href="#SEPC">17. SEPC</a></li> <li><a href="#Maze">18. Maze</a></li> </ul> </li> </ul> <h2>Difficulty: Medium </h2> <div id="Debugme"></div> <h3>Challenge 13: Debugme</h3> A develper is experiementing with different ways to protect their software. They have sent in a windows binary that is suposed to super secureand really hard to debug. Debug and see if you can find the flag. <a href="https://drive.google.com/file/d/1dKbK8dDZe4KIOgabWaGanNNEVtmiLrAx/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp. ![image](https://hackmd.io/_uploads/rJF3YdqqT.png) Mở file trong IDA32, quan sát trong hàm `mainCRTStartup_0` ta thấy chương trình sử dụng `BeingDebugged và NtGlobalFlag field` của `PEB` để kiểm tra chương trình có đang debug không. ![image](https://hackmd.io/_uploads/BJBac_9cT.png) Sau đó, thực hiện `XOR` các byte của hàm `main()` với opcode 0x5C để có thể thực thi được. :::info ```python import ida_bytes start = 0x00401620 end = 0x00401791 for i in range(start,end): tmp = ida_bytes.get_byte(i) ida_bytes.patch_byte(i,tmp^0x5C) ``` ::: Ta được nội dụng hàm `main()` như sau: ![image](https://hackmd.io/_uploads/BkFjiO9ca.png) Chương trình thực hiện lấy `v11 XOR 0x4B` rồi trả về kết quả tính được. :::info ``` v11 = [0x277B391F, 0x2C252227, 0x3F250A14, 0x780F147A, 0x0C0C3E29, 0x3F14192E, 0x20282239, 0x14191431, 0x6A253E2D] data = "" for num in v11: hex_str = format(num, '08x') reversed_str = ''.join(reversed([hex_str[i:i+2] for i in range(0, len(hex_str), 2)])) data += reversed_str print(data) # 1f397b272722252c140a253f7a140f78293e0c0c2e19143f39222820311419142d3e256a ``` ::: ![image](https://hackmd.io/_uploads/r1aLad99T.png) :::success ``` Flag: HTB{Tr0lling_Ant1_D3buGGeR_trickz_R_fun!} ``` ::: <div id="Iterative Virus"></div> <h3>Challenge 14: Iterative Virus</h3> While cleaning up the workspace of a recently retired employee, we noticed that one of the core files of the very important programs they were working on didn't match up with the backups we have of it, could you check it out for us? <a href="https://drive.google.com/file/d/12oKjvI8RwAKibtE5cfEasloMNxNmjds_/view?usp=sharingF">Download Challenge Here</a> <h3>Solution</h3> Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp. ![image](https://hackmd.io/_uploads/rkTH6Knca.png) ![image](https://hackmd.io/_uploads/ByHS8oxb0.png) ![image](https://hackmd.io/_uploads/H14Dwjg-0.png) Tệp có 7 `section`, khi ta mở file trong `PEBear`, ta tìm thấy tệp có một `section` tên `ivir`. Đây là một `section` lạ. Đồng thời, ta lại thấy `Timestamp = deadc0de`. ![image](https://hackmd.io/_uploads/rJUdg5h9T.png) Mở chương trình trong IDA64. ![image](https://hackmd.io/_uploads/Bkeh353qT.png) Trong hệ điều hành Windows, cấu trúc Thread Environment Block (TEB) sẽ chứa thông tin chi tiết cần thiết để quản lý luồng (thread) đang chạy. TEB là một thành phần quan trọng trong không gian người dùng của hệ điều hành, liên quan mật thiết đến việc thực thi và điều hành các chương trình. Bên trong TEB, ta có ProcessEnvironmentBlock (PEB) nắm giữ thông tin môi trường chi tiết của quá trình mà luồng nằm trong. PEB cũng chứa thành viên Ldr – nó cung cấp quyền truy cập vào danh sách liên kết InMemoryOrderModuleList, nơi liệt kê tất cả các module đã được nạp theo đúng thứ tự trong bộ nhớ. Thông qua danh sách này, Ldr giúp quản lý các module khác nhau Từng API trong module sẽ được tính checksum CRC32 và kiểm tra có bằng 0xBC553B82. Ta sẽ tìm được chương trình muốn gọi `GetProcAddress` ![image](https://hackmd.io/_uploads/rJmy09h5T.png) Hàm `sub_14001C1A8` để xác định hành động cần thực hiện - sao chép tên các API để sử dụng GetProcAddress sau này gọi các API đó. ![image](https://hackmd.io/_uploads/HJUJGNTq6.png) Từ đây, ta có thể thay đổi tên của các biến để chương trình rõ ràng và dễ hiểu hơn. Mục đích của nó để tải động các hàm từ `kernel32.dll`, sử dụng trong việc xử lý tệp và quản lý tiến trình. ![image](https://hackmd.io/_uploads/Hk-aG3gW0.png) Chương trình kiểm tra byte thứ năm từ EntryPoint có giá trị là 5 hay không. Nếu có, nó sẽ gọi một hàm hiện tại được mã hóa, nếu không, mã sẽ chọn và lưu trữ một số 64-bit sẽ được sử dụng sau này để giải mã. Khi chưa thực thi, giá trị byte đó là 1. ![image](https://hackmd.io/_uploads/H1Moqnysp.png) Chương trình sẽ kiểm tra qua các tệp có phần mở rộng `exe`. Nếu tìm thấy, nó tệp với tên đã có và cấp quyền truy cập (GENERIC_READ và GENERIC_WRITE). Nếu việc mở file thành công sẽ lấy kích thước của file. Sau đó, kích thước mới của file được tính bằng cách cộng thêm một giá trị cố định (0xD80) vào kích thước hiện tại của file, mục đích để ghi thêm một section mới. Hàm này tạo ra một đối tượng file mapping. Khi một file được mapped, dữ liệu của nó có thể được xem như một mảng liên tục trong không gian địa chỉ của quá trình. Khi đã có một đối tượng file mapping, MapViewOfFile cho phép ánh xạ nó vào không gian địa chỉ của quá trình gọi hàm. Nó cũng cho phép bạn chỉ định cặp quyền truy cập và bảo vệ khi ánh xạ, như chỉ đọc, chỉ ghi, hoặc ghi đè. Như ta đều đã biết, cấu trúc của một `PE File` bao gồm: 1. DOS Header 1. Rich Header 1. NT Headers 1. Data Directories (within the Optional Header) 1. Section Headers 1. Import Table 1. Base Relocations Table ![image](https://hackmd.io/_uploads/rkWfkrpcp.png) Đây là hình ảnh mô tả về phần DOS Header, DOS Stub and PE Header. Tại đây ta thấy, thành phần cuối cùng của `DOS Header` là `File address of new exe header` = `0xF8`. Thành viên này rất quan trọng đối với trình tải PE trên hệ thống Windows vì nó cho trình tải biết nơi tìm `PE Header`. ![image](https://hackmd.io/_uploads/HJMbMBacT.png) Ta kết luận `v25 = 0xF8` => `v25 + 4 = 0xFC` và `v25 + 8 = 0x100`. Tương ứng với `Machine` và `Time Date Stamp`. Biết `v26 = v25 + 20 = 0x10C` và `v27 = v26 + 40 * Section Count = 0x224`. `RVA` và `FileOffset` sẽ có giá trị là phần đầu của `section`. :::warning Ở đây tôi đang ví dụ với tệp đề cho. Trên thực thế, nó không thể load chính nó được vì tệp được load sẽ bị chương trình take control một cách tuyệt đối. Không thể mở nó trong các chương trình khác. ::: Hiểu đến đây, ta sẽ sử dụng struct của PE header để sửa chương trình cho thuận tiện trong phân tích sau này. :::info ``` struct _IMAGE_DOS_HEADER { USHORT e_magic; //0x0 USHORT e_cblp; //0x2 USHORT e_cp; //0x4 USHORT e_crlc; //0x6 USHORT e_cparhdr; //0x8 USHORT e_minalloc; //0xa USHORT e_maxalloc; //0xc USHORT e_ss; //0xe USHORT e_sp; //0x10 USHORT e_csum; //0x12 USHORT e_ip; //0x14 USHORT e_cs; //0x16 USHORT e_lfarlc; //0x18 USHORT e_ovno; //0x1a USHORT e_res[4]; //0x1c USHORT e_oemid; //0x24 USHORT e_oeminfo; //0x26 USHORT e_res2[10]; //0x28 LONG e_lfanew; //0x3c }; ``` ::: :::info ``` struct _IMAGE_NT_HEADERS { ULONG Signature; //0x0 struct _IMAGE_FILE_HEADER FileHeader; //0x4 struct _IMAGE_OPTIONAL_HEADER OptionalHeader; //0x18 }; ``` ::: ![image](https://hackmd.io/_uploads/Syc2vpgWR.png) Chương trình thực hiện kiểm tra: * Kiểm tra xem vùng nhớ được ánh xạ không rỗng nhằm đảm bảo rằng việc ánh xạ file vào bộ nhớ đã thành công. * Kiểm tra signature của DOS header là "MZ" * Kiểm tra xem architecture của file có kiến trúc 64bit * Kiểm tra timestamp của file giá trị là 'THIS' * Kiểm tra xem kích thước của các phần header và section không vượt quá kích thước của header của tệp ![image](https://hackmd.io/_uploads/rJpChTlZR.png) Lấy giá trị của trường `SizeOfHeaders` từ Optional Header. Kiểm tra xem kích thước mới của section .ivir (0xD80) có phải là bội số của `SizeOfHeaders` không, nếu không thì bổ sung thêm. Tính toán con trỏ đến dữ liệu thô của `section .ivir` bằng cách cộng trường `PointerToRawData` và `VirtualSize` của section. Đặt các cờ của section .ivir với các quyền truy cập thích hợp. Cập nhật kích thước của `image` trong `File Header` và `Timestamp`. ![image](https://hackmd.io/_uploads/ryrRWh1oa.png) Lấy giá trị của các cờ của `section .ivir` gán với 0x60500060, ta đặt tên biến là IvirSectionFlag. Các thay đổi này tạo ra một section mới trong file thực thi và cập nhật các giá trị `SizeOfCode` `Initialized Data` và `Uninitialized Data` nếu cần thiết. Dựa trên những giá trị cài đặt của các cờ bit để điều chỉnh kích thước section trong file thực thi. ![image](https://hackmd.io/_uploads/BJqwk0gWR.png) Nếu đủ vùng nhớ phần cho phần section mới, nó sẽ được ghi thêm section đó và section header được thêm và sửa đổi để đảm bảo chúng tuân thủ các quy tắc căn chỉnh và phần còn lại của quá trình chỉ là sao chép mã lây nhiễm và làm cho nó `thay thế EntryPoint của injected file` ![image](https://hackmd.io/_uploads/HJFfBRgWA.png) ![image](https://hackmd.io/_uploads/S1lALAeZ0.png) Thiết lập để trỏ tới ký tự cuối cùng trong file có kích thước mới. Nếu vị trí con trỏ vượt qua giới hạn của vùng nhớ hiện tại, nó sẽ di chuyển dữ liệu cũ sang phía sau để tạo không gian cho dữ liệu mới. Sau đó, nó thực hiện việc sao chép dữ liệu mới từ vị trí bắt đầu của `start` vào vùng nhớ đã được làm trống. Sau khi hoàn thành việc xử lý dữ liệu, nó đóng tài nguyên bằng cách gọi hàm `CloseHandle()`. ![image](https://hackmd.io/_uploads/Hy2Ushysp.png) Phần cuối của chương trình thực hiện giải mã nhiều lần bằng cách sử dụng các khóa đã đề cập ở trên - `start + 5`. Lúc đầu nó có giá trị là 1, sau mỗi lần giải mã thì tăng 1 cho giá trị đó, túc là lặp lại 4 lần đến khi `*(start + 5) = 5` thì gọi `hàm byte_14001C7E4()`. Ta viết đoạn mã để giải mã hàm này. :::info ```python import ida_bytes keys = [0x6E2368B9C685770B,0xEB7FD64E061C1A3D,0xCB8FF2D53D7505A1,0x0F1EF554206DCE4D] for i in range(0x14001C7E4,0x14001C7E4+0x198,8): data = (ida_bytes.get_qword(i)) for key in keys: data = (data * key) & 0xFFFFFFFFFFFFFFFF ida_bytes.patch_qword(i,data) ``` ::: Ta di chuyển đến và bôi đen `từ 0x14001C7E4 đến 14001C971` và `make code -> make function`. Hãy chắc rằng bạn đã NOP bốn byte tại `byte_14001C018`. Ta sẽ nhận được các hàm sau. ![image](https://hackmd.io/_uploads/H18cUpJoT.png) Đoạn mã load một số hàm quan trọng từ thư viện kernel32.dll và user32.dll bằng cách sử dụng hàm `GetFunction_v2`, sau đó gọi một số hàm API của hệ thống như `GetUserNameA` và `MessageBoxA` để thực hiện các tác vụ như hiển thị hộp thoại thông báo và lấy tên người dùng. Sau đó, mã kiểm tra xem tên người dùng có khớp với một giá trị cụ thể không. Nếu có thì tạo `MessageBoxA` và in ra `flag` ![image](https://hackmd.io/_uploads/rybN20e-A.png) :::success ``` Flag: HTB{f1V3_it3RaTiOn_V1rus} ``` ::: <div id="Coffee Invocation"></div> <h3>Challenge 15: Coffee Invocation</h3> Our new crazy conspiracy theorist intern, has blocked everyone from the coffee machine because he saw that aliens were trying to steal the "out of the world" secret recipe. Your mission is to unveil the secrets that lie behind his profound madness and teach him a javaluable lesson. <a href="https://drive.google.com/file/d/1O8E0T3y999AJFcxtEhGUy94oPa_Y22VE/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp. ![image](https://hackmd.io/_uploads/rJrx6aJja.png) Mở chương trình trong IDA64. ![image](https://hackmd.io/_uploads/rkf1Lvgia.png) `JNI (java native interface)` là framework cho phép gọi các hàm java trong JVM(java virtual machine) từ các ngôn ngữ thấp hơn như C++, C, assembly... Cocos2dx cung cấp 1 class singleton để có thể sử dụng JNI đó là `JNIHelper`. Để sử dụng `JNI_CreateJavaVM`, bạn cần bao gồm tệp `jni.h` trong chương trình C của mình. Hàm sẽ có cấu trúc như sau: `JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);`. ![image](https://hackmd.io/_uploads/r1SBP_eoT.png) Khi chạy chương trình bình thường, nó sẽ thông báo thiếu thư viện `libjvm.so`. Ta thực hiện các bước sau: 1. `sudo apt update` 2. `sudo apt install openjdk-17-jdk` 3. `sudo gedit ~/.bashrc` `export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64` 4. `LD_LIBRARY_PATH=/usr/lib/jvm/java-17-openjdk-amd64/lib/server ./coffee_invocation` ![image](https://hackmd.io/_uploads/B1hduOejT.png) Ta đã biết thực chất đây là một chương trình C/C++ sử dụng `JNI` để chạy các hàm Java. Ta sẽ xây dựng struct của các `function` trong Java. Tôi đã tham khảo: * https://gist.githubusercontent.com/Jinmo/048776db75067dcd6c57f1154e65b868/raw/89af26807eaa8bb31e35da63e102b0abfa311580/jni_all.h * https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp2556 Ta viết đoạn struct có nội dung sau: :::info ```cpp! struct JNINativeInterface { _QWORD NULL1; _QWORD NULL2; _QWORD NULL3; _QWORD NULL4; _QWORD GetVersion; _QWORD DefineClass; _QWORD FindClass; _QWORD FromReflectedMethod; _QWORD FromReflectedField; _QWORD ToReflectedMethod; _QWORD GetSuperclass; _QWORD IsAssignableFrom; _QWORD ToReflectedField; _QWORD Throw; _QWORD ThrowNew; _QWORD ExceptionOccurred; _QWORD ExceptionDescribe; _QWORD ExceptionClear; _QWORD FatalError; _QWORD PushLocalFrame; _QWORD PopLocalFrame; _QWORD NewGlobalRef; _QWORD DeleteGlobalRef; _QWORD DeleteLocalRef; _QWORD IsSameObject; _QWORD NewLocalRef; _QWORD EnsureLocalCapacity; _QWORD AllocObject; _QWORD NewObject; _QWORD NewObjectV; _QWORD NewObjectA; _QWORD GetObjectClass; _QWORD IsInstanceOf; _QWORD GetMethodID; _QWORD CallObjectMethod; _QWORD CallObjectMethodV; _QWORD CallObjectMethodA; _QWORD CallBooleanMethod; _QWORD CallBooleanMethodV; _QWORD CallBooleanMethodA; _QWORD CallByteMethod; _QWORD CallByteMethodV; _QWORD CallByteMethodA; _QWORD CallCharMethod; _QWORD CallCharMethodV; _QWORD CallCharMethodA; _QWORD CallShortMethod; _QWORD CallShortMethodV; _QWORD CallShortMethodA; _QWORD CallIntMethod; _QWORD CallIntMethodV; _QWORD CallIntMethodA; _QWORD CallLongMethod; _QWORD CallLongMethodV; _QWORD CallLongMethodA; _QWORD CallFloatMethod; _QWORD CallFloatMethodV; _QWORD CallFloatMethodA; _QWORD CallDoubleMethod; _QWORD CallDoubleMethodV; _QWORD CallDoubleMethodA; _QWORD CallVoidMethod; _QWORD CallVoidMethodV; _QWORD CallVoidMethodA; _QWORD CallNonvirtualObjectMethod; _QWORD CallNonvirtualObjectMethodV; _QWORD CallNonvirtualObjectMethodA; _QWORD CallNonvirtualBooleanMethod; _QWORD CallNonvirtualBooleanMethodV; _QWORD CallNonvirtualBooleanMethodA; _QWORD CallNonvirtualByteMethod; _QWORD CallNonvirtualByteMethodV; _QWORD CallNonvirtualByteMethodA; _QWORD CallNonvirtualCharMethod; _QWORD CallNonvirtualCharMethodV; _QWORD CallNonvirtualCharMethodA; _QWORD CallNonvirtualShortMethod; _QWORD CallNonvirtualShortMethodV; _QWORD CallNonvirtualShortMethodA; _QWORD CallNonvirtualIntMethod; _QWORD CallNonvirtualIntMethodV; _QWORD CallNonvirtualIntMethodA; _QWORD CallNonvirtualLongMethod; _QWORD CallNonvirtualLongMethodV; _QWORD CallNonvirtualLongMethodA; _QWORD CallNonvirtualFloatMethod; _QWORD CallNonvirtualFloatMethodV; _QWORD CallNonvirtualFloatMethodA; _QWORD CallNonvirtualDoubleMethod; _QWORD CallNonvirtualDoubleMethodV; _QWORD CallNonvirtualDoubleMethodA; _QWORD CallNonvirtualVoidMethod; _QWORD CallNonvirtualVoidMethodV; _QWORD CallNonvirtualVoidMethodA; _QWORD GetFieldID; _QWORD GetObjectField; _QWORD GetBooleanField; _QWORD GetByteField; _QWORD GetCharField; _QWORD GetShortField; _QWORD GetIntField; _QWORD GetLongField; _QWORD GetFloatField; _QWORD GetDoubleField; _QWORD SetObjectField; _QWORD SetBooleanField; _QWORD SetByteField; _QWORD SetCharField; _QWORD SetShortField; _QWORD SetIntField; _QWORD SetLongField; _QWORD SetFloatField; _QWORD SetDoubleField; _QWORD GetStaticMethodID; _QWORD CallStaticObjectMethod; _QWORD CallStaticObjectMethodV; _QWORD CallStaticObjectMethodA; _QWORD CallStaticBooleanMethod; _QWORD CallStaticBooleanMethodV; _QWORD CallStaticBooleanMethodA; _QWORD CallStaticByteMethod; _QWORD CallStaticByteMethodV; _QWORD CallStaticByteMethodA; _QWORD CallStaticCharMethod; _QWORD CallStaticCharMethodV; _QWORD CallStaticCharMethodA; _QWORD CallStaticShortMethod; _QWORD CallStaticShortMethodV; _QWORD CallStaticShortMethodA; _QWORD CallStaticIntMethod; _QWORD CallStaticIntMethodV; _QWORD CallStaticIntMethodA; _QWORD CallStaticLongMethod; _QWORD CallStaticLongMethodV; _QWORD CallStaticLongMethodA; _QWORD CallStaticFloatMethod; _QWORD CallStaticFloatMethodV; _QWORD CallStaticFloatMethodA; _QWORD CallStaticDoubleMethod; _QWORD CallStaticDoubleMethodV; _QWORD CallStaticDoubleMethodA; _QWORD CallStaticVoidMethod; _QWORD CallStaticVoidMethodV; _QWORD CallStaticVoidMethodA; _QWORD GetStaticFieldID; _QWORD GetStaticObjectField; _QWORD GetStaticBooleanField; _QWORD GetStaticByteField; _QWORD GetStaticCharField; _QWORD GetStaticShortField; _QWORD GetStaticIntField; _QWORD GetStaticLongField; _QWORD GetStaticFloatField; _QWORD GetStaticDoubleField; _QWORD SetStaticObjectField; _QWORD SetStaticBooleanField; _QWORD SetStaticByteField; _QWORD SetStaticCharField; _QWORD SetStaticShortField; _QWORD SetStaticIntField; _QWORD SetStaticLongField; _QWORD SetStaticFloatField; _QWORD SetStaticDoubleField; _QWORD NewString; _QWORD GetStringLength; _QWORD GetStringChars; _QWORD ReleaseStringChars; _QWORD NewStringUTF; _QWORD GetStringUTFLength; _QWORD GetStringUTFChars; _QWORD ReleaseStringUTFChars; _QWORD GetArrayLength; _QWORD NewObjectArray; _QWORD GetObjectArrayElement; _QWORD SetObjectArrayElement; _QWORD NewBooleanArray; _QWORD NewByteArray; _QWORD NewCharArray; _QWORD NewShortArray; _QWORD NewIntArray; _QWORD NewLongArray; _QWORD NewFloatArray; _QWORD NewDoubleArray; _QWORD GetBooleanArrayElements; _QWORD GetByteArrayElements; _QWORD GetCharArrayElements; _QWORD GetShortArrayElements; _QWORD GetIntArrayElements; _QWORD GetLongArrayElements; _QWORD GetFloatArrayElements; _QWORD GetDoubleArrayElements; _QWORD ReleaseBooleanArrayElements; _QWORD ReleaseByteArrayElements; _QWORD ReleaseCharArrayElements; _QWORD ReleaseShortArrayElements; _QWORD ReleaseIntArrayElements; _QWORD ReleaseLongArrayElements; _QWORD ReleaseFloatArrayElements; _QWORD ReleaseDoubleArrayElements; _QWORD GetBooleanArrayRegion; _QWORD GetByteArrayRegion; _QWORD GetCharArrayRegion; _QWORD GetShortArrayRegion; _QWORD GetIntArrayRegion; _QWORD GetLongArrayRegion; _QWORD GetFloatArrayRegion; _QWORD GetDoubleArrayRegion; _QWORD SetBooleanArrayRegion; _QWORD SetByteArrayRegion; _QWORD SetCharArrayRegion; _QWORD SetShortArrayRegion; _QWORD SetIntArrayRegion; _QWORD SetLongArrayRegion; _QWORD SetFloatArrayRegion; _QWORD SetDoubleArrayRegion; _QWORD RegisterNatives; _QWORD UnregisterNatives; _QWORD MonitorEnter; _QWORD MonitorExit; _QWORD GetJavaVM; _QWORD GetStringRegion; _QWORD GetStringUTFRegion; _QWORD GetPrimitiveArrayCritical; _QWORD ReleasePrimitiveArrayCritical; _QWORD GetStringCritical; _QWORD ReleaseStringCritical; _QWORD NewWeakGlobalRef; _QWORD DeleteWeakGlobalRef; _QWORD ExceptionCheck; _QWORD NewDirectByteBuffer; _QWORD GetDirectBufferAddress; _QWORD GetDirectBufferCapacity; _QWORD GetObjectRefType; }; struct JNIEnv { JNINativeInterface *function; }; ``` ::: Trong `IDA -> View -> Open subviews -> Local types -> Insert` vào tạo struct như trên. Lưu ý, tôi đã dùng tên `NULL1, NULL2, NULL3 ,NULL4` để tránh trùng tên khi xây dựng `struct`. Hãy chắc rằng bạn `Set type` cho `_int64 a1` thành `JNINativeInterface *env`. Từ đây ta phân tích chương trình bình thường. ![image](https://hackmd.io/_uploads/rkf1Lvgia.png) Nếu số lượng tham số nhỏ hơn hoặc bằng 1, chương trình sẽ in ra một thông báo cảnh báo. Ngược lại, nếu có ít nhất một tham số truyền vào, chương trình sẽ gọi hàm `sub_1FB9()` với tham số thứ nhất của dòng lệnh. ![image](https://hackmd.io/_uploads/Hyit24Ws6.png) Tại hàm `sub_2121()` chương trình sẽ hiển thị `menu` lựa chọn: `Normal Coffee`, `Espresso`, `[REDACTED]`, `Exit`. Tất cả đều dẫn đến kết thúc chương trình ![image](https://hackmd.io/_uploads/ryrs64bop.png) Hàm bắt đầu bằng việc gọi hai hàm khác `check1` và `check2 ` để kiểm tra quyền truy cập vào cà phê. Nếu bất kỳ một trong số hàm này trả về kết quả khác không (có nghĩa là không có quyền truy cập), hàm sẽ in ra thông báo `"No coffee for you!"` và trả về 1. Nếu không có vấn đề gì với quyền truy cập, hàm sẽ in ra thông báo `"Access granted."` và tiếp tục với việc in ra danh sách cà phê có sẵn để lựa chọn. Sau khi in ra danh sách cà phê, hàm sẽ in ra thông báo `"Enjoy!"` và `flag`. ==Hàm check1():== Đầu tiên chúng ta cần vượt qua hàm `check1`. :::danger ```cpp __int64 __fastcall loadShutdownNativeFunctions(JNIEnv *env, __int64 a2) { __int64 ShutdownClassObject; qword_87D0 = a2; ShutdownClassObject = env->function->FindClass(env, "java/lang/Shutdown"); return env->function->RegisterNatives(env,v3,halt0,2LL); } ``` ::: Tại hàm `loadShutdownNativeFunctions`, nó gọi `RegisterNatives ` - cho phép ta thay đổi hàm tại `halt0` và `runAllFinalizers`. Giải thích sơ qua về hai hàm. * `halt0:` thường được gọi sau khi hàm `System.exit(status_code)` được thực thi trong chương trình Java. Hàm này sẽ kết thúc `Java Virtual Machine`. Tuy nhiên, hàm `register_shutdown` sẽ chặn `hàm halt0` và chuyển hướng nó đến hàm được trỏ bởi con trỏ `on_halt`. Điều này cho phép bạn thực hiện các hành động tùy chỉnh `trước khi JVM kết thúc hoàn toàn`. * `runAllFinalizers:` thường chạy tất cả các `finalizer` đã `đăng ký trước khi JVM kết thúc`. Finalizer là một phương thức được gọi tự động khi đối tượng không còn được tham chiếu bởi bất kỳ biến nào. Finalizer thường được sử dụng để giải phóng tài nguyên được cấp phát bởi đối tượng. Họ đã không đề cập gì về nó, nên không có thay đổi gì. :::danger ```cpp __int64 __fastcall set_bytes_to_var_in_jvm(JNIEnv *env, __int64 mangJNI1) { ByteClassObject = env->function->FindClass(env, "java/lang/Byte"); MethodID = env->function->GetStaticMethodID(env,ByteClassObject,"valueOf","(B)Ljava/lang/Byte;"); FieldID = env->function->GetFieldID(env,ByteClassObject,"value","B"); for ( index = 0; index <= 255; ++index ) { byteObject = env->function->CallStaticObjectMethod(env, ByteClassObject, MethodID, index); env->function->SetByteField(env, byteObject, FieldID, (unsigned int)*(mangJNI1 + index); } return byteObject; } ``` ::: Thực hiện đặt các `byte` từ `mangJNI1` vào một biến trong môi trường JVM :::danger ```cpp __int64 __fastcall set_short_to_var_in_jvm(JNIEnv *env, __int64 mangJNI2) { ShortClassObject = env->function->FindClass(env, "java/lang/Short"); MethodID = env->function->GetStaticMethodID(env,ShortClassObject,"valueOf","(S)Ljava/lang/Short); FieldID = env->function->GetFieldID(env,ShortClassObject,"value","S"); for ( index = 0; index <= 255; ++index ) { shortObject = env->function->CallStaticObjectMethod(env, ShortClassObject, MethodID, index); env->function->SetShortField(env,v8,FieldID,(unsigned int)*(mangJNI2 +index)); } return shortObject; } ``` ::: Thực hiện đặt các `short (2 byte)` từ `mangJNI2` vào một biến trong môi trường JVM :::danger ```cpp __int64 __fastcall check1(JNIEnv *env, __int64 password){ // trả về hàm halt được lưu trong code dạng biến toàn cục loadShutdownNativeFunctions(env, (__int64)on_halt); // trỏ tới các mảng byte và short sẽ truyền cho biến của JVM - dùng để ánh xạ array1 = return_array_for_mapping(1); set_bytes_to_var_in_jvm(env, array1); array2 = return_array_for_mapping(2); set_short_to_var_in_jvm(env, array2); // tạo Java Class Object BufferContainClassData = get_verify_class(0, 0xCAFEBABE); Verify1ClassObject = env->function->DefineClass(env, "Verify1", 0LL, BufferContainClassData, 0XCAFEBABE); // tạo mảng cho vùng nhớ unk_3140 để lưu các mảng, nó là Java Array Object NewArrayObject = env->function->NewObjectArray; javaStringObject = env->function->NewStringUTF(env, &unk_3140); // tạo 2 Array Object để lưu trữ Password và Check_password_byte javaStringClass = env->function->FindClass(env, "java/lang/String"); stringArrayObject = NewArrayObject(env, 2LL, javaStringClass, javaStringObject); // tạo Java Array Object từ Password NewPasswordStringObject = env->function->NewStringUTF(env, password); PasswordStringObjectClass = env->function->GetObjectClass(env,NewPasswordStringObject); // nhận ID của phương thức Substring SubstringMethod = env->function->GetMethodID(env,PasswordStringObjectClass,"substring","(II)Ljava/lang/String;"); // Lấy giá trị Password từ 0->0x1A (vẫn là Array Object) SetObjectArrayElement = env->function->_SetObjectArrayElement; PasswordSubstring = env->function->CallObjectMethod)(env,NewPasswordStringObject,SubstringMethod,0LL,0x1A); SetObjectArrayElement(env, stringArrayObject, 0LL, PasswordSubstring); // Lấy mảng byte để kiểm tra mật khẩu (vẫn là Array Object) _SetObjectArrayElement = env->function->_SetObjectArrayElement; NewString = env->function->NewStringUTF(env, &check_password_byte); _SetObjectArrayElement(env, stringArrayObject, 1LL, NewString); // nhận ID của phương thức main() và thực hiện gọi (verify1.class,main(),password,unknown_byte) MethodString = env->function->GetStaticMethodID(env,Verify1ClassObject,"main","([Ljava/lang/String;)V"); env->function->CallStaticVoidMethod(env,Verify1ClassObject,MethodString,stringArrayObject); // trả về ánh xạ bình thường v11 = return_array_for_mapping(0); set_bytes_to_var_in_jvm(env, (__int64)v11); v12 = return_array_for_mapping(0); set_short_to_var_in_jvm(env, (__int64)v12); return (unsigned int)dword_87F4; } ``` ::: Hãy đọc mô tả hoạt động của hàm `check1()` ở trong phần mô ta code ở trên, tôi đã comment khá kĩ. `Binwalk` là một công cụ mạnh mẽ và linh hoạt cho phép bạn phân tích, trích xuất và khám phá nội dung ẩn trong các file binary. Ta dùng `binwalk` để lấy các file ẩn, với câu lệnh: `binwalk -D='.*' ./coffee_invocation`. Sau khi trích xuất được, ta dùng http://www.javadecompilers.com/ để decompile chương trình. Tôi dùng `Bytecode Viewer` để xem thêm thông tin về `Bytecode Disassembler` :::info ```javascript public class Verify1 { private static boolean compareByte(Byte var0, Short var1) { return var0 == var1; } public static void main(String[] var0) { if (var0 != null && var0.length == 2) { String var1 = var0[0]; String var2 = var0[1]; if (var1 != null && var2 != null) { if (var1.length() != var2.length()) { System.out.println("Source and Target don't have the same length"); System.exit(2); } else { System.out.println("Verifying user is of terrestrial origin..."); for(int var3 = 0; var3 < var1.length(); ++var3) { if (!compareByte((byte)var1.charAt(var3), (short)((byte)var2.charAt(var3)))) { System.out.println("=> User might be an alien!!!"); System.exit(3); return; } } } } else { System.out.println("Source and Target may not be null"); System.exit(2); } } else { System.out.println("Verifying requires source and target"); System.exit(1); } } } ``` ::: Trong lớp `Verify1`, thực hiện kiểm tra hai chuỗi. Nó so sánh từng ký tự của hai chuỗi và in ra một thông báo nếu chúng không giống nhau. Nếu một trong hai chuỗi là `null` hoặc nếu `chiều dài của chúng không giống nhau`, nó cũng in ra một thông báo tương ứng. Như ta đã phân tích ở trên, hai chuỗi đó chính là `password` và `check_password_byte`. Ta viết chương trình đề tìm ra nửa đầu của `flag`. Chú ý: `bytes != Bytes và short != Short` :::info ``` bytes_mapping = [0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] short_mapping = [0x00, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, 0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0, 0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0, 0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8, 0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0, 0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8, 0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0, 0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] cipher = [0x7E, 0x50, 0x4C, 0x7B, 0x41, 0x3B, 0x50, 0x4C, 0x7B, 0x3F, 0x3B, 0x3A, 0x3D, 0x7C, 0x50, 0x49, 0x43, 0x7B, 0x48, 0x7A, 0x50, 0x3A, 0x41, 0x3B, 0x7E, 0x78] stage1 = ''.join(chr(short_mapping[bytes_mapping[(value)]]) for value in cipher) print(stage1) # stage1 = 1_c4nt_c4ptur3_fl4g5_unt17 ``` ::: Sau khi `lớp Verify1` được thực thi, ánh xạ của Byte và Short được trả về ánh xạ bình thường của chúng. ==Hàm check2():== Ta phân tích hàm `check2()`, nó cũng gần tương tự như hàm `check1()`, nó có hơi phức tạp hơn một chút. :::danger ```cpp __int64 __fastcall SetBooleanField(JNIEnv *env) { ByteClassObject = env->function->FindClass(env, "java/lang/Boolean"); FalseMethodID = env->function->GetStaticMethodID(env,ByteClassObject,"FALSE","Ljava/lang/Boolean;"); TrueMethodID = env->function->GetStaticMethodID(env,ByteClassObject,"TRUE","Ljava/lang/Boolean;"); False_MethodID = env->function->GetStaticMethodID(env,ByteClassObject,TrueMethodID); True_MethodID = env->function->GetStaticMethodID(env,ByteClassObject,FalseMethodID); env->function->SetStaticObjectField(env,ByteClassObject,FalseMethodID,True_MethodID); env->function->SetStaticObjectField(env,ByteClassObject,TrueMethodID,False_MethodID); } Thực hiện đặt các byte từ mangJNI1 vào một biến trong môi trường JVM ``` ::: Nó cũng hoán đổi ý nghĩa của `True và False`, do đó `True trở thành False và False trở thành True`. ![image](https://hackmd.io/_uploads/r1tREeYoT.png) Tại hàm `loadShutdownNativeFunctions`, `halt0` ánh xạ tới hàm `sub_190F()`, thay vì thay đổi giá trị `Byte và Short`, nó thay đổi giá trị của `Characters`. Điều này có thể được thực hiện lên đến 13 lần. :::danger ```cpp __int64 __fastcall check2(JNIEnv *env, __int64 password){ // trả về hàm sub_190F() loadShutdownNativeFunctions(env, sub_190F); // trỏ tới các mảng character sẽ truyền cho biến của JVM - dùng để ánh xạ array3 = return_array_for_mapping(3); copy_ascii_table(env,array3) SetBooleanField(env); // tạo Java Class Object BufferContainClassData = get_verify_class(0, 0xCAFEBABE); Verify2ClassObject = env->function->DefineClass(env, "Verify2", 0LL, BufferContainClassData, 0XCAFEBABE); // tạo mảng cho vùng nhớ unk_3140 để lưu các mảng, nó là Java Array Object NewArrayObject = env->function->NewObjectArray; javaStringObject = env->function->NewStringUTF(env, &unk_3140); // tạo 1 Array Object để lưu trữ Password và Check_password_byte javaStringClass = env->function->FindClass(env, "java/lang/String"); stringArrayObject = NewArrayObject(env, 1LL, javaStringClass, javaStringObject); // tạo Java Array Object từ Password NewPasswordStringObject = env->function->NewStringUTF(env, password); PasswordStringObjectClass = env->function->GetObjectClass(env,NewPasswordStringObject); // nhận ID của phương thức Substring SubstringMethod = env->function->GetMethodID(env,PasswordStringObjectClass,"substring","(II)Ljava/lang/String;"); // Lấy giá trị Password từ 0x1A->0x1A*2 (vẫn là Array Object) SetObjectArrayElement = env->function->_SetObjectArrayElement; PasswordSubstring = env->function->CallObjectMethod)(env,NewPasswordStringObject,SubstringMethod,0x1A,0x1A+0x1A); SetObjectArrayElement(env, stringArrayObject, 0LL, PasswordSubstring); // nhận ID của phương thức main() và thực hiện gọi (verify1.class,main(),password) MethodString = env->function->GetStaticMethodID(env,Verify1ClassObject,"main","([Ljava/lang/String;)V"); env->function->CallStaticVoidMethod(env,Verify1ClassObject,MethodString,stringArrayObject); // trả về ánh xạ bình thường SetBooleanField(env); return (unsigned int)dword_87F4; } ``` ::: Hãy đọc mô tả hoạt động của hàm `check2()` ở trong phần mô ta code ở trên, tôi đã comment khá kĩ. :::info ```java import java.io.PrintStream; import java.util.Arrays; import java.util.stream.Collectors; public class Verify2 { private static boolean compareByte(Byte var0, Short var1) { PrintStream var10000 = System.out; byte var10001 = var0; var10000.println(var10001 + " == " + var1); return var0 == var1; } private static String complexSort(String var0, Boolean var1) { Object[] var2 = var0.chars().mapToObj((var0x) -> { return (char)var0x; }).toArray(); if (var1) { Arrays.sort(var2); } String var3 = (String)Arrays.stream(var2).map(Object::toString).collect(Collectors.joining()); return var3; } private static Boolean verifyPassword(String var0, String var1) { return var0.equals(var1); } public static void main(String[] var0) { if (var0 != null && var0.length == 1) { String var1 = var0[0]; if (var1 == null) { System.out.println("Source may not be null"); System.exit(1); } else if (var1.length() % 2 != 0) { System.out.println("Length must be even"); System.exit(1); } else { System.out.println("Verifying user has authorization..."); for(int var2 = 0; var2 < var1.length() / 2; ++var2) { String var3 = var1.substring(var2 * 2, var2 * 2 + 2); String var4 = complexSort(var3, true); String var5 = complexSort("Cr1KD5mk0_uUzQYifaGVqlN2B3wvpgPtSx6Odo{8hjJLHy9IXb4RnWZ}TAFEsMce7", false); if (var4.equals(var5.substring(var2 * 2, var2 * 2 + 2))) { System.exit(var2 + 3); } } if (!verifyPassword(var1, "Tinfoil")) { System.out.println("Please enter the correct password"); System.exit(2); } } } else { System.out.println("Verifying requires source"); System.exit(1); } } } ``` ::: Có thể thấy, có một vài `Boolean` được hoán đổi, `System.exit(i+3)` sẽ hoán đổi các bảng giá trị ở mỗi lần lặp của vòng lặp, v.v. Điều này có nghĩa là cứ sau 2 lần lặp lại các ký tự sẽ cần một bảng thay thế khác được lưu trữ trong tệp. Ta viết chương trình đề tìm ra nửa sau của `flag`. :::info ``` mapping = [ [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x69,0x31,0x6C,0x64,0x5F,0x4E,0x34,0x61,0x6B,0x50,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x53,0x4F,0x65,0x71,0x41,0x76,0x46,0x32,0x52,0x43,0x4D,0x38,0x55,0x45,0x75,0x68,0x57,0x72,0x73,0x54,0x7B,0x47,0x62,0x56,0x49,0x7D,0x5B,0x5C,0x5D,0x5E,0x30,0x60,0x42,0x4B,0x67,0x63,0x6E,0x77,0x5A,0x4C,0x79,0x37,0x33,0x36,0x48,0x6A,0x6F,0x44,0x51,0x35,0x66,0x78,0x6D,0x74,0x7A,0x58,0x4A,0x70,0x59,0x7C,0x39,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x34,0x6F,0x4B,0x33,0x68,0x59,0x37,0x47,0x7A,0x4E,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x6E,0x45,0x51,0x7D,0x62,0x77,0x49,0x4A,0x38,0x57,0x79,0x67,0x35,0x74,0x78,0x58,0x56,0x66,0x71,0x65,0x54,0x73,0x6C,0x7B,0x43,0x76,0x5B,0x5C,0x5D,0x5E,0x36,0x60,0x75,0x69,0x6D,0x53,0x5F,0x63,0x6A,0x4F,0x6B,0x30,0x48,0x70,0x5A,0x52,0x4D,0x39,0x50,0x55,0x46,0x4C,0x31,0x32,0x64,0x42,0x41,0x72,0x61,0x7C,0x44,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x7D,0x46,0x6D,0x6E,0x72,0x64,0x54,0x37,0x75,0x5F,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x4A,0x41,0x70,0x66,0x30,0x68,0x50,0x43,0x57,0x39,0x69,0x65,0x4C,0x4B,0x71,0x53,0x47,0x55,0x62,0x42,0x49,0x67,0x6B,0x56,0x74,0x78,0x5B,0x5C,0x5D,0x5E,0x34,0x60,0x77,0x4F,0x38,0x7B,0x52,0x36,0x44,0x35,0x59,0x6F,0x61,0x76,0x73,0x45,0x33,0x31,0x51,0x58,0x63,0x6C,0x48,0x7A,0x4D,0x5A,0x32,0x4E,0x79,0x7C,0x6A,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x34,0x6C,0x32,0x5F,0x36,0x79,0x39,0x70,0x6F,0x74,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x50,0x4D,0x61,0x69,0x4F,0x67,0x68,0x51,0x75,0x63,0x58,0x72,0x7D,0x64,0x4C,0x57,0x5A,0x48,0x4E,0x31,0x77,0x42,0x71,0x49,0x53,0x6E,0x5B,0x5C,0x5D,0x5E,0x6D,0x60,0x30,0x54,0x59,0x37,0x35,0x6B,0x44,0x55,0x52,0x43,0x7B,0x66,0x33,0x7A,0x46,0x4B,0x4A,0x41,0x78,0x62,0x45,0x73,0x47,0x76,0x38,0x6A,0x65,0x7C,0x56,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x7B,0x79,0x70,0x6B,0x75,0x65,0x71,0x56,0x61,0x51,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x64,0x66,0x4E,0x74,0x58,0x48,0x47,0x42,0x4A,0x73,0x44,0x4C,0x36,0x7D,0x54,0x77,0x76,0x7A,0x4D,0x78,0x45,0x6D,0x59,0x62,0x67,0x50,0x5B,0x5C,0x5D,0x5E,0x38,0x60,0x39,0x5A,0x31,0x41,0x6F,0x37,0x46,0x35,0x49,0x72,0x69,0x43,0x33,0x57,0x32,0x6C,0x52,0x63,0x4B,0x55,0x68,0x34,0x53,0x30,0x6E,0x4F,0x5F,0x7C,0x6A,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x62,0x41,0x46,0x7A,0x56,0x58,0x4A,0x44,0x77,0x64,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x51,0x30,0x31,0x76,0x63,0x79,0x37,0x7D,0x72,0x59,0x61,0x45,0x32,0x4C,0x71,0x7B,0x54,0x35,0x69,0x6B,0x48,0x6C,0x75,0x5A,0x55,0x52,0x5B,0x5C,0x5D,0x5E,0x57,0x60,0x66,0x4B,0x4E,0x65,0x49,0x6E,0x74,0x67,0x38,0x5F,0x78,0x42,0x43,0x4F,0x36,0x53,0x50,0x34,0x70,0x33,0x6D,0x6F,0x39,0x6A,0x4D,0x68,0x47,0x7C,0x73,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x59,0x52,0x68,0x76,0x6E,0x7B,0x65,0x6A,0x5A,0x6D,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x45,0x31,0x79,0x7D,0x38,0x42,0x61,0x78,0x7A,0x63,0x6F,0x30,0x4D,0x57,0x41,0x50,0x39,0x67,0x64,0x4A,0x4C,0x56,0x58,0x4B,0x75,0x46,0x5B,0x5C,0x5D,0x5E,0x43,0x60,0x6B,0x6C,0x55,0x33,0x5F,0x71,0x47,0x4E,0x73,0x72,0x4F,0x32,0x44,0x49,0x74,0x54,0x70,0x34,0x77,0x66,0x35,0x69,0x51,0x53,0x62,0x36,0x37,0x7C,0x48,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x56,0x30,0x6F,0x78,0x64,0x4A,0x38,0x32,0x42,0x4D,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x75,0x62,0x7B,0x37,0x7D,0x7A,0x43,0x49,0x6E,0x53,0x50,0x5F,0x69,0x54,0x6D,0x72,0x65,0x6A,0x48,0x4F,0x58,0x41,0x6B,0x66,0x79,0x71,0x5B,0x5C,0x5D,0x5E,0x46,0x60,0x70,0x59,0x77,0x39,0x67,0x4C,0x35,0x68,0x52,0x33,0x47,0x55,0x36,0x5A,0x74,0x73,0x76,0x6C,0x51,0x4E,0x63,0x31,0x44,0x34,0x45,0x4B,0x61,0x7C,0x57,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x47,0x70,0x42,0x6C,0x30,0x71,0x4B,0x6F,0x59,0x62,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x34,0x4A,0x66,0x75,0x41,0x39,0x61,0x53,0x46,0x52,0x43,0x4D,0x79,0x73,0x49,0x38,0x54,0x50,0x55,0x65,0x57,0x7B,0x58,0x6A,0x32,0x56,0x5B,0x5C,0x5D,0x5E,0x7D,0x60,0x7A,0x36,0x68,0x69,0x76,0x31,0x4C,0x5F,0x6B,0x77,0x4F,0x37,0x78,0x6E,0x74,0x67,0x72,0x35,0x64,0x44,0x33,0x6D,0x63,0x48,0x4E,0x51,0x5A,0x7C,0x45,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x71,0x39,0x66,0x41,0x7A,0x62,0x76,0x30,0x4F,0x67,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x4A,0x55,0x49,0x38,0x59,0x51,0x61,0x69,0x45,0x6E,0x75,0x7B,0x47,0x68,0x33,0x34,0x58,0x54,0x5A,0x37,0x5F,0x44,0x74,0x50,0x4E,0x79,0x5B,0x5C,0x5D,0x5E,0x57,0x60,0x4D,0x35,0x77,0x6B,0x64,0x46,0x4C,0x36,0x42,0x56,0x31,0x52,0x6D,0x53,0x4B,0x70,0x48,0x73,0x7D,0x43,0x6C,0x65,0x32,0x6A,0x78,0x6F,0x63,0x7C,0x72,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x75,0x4E,0x72,0x42,0x74,0x44,0x45,0x63,0x4D,0x53,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x43,0x51,0x50,0x30,0x4C,0x4B,0x68,0x5F,0x67,0x33,0x32,0x66,0x70,0x52,0x7A,0x6A,0x76,0x47,0x4A,0x49,0x77,0x6E,0x64,0x7D,0x61,0x41,0x5B,0x5C,0x5D,0x5E,0x5A,0x60,0x46,0x73,0x7B,0x38,0x39,0x54,0x34,0x35,0x55,0x79,0x58,0x6C,0x62,0x71,0x69,0x48,0x36,0x4F,0x6D,0x6B,0x56,0x57,0x78,0x31,0x59,0x6F,0x65,0x7C,0x37,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x36,0x56,0x4B,0x4C,0x31,0x6F,0x47,0x7D,0x54,0x48,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x4E,0x4D,0x51,0x52,0x42,0x77,0x59,0x38,0x7B,0x32,0x41,0x74,0x57,0x6E,0x50,0x30,0x4A,0x79,0x46,0x58,0x6C,0x44,0x72,0x5F,0x43,0x6B,0x5B,0x5C,0x5D,0x5E,0x37,0x60,0x76,0x69,0x4F,0x6A,0x35,0x66,0x55,0x63,0x33,0x65,0x73,0x5A,0x67,0x7A,0x71,0x61,0x75,0x68,0x70,0x78,0x49,0x45,0x6D,0x39,0x64,0x53,0x62,0x7C,0x34,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], [0x00,0x01,0x02,0x03,0x04,0x0c5,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x36,0x39,0x71,0x57,0x6F,0x38,0x4C,0x4A,0x51,0x56,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x7A,0x4F,0x48,0x4D,0x50,0x5A,0x68,0x75,0x58,0x73,0x55,0x49,0x4E,0x44,0x78,0x72,0x6B,0x63,0x4B,0x67,0x35,0x43,0x6E,0x62,0x70,0x74,0x5B,0x5C,0x5D,0x5E,0x66,0x60,0x64,0x30,0x77,0x46,0x34,0x41,0x32,0x45,0x6C,0x47,0x54,0x7D,0x61,0x65,0x33,0x6A,0x31,0x69,0x53,0x59,0x37,0x5F,0x52,0x42,0x76,0x7B,0x6D,0x7C,0x79,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] ] comparingstr = b'Cr1KD5mk0_uUzQYifaGVqlN2B3wvpgPtSx6Odo{8hjJLHy9IXb4RnWZ}TAFEsMce7' def complexSort(s, mapping): mapped_chars = [mapping[c] for c in s] sorted_chars = sorted(mapped_chars) return sorted_chars stage2 = "" for i in range(13): secret = complexSort(comparingstr, mapping[i]) stage2 += chr(mapping[i].index(secret[i*2])) + chr(mapping[i].index(secret[i*2+1])) print(stage2) # stage2 = _1v3_h4d_a1l_my_0xCAFEBABE ``` ::: Tiến hành nhập `flag` ta vừa tìm được. ![image](https://hackmd.io/_uploads/Sk1psV7ja.png) :::success ``` Flag: HTB{1_c4nt_c4ptur3_fl4g5_unt17_1v3_h4d_a1l_my_0xCAFEBABE} ``` ::: <div id="FFModule"></div> <h3>Challenge 16: FFModule</h3> After more and more recent hits of the infamous Jupiter Banking Malware we finally managed to get a sample of one module. Supposedly it steals secrets from Firefox users? <a href="https://drive.google.com/file/d/1sAdBv-pOBSKuXtDWH7HRo5li2GLmVSdw/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp. ![image](https://hackmd.io/_uploads/SJuvyZto6.png) Mở chương trình trong IDA. ![image](https://hackmd.io/_uploads/BJjCxWFjT.png) Khả năng cao chương trình sẽ `hook module` của Firefox. Vì vậy mình đã cài Firefox cho máy tính. Ta có thể quan sát hàm `sub_140001000`. ![image](https://hackmd.io/_uploads/B1_iwZtjp.png) Sử dụng hàm `CreateToolhelp32Snapshot` để tạo ảnh chụp nhanh của các tiến trình đang chạy. Lặp qua danh sách các tiến trình và tìm tiến trình `firefox.exe`. Hàm `CreateRemoteThread` khiến một luồng thực thi mới bắt đầu trong không gian địa chỉ của quy trình đã chỉ định. `Thread` có quyền truy cập vào tất cả các đối tượng mà tiến trình mở ra => khả năng cao nó sẽ `injected Firefox process`. Các chương trình mã độc sẽ sử dụng CreateRemoteThread API để có thể chạy mã lệnh trên một tiến trình khác. Ta so sánh giữa `CreateThread` và `CreateRemoteThread` :::info ```c HANDLE CreateThread( [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes, [in] SIZE_T dwStackSize, [in] LPTHREAD_START_ROUTINE lpStartAddress, [in, optional] __drv_aliasesMem LPVOID lpParameter, [in] DWORD dwCreationFlags, [out, optional] LPDWORD lpThreadId ); ``` ::: :::info ```c HANDLE CreateRemoteThread( [in] HANDLE hProcess, [in] LPSECURITY_ATTRIBUTES lpThreadAttributes, [in] SIZE_T dwStackSize, [in] LPTHREAD_START_ROUTINE lpStartAddress, [in] LPVOID lpParameter, [in] DWORD dwCreationFlags, [out] LPDWORD lpThreadId ); ``` ::: Cả hai API đều khá giống nhau, tuy nhiên `CreateRemoteThread` có nhiều thuộc tính hơn. * `hProcess:` lấy handle của tiến trình mà ta sẽ thực thi lệnh * `lpStartAddress:` con trỏ tới hàm do ứng dụng xác định sẽ được luồng thực thi. Con trỏ này đại diện cho địa chỉ bắt đầu của luồng. * `lpParameter:` Một con trỏ tới một biến được truyền tới luồng. ![image](https://hackmd.io/_uploads/HyiiLDnnT.png) Cách thức hoạt động: đầu tiên, `Injector Process` sẽ tạo nhớ trong không gian địa chỉ ảo và ghi `DLL file path` lên vùng nhớ đó. Sau đó, `CreateRemoteThread` sẽ gọi `LoadLibrary API` (hàm này sẽ cần path của các thư viện API). Khi ta tạo thread trong `Target Pcocess` - thread này sẽ trỏ đến `LoadLibrary` và load DLL mà ta đã ghi path vào vùng nhớ ở trên => `injected DLL` Ta viết đoạn mã IDAPython để `XOR` vùng nhớ `sub_140017000 và 0x72`. Từ đó ta có thể quan sát hàm `sub_140017005` chính xác hơn. :::info ```python import ida_bytes start = 0x140017000 for i in range(0x5A4): byte = ida_bytes.get_byte(start+i) ida_bytes.patch_byte(start+i,byte^0x72) ``` ::: ![image](https://hackmd.io/_uploads/BJ17aWFia.png) Hàm lấy con trỏ đến danh sách liên kết các module. `NtCurrentTeb()` trả về con trỏ đến cấu trúc `Thread Environment Block`, từ đó chúng ta truy cập thông tin về tiến trình thông qua `ProcessEnvironmentBlock` và danh sách liên kết các module bởi `Ldr->InMemoryOrderModuleList`. Tính mã CRC32 của module và so sánh để load module cần dùng Một kĩ thuật hay hơn mình học được từ bạn `kvn11` là mình có thể viết đoạn mã để tạo danh sách các module và tính CRC32. Ta sẽ chạy đoạn mã python để tạo danh sách các module, sau đó đưa danh sách ấy vào mảng name trong đoạn mã C :::info ```python import requests from bs4 import BeautifulSoup URL = "https://www.geoffchappell.com/studies/windows/win32/kernel32/api/" resp = requests.get(URL) h = resp.text soup = BeautifulSoup(h, 'html.parser') fns = [tag.text for tag in soup.find_all('span', class_='function')] print(fns) ``` ::: :::info ```cpp // g++ -o api api.cpp -msse4.2 #include <immintrin.h> #include <iostream> #include <cstring> unsigned int custom_crc32_u8(const char* data, size_t length, unsigned int crc) { for (size_t i = 0; i < length; i++) { crc = _mm_crc32_u8(crc, data[i]); } return crc; } int main() { const char* names[] = { "functionNames", }; unsigned int initial_value = 0xFFFFFFFF; for (const char* name : names) { unsigned int crc = custom_crc32_u8(name, strlen(name), initial_value); if ( ~crc == 0x43AAC47D) { std::cout << "~CRC-32 for '" << name << "': 0x" << std::hex << crc << std::dec << std::endl; break; } } return 0; } ``` ::: Ta tính được mã CRC32 là của hàm `GetProcessAddress()`. Chương trình lưu GetProcessAddress() vào r12 và sẽ thực hiện gọi nhiều lần. Ta tiếp tục quan sát `hàm sub_14001742D()`, chương trình tiếp tục tính mã CRC32 của các module (ở đây là các *.dll). ![image](https://hackmd.io/_uploads/rkPNrKSRa.png) Ta chạy đoạn mã python để tạo danh sách các module, sau đó đưa danh sách ấy vào mảng name trong đoạn mã C. :::info ```python import requests from bs4 import BeautifulSoup from concurrent.futures import ThreadPoolExecutor URL = "https://wikidll.com/{}-list?page=" def get_dll_links(char): dll_links = [] url = URL.format(chr(char)) for i in range(10): temp_url = url + str(i) resp = requests.get(temp_url) html_content = resp.text soup = BeautifulSoup(html_content, 'html.parser') dll_links += [tag.text for tag in soup.find_all('a') if '.dll' in tag.text] return dll_links with ThreadPoolExecutor() as executor: results = executor.map(get_dll_links, range(0x61, 0x7b)) dll_links = [] for result in results: dll_links.extend(result) print(dll_links) ``` ::: :::info ```cpp! // g++ -o api api.cpp -msse4.2 #include <immintrin.h> #include <iostream> #include <cstring> unsigned int custom_crc32_u8(const char* data, size_t length, unsigned int crc) { for (size_t i = 0; i < length; i++) { crc = _mm_crc32_u8(crc, data[i]); } return crc; } int main() { const char* names[] = { "NSS3.DLL","NSS3.dll","nss3.dll" }; unsigned int initial_value = 0xFFFFFFFF; for (const char* name : names) { unsigned int crc = custom_crc32_u8(name, strlen(name), initial_value); // if ( ~crc == 0x8861D80B || ~crc == 0x3DCE28A2 || ~crc == 0x83BCBE6A) { if ( ~crc == 0x43AAC47D || ~crc == 0x8861D80B || ~crc == 0x3DCE28A2 || ~crc == 0x83BCBE6A) { std::cout << "CRC-32 for " << name << ": 0x" << std::hex << crc << std::dec << std::endl; std::cout << "~CRC-32 for " << name << ": 0x" << std::hex << ~crc << std::dec << std::endl; // break; } } return 0; } ``` ::: Sau khi đưa danh sách các DLL và tính toán, ta biết được kết ứng với `nss3.dll` và là kết quả duy nhất. Mình dự đoán chương trình sẽ chỉ gọi bản sao tên của `nss3.dll` nên đã thử và tìm được: * `0x3DCE28A2` ứng với `NSS3.dll` * `0x8861d80b` ứng với `nss3.dll` * `0x83bcbe6a` ứng với `NSS3.DLL` Sau khi có địa chỉ bắt đầu của thư viện đó, Firefox sẽ lấy địa chỉ của hàm `PR_Write` trong Firefox's NSPR - được sử dụng để ghi dữ liệu vào một tệp hoặc socket. Hàm này trả về số byte đã được ghi thành công hoặc -1 nếu có lỗi xảy ra. :::info ```python PRInt32 PR_Write( PRFileDesc *fd, const void *buf, PRInt32 amount); ``` ::: Tại hàm`sub_1400174B7()`, chương trình thực hiện sao chép từ `PR_Write` sẽ được sao chép lên vùng nhớ của tiến trình. ![image](https://hackmd.io/_uploads/S1GNcYrAp.png) Sau đó chương trình kiểm tra giá trị của `RBX` liệu có nhỏ hơn 4 và giá trị tại `RDX` có phải là `STOP` không. Ta có thể bỏ qua bước kiểm tra bằng cách thay RIP hiện tại. Để bắt đầu sử dụng API Windows Sockets (ws2_32.dll), chương trình khởi tạo việc sử dụng WS2_32.DLL bằng lệnh gọi tới WSAStartup. Hàm này phải là hàm Windows Sockets đầu tiên được gọi bởi một ứng dụng hoặc DLL, cho biết phiên bản đặc tả Windows Sockets mà ứng dụng hoặc DLL mong muốn sử dụng và bắt đầu sử dụng WS2_32.DLL. Chương trình gọi `socket(2, 2, 17)` để tạo một socket với các tham số cụ thể: Số đầu tiên 2 đại diện cho loại địa chỉ (AF_INET cho IPv4), số thứ hai 2 chỉ loại socket (SOCK_DGRAM cho gói tin datagram), và 17 chỉ định giao thức (IPPROTO_UDP cho giao thức UDP). Lệnh này sẽ tạo một socket UDP để giao tiếp qua IPv4. Chương trình lấy địa chỉ của hàm `sendto`. Tiếp đó, chương trình tiến hành giải mã các byte và gửi dữ liệu đến một đích cụ thể. ![image](https://hackmd.io/_uploads/ryJjCFrAa.png) Sau khi thực hiện xong, chương trình gọi `closesocket` để đóng socket hiện có. Từ đây, ta có thể viết đoạn mã để giải mã các byte được gửi đó. :::info ```python encoded_message = [0x54, 0xD5, 0x13, 0x3A, 0x41, 0x99, 0xD4, 0xB6, 0x93, 0x74, 0x19, 0x41, 0x97, 0x61, 0x5A, 0xB6, 0x54, 0x61, 0x61, 0x38, 0x81, 0x98, 0xB7, 0xB6, 0xF4, 0xE1, 0xD8, 0xB9, 0x77, 0x19, 0xF7, 0xFA] def rotate_left(data, shift, size=8): return ((data << shift) | (data >> (size - shift))) & ((1 << size) - 1) flag = ''.join(chr(rotate_left((byte + 0xED) & 0xFF, 3) ^ 0x42) for byte in encoded_message) ``` ::: :::success ``` Flag: HTB{3vL_FIr3f0x_H00k1ng_M4lware} ``` ::: <div id="SEPC"></div> <h3>Challenge 17: SEPC</h3> We've extracted an embedded operating system running on an intercepted deep-space satellitle launched by Arodor. If we can breach the secure enclave and extract their security mechanisms, we can crack their encrypted communications <a href="https://drive.google.com/file/d/1I1cts3CpbGq6W10t9YyzscZI3rgt3uAA/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp. ![image](https://hackmd.io/_uploads/rJdlJpq3p.png) Ta được cung cấp các tệp tin sau: * `bzImage` là kernel Linux image, được sử dụng để khởi động hệ điều hành. * `initramfs.cpio.gz` là hệ thống tập tin ban đầu được nén, chứa các công cụ và tập tin cần thiết để khởi động hệ thống. * `run.sh` là tập tin script bash, chứa các lệnh để tự động hóa việc khởi động hệ thống hoặc thực hiện các tác vụ khác. :::danger ``` qemu-system-x86_64 \ -kernel bzImage \ -initrd initramfs.cpio.gz \ --append "console=ttyS0" \ -nographic `# qemu-system-x86_64` lệnh QEMU để mô phỏng hệ thống 64-bit. `# `-kernel bzImage` là compressed Linux kernel, được sử dụng để khởi động hệ điều hành `# `-initrd initramfs.cpio.gz` là filesystem được tạo trong bộ nhớ RAM trong quá trình khởi động ban đầu mà QEMU sẽ sử dụng. `# `--append "console=ttyS0"` chỉ định các tham số được chuyển đến kernel khi nó được khởi động. Khi kernel được yêu cầu sử dụng console trên cổng serial ttyS0. `# `-nographic`: QEMU không sử dụng giao diện đồ họa. Nó sẽ xuất ra thông tin ra terminal. ``` ::: Ta biết được đây là thử thách kiểu `kernel exploitation`. Đây là lần đầu tiên mình làm dạng bài này nên gặp nhiều khó khăn. Ta tiến hành giải nén bằng lệnh `gunzip -c initramfs.cpio.gz > initramfs.cpio`. Tệp `initramfs.cpio` là một tập tin nén được sử dụng trong quá trình khởi động của hệ điều hành Linux. Nó chứa một hệ thống tệp cơ bản được giải nén vào bộ nhớ RAM trong quá trình khởi động ban đầu. Tệp này bao gồm các chương trình và thư viện cần thiết để khởi động hệ điều hành và thiết lập môi trường người dùng. Ta tiếp tục giải nén tệp `initramfs.cpio` bằng lệnh `cpio -i -F initramfs.cpio` Trong tất cả các tệp được giải nén, chỉ có tệp `checker` và `checker.ko` là đáng chú ý. Tệp `checker.ko` là một phần của một mô-đun nhân Linux có trách nhiệm quản lý một thiết bị ký tự có tên là `checker`. Giá trị nhập vào sẽ được lưu trong biến của tệp `checker` và đưa cho tệp `checker.ko` thực hiện kiểm tra. Kết quả trả về sẽ được `check` in ra thông báo. Ta dễ dàng tìm ra hàm thực hiện kiểm tra giá trị ta nhập như sau: ![image](https://hackmd.io/_uploads/BkuEuks3a.png) Nó chỉ là một phép xor đơn giản, ta viết chương trình để tìm ra giá trị đó. :::info ```python data = [0xB4, 0xE4, 0xE9, 0xAB, 0x09, 0x36, 0x4A, 0xC2, 0xA5, 0x14, 0xE5, 0x35, 0x66, 0xC3, 0x99, 0x14, 0x5A, 0x34, 0xF1, 0x18, 0x91, 0x7D, 0x23, 0x70, 0xFA, 0xB5, 0x3D, 0xFA, 0x3D, 0xE5, 0x00, 0xD1, 0x69, 0x15, 0xF0, 0xA6, 0x83, 0x48, 0xC6, 0x30, 0x2E, 0x45, 0x29, 0x02, 0x0A, 0xA9, 0x0F, 0x38, 0x89, 0x0D, 0xAC, 0x1C, 0x89, 0x7C, 0xF4, 0xD3, 0xF0, 0x6B, 0x2F, 0x21, 0xB7, 0xD8, 0xC0, 0xFB] xor = [0xFC, 0xB0, 0xAB, 0xD0, 0x6E, 0x44, 0x2B, 0xA0, 0xC7, 0x7D, 0x8B, 0x52, 0x39, 0xA7, 0xAD, 0x60, 0x6E, 0x6B, 0x97, 0x6A, 0xA1, 0x10, 0x7C, 0x1B, 0xC9, 0xC7, 0x53, 0xC9, 0x51, 0xD0, 0x70, 0xE5, 0x0A, 0x26] flag = ''.join(chr(data[i] ^ xor[i % len(xor)]) for i in range(len(0x22))) print(flag) ``` ::: :::success ``` Flag: HTB{grabbing_d4t4_fr0m_k3rn3l5p4c3} ``` ::: <div id="Maze"></div> <h3>Challenge 18: Maze</h3> I am stuck in a maze. Can you lend me a hand to find the way out? <a href="https://drive.google.com/file/d/1NuYjt1B7Rc7uf_n02KCh88sevBBigXyD/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Ta có được ba tệp: `enc_maze.zip`, `maze.exe`, `maze.png`. Mở tệp `maze.exe` trong DIE. ![image](https://hackmd.io/_uploads/S12Kacmhp.png) Ta biết được tệp này có trình nén là `PyInstaller`. Tôi sử dụng <a href="[pyinstxtractor-ng](https://github.com/pyinstxtractor/pyinstxtractor-ng/)">pyinstxtractor-ng</a> trích các tệp được nhúng bên trong. Bạn cũng có thể dùng <a href="https://pyinstxtractor-web.netlify.app/">link</a> để thao tác trên web mà không cần tải về. ![image](https://hackmd.io/_uploads/r1GilbA36.png) Ta biết EntryPoint có khả năng là `maze.pyc` và `pyiboot01_bootstrap.pyc`. Ta sử dụng <a href="https://github.com/rocky/python-uncompyle6/">Uncompyle6</a> để decompile Python bytecode. :::info ```python # uncompyle6 .\maze.pyc > maze.py import sys, obf_path ZIPFILE = 'enc_maze.zip' print('Look who comes to me :)') print() inp = input('Now There are two paths from here. Which path will u choose? => ') if inp == 'Y0u_St1ll_1N_4_M4z3': obf_path.obfuscate_route() else: print('Unfortunately, this path leads to a dead end.') sys.exit(0) import pyzipper def decrypt(file_path, word): with pyzipper.AESZipFile(file_path, 'r', compression=(pyzipper.ZIP_LZMA), encryption=(pyzipper.WZ_AES)) as (extracted_zip): try: extracted_zip.extractall(pwd=word) except RuntimeError as ex: try: try: print(ex) finally: ex = None del ex finally: ex = None del ex decrypt(ZIPFILE, 'Y0u_Ar3_W4lkiNG_t0_Y0uR_D34TH'.encode()) with open('maze', 'rb') as (file): content = file.read() data = bytearray(content) data = [x for x in data] key = [0] * len(data) for i in range(0, len(data), 10): data[i] = (data[i] + 80) % 256 else: for i in range(0, len(data), 10): data[i] = (data[i] ^ key[i % len(key)]) % 256 else: with open('dec_maze', 'wb') as (f): for b in data: f.write(bytes([b])) ``` ::: Ta biết được mật khẩu của `enc_maze.zip` là `Y0u_Ar3_W4lkiNG_t0_Y0uR_D34TH` và chương trình có `import obf_path` nên ta cũng hãy cùng xem đoạn mã của nó. :::info ```python # uncompyle6 .\obf_path.pyc > obf_path.py def obfuscate_route(): from marshal import loads exec(loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s(\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01e\x02e\x00\xa0\x03e\x01\xa0\x03d\x02\xa1\x01\xa1\x01\x83\x01\x01\x00d\x01S\x00)\x03\xe9\x00\x00\x00\x00Ns4\x03\x00\x00\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x02\xf6x\x9c\xedV[o\xd30\x14\xfe+^_\xd6\x02+Kz\xdf\x18\x9a\xe0\x01\x8d\x07@\x82\xa7)R\xe5\xc4\'\xa9\xb7\xd4\x8elgk#~<\xc7\x8e=\xba\xb6\x13\x9ax\xe9C#\xc5\xf9\xce\xfd\xf8\xf3q\xd5\xf9\\A\x91J\xad\xe7\xf8\x1c*\xbc\xea\x1cB\x17\xff\x84\x9d\xcbC\xe8\xe2\xc8\xe6\x91\xcd}l\xc2\n\xb2n))\xd3\xdd\xb4\x93\xac`\x90\xac\xce\xcf\xff\xf3\x1do\xca\xd7\x9b\x82\xc6\n\xd3M\x05\x0bKTZt\xbb\xab\x8b\xac.z\xd2\xc5V\x17/q\x19X\x83m7\xb26\xb0\xe0\x0e\x97!ksG\xb3\x90p\x04\xad\x86\xfa\xdeh\x14,\x13\x16\xf2L-\x1aZ\xc7\xd1\xbd\xf5R\xbf 1V7JV\xd3P\xc4\x17r\xfa\xf1\xae\xde\x01,"|\x074\xda\xb6\x9f\xdf\xb5\x19]\'\xe9\x8e&\xb3\x9a\x89]\xa6>:\x0eY\xf4o_w\xf2\xfa\xba\n\xc2\x06\xa7>8\xf6\x05a\x93\x8c\xdc\xba\xe5,1\x81;/\x8b \xe3w\xb2\xa1\xc7\x1d\xbch\xc9\xb6-X j\xa9S/\x10\n\xfb66\xb0\x96|\x7f\x84\xcd\x87K\xb2\x9a\xa5~8"\xb4\xceX;\x15{#\xe2\xd7\x92\xe7\xa6\xf0\xa7E=\x0c\xc7P\x98m\xcf\xfb\xb7^\xeb\xcc\xa8=I]\x02T\x8d\xa5zI\x1b\xe8W\xa2\xb0\xc2\xa0_\xad\x9b\xb3\x9bBH\xc5EA\xcc\x02H\xa5dZ\xc2\x92<Jqj\xc8\x92\xde\x03\xe1\x860\xaeiU\x01U\x97\xcdU&E\xae\xa406\x82\nF(c\n\xb4\xb6"zr\xed\xd2\x18Uc.j\x16\xc4H\x82fY\xd6\x86K\xd1o\xbe~\xbfG\x07jN5)\xa4d$\xad\r\xb9!E\x8d\x19\x9c\x9e\xd4D/d]2"\xe4#F\x9aZ\t\x82\xf5\x96\xbe;x\xe0\xb2\xd6.\xb5\xdf[\xacR\x8e0jyl7\xcf\xaf\xedxx\xfcc\x03\xb7\x9c\x06\xb19C,\xbe \x9f\'\'d-k\x92\xb9\xca\xa03Z\x81+(\xd3\xbcF\xc9\x00s%\x91\xb4(5\x96\x14\xb3\xc0\x9dr\xcb\xd0\x9a,\xa0\xacl\xf8\x05\xf1\x07\x11o\x1eD\xe3n\xa5\xd0\x00\xac\xdb\xbc\xed%"\x97\x8ap\xc2\x05QT\x14\xd0\x1d\xe0!^$\x82\xe0\x83\n\xc6\x85\xe9\x0e\xe2wQ<B\xd7\xe6\xfd\' \x9f\xa9\x82\xbc.O\xf0q=)Y\x1bh9Y\x80\x02K\xb9\x90\x86h\x9aC\xbf\xd7N[K\x8c\xd4\x1e\r\xf4:\xc0\xa1\xe1KP\xdb=\x06#U\xc5C\xc0\x1b\x14\x8f\x0b0\xd9#\xb3\x97%\xcaj\xa5@\x989\xe3\n2#\xd5\xfa6\x11\\0X\xcds^B\x98\xb7\n\x07\xca\x84L\xb0\xe2\x01\x8f\x11k\xf3\xd4\xcc\x9d\xe4"`Y\xc1\x13V@YH\xe5\x92\x07\x83e\x11\xcf\xd0M\xbbjG\xff\xef.v\x14>j\x92I\x86\x94)/N?,Q.\xe1c\xb8M\xe1\xd5o\x9e\x07\xdbK\xec<2\xc7\x97\xf0\xd2\xd4\x7f\x87\x9e\xc5\xe9\x96\xbe\xfdz\xefh\xbcO\xdb^p\xb27\xf0y\x01\xffk\x9b\xe7.t\x14\xac\x9d^\xef\xf8\x87\xe3\xf8\xf7\xed@a\xe7\x0f\xdc9\x01G\x00\x00(\xe3\xdf}\x13\x01@\xad\x00\x01\x8f\x06\xf7\x05\x00\x00\x85k\x89\xbe\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ)\x04\xda\x04zlib\xda\x04lzma\xda\x04exec\xda\ndecompress\xa9\x00r\x06\x00\x00\x00r\x06\x00\x00\x00\xda\x07coduter\xda\x08<module>\x01\x00\x00\x00s\x02\x00\x00\x00\x10\x01')) ``` ::: Ta gần như không thể đọc đoạn mã từ đây do đã bị mã hóa, <a href="https://github.com/ConfusedCharacter/Decrypte-Marshal " >bạn hãy làm theo tại đây </a> để tìm được nội dung đoạn mã gốc. `Chương trình giải mã đầu tiên` :::info ```python import marshal,dis marshal_c = marshal.loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s(\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01e\x02e\x00\xa0\x03e\x01\xa0\x03d\x02\xa1\x01\xa1\x01\x83\x01\x01\x00d\x01S\x00)\x03\xe9\x00\x00\x00\x00Ns4\x03\x00\x00\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x02\xf6x\x9c\xedV[o\xd30\x14\xfe+^_\xd6\x02+Kz\xdf\x18\x9a\xe0\x01\x8d\x07@\x82\xa7)R\xe5\xc4\'\xa9\xb7\xd4\x8elgk#~<\xc7\x8e=\xba\xb6\x13\x9ax\xe9C#\xc5\xf9\xce\xfd\xf8\xf3q\xd5\xf9\\A\x91J\xad\xe7\xf8\x1c*\xbc\xea\x1cB\x17\xff\x84\x9d\xcbC\xe8\xe2\xc8\xe6\x91\xcd}l\xc2\n\xb2n))\xd3\xdd\xb4\x93\xac`\x90\xac\xce\xcf\xff\xf3\x1do\xca\xd7\x9b\x82\xc6\n\xd3M\x05\x0bKTZt\xbb\xab\x8b\xac.z\xd2\xc5V\x17/q\x19X\x83m7\xb26\xb0\xe0\x0e\x97!ksG\xb3\x90p\x04\xad\x86\xfa\xdeh\x14,\x13\x16\xf2L-\x1aZ\xc7\xd1\xbd\xf5R\xbf 1V7JV\xd3P\xc4\x17r\xfa\xf1\xae\xde\x01,"|\x074\xda\xb6\x9f\xdf\xb5\x19]\'\xe9\x8e&\xb3\x9a\x89]\xa6>:\x0eY\xf4o_w\xf2\xfa\xba\n\xc2\x06\xa7>8\xf6\x05a\x93\x8c\xdc\xba\xe5,1\x81;/\x8b \xe3w\xb2\xa1\xc7\x1d\xbch\xc9\xb6-X j\xa9S/\x10\n\xfb66\xb0\x96|\x7f\x84\xcd\x87K\xb2\x9a\xa5~8"\xb4\xceX;\x15{#\xe2\xd7\x92\xe7\xa6\xf0\xa7E=\x0c\xc7P\x98m\xcf\xfb\xb7^\xeb\xcc\xa8=I]\x02T\x8d\xa5zI\x1b\xe8W\xa2\xb0\xc2\xa0_\xad\x9b\xb3\x9bBH\xc5EA\xcc\x02H\xa5dZ\xc2\x92<Jqj\xc8\x92\xde\x03\xe1\x860\xaeiU\x01U\x97\xcdU&E\xae\xa406\x82\nF(c\n\xb4\xb6"zr\xed\xd2\x18Uc.j\x16\xc4H\x82fY\xd6\x86K\xd1o\xbe~\xbfG\x07jN5)\xa4d$\xad\r\xb9!E\x8d\x19\x9c\x9e\xd4D/d]2"\xe4#F\x9aZ\t\x82\xf5\x96\xbe;x\xe0\xb2\xd6.\xb5\xdf[\xacR\x8e0jyl7\xcf\xaf\xedxx\xfcc\x03\xb7\x9c\x06\xb19C,\xbe \x9f\'\'d-k\x92\xb9\xca\xa03Z\x81+(\xd3\xbcF\xc9\x00s%\x91\xb4(5\x96\x14\xb3\xc0\x9dr\xcb\xd0\x9a,\xa0\xacl\xf8\x05\xf1\x07\x11o\x1eD\xe3n\xa5\xd0\x00\xac\xdb\xbc\xed%"\x97\x8ap\xc2\x05QT\x14\xd0\x1d\xe0!^$\x82\xe0\x83\n\xc6\x85\xe9\x0e\xe2wQ<B\xd7\xe6\xfd\' \x9f\xa9\x82\xbc.O\xf0q=)Y\x1bh9Y\x80\x02K\xb9\x90\x86h\x9aC\xbf\xd7N[K\x8c\xd4\x1e\r\xf4:\xc0\xa1\xe1KP\xdb=\x06#U\xc5C\xc0\x1b\x14\x8f\x0b0\xd9#\xb3\x97%\xcaj\xa5@\x989\xe3\n2#\xd5\xfa6\x11\\0X\xcds^B\x98\xb7\n\x07\xca\x84L\xb0\xe2\x01\x8f\x11k\xf3\xd4\xcc\x9d\xe4"`Y\xc1\x13V@YH\xe5\x92\x07\x83e\x11\xcf\xd0M\xbbjG\xff\xef.v\x14>j\x92I\x86\x94)/N?,Q.\xe1c\xb8M\xe1\xd5o\x9e\x07\xdbK\xec<2\xc7\x97\xf0\xd2\xd4\x7f\x87\x9e\xc5\xe9\x96\xbe\xfdz\xefh\xbcO\xdb^p\xb27\xf0y\x01\xffk\x9b\xe7.t\x14\xac\x9d^\xef\xf8\x87\xe3\xf8\xf7\xed@a\xe7\x0f\xdc9\x01G\x00\x00(\xe3\xdf}\x13\x01@\xad\x00\x01\x8f\x06\xf7\x05\x00\x00\x85k\x89\xbe\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ)\x04\xda\x04zlib\xda\x04lzma\xda\x04exec\xda\ndecompress\xa9\x00r\x06\x00\x00\x00r\x06\x00\x00\x00\xda\x07coduter\xda\x08<module>\x01\x00\x00\x00s\x02\x00\x00\x00\x10\x01') byte_string = b'a\r\r\n\x00\x00\x00\x00\xf6\x971a\x00\x00\x00\x00' with open('ConfusedCharacter.pyc', 'wb') as pyc: pyc.write(byte_string ) marshal.dump(dis.Bytecode(marshal_c).codeobj, pyc) ``` ::: `Câu lệnh đầu tiên để giải mã` :::danger ``` ./pycdc ConfusedCharacter.pyc > stage1.py ``` ::: `Kết quả giải mã đầu tiên` :::info ```python import zlib import lzma exec(zlib.decompress(lzma.decompress(b'\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x02\xf6x\x9c\xedV[o\xd30\x14\xfe+^_\xd6\x02+Kz\xdf\x18\x9a\xe0\x01\x8d\x07@\x82\xa7)R\xe5\xc4\'\xa9\xb7\xd4\x8elgk#~<\xc7\x8e=\xba\xb6\x13\x9ax\xe9C#\xc5\xf9\xce\xfd\xf8\xf3q\xd5\xf9\\A\x91J\xad\xe7\xf8\x1c*\xbc\xea\x1cB\x17\xff\x84\x9d\xcbC\xe8\xe2\xc8\xe6\x91\xcd}l\xc2\n\xb2n))\xd3\xdd\xb4\x93\xac`\x90\xac\xce\xcf\xff\xf3\x1do\xca\xd7\x9b\x82\xc6\n\xd3M\x05\x0bKTZt\xbb\xab\x8b\xac.z\xd2\xc5V\x17/q\x19X\x83m7\xb26\xb0\xe0\x0e\x97!ksG\xb3\x90p\x04\xad\x86\xfa\xdeh\x14,\x13\x16\xf2L-\x1aZ\xc7\xd1\xbd\xf5R\xbf 1V7JV\xd3P\xc4\x17r\xfa\xf1\xae\xde\x01,"|\x074\xda\xb6\x9f\xdf\xb5\x19]\'\xe9\x8e&\xb3\x9a\x89]\xa6>:\x0eY\xf4o_w\xf2\xfa\xba\n\xc2\x06\xa7>8\xf6\x05a\x93\x8c\xdc\xba\xe5,1\x81;/\x8b \xe3w\xb2\xa1\xc7\x1d\xbch\xc9\xb6-X j\xa9S/\x10\n\xfb66\xb0\x96|\x7f\x84\xcd\x87K\xb2\x9a\xa5~8"\xb4\xceX;\x15{#\xe2\xd7\x92\xe7\xa6\xf0\xa7E=\x0c\xc7P\x98m\xcf\xfb\xb7^\xeb\xcc\xa8=I]\x02T\x8d\xa5zI\x1b\xe8W\xa2\xb0\xc2\xa0_\xad\x9b\xb3\x9bBH\xc5EA\xcc\x02H\xa5dZ\xc2\x92<Jqj\xc8\x92\xde\x03\xe1\x860\xaeiU\x01U\x97\xcdU&E\xae\xa406\x82\nF(c\n\xb4\xb6"zr\xed\xd2\x18Uc.j\x16\xc4H\x82fY\xd6\x86K\xd1o\xbe~\xbfG\x07jN5)\xa4d$\xad\r\xb9!E\x8d\x19\x9c\x9e\xd4D/d]2"\xe4#F\x9aZ\t\x82\xf5\x96\xbe;x\xe0\xb2\xd6.\xb5\xdf[\xacR\x8e0jyl7\xcf\xaf\xedxx\xfcc\x03\xb7\x9c\x06\xb19C,\xbe \x9f\'\'d-k\x92\xb9\xca\xa03Z\x81+(\xd3\xbcF\xc9\x00s%\x91\xb4(5\x96\x14\xb3\xc0\x9dr\xcb\xd0\x9a,\xa0\xacl\xf8\x05\xf1\x07\x11o\x1eD\xe3n\xa5\xd0\x00\xac\xdb\xbc\xed%"\x97\x8ap\xc2\x05QT\x14\xd0\x1d\xe0!^$\x82\xe0\x83\n\xc6\x85\xe9\x0e\xe2wQ<B\xd7\xe6\xfd\' \x9f\xa9\x82\xbc.O\xf0q=)Y\x1bh9Y\x80\x02K\xb9\x90\x86h\x9aC\xbf\xd7N[K\x8c\xd4\x1e\r\xf4:\xc0\xa1\xe1KP\xdb=\x06#U\xc5C\xc0\x1b\x14\x8f\x0b0\xd9#\xb3\x97%\xcaj\xa5@\x989\xe3\n2#\xd5\xfa6\x11\\0X\xcds^B\x98\xb7\n\x07\xca\x84L\xb0\xe2\x01\x8f\x11k\xf3\xd4\xcc\x9d\xe4"`Y\xc1\x13V@YH\xe5\x92\x07\x83e\x11\xcf\xd0M\xbbjG\xff\xef.v\x14>j\x92I\x86\x94)/N?,Q.\xe1c\xb8M\xe1\xd5o\x9e\x07\xdbK\xec<2\xc7\x97\xf0\xd2\xd4\x7f\x87\x9e\xc5\xe9\x96\xbe\xfdz\xefh\xbcO\xdb^p\xb27\xf0y\x01\xffk\x9b\xe7.t\x14\xac\x9d^\xef\xf8\x87\xe3\xf8\xf7\xed@a\xe7\x0f\xdc9\x01G\x00\x00(\xe3\xdf}\x13\x01@\xad\x00\x01\x8f\x06\xf7\x05\x00\x00\x85k\x89\xbe\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ'))) ``` ::: `Chương trình giải mã thứ hai sau khi bỏ chuỗi "__regboss__"` :::info ``` import marshal,dis marshal_c = marshal.loads(b"\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s\xe8\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01d\x00d\x02l\x02m\x03Z\x03\x01\x00e\x01j\x04d\x00\x19\x00Z\x05e\x00\xa0\x06\xa1\x00Z\x07d\x03Z\x08d\x04e\x05k\x06rTe\td\x05\x83\x01\x01\x00e\td\x06\x83\x01\x01\x00e\x01\xa0\nd\x00\xa1\x01\x01\x00e\x00j\x05\xa0\x0be\x00j\x05\xa0\x0ce\x07e\x08\xa1\x02\xa1\x01s|e\td\x07\x83\x01\x01\x00e\x01\xa0\nd\x00\xa1\x01\x01\x00e\re\x08d\x08\x83\x02\xa0\x0e\xa1\x00Z\x0fe\x0fd\t\x19\x00e\x0fd\n\x19\x00\x17\x00e\x0fd\x0b\x19\x00\x17\x00e\x0fd\x0c\x19\x00\x17\x00Z\x10e\td\r\x83\x01\x01\x00e\td\x0e\x83\x01\x01\x00e\x03d\x0f\x83\x01\x01\x00e\td\x10e\x10\x9b\x00d\x11\x9d\x03\x83\x01\x01\x00e\td\x12\x83\x01\x01\x00e\x01\xa0\nd\x00\xa1\x01\x01\x00d\x01S\x00)\x13\xe9\x00\x00\x00\x00N)\x01\xda\x05sleepz\x08maze.pngz\x03.pyz-Ignoring the problem won\'t make it disappear;z=confronting and addressing it is the true path to resolution.zJOk that\'s good but I guess that u should now return from the previous path\xda\x02rbi\xd1\x12\x00\x00i@\n\x00\x00iP\n\x00\x00i\xa0\n\x00\x00z-\n\nG00d!! you could escape the obfuscated pathz\x1btake this it may help you: \xe9\x02\x00\x00\x00z\x06\nseed(z+)\nfor i in range(300):\n randint(32,125)\nz/Be Careful!!!! the route from here is not safe.)\x11\xda\x02os\xda\x03sys\xda\x04timer\x02\x00\x00\x00\xda\x04argv\xda\x04path\xda\x06getcwdZ\x11current_directoryZ\nindex_file\xda\x05print\xda\x04exit\xda\x06exists\xda\x04join\xda\x04open\xda\x04read\xda\x05index\xda\x04seed\xa9\x00r\x13\x00\x00\x00r\x13\x00\x00\x00\xda\x07coduter\xda\x08<module>\x01\x00\x00\x00s*\x00\x00\x00\x10\x01\x0c\x02\n\x01\x08\x01\x04\x02\x08\x01\x08\x01\x08\x01\n\x01\x16\x01\x08\x01\n\x01\x0e\x01 \x01\x08\x01\x08\x01\x08\x01\x04\x01\x02\xff\n\x05\x08\x01") byte_string = b'a\r\r\n\x00\x00\x00\x00\xf6\x971a\x00\x00\x00\x00' with open('ConfusedCharacter.pyc', 'wb') as pyc: pyc.write(byte_string ) marshal.dump(dis.Bytecode(marshal_c).codeobj, pyc) ``` ::: `Câu lệnh thứ hai để giải mã` :::danger ``` ./pycdc ConfusedCharacter.pyc > stage2.py ``` ::: `Kết quả giải mã thứ hai` :::info ```python import os import sys from time import sleep path = sys.argv[0] current_directory = os.getcwd() index_file = 'maze.png' if '.py' in path: print("Ignoring the problem won't make it disappear;") print('confronting and addressing it is the true path to resolution.') sys.exit(0) if not os.path.exists(os.path.join(current_directory, index_file)): print("Ok that's good but I guess that u should now return from the previous path") sys.exit(0) index = open(index_file, 'rb').read() seed = index[4817] + index[2624] + index[2640] + index[2720] print('\n\nG00d!! you could escape the obfuscated path') print('take this it may help you: ') sleep(2) print(f'''\nseed({seed})\nfor i in range(300):\n randint(32,125)\n''') print('Be Careful!!!! the route from here is not safe.') sys.exit(0) ``` ::: Thực thi đoạn mã trên ta có gợi ý `seed = 493` và `for i in range(300): randint(32,125)`. Trong đoạn mã của `maze.py`, tôi đã thắc mắc vì sao lại dùng mảng key rỗng để giải mã tệp. Nên mình để `key = RandomNumberArray`. :::info ```python ZIPFILE = 'enc_maze.zip' import pyzipper import random def decrypt(file_path, word): with pyzipper.AESZipFile(file_path, 'r', compression=(pyzipper.ZIP_LZMA), encryption=(pyzipper.WZ_AES)) as (extracted_zip): extracted_zip.extractall(pwd=word) decrypt(ZIPFILE, 'Y0u_Ar3_W4lkiNG_t0_Y0uR_D34TH'.encode()) with open('maze', 'rb') as (file): content = file.read() data = bytearray(content) data = [x for x in data] seed = 493 random.seed(seed) key = [random.randint(32, 125) for _ in range(300)] for i in range(0, len(data), 10): data[i] = (data[i] + 80) % 256 else: for i in range(0, len(data), 10): data[i] = (data[i] ^ key[i % len(key)]) % 256 else: with open('dec_maze', 'wb') as (f): for b in data: f.write(bytes([b])) ``` ::: Ta nhận được một tệp ELF64. Mở nó trong IDA. ![image](https://hackmd.io/_uploads/HkLR4XA3a.png) Chương trình kiểm tra dữ liệu nhập đúng hay sai bằng cách tính tổng của ba kí tự kế nhau và so sánh với mảng `unk_2060`. Tới đây ta viết đoạn giải mã thôi. :::info ```python data = [0x111, 0x134, 0x122, 0xFE, 0xE6, 0x10F, 0xE8, 0xFE, 0x104, 0x117, 0xD2, 0xE8, 0x111, 0x145, 0x12F, 0x108, 0xD9, 0xDD, 0xCC, 0x107, 0xD7, 0x102, 0xE6, 0x11B, 0xED, 0x10C, 0x103, 0x11F, 0xE0, 0xDB, 0xC1, 0xC0, 0x87, 0x75, 0xBF] flag = "HTB" for i in range(len(data)): flag += chr(data[i] - ord(flag[-1]) - ord(flag[-2])) print(flag) ``` :::