A hasherezade's crack me challenge


LỜI GIỚI THIỆU
Hello mọi người :> . Thấy mọi người xung quanh viết blog hay quá nên mình cũng viết để nếm thử mùi vị bú fame các anh tài ở BlueCyber:D . Lần đầu viết blog chứ không phải chuyện như mn nghĩ nhá nên chắc sẽ có nhiều chỗ hơi non mọi người đọc hãy cứ relax và have fun nhá
Ban đầu cũng nghĩ mãi nên viết blog về chủ đề gì thì trong lúc lướt twitter dạo dạo thì thấy @hasherezade . Mình khá là thích cô ấy (Cái ảnh tittle còn là lấy từ ảnh bìa của cô ấy trên twitter mà :D ) . Trong cái lĩnh vực Security ,mình thấy số lượng nữ giới có niềm đam mê với công việc phân tích mã độc là không nhiều nên với có 1 cô gái tài năng rất là hiếm
Mình thấy cô có làm rất nhiều crackme hay và thú vị nên mình quyết định viết 1 blog về 1 crackme của cô mà mình thấy ấn tượng
Dài dòng đủ rồi thôi vào vấn đề luôn cho nóng . Ai có mong muốn thử sức với chall này có thể tải ở đây https://www.hybridanalysis.com/sample/4ba96615dd4f38d5bf75c192c6bee81ecac595fda911d6974739557118eda032?environmentId=100
(Để tải được trên hybridanalysis phải có tài khoản business nhưng mình làm gì có cũng may trong bài viết của cổ có link file binary này :>)
Như mọi khi thôi điều đầu tiên mình làm là ném nó vào Delect it easy .
Hay quá nó không bị pack :> tiếp tục đi vào Strings xem có gì hay ho không . Thấy có khá nhiều thứ đang chú ý
Có vẻ như nó sẽ có connect mạng và 1 số thủ tục mã hóa dễ thấy như RSA ngoài ra mình có thấy 1 dãy có khả năng là key của base64 . Mình đoán nó tạo sẽ 1 payload và thực thi payload này . Quan sát thông tin cơ bản là thế giờ thì chạy nó thôi xem nó làm mô tê gì máy mình :D . Sau khi chạy được thế này
Có vẻ như chúng ta sẽ phải tìm 1 flag có dạng flag{...} . Ngoài ra nó kêu có nhiều stages có vẻ như chúng ta sẽ phải làm qua 1 số giai đoạn để có được flag . Ném nó vào IDA để có cái nhìn sâu hơn . Chúng ta vào strings và tìm xem có nơi nào gọi chuỗi 'I am so sorry, you failed! :(' . Chúng ta có thể dễ dàng thấy nơi nó được gọi là hàm main
Chúng ta thấy check 1 sub_2E14F0 nếu nó thỏa mãn thì điều kiện thì nó sẽ đi vào hàm sub_2E1690 nên mình rename 2 hàm thành check() và next_step() . Đi vào hàm check xem có gì hay ho .
Chúng ta có thể dễ dàng trông thấy nó gọi rất nhiều hàm sau đó gọi gán 1 loạt các giá trị vào v2 ; sau đó nó tiếp tục call 2 hàm sub_2E31C0 và sub_2E3380 và cuối cùng compare giá trị trả về với eax 0x3B47B2E6 . Chúng ta sẽ đi phân tích chi iết từng hàm . Đầu tiên nó call __rdtsc và gán vào qword_309E68 . __rdtsc hay được sử dụng trong các chương trình anti-debug nên mình nghĩ có vẻ chương trình này sẽ sử dụng các cơ chế anti-debug . Đi vào hàm sub_2E19D0 xem có gì
Ban đầu khi nhìn vào hàm này tôi thấy 1 loạt các API để anti-debug nhưng sau khi quan sát xuống dưới tôi nhận ra mục đích của nó là kiểm tra program có bị debug hay không để gán giá trị vào 1 mảng . Nó sẽ gán trị vào mảng dword_309A60 .Chúng ta có thể thấy nó đã gán giá trị đầu tiên vào mảng sau khi kết thúc hàm đầu tiên
Đi vào hàm tiếp theo chúng ta thấy nó tiếp tục kiểm tra RaiseException và tiếp tục gán giá trị thứ 2 vào mảng .
Tiếp tục đi vào hàm tiếp theo . Ở hàm sub_1001B00 nó có mục đích là check xem cái thread đang chạy này có debug registers hay không để gán giá trị thứ 3 vào mảng . Tôi chỉ việc bp và quan sát thôi
Xem hàm sub_1001C20 là hàm thứ 4 xem có gì . Ở hàm này nó sẽ kiểm tra NtGlobalFlag & BeingDebugged trong cấu trúc PEB_block . Nó cũng kiểm tra giá trị ở dword_1029A64 , nếu các trường này có giá trị khác không thì sẽ thực hiện gán giá trị cho mảng. Tôi thấy đây là cách antidebug hay gặp ở malware. Nhưng sau khi xem qua các hàm thì rõ ràng ở đây tôi thấy mục đích của crackme này không phải là để anti-debug :/
Ở hàm sub_1002730 chúng ta thấy như sau . Ban đầu khi nhìn vào hàm này mình cũng chưa hình dung rằng nó sẽ làm gì . Mỗi lần nó đều khởi tạo 1 giá trị khác nhau và cho vào sub_1001EB0
Sau đó mình có đi vào hàm sub_10025F0 . Ở đó mình nhìn thấy nó sử dụng API QueryDosDevice . Theo mình tìm hiểu thì API này get infomation về tên các MS-DOS device, và lưu tại buffer là lpTargetPath . Sau nó sẽ qua hàm sub_1003350 để tính toán 1 giá trị nào đó . Mình sẽ rename hàm đó thành check_sum . Nó sẽ so sánh từng giá trị trong cái list device đó với các giá trị đã get ở các hàm trước . Nếu như có thì sẽ gán giá trị cho mảng tương tự các hàm trước
Nhưng máy mình làm gì có cái nào thỏa mãn :D nên thôi cứ patch mà vã thôi chứ đắn đó gì miễn nó gán giá trị cho mảng mà . Như chúng ta thấy trong ảnh nó đã gán giá trị thứ 5 cho mảng
Đi tiếp vào hàm thứ 6 nào . Ở hàm này sử dụng cơ chế anti-debug hay gặp là có debug trong virtual machine không . Chúng ta có thể dễ dàng thấy nó check xem có đang debug trong VirtualBox không nhưng mình dùng VmWare nên .... tất nhiên rồi patch tiếp thôi để nó gán giá trị tiếp theo vào mảng ://///
Sang đến hàm thứ 7 nào . Hàm này chúng ta lại thấy get thông tin về 1 số module nào đó mình chịu nhưng về cơ bản trông nó khá giống hàm thứ 5 nhưng khác hàm trước là nó sử dụng các API như API GetCurrentProcessId() , CreateToolhelp32Snapshot() để tìm duyệt các module . Nó cũng sẽ tính check_sum như hàm trước . Thôi patch cho nhanh gọn lẹ chứ tìm hiểu kỹ từng module lú lắm :D
Let's go sang hàm tiếp theo nào . Đậu móa mở ra lại thấy na ná giống hàm trước
:<<< . Có vẻ lần này nó duyệt tìm các Process nếu nó Process nào thỏa mãn thì mới gán thôi cứ patch patch patch cho nhanh .
Có vẻ theo như quá trình thì đây sẽ là hàm gán cuối cùng . Đi vào xem có gì . Nó truyền parameter là giá trị qword_309E68 được get ở hàm call __rdtsc ban đầu . __rdtsc() thì là hàm tính time khi nó bắt đầu chạy . Hàm này cũng khá đơn giản thôi nó check xem time có = 0 hay không. Dù gì cũng patch lại cho nhanh . Sau đó chúng ta sẽ được mảng đã gán đầy đủ giá trị
Tiếp theo chúng ta thấy nó gọi 1 hàm sub_10031C0 . Hàm này truyền mảng giá trị v2 đã gán ở trên . 1 size buffer Url gì đó , 0x100 , 0x400 và mảng giá trị đã được gán ở trên .
Ở hàm này chúng ta thấy nó gọi rất nhiều API cho việc mã hóa như bên trên đã nói . Về cơ bản giải thích từng API và từng dòng thì khá dài nên mình sẽ tóm gọn mục đích của hàm này . Nó sẽ thực hiện quá trình giải mã cái mảng v2 để lấy plaintext url và gán vào szUrl với key là cái mảng đã gán giá trị của các hàm . Thuật toán mà nó sử dụng là SHA_256 . Sau khi chạy xong hàm đó chúng ta sẽ nhận được 1 url như hình . Đến tầm này thì hơi lười giải thích quá :<<<< nên chốt cho nhanh gọn lẹ
Ở hàm sub_1003380 nó truyền vào 3 tham số là url vừa gán , 256 , 1 . Hàm này nó sẽ tính toán và so sánh giá trị trả về với 0x3B47B2E6 . Có vẻ như mục đích của cả cái hàm check() lớn là tìm cái URL từ những giá trị kia . Nếu đúng thì sẽ vào hàm next_step() còn k thì in ra màn hình cái "I am so sorry, you failed! :(\n"
tiếp tục phân tích hàm next_step() . Ban đầu chúng ta thấy nó check xem có connect tới internet sau đó nó sẽ cấp phát 1 vùng nhớ . Vùng nhớ này sẽ được sử dụng để chứa dữ liệu tải về từ URL ở trên .Ở hàm sub_4033D0 sử dụng API InternetOpenA(), InternetOpenUrlA(), InternetReadFile() , user_agent là ‘Mal-Zilla’. Thực hiện download toàn bộ nội dung từ URL và lưu vào vùng nhớ đã cấp phát. Download xong sẽ in ra màn hình thông báo: “You are on the right track!\n”
Tiếp theo nó cấp phát vùng nhớ khác toàn bytes 0 với kích thước thật này 0xC20B bytes. Thực hiện giải mã toàn bộ khối dữ liệu Base64 đã download và lưu vào vùng nhớ mới được cấp phát . Đặt bp chúng ta có thể dễ dàng quan sát vùng memory đó .
Nó tiếp tục cấp phát một vùng nhớ mới, sử dụng API RtlDecompressBuffer() để giải nén buffer ở trên . Tiếp tục đặt bp để quan sát vùng nhớ sau khi gọi hàm sub_9E5960()
Tiếp theo đến hàm sub_9E6B20() (Get_Clipboard_Data()): sử dụng các hàm API IsClipboardFormatAvailable(), OpenClipboard(), GetClipboardData() để copy dữ liệu của clipboard vào vùng nhớ đã cấp phát. Nếu nó thành công nó sẽ call đến hàm sub_9E11A0() . Đi vào hàm đó tôi thấy nó làm encrypt bằng 1 thuật toán xor .
Và sau khi xor xong nó so sánh 2 byte đầu của vùng nhớ đã encrypt với 2 giá trị 0x4D và 0x5A . Đây là 2 byte đầu của cấu trúc tệp PE nên tôi đoán rằng nó sẽ tạo 1 1 PE file ở đây . Nếu không đúng thì nó sẽ in ra "Better luck next time!", "Nope :(" . Chúng ta sẽ phải tìm key xor . Dựa vào 2 byte đầu tôi tìm ra 2 ký tự đầu tiên của key là 'ma' . Sau 1 hồi quan sát vùng nhớ tôi thấy có rất nhiều chuỗi được lặp đi lặp lại là malwarebytes . Tôi nghĩ key là malwarebytes sai thì thôi tội gì không thử :D . Sau khi chạy hàm sub_9E6B20() tôi patch lại vùng nhớ v10 thành malwarebytes .
Chạy nó và quan sát vùng nhớ :D có vẻ như key là đúng nè
Tiếp theo nó sử dụng 1 API sao chép chuỗi kia vào vùng nhớ và call đến hàm Dst . ĐI vào hàm sub_9E11F0 xem có gì . Sau khi quan sát hàm này gặp toàn các API như GetModuleHandleA , GetThreadContext , ReadProcessMemory , VirtualAllocEx , WriteProcessMemory , SetThreadContext , SetThreadContext . Các bạn nhìn các API này trông có quen quen không :D nó sử dụng kỹ thuật mà malware hay dùng để bypass các cơ chế protect của window là process hollowing hay gọi ngắn gọn là RunPE :v . Mình sẽ không đi sâu vào giải thích chi tiết kỹ thuật này . Các bạn có thể đọc ví dụ về kỹ thuật này ở đây
https://viblo.asia/p/tim-hieu-ve-process-hollowing-V3m5WRmxlO7
Mình sẽ giải thích qua nó sẽ sử dụng CreateProcess để tạo 1 instance
Lấy thông tin về context của hThread ứng với tiến trình vừa được khởi tạo ở trên thông qua API GetThreadContext(hThread, &Context).
API ReadProcessMemory để kiểm tra toàn bộ dữ liệu tại base address và vùng nhớ với kích thước được chỉ định có thể truy cập để đọc dữ liệu .
API VirtualAlloc() để cấp phát một vùng nhớ mới có quyền “PAGE_EXECUTE_READWRITE” dùng để lưu code của file PE .
Nó sẽ copy toàn bộ dữ liệu từ vùng PE buffer đã được giải mã ở trên vào vùng nhớ mới được tạo ra .
API SetThreadContext() và ResumeThread() để thực thi process từ EP .
Tôi cần dump vùng nhớ PE đó để xem nó làm gì .Có 2 cách để dump .
Cách 1 Đầu tiên truy cập đến vùng nhớ đó trên IDA . và save lại . Nhớ để ý size vùng nhớ nhá .
Cách 2 thì easy hơn dùng process hacker để dump thôi .
Mình được 1 file như thế này . Sau đó mình dùng tool pd64 để fix file . Chúng ta sẽ được 1 file exe . Chạy thử nó thì chúng ta thấy như sau
Có vẻ như chúng ta đã sang stage 2 . Ném nó vào IDA thôi . Lần theo string trong thông báo nó nằm tại hàm main . Xem hàm main có gì
ở hàm sub_2E710C0 nó sẽ lấy địa chỉ của các hàm API “NtQueueApcThread”, “ZwSetInformationThread”, “ZwCreateThreadEx”, “RtlCreateUserThread”, thuộc thư viện ntdll.dll
Tiếp theo nó sẽ so sánh xem có chạy file tại hướng dẫn Dst không bằng cách tính check_sum nhưng mình k chạy ở đường dẫn đó nên patch lại thôi .
Nó gọi 1 hàm EnumFunc đi vào hàm đó
Nó sẽ check toàn bộ process và tính get classname để tính check_sum nếu bằng parameter a2 thì nó sẽ ẩn cái process đó đi và gán nó id nó vào ThreadContext và so sánh với 0 để nhảy xuống giá trị Faild . Mình open 1 process notepad lên và truyền vào handle của nó để hàm này trả về giá trị thoải mãn .
Tiếp nó sẽ lấy giá trị của PEB.BeingDebugged Flag (nếu bị debug sẽ có giá trị là 1), sau đó lấy 4 bytes đầu tiên của một vùng nhớ để thực hiện tính toán xor. Các bytes tính checksum cho vùng có độ dài 0x177 bytes và so sánh với giá trị checksum mặc định là 0xCA1C7FCF. Nếu không bằng thì sẽ hiện thông báo: “You failed :(\nBetter luck next time!”, “Stage 2”.
Nó sẽ tính toán 1 shell để inject
Đoạn code tiếp theo sẽ thực hiện inject toàn bộ shell_code vào notepad thông qua handle đã có được ở trên. Sử dụng ZwCreateSection() để tạo section có thuộc tính PAGE_EXECUTE_READWRITE, NtMapViewOfSection() để maps section được tạo vào trong vùng nhớ của process hiện tại.
Cuối cùng, tính toán một giá trị random bằng GetTickCount() % 3. Tùy vào giá trị trả về mà thực thi khác nhau
Nhưng sau khi run mình phát hiện là nó mặc dù inject thành công nhưng không thể chạy shell nó đã inject . Mình tìm hiểu và phát hiện là cái shell nó là 32bit nên vốn k thể chạy trên các process explorer 64 bit vậy nên mình đã inject chính nó luôn :D nghe giống mùi .........
Dump vùng shell đó ra trên IDA được 1 file
Mình dùng tool PeBear để tạo 1 thêm section . Dump vùng nhớ shell đó ra vào gán vào section vừa khởi tạo của PeBear(Nhớ fix lại 1 số trường trong header nhá và cấp thêm memory) .
Mình chạy lại nó và ra flag thôi :D
Mình thấy chall này khá là thú vị sử dụng khá nhiều kỹ thuật mà malware hay sử dụng để anti-debug . Ngoài ra còn sử dụng kỹ thuật malware khá phổ biến là RunPE nữa .
Cuối cùng cũng xong :D mệt quá . Mọi người đọc góp ý cho mình với ạ . Cảm ơn mọi người nhiều :> Chúc mn có ngày tốt lành
Subscribe to my newsletter
Read articles from Yurri0309 directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
