Lời đầu tiên chúng tôi xin thay mặt BTC gửi lời cảm ơn đến các đội đã tham gia cuộc thi. Sau một thời gian để các đội tiếp tục tự nghiên cứu và tìm hướng giải cho các thử thách còn lại nhằm nâng cao chuyên môn cũng như kỹ năng nghiệp vụ của mình, hôm nay BTC sẽ công khai lời giải cho các thử thách có ít đội giải được. Đối với các thử thách có nhiều đội giải được các đội nếu có thắc mắc có thể liên hệ BTC thông qua kênh hỗ trợ Discord để được giúp đỡ.
Backdoor Detected (Category: Webshell)
Ở thử thách này BTC gửi cho các đội một tập tin bao gồm một file access_log.txt và một thư mục ROOT của web server. Sau khi xem qua các tệp do BTC cung cấp, tệp tin đáng ngờ nhất là tệp tin banking.jsp.
Step 1: Decode UTF-16
Thoạt nhìn qua chúng ta có thể phát hiện đây là một kiểu encode dạng UTF-16, chính vì thế chúng ta cần thực hiện decode UTF-16 để có thể có được một nội dung có thể đọc được.
Sau khi thực hiện decode UTF-16 chúng ta có thể thấy đây là một đoạn mã java, đoạn mã này tiếp tục bị làm rối bằng cách thay đổi tên các biến có khuôn dạng $_$ làm cho việc đọc hiểu đoạn mã trở nên khó khăn hơn.
Step 2: Khôi phục các hàm, biến và string của webshell
Sau khi có được tên webshell là banking.jsp, kết hợp với access_log.txt, bước đầu có thể thấy payload được gửi đến webshell qua POST method và ta hoàn toàn không có trong tay payload, vì vậy flag có thể được giấu đâu đó trong webshell hoặc ở một trong số các tệp còn lại của thư mục ROOT. Để biết được nội dung bị đánh cắp được lưu ở đâu chúng ta cần phải hiểu được cách thức hoạt động của web shell này.
Sử dụng một trang web https://kt.gy để khôi phục nhanh các chuỗi byte thành các string
Dựa vào các string, class và function mặc định được sử dụng ta có thể dự đoán được chức năng chính của các hàm được sử dụng trong web shell
Step 3: Khôi phục hàm main của webshell
Thực hiện tương tự như các bước ở step 2 chúng ta có được nội dung hàm main như sau
Có thể viết một cách ngắn gọn lại như sau
Có thể nhận thấy sau khi payload được gửi lên, web shell thực hiện giải mã chúng, sau đó thực thi, mã hóa output và ghi vào file 404.html.
Như đã trình bày ở step 2, ta không có payload của kẻ tấn công và payload của kẻ tấn công gửi lên sẽ được giải mã và thực thi trong hàm Exec_Command. Do đó, ta chỉ tiến hành dịch ngược đầy đủ hàm Base64_Encode_AES_Encrypt để có các giá trị, từ đó khôi phục data được giấu trong tệp “404.html”
Step 4: Dịch ngược Base64_Encode_AES_Encrypt và giải mã dữ liệu
Sau khi trích xuất được dữ liệu được mã hóa và giấu trong file 404.html, chúng ta cần phải nắm được cách thức mà web shell đã thực hiện mã hóa chúng mà không cần quan tâm payload kẻ tấn công gửi lên được giải mã như thế nào. Chính vì thế chúng ta chỉ cần tập trung vào đọc hiểu hàm Base64_Encode_AES_Encrypt.
Lời gọi hàm Base64_Encode_AES_Encrypt dạng ngắn gọn
Dựa vào string, class và tham số, biến được sử dụng trong các hàm, ta dịch ngược hàm Base64_Encode_AES_Encrypt.
Có thể thấy các tham số được truyền vào hàm Base64_Encode_AES_Encrypt bao gồm như sau:
- Param1 = “99wp_B0uNTy_p1Z!”
- Param2 = “192.168.18.80” chính là remote addr, ip nguồn của kẻ tấn công được lấy từ file access_log.txt
- data = nội dung được đưa vào để mã hóa
Step 5: Thực hiện giải mã bằng cách viết lại script bằng python.
Zerologon 01 (Category: Zerologon)
Lỗ hổng Zerologon được khai thác theo flow sau:
Vì là zerologon nên ta sẽ tập trung vào giao thức RPC_NETLOGON (trong file pcap được ký hiệu là những packets màu tím). Trong zerologon, có hai lần chúng ta xác thực thành công Netlogon, một là khi ta muốn set password về rỗng, và 2 là khi chúng ta muốn set lại về password ban đầu.
Step 1: Set empty password
Forensic một lượt từ đầu file pcap, tại packet 3816, đây là lần xác thực thành công đầu tiên dựa vào status của packet:
Trong packet 3818, là request NetrServerPasswordSet2 -> set password về rỗng. Malformed Packet (được chú thích bên trong packet này) nghĩa là wireshark không thể phân tích nội dung gói tin thêm nữa.
Step 2: Secrets dump
Và một đoạn các gói tin tiếp là là quá trình dump data. Flag cần tìm là NTLM hash ban đầu của account computer, đó cũng là data được lấy ra trong quá trình dump. Tuy nhiên việc đọc được NTLM hash từ dữ liệu thu được trong quá trình dump là không khả thi. Chính vì thế ta cần quan tâm đến bước tiếp theo là bước reinstall password của account computer.
Step 3: Reinstall original password
Tiếp theo là quá trình reinstall original password, mà NTLM hash của nó chính là cái chúng ta cần tìm. Theo dõi tiếp file pcap, sau đoạn dump data và tập trung vào những packet màu tím, ta tìm được đoạn xác thực thành công số hai như hình dưới:
Sau khi xác thực thành công, ta thấy packet NetServerPasswordSet request được sử dụng để cài đặt lại mật khẩu của account computer. Đi sâu vào packet này, ta thấy được Encrypted NTLM Pwd:
NTLM dùng thuật toán mã hóa SAM, để decrypt thì chúng ta còn cần thêm key, trong trường hợp này, chính là sessionkey, mà sessionkey được tính toán dựa trên giá trị của server challenge:
Tại packet 8787, là response từ server, ta thấy giá trị của server challenge:
Sau khi đã có đủ ciphertext + key, ta dùng thư viện có sẵn của python để decrypt và tìm được flag:
Zerologon02 (Category: Zerologon)
Step 1: Tìm kiếm câu lệnh được thực thi
Trong quá trình phân tích file pcap, chúng tôi phát hiện có một số packet chứa nhiều chuỗi được mã hóa base64. Nghi ngờ kẻ tấn công sử dụng script powershell được mã hóa base64 tấn công máy chủ AD. Chúng tôi thực hiện search chuỗi string “powershell -e” hoặc “powershell.exe -e”
Thực hiện bóc tách script powershell từ pcap cần lưu ý rằng data bắt đầu từ sau cặp từ “IO” do script được chia thành nhiều packet để gửi đi.
Step 2: Dịch ngược script tấn công
Thực hiện decode base64 ta được một đoạn mã powershell được encrypt bằng SecureString
Thực hiện decrypt đoạn powershell ở trên bằng script sau:
Sau khi decrypt ta được một đoạn mã powershell như sau:
Các số ở đầu là index của các string phía sau, chúng ta có thể viết script python convert về script ps ban đầu, hoặc dùng tool PSDecode. Từ đó ta có được đoạn mã powershell như sau:
Với k là mảng đã biết, host name trong file pcap đã có là ABC-DC-01, dùng xor để tìm được nội dung đã ghi vào file và đó chính là flag.
Malware 02 (Category: Malware)
Step 1: Phân tích
Phân tích file mã độc được BTC cung cấp ta thấy mã độc thực hiện các hành động sau:
- decrypt resource để có được shellcode
- copy file mã độc vào %APPDATA%
- Ghi key auto run vào registry
- Thực hiện injection shellcode vào một process phù hợp bất kỳ được tìm thấy
Có thể thấy file mã độc này đơn giản chỉ inject shellcode vào một process khác trong máy tính và thực thi. Chính vì thế ta cần tập trung phân tích shellcode này.
Có nhiều hướng để có thể phân tích shellcode trong mã độc này, tuy nhiên chúng tôi sử dụng cách làm tương tự như các bước được mô tả trong bài viết tại đường [link] đối với thử thách này ta có được file dll
Step 2: Phân tích file dll được dump ra
Bắt đầu với DllMain:
Trong hàm init có define một số chức năng và mã ảnh hưởng đến thuật toán dùng để encrypt dữ liệu của các hàm như sau:
- RemoteCommand => cmd = 3
- Upload => cmd = 5
- Keylogger => cmd = 2
- Download => cmd = 4
- Screenshot => cmd = 1
IP và port mà file kết nối đến:
Parse chức năng của các hàm trên
RemoteCommand
Trong hàm Command, ta thấy một số chức năng mà file thực thi.
Download
Dữ liệu từ file được đọc, sau đó đi qua hàm nén dữ liệu (rice compress) và được mã hóa trong hàm flow_send_data trước khi gửi về c&c.
Screenshot
Tương tự như hàm Download, dữ liệu từ ảnh chụp màn hình được nén lại qua hàm rice compress -> mã hóa -> gửi về c&c. Mà yêu cầu của challenge này chính là một trong số các ảnh chụp được gửi đi.
Flow send data
Hàm này được sử dụng để xử lý và gửi dữ liệu đến c&c
Sau khi phân tích ta thấy hàm này dựa trên giá trị của cmd để random một số thuật toán mã hóa, và tạo 16 bytes key random. Trong hàm algorithm, chúng ta thấy có 4 thuật toán được sử dụng ở đây
Vì ScreenShot có cmd = 1 thuật toán mã hóa sẽ là random XOR, RC4 hoặc là AES. Cuối cùng, quá trình encrypt dữ liệu screenshot giống như sơ đồ sau:
Step 3: Lấy dữ liệu ảnh chụp màn hình
Đầu tiên, chúng ta cần extract data từ file pcap bằng cách filter theo ip và port, sau đó viết script đơn giản để lấy từng packet send and recv.
Sau khi đã có các packet, phân tích theo struct của các packet như sau (trừ serpent encrypt):
- 4 bytes đầu là signature
- 4 bytes sau là insize
- 1 bytes tiếp là định danh hàm encrypt (0 => XOR, 1 => RC4, 2 =>AES)
- 16 bytes kế tiếp là key
- 4 bytes tiếp là outsize
- Và còn lại là data
Viết script đơn giản để decrypt 3 thuật toán mã hóa trên (trừ serpent):
Tiếp đó là decompress rice. Dùng hàm decompress tương tự như [link] để giải nén dữ liệu và ta thu được một số ảnh màn hình gửi đi trong đó có một ảnh có chứa flag.
Malware 03 (Category: Malware)
Từ dữ liệu lấy được ở thử thách Malware 02 ta nhận thấy có một số packet sử dụng serpent là thuật toán mã hóa sẽ được parse theo struct sau:
- 4 bytes đầu là signature
- 4 bytes sau là insize
- 1 bytes tiếp là định danh hàm encrypt bằng serpent với giá trị mặc định bằng 4
- Và còn lại là data
Step 1: Decrypt serpent
Sử dụng hàm như trong [link] để decrypt dữ liệu extract được từ file pcap được mã hóa bằng serpent.
Tại packet số 30, sau khi decrypt ta nhận thấy có signature của file zip và một file có tên là flag2.txt trong đó và một số file Keylogger khác.
Thực hiện giải nén file zip này ta thấy có yêu cầu nhập password. Khả năng password được lưu ở đâu đó trong những file Keylogger.
Có thể thấy trong các file Keylogger có một nội dung dạng “Th1s_1s_p4ssw0rd” tuy nhiên đây không phải là password cần tìm vì sử dựng để giải nén không thành công.
Quay trở lại đọc kỹ hơn hàm Keylogger trong file dll, ta thấy có một hàm hook_keylogger, chính hàm này đã thay đổi giá trị của phím được nhấn trước khi ghi vào file.
Theo như trên, nó đã thay đổi i -> 1, a -> 4, o -> 0. Từ đó ta có thể suy ra được password chính xác sẽ là: This_is_password
Thực hiện extract zip file với password có được ta có flag như sau: