Bài viết này trình bày chi tiết cách tiếp cận và giải quyết các thử thách pháp y bộ nhớ từ nhiều cuộc thi CTF khác nhau, sử dụng chủ yếu Volatility Framework cùng với các công cụ phụ trợ khác. Chúng ta sẽ khám phá cách trích xuất thông tin nhạy cảm, phân tích hoạt động của hệ thống, điều tra mã độc và khôi phục dữ liệu từ các bản trích xuất bộ nhớ.
OtterCTF
1 - Mật khẩu là gì?
Để tìm mật khẩu, chúng ta sử dụng công cụ Mimikatz để trích xuất thông tin xác thực từ bản ghi bộ nhớ. Sau khi chạy, mật khẩu được tìm thấy là: MortyIsReallyAnOtter
2 - Thông tin chung về hệ thống
Câu hỏi yêu cầu tìm tên máy tính và địa chỉ IP. Chúng ta bắt đầu bằng cách liệt kê các kết nối mạng hoạt động trên hệ thống.
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 netscan
Từ kết quả đầu ra của lệnh netscan, chúng ta có thể xác định địa chỉ IP của máy tính. Tên máy tính thường xuất hiện cùng với thông tin kết nối hoặc trong các kết quả khác liên quan đến hệ thống.
3 - Thời gian giải trí
Người dùng Rick thích chơi trò chơi điện tử. Câu hỏi là: anh ấy đang chơi trò gì và địa chỉ IP của máy chủ trò chơi là gì?
Đầu tiên, chúng ta liệt kê tất cả các tiến trình đang chạy để tìm kiếm các dấu hiệu của trò chơi.
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 pslist
Nếu danh sách tiến trình quá dài, chúng ta có thể lọc các tiến trình có tên gợi ý đến trò chơi. Sau đó, để tìm địa chỉ IP của máy chủ trò chơi, chúng ta có thể kết hợp với phân tích mạng hoặc các plugin khác.
Địa chỉ IP máy chủ: 77.102.199.102
4 - Trò chơi đặt tên (Phần 1)
Một tài khoản đã đăng nhập vào kênh có tên 'Lunar-3'. Tên tài khoản đó là gì?
Chúng ta cần tìm tiến trình liên quan đến ứng dụng chứa kênh 'Lunar-3', sau đó trích xuất bộ nhớ của tiến trình đó và tìm kiếm chuỗi ký tự.
# Giả sử chúng ta đã xác định PID của tiến trình liên quan
# Bước 1: Trích xuất các chuỗi ký tự từ toàn bộ bộ nhớ hoặc từ tiến trình cụ thể
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 strings | grep "Lunar-3"
Nếu cần, chúng ta có thể dump một tiến trình cụ thể và chạy công cụ strings trên tệp đã dump.
5 - Trò chơi đặt tên (Phần 2)
Tên người dùng của nhân vật đăng nhập luôn xuất hiện sau một chuỗi byte đặc trưng: 0x64 0x??{6-8} 0x40 0x06 0x??{18} 0x5a 0x0c 0x00{2}. Tên nhân vật của Rick là gì?
Mở tệp bộ nhớ của tiến trình đã được trích xuất ở câu trước (hoặc tệp bộ nhớ toàn cục) bằng một trình soạn thảo hex (ví dụ: 010 Editor). Tìm kiếm chuỗi byte đặc trưng đã cho. Tên nhân vật sẽ xuất hiện ngay sau đó.
Tên nhân vật được tìm thấy là: M0rtyL0L
6 - Rick ngớ ngẩn
Rick luôn quên mật khẩu email của mình nên anh ấy sử dụng một dịch vụ lưu trữ mật khẩu trực tuyến. Anh ấy luôn sao chép và dán mật khẩu để tránh nhập sai. Mật khẩu email của Rick là gì?
Vì Rick sao chép và dán mật khẩu, chúng ta có thể kiểm tra lịch sử clipboard trong bộ nhớ để tìm mật khẩu. Plugin clipboard của Volatility sẽ giúp ích trong trường hợp này.
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 clipboard
Kết quả đầu ra sẽ hiển thị nội dung gần đây đã được sao chép vào clipboard, trong đó có thể chứa mật khẩu email.
7 - Trốn tìm
Máy tính của Rick bị nhiễm mã độc. Hãy tìm tên tiến trình của mã độc (bao gồm cả phần mở rộng).
Kiểm tra danh sách các tiến trình đang chạy và tìm kiếm các tiến trình đáng ngờ hoặc không điển hình.
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 pslist
Trong trường hợp này, tiến trình mã độc được xác định là: vmware-tray.exe
8 - Con đường vinh quang (Phần 1)
Mã độc đã xâm nhập vào máy tính của Rick bằng cách nào? Chắc hẳn là do một trong những thói quen xấu cũ của Rick.
Sau khi xác định tiến trình mã độc, chúng ta cần tìm hiểu cách nó được khởi chạy hoặc từ đâu nó xuất hiện. Đầu tiên, dump tiến trình mã độc ra tệp.
# Giả sử PID của vmware-tray.exe là XXXXX
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 procdump -p XXXXX -D .
Sau đó, sử dụng strings trên tệp đã dump để tìm kiếm các chuỗi ký tự có thể tiết lộ nguồn gốc của mã độc.
strings vmware-tray.exe.XXXXX.exe | grep -i "download"
9 - Con đường vinh quang (Phần 2)
Tiếp tục tìm kiếm cách mã độc xâm nhập.
Để tìm hiểu sâu hơn về cách mã độc xâm nhập, chúng ta cần phân tích hoạt động trình duyệt. Có thể Rick đã tải xuống mã độc thông qua trình duyệt web. Chúng ta sẽ trích xuất toàn bộ bộ nhớ của các tiến trình trình duyệt Chrome.
Tìm kiếm các tiến trình chrome.exe:
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 pslist | grep "chrome.exe"
Sau đó, tạo một thư mục riêng để lưu trữ các bản dump của Chrome để tránh lộn xộn, rồi dump tất cả tiến trình chrome.exe.
mkdir chrome_dumps
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 memdump -n chrome.exe -D ./chrome_dumps
Cuối cùng, sử dụng lệnh strings kết hợp với grep trên các tệp đã dump để tìm kiếm dấu vết của việc tải xuống mã độc, ví dụ như tên tệp chứa mã độc.
strings ./chrome_dumps/* | grep 'Rick And Morty season 1 download.exe' -C 10
Qua quá trình này, chúng ta tìm thấy flag liên quan đến cách thức mã độc xâm nhập: CTF{Hum@n_I5_Th3_Weak3s7_Link_In_Th3_Ch@in}
10 - Bit vì Bit
Mã độc được xác định là ransomware. Hãy tìm địa chỉ Bitcoin của kẻ tấn công.
Có hai phương pháp chính để giải quyết vấn đề này:
-
Phân tích ngược phần mềm:
Đầu tiên, xác định PID của tiến trình ransomware thông qua
pstreeđể hiểu mối quan hệ cha-con của các tiến trình.vol.py -f OtterCTF.vmem --profile=Win7SP1x64 pstreeSau đó, dump tiến trình ransomware thành một tệp thực thi bằng
procdump.# Giả sử PID của ransomware là 3720 vol.py -f OtterCTF.vmem --profile=Win7SP1x64 procdump -p 3720 -D ./dump_filesSử dụng một công cụ phân tích ngược như ILSpy (cho các ứng dụng .NET) hoặc các IDE có khả năng phân tích mã để tìm kiếm chuỗi "address" hoặc các định dạng địa chỉ Bitcoin trong mã nguồn đã decompiled.
-
Tìm kiếm chuỗi trực tiếp trong bộ nhớ:
Do đây là ransomware, nó có thể chứa các chuỗi liên quan đến địa chỉ Bitcoin hoặc thông báo đòi tiền chuộc trực tiếp trong bộ nhớ. Sử dụng
stringsvới tùy chọn unicode (-e l) vàgrepđể tìm kiếm các từ khóa như "ransomware" hoặc "bitcoin".strings -e l OtterCTF.vmem | grep -i -A 5 "ransomware"
Flag chứa địa chỉ Bitcoin là: CTF{1MmpEmebJkqXG8nQv4cjJSmxZQFVmFo63M}
11 - Đồ họa cho kẻ yếu
Có điều gì đó đáng ngờ trong đồ họa của mã độc.
Điều này ngụ ý rằng có thể có các tài nguyên hình ảnh được nhúng trong tệp mã độc hoặc được sử dụng bởi nó có chứa thông tin ẩn. Chúng ta cần trích xuất tệp mã độc và kiểm tra các tài nguyên đồ họa bên trong.
# Sau khi dump tệp mã độc (ví dụ: vmware-tray.exe), có thể sử dụng các công cụ như binwalk, foremost, hoặc trình xem tài nguyên để kiểm tra
12 - Phục hồi
Rick cần khôi phục các tệp của mình! Mật khẩu ngẫu nhiên được sử dụng để mã hóa các tệp là gì?
Chúng ta cần tìm khóa giải mã. Thông thường, ransomware sẽ lưu trữ khóa này ở đâu đó trong bộ nhớ trước hoặc trong quá trình mã hóa. Chúng ta có thể bắt đầu bằng cách liệt kê các tài khoản người dùng và sau đó tìm kiếm trong bộ nhớ các chuỗi liên quan đến mật khẩu hoặc khóa.
# Liệt kê các tài khoản người dùng
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 hashdump
# Sau đó, tìm kiếm chuỗi trong bộ nhớ chung hoặc trong tiến trình ransomware đã dump
strings vmware-tray.exe.XXXXX.exe | grep -i "password"
Khóa giải mã được tìm thấy.
13 - Kết thúc
Với mật khẩu đã được trích xuất từ bộ nhớ, liệu bạn có thể giải mã các tệp của Rick không?
Chúng ta biết rằng có một tệp flag.txt trên màn hình nền của Rick. Đầu tiên, chúng ta cần tìm và trích xuất tệp này từ bộ nhớ.
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 filescan | grep "flag.txt"
# Giả sử chúng ta tìm thấy Offset của flag.txt là 0x00000000XXXXXXXX
vol.py -f OtterCTF.vmem --profile=Win7SP1x64 dumpfiles -Q 0x00000000XXXXXXXX -D .
Sau khi có tệp flag.txt.locked (giả sử phần mở rộng là .locked như thông thường với ransomware), và chúng ta đã có khóa giải mã từ câu trước. Sử dụng một công cụ giải mã ransomware tương ứng (ví dụ: HiddenTear Decrypter nếu mã độc là biến thể của HiddenTear) để giải mã tệp.
Flag cuối cùng là: flag{b1c16538-33f1-56b1-e620-b3a3f403a7f4}
DASCTF
baby_misc
Chúng ta bắt đầu bằng cách tìm kiếm các tệp văn bản (.txt) trong bản ghi bộ nhớ.
vol.py -f baby_misc.raw --profile=Win7SP1x64 filescan | grep txt
Sau khi xác định được offset của tệp văn bản đáng ngờ, chúng ta trích xuất nó.
# Giả sử offset của tệp nén là 0x000000003e7d2650
vol.py -f baby_misc.raw --profile=Win7SP1x64 dumpfiles -Q 0x000000003e7d2650 -D ./output_dir
Tiếp theo, chúng ta kiểm tra các tiến trình đang chạy và trích xuất bộ nhớ của một tiến trình cụ thể (ví dụ: PID 1516) có thể chứa thông tin quan trọng.
vol.py -f baby_misc.raw --profile=Win7SP1x64 memdump -p 1516 -D ./output_dir
Nếu có một tệp hình ảnh được tìm thấy, chúng ta có thể sử dụng công cụ như GIMP để xem nội dung của nó. Trong trường hợp này, một chuỗi số 132424464 được tìm thấy trên hình ảnh hoặc trong một tệp nào đó.
Sử dụng plugin windows của Volatility để tìm kiếm thông tin liên quan đến chuỗi số này, có thể là tiêu đề cửa sổ hoặc nội dung nào đó.
vol.py -f baby_misc.raw --profile=Win7SP1x64 windows | grep 132424464
Thông tin thu được sau đó có thể được chuyển đổi từ hệ thập lục phân để tìm mật khẩu giải nén.
Mật khẩu được tìm thấy là: ^&G12BDd
Sau khi giải nén, chúng ta thu được flag: flag{fba99a87-2278-f175-5055-a47f5773c131}
[Hồ Tương Cup 2021] Bài toán pháp y
Chúng ta bắt đầu bằng cách tìm kiếm và trích xuất một tệp hình ảnh JPEG từ bản ghi bộ nhớ.
vol.py -f PC11.raw --profile=Win7SP1x64 filescan | grep jpg
# Giả sử offset của tệp JPG là 0x000000007e353630
vol.py -f PC11.raw --profile=Win7SP1x64 dumpfiles -Q 0x000000007e353630 -D ./extracted_files
Tệp hình ảnh này có thể chứa một phần của flag hoặc gợi ý.
Kiểm tra lịch sử trình duyệt Internet Explorer để tìm kiếm các tệp nén (.zip) hoặc các hoạt động tải xuống đáng ngờ.
vol.py -f PC11.raw --profile=Win7SP1x64 iehistory | grep zip
Nếu không tìm thấy tệp ZIP trực tiếp, chúng ta kiểm tra các tiến trình đang chạy. Phát hiện tiến trình Wireshark.exe cho thấy có thể có một tệp capture mạng chứa thông tin.
Dump bộ nhớ của tiến trình Wireshark.
# Giả sử PID của Wireshark.exe là 1096
vol.py -f PC11.raw --profile=Win7SP1x64 memdump -p 1096 -D ./extracted_files
Sau khi dump, chúng ta có thể sử dụng các công cụ khôi phục tệp (file carving) hoặc binwalk để trích xuất các tệp con từ bản dump Wireshark, và tìm thấy một tệp nén (zip archive).
Tệp nén này có thể yêu cầu mật khẩu. Chúng ta sử dụng tấn công Known-Plaintext Attack (KPA) với công cụ bkcrack, sử dụng tệp JPG đã được trích xuất làm phần đã biết trong tệp nén.
# Tạo file với dữ liệu đầu đã biết từ tệp JPG
# ./bkcrack -L target.zip # (có thể mất nhiều thời gian nếu không có plaintext)
# Thực hiện tấn công KPA với tệp nén (target.zip) và tệp plaintext (t.jpg) cùng với offset hex đã biết
# Offset 0 ffd8ffe000104a46494600 là signature của JPEG.
./bkcrack -C target.zip -c t.jpg -x 0 ffd8ffe000104a46494600
# Sau khi tìm được các khóa, sử dụng chúng để giải mã tệp zip
./bkcrack -C target.zip -k b0a90b36 14dd97b9 f5d648cf -U flag.zip 123456
Flag được tìm thấy là: flag{2911364c-7f0c-4d37-b92c-accaf9d1de2d}
[Bằng Thành Cup 2022] Pháp y cơ bản
Chúng ta bắt đầu bằng cách xác định thông tin về hình ảnh bộ nhớ và tìm kiếm các tệp hình ảnh JPEG.
vol.py -f file.raw imageinfo
vol.py -f file.raw --profile=WinXPSP2x86 filescan | grep jpg
Trích xuất tệp hình ảnh JPG đã tìm thấy.
# Giả sử offset của tệp JPG là 0x0000000002325028
vol.py -f file.raw --profile=WinXPSP2x86 dumpfiles -Q 0x0000000002325028 -D ./extracted_files
Tệp này có thể là một chuỗi Base64 ẩn trong dữ liệu hình ảnh hoặc bên cạnh nó, cần được giải mã.
Kiểm tra lịch sử lệnh đã được thực thi (cmdscan) để tìm kiếm mật khẩu hoặc các chuỗi ký tự hữu ích khác.
vol.py -f file.raw --profile=WinXPSP2x86 cmdscan
Sau khi giải nén hoặc giải mã, chúng ta có thể nhận được một tệp chứa các cặp tọa độ. Chúng ta sẽ sử dụng một tập lệnh Python để chuyển đổi các tọa độ này thành một hình ảnh.
from PIL import Image
def tao_anh_tu_toa_do(duong_dan_tep_toa_do, kich_thuoc_anh=(350, 350), duong_dan_luu_anh="ket_qua_hinh_anh.png"):
"""
Tạo một hình ảnh từ các cặp tọa độ X Y trong một tệp văn bản.
Mỗi dòng trong tệp văn bản phải chứa một cặp tọa độ cách nhau bằng dấu cách.
"""
hinh_anh_ket_qua = Image.new("RGB", kich_thuoc_anh, (0, 0, 0)) # Tạo ảnh đen
try:
with open(duong_dan_tep_toa_do, "r") as t:
noi_dung_file = t.read()
except FileNotFoundError:
print(f"Lỗi: Không tìm thấy tệp {duong_dan_tep_toa_do}")
return
cac_dong_toa_do = noi_dung_file.strip().split("\n")
for dong_hien_tai in cac_dong_toa_do:
if not dong_hien_tai: # Bỏ qua dòng trống
continue
try:
toa_do_x_str, toa_do_y_str = dong_hien_tai.split(" ")
toa_do_x = int(toa_do_x_str)
toa_do_y = int(toa_do_y_str)
# Đặt pixel tại tọa độ (x, y) màu trắng
hinh_anh_ket_qua.putpixel((toa_do_x, toa_do_y), (255, 255, 255))
except ValueError:
print(f"Bỏ qua dòng không hợp lệ: '{dong_hien_tai}'")
continue
hinh_anh_ket_qua.save(duong_dan_luu_anh)
print(f"Hình ảnh đã được lưu tại: {duong_dan_luu_anh}")
# Ví dụ sử dụng:
# Giả sử tệp tọa độ được đặt tên là flag.txt
tao_anh_tu_toa_do("flag.txt", (350, 350), "flag.png")
Sau khi chạy tập lệnh, một hình ảnh sẽ được tạo, hiển thị flag.
Flag cuối cùng là: flag{a6b93e36-f097-11ec-a9b2-5254002d2b31}