Bài 36. (Lab) Phân tích email phishing và trích xuất IoC
Khóa học CompTIA Security+ SY0-801 · Phần 2: Mối đe dọa, lỗ hổng và tấn công · Bài 36 · 🎯 Objective 2.5 · ⏱️ Thực hành khoảng 30 phút · 🧪 Có lab · 📝 5 câu kiểm tra cuối bài
🎯 Mục tiêu bài học
- Đọc tiêu đề (header) của một email và nhận ra nơi nó thật sự đến từ đâu.
- Đọc kết quả SPF, DKIM, DMARC và so khớp
From,Reply-To,Return-Path. - Phát hiện liên kết có chữ hiển thị khác đích thật và tệp đính kèm đuôi kép.
- Trích xuất IoC (IP, domain, URL, hash), defang chúng và ghi ra tệp CSV để chuyển cho đội phòng thủ.
📎 Vị trí trong đề thi: bài này là thực hành cho Bài 22 (phishing, SPF/DKIM/DMARC), Bài 28 (trojan) và Bài 33 (IoC). Đề thi không bắt bạn viết mã, nhưng người đã tự đọc một email giả từ đầu đến cuối sẽ nhớ rất lâu những chỗ cần nhìn.
⚠️ Chỉ dùng dữ liệu mẫu trong bài. Email, tên miền và tệp đính kèm ở đây đều giả: tên miền dùng đuôi
.example(dành riêng cho tài liệu, không tồn tại thật), địa chỉ IP thuộc dải203.0.113.0/24(dải dành cho ví dụ), và "tệp đính kèm" chỉ là một dòng chữ vô hại. Khi gặp email đáng ngờ thật, đừng bấm liên kết, đừng mở tệp, hãy lưu thư dưới dạng.emlvà báo cho bộ phận bảo mật. Mọi phân tích mã độc thật cần làm trong môi trường cách ly.
💡 Liên hệ thực tế: lá thư lúc hai giờ sáng
Sáng thứ Hai, chị Lan chuyển cho Nam một email "Ngân hàng ABC" báo tài khoản sẽ bị khóa trong 24 giờ. Thư đến lúc 02:14, kèm một tệp "hóa đơn". Chị chưa bấm gì nhưng thấy lạ. Đây là tình huống minh họa, không phải vụ việc có thật.
Nam không đọc thư theo cảm tính. Anh lưu nó thành tệp .eml rồi đi qua một danh sách cố định: thư đến từ đâu, có vượt qua kiểm tra xác thực không, các tên miền có khớp nhau không, liên kết dẫn đi đâu, tệp đính kèm là gì. Kết quả là một danh sách IoC ngắn để đưa vào tường lửa, bộ lọc thư và công cụ tìm kiếm nhật ký, để biết còn ai khác đã nhận hoặc bấm vào thư này không.
Bài lab này là bản thu gọn của buổi sáng đó, dựng bằng Python, không cần kết nối mạng.
🔍 Hình 36a. Nguồn gốc, kết quả xác thực, liên kết và tệp đính kèm: mỗi chỗ để lộ một mâu thuẫn.
🧪 Chuẩn bị
| Yêu cầu | Chi tiết |
|---|---|
| Hệ điều hành | Linux, macOS hoặc Windows |
| Python | Phiên bản 3.8 trở lên. Kiểm tra bằng python3 --version (trên Windows có thể là python --version) |
| Mạng | Không cần. Mọi thứ chạy cục bộ, chỉ dùng thư viện chuẩn của Python |
| Thư mục làm việc | Một thư mục trống, ví dụ lab-phishing |
| Thời gian | Khoảng 30 phút |
bash
mkdir lab-phishing && cd lab-phishing python3 --version
Các kết quả mẫu dưới đây lấy từ lần chạy thật với Python 3.13. Với cùng dữ liệu mẫu, mã băm SHA-256 của bạn sẽ giống hệt, vì tệp đính kèm có nội dung cố định.
📨 Phần 1: tạo email mẫu
Bước 1. Tạo tệp tao_mau.py với nội dung sau. Tập lệnh dựng một email giả có đủ các điểm đáng ngờ rồi ghi ra mau.eml.
python
from email.message import EmailMessage
msg = EmailMessage()
msg["Received"] = ("from mail-relay.fake-vendor.example (unknown [203.0.113.45]) "
"by mx.congty.example with ESMTP; Mon, 19 Oct 2026 02:14:08 +0700")
msg["Return-Path"] = "<bounce@mail-relay.fake-vendor.example>"
msg["Authentication-Results"] = ("mx.congty.example; spf=fail smtp.mailfrom=mail-relay.fake-vendor.example; "
"dkim=none; dmarc=fail header.from=ngan-hang-abc.example")
msg["From"] = '"Ngân hàng ABC - Bộ phận Bảo mật" <baomat@ngan-hang-abc.example>'
msg["Reply-To"] = "<hotro.khancap@mail-ngan-hang-abc.example>"
msg["To"] = "lan.ketoan@congty.example"
msg["Subject"] = "[KHẨN] Tài khoản của quý khách sẽ bị khóa trong 24 giờ"
msg["Date"] = "Mon, 19 Oct 2026 02:13:55 +0700"
msg["Message-ID"] = "<20261019021355.7f3a@mail-relay.fake-vendor.example>"
msg.set_content("Vui lòng xem bản HTML của thư này.")
msg.add_alternative("""\
<html><body>
<p>Kính gửi quý khách,</p>
<p>Chúng tôi phát hiện đăng nhập bất thường. Tài khoản sẽ bị <b>khóa trong 24 giờ</b> nếu quý khách không xác minh ngay.</p>
<p><a href="http://203.0.113.45/login/abc">https://ngan-hang-abc.example/xac-minh</a></p>
<p>Xem thêm hướng dẫn tại <a href="http://ngan-hang-abc-secure.example/huong-dan">trang hướng dẫn</a>.</p>
<p>Trân trọng,<br>Bộ phận Bảo mật</p>
</body></html>
""", subtype="html")
msg.add_attachment("Day la tep mau vo hai dung cho bai lab.\n".encode(),
maintype="application", subtype="octet-stream",
filename="HoaDon_T10.pdf.exe")
open("mau.eml", "wb").write(msg.as_bytes())
print("Da tao mau.eml")
Bước 2. Chạy nó.
bash
python3 tao_mau.py
text
Da tao mau.eml
Bạn có tệp mau.eml. Thật ra bạn có thể thay bước này bằng một email thật được lưu dưới dạng .eml (hầu hết ứng dụng thư đều có "Lưu thư" hoặc "Xem nguồn thư"), nhưng chỉ làm với thư của chính bạn và không mở tệp đính kèm.
👀 Phần 2: đọc bằng mắt trước khi chạy công cụ
Bước 3. Mở mau.eml bằng trình soạn thảo văn bản. Đây là điều đáng để làm một lần: phần đầu tệp chính là tiêu đề, phần sau là thân thư và tệp đính kèm (mã hóa base64). Chưa cần hiểu hết, hãy tìm bốn dòng sau:
From:(người gửi hiển thị),Reply-To:(nơi nhận khi bạn bấm Trả lời),Return-Path:(nơi nhận thư báo lỗi, thường là người gửi thật ở tầng SMTP).Received:cho biết thư đi qua máy chủ nào và địa chỉ IP của máy gửi.Authentication-Results:là kết quả kiểm tra của máy chủ nhận: SPF, DKIM, DMARC.
Ở thư mẫu, ngay từ bước này đã thấy ba điều lạ: From nói là ngan-hang-abc.example, nhưng Reply-To là mail-ngan-hang-abc.example và Return-Path thuộc một miền khác hẳn. Authentication-Results ghi spf=fail.
🔬 Phần 3: phân tích bằng tập lệnh
Bước 4. Tạo tệp phan_tich.py. Tập lệnh đọc .eml, so khớp các tên miền, tìm liên kết có chữ hiển thị khác đích thật, tính SHA-256 của tệp đính kèm và ghi IoC ra ioc.csv.
python
import csv, email, hashlib, re, sys
from email import policy
from html.parser import HTMLParser
def defang(s):
return s.replace("http", "hxxp").replace(".", "[.]")
msg = email.message_from_binary_file(open(sys.argv[1], "rb"), policy=policy.default)
def domain_of(addr):
m = re.search(r"@([\w.-]+)", addr or "")
return m.group(1).lower() if m else ""
print("== 1. Tiêu đề và nguồn gốc ==")
for h in ("From", "Reply-To", "Return-Path", "Subject", "Date", "Message-ID"):
print(f"{h:12}: {msg[h]}")
print("Received :", msg["Received"])
ip = re.search(r"\[(\d+\.\d+\.\d+\.\d+)\]", msg["Received"] or "")
ip = ip.group(1) if ip else ""
print("\n== 2. Xác thực (SPF/DKIM/DMARC) ==")
auth = msg["Authentication-Results"] or ""
for k in ("spf", "dkim", "dmarc"):
m = re.search(rf"{k}=(\w+)", auth)
print(f"{k.upper():6}: {m.group(1) if m else 'không có'}")
print("\n== 3. So khớp tên miền ==")
d_from, d_reply, d_ret = domain_of(msg["From"]), domain_of(msg["Reply-To"]), domain_of(msg["Return-Path"])
print("From :", d_from)
print("Reply-To :", d_reply, "" if d_reply == d_from else " <-- KHÁC From")
print("Return-Path:", d_ret, "" if d_ret == d_from else " <-- KHÁC From")
class Links(HTMLParser):
def __init__(self):
super().__init__(); self.links = []; self._href = None; self._text = ""
def handle_starttag(self, tag, attrs):
if tag == "a":
self._href = dict(attrs).get("href"); self._text = ""
def handle_data(self, data):
if self._href is not None: self._text += data
def handle_endtag(self, tag):
if tag == "a" and self._href is not None:
self.links.append((self._text.strip(), self._href)); self._href = None
body = msg.get_body(preferencelist=("html",)).get_content()
p = Links(); p.feed(body)
print("\n== 4. Liên kết ==")
urls = []
for text, href in p.links:
flag = ""
if text.startswith("http") and domain_of("x@" + re.sub(r"^https?://", "", text).split("/")[0]) != re.sub(r"^https?://", "", href).split("/")[0]:
flag = " <-- chữ hiển thị KHÁC đích thật"
print(f"Hiển thị: {text}\n Đích : {href}{flag}")
urls.append(href)
print("\n== 5. Tệp đính kèm ==")
files = []
for part in msg.iter_attachments():
name = part.get_filename()
data = part.get_payload(decode=True)
sha = hashlib.sha256(data).hexdigest()
dbl = len(name.split(".")) > 2
print(f"Tên : {name}{' <-- đuôi kép' if dbl else ''}\nSHA-256: {sha}")
files.append((name, sha))
print("\n== 6. Danh sách IoC (đã defang) ==")
rows = [("ip", defang(ip)), ("domain", defang(d_reply)), ("domain", defang(d_ret))]
for u in urls:
rows.append(("url", defang(u)))
host = re.sub(r"^https?://", "", u).split("/")[0]
if not re.fullmatch(r"[\d.]+", host): rows.append(("domain", defang(host)))
for n, s in files: rows.append(("sha256", s)); rows.append(("filename", n))
seen = set(); out = []
for r in rows:
if r not in seen and r[1]: seen.add(r); out.append(r)
with open("ioc.csv", "w", newline="") as f:
w = csv.writer(f); w.writerow(["loai", "gia_tri"]); w.writerows(out)
for r in out: print(f"{r[0]:9} {r[1]}")
print("\nĐã ghi ioc.csv")
Bước 5. Chạy.
bash
python3 phan_tich.py mau.eml
text
== 1. Tiêu đề và nguồn gốc == From : Ngân hàng ABC - Bộ phận Bảo mật <baomat@ngan-hang-abc.example> Reply-To : hotro.khancap@mail-ngan-hang-abc.example Return-Path : <bounce@mail-relay.fake-vendor.example> Subject : [KHẨN] Tài khoản của quý khách sẽ bị khóa trong 24 giờ Date : Mon, 19 Oct 2026 02:13:55 +0700 Message-ID : <20261019021355.7f3a@mail-relay.fake-vendor.example> Received : from mail-relay.fake-vendor.example (unknown [203.0.113.45]) by mx.congty.example with ESMTP; Mon, 19 Oct 2026 02:14:08 +0700 == 2. Xác thực (SPF/DKIM/DMARC) == SPF : fail DKIM : none DMARC : fail == 3. So khớp tên miền == From : ngan-hang-abc.example Reply-To : mail-ngan-hang-abc.example <-- KHÁC From Return-Path: mail-relay.fake-vendor.example <-- KHÁC From == 4. Liên kết == Hiển thị: https://ngan-hang-abc.example/xac-minh Đích : http://203.0.113.45/login/abc <-- chữ hiển thị KHÁC đích thật Hiển thị: trang hướng dẫn Đích : http://ngan-hang-abc-secure.example/huong-dan == 5. Tệp đính kèm == Tên : HoaDon_T10.pdf.exe <-- đuôi kép SHA-256: 44085bd41016f20be3f34d7635fb9aa00672de80aeb88e10027087b2bbce7984 == 6. Danh sách IoC (đã defang) == ip 203[.]0[.]113[.]45 domain mail-ngan-hang-abc[.]example domain mail-relay[.]fake-vendor[.]example url hxxp://203[.]0[.]113[.]45/login/abc url hxxp://ngan-hang-abc-secure[.]example/huong-dan domain ngan-hang-abc-secure[.]example sha256 44085bd41016f20be3f34d7635fb9aa00672de80aeb88e10027087b2bbce7984 filename HoaDon_T10.pdf.exe Đã ghi ioc.csv
Đọc kết quả từng phần
| Phần | Điều quan sát | Ý nghĩa |
|---|---|---|
| 1 | Received cho thấy máy gửi có IP 203.0.113.45, tên mail-relay.fake-vendor.example |
Thư không đi ra từ hệ thống của ngân hàng. Đây là nơi bắt đầu truy vết |
| 2 | SPF: fail, DKIM: none, DMARC: fail |
Máy gửi không được phép gửi thay tên miền ngân hàng, thư không có chữ ký, và chính sách DMARC không đạt (Bài 22) |
| 3 | Reply-To và Return-Path đều khác From |
Trả lời sẽ đi tới miền khác. Đây là dấu hiệu giả mạo rất hay gặp |
| 4 | Chữ hiển thị là https://ngan-hang-abc.example/xac-minh nhưng đích thật là http://203.0.113.45/login/abc |
Liên kết lừa mắt: nạn nhân tin vào chữ, trình duyệt đi theo đích. Đích còn là địa chỉ IP trần chứ không phải tên miền của ngân hàng |
| 5 | Tệp tên HoaDon_T10.pdf.exe |
Đuôi kép: trông như PDF nhưng thật ra là chương trình chạy được (.exe). Đây là dấu hiệu của trojan (Bài 28) |
| 6 | Danh sách IoC | Thành phẩm để đưa cho đội phòng thủ |
Điều quan trọng cần nhớ: không dấu hiệu nào một mình là bằng chứng tuyệt đối, nhưng nhiều dấu hiệu khớp nhau thì kết luận rất chắc (Bài 33).
🧾 Phần 4: IoC, defang và ghi ra CSV
Phần 6 của kết quả là danh sách IoC. Ba điểm đáng chú ý:
- Defang là viết lại để không bấm nhầm được:
httpthànhhxxp, dấu chấm.thành[.]. Nhờ vậy khi dán vào email, tài liệu hay chat, liên kết không tự động trở thành đường dẫn bấm được và trình đọc thư không tự truy cập. - IoC khác nhau cho mục đích khác nhau: IP và domain để chặn ở tường lửa hoặc lọc DNS, URL để chặn ở proxy, hash để tìm tệp ở máy người dùng bằng EDR, tên tệp để tìm trong nhật ký cổng thư.
- Thư mẫu cũng cho thấy một tên miền na ná thương hiệu (
ngan-hang-abc-secure.example) trong liên kết thứ hai. Dạng tên miền tương tự thương hiệu này là typosquatting (Bài 23).
Bước 6. Xem tệp CSV vừa ghi.
bash
cat ioc.csv
text
loai,gia_tri ip,203[.]0[.]113[.]45 domain,mail-ngan-hang-abc[.]example domain,mail-relay[.]fake-vendor[.]example url,hxxp://203[.]0[.]113[.]45/login/abc url,hxxp://ngan-hang-abc-secure[.]example/huong-dan domain,ngan-hang-abc-secure[.]example sha256,44085bd41016f20be3f34d7635fb9aa00672de80aeb88e10027087b2bbce7984 filename,HoaDon_T10.pdf.exe
Trên Windows dùng type ioc.csv. Tệp này có thể nhập thẳng vào nhiều công cụ phòng thủ. Điều Nam làm tiếp theo trong thực tế: chặn các IoC mạng, tìm trong nhật ký cổng thư xem ai khác đã nhận cùng thư, kiểm tra ai đã bấm liên kết, và gửi báo cáo cho đội ứng phó.
🧭 Hình 36b. Bốn bước: thu thập, phân tích, trích IoC, hành động.
🔄 Phần 5 (làm thêm): thử đổi dữ liệu và quan sát
Thử 1. Trong tao_mau.py, đổi spf=fail thành spf=pass rồi chạy lại cả hai tập lệnh. Phần 2 đổi, nhưng phần 3, 4, 5 vẫn báo bất thường. Bài học: SPF đạt không có nghĩa là thư an toàn. Kẻ tấn công có thể dùng chính tên miền của họ, hợp lệ về mặt kỹ thuật nhưng giả mạo về mặt giao diện.
Thử 2. Sửa Reply-To trùng với From. Dòng "KHÁC From" ở Reply-To biến mất, nhưng liên kết và tệp đính kèm vẫn còn dấu hiệu.
Thử 3. Đổi tên tệp đính kèm thành HoaDon_T10.pdf. Cờ "đuôi kép" biến mất. Nhưng tên tệp chỉ là một dấu hiệu, và hash vẫn là IoC chính xác nhất cho tệp đó (khi so với nguồn thông tin mối đe dọa).
Qua ba thử nghiệm bạn thấy vì sao cần nhìn nhiều chỗ cùng lúc thay vì dựa vào một kiểm tra duy nhất.
🧹 Dọn dẹp và bước tiếp theo
bash
cd .. && rm -rf lab-phishing
Trên Windows: xóa thư mục lab-phishing bằng Explorer. Trong thực tế, các tổ chức thường dùng bộ lọc thư tự động, công cụ sandbox để mở tệp đính kèm trong môi trường cách ly, và quy trình báo cáo phishing một chạm cho nhân viên. Tập lệnh trong bài chỉ để bạn hiểu từng bước diễn ra bên trong.
🛠️ Gỡ lỗi thường gặp
| Triệu chứng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
python3: command not found |
Chưa cài Python hoặc trên Windows tên lệnh là python |
Cài Python 3 hoặc dùng python |
SyntaxError khi chạy |
Sao chép thiếu hoặc thừa dòng, thụt lề sai | Sao chép lại nguyên khối mã, giữ nguyên thụt lề |
FileNotFoundError: mau.eml |
Chưa chạy tao_mau.py hoặc đang ở thư mục khác |
Chạy tao_mau.py trước, và chạy cả hai lệnh trong cùng một thư mục |
| Chữ tiếng Việt bị lỗi trên Windows | Bảng mã của cửa sổ lệnh | Chạy trong Windows Terminal hoặc đặt chcp 65001 |
| SHA-256 khác với bài | Sửa nội dung hoặc tên tệp đính kèm trong tao_mau.py |
Dùng đúng nội dung mẫu, hoặc chấp nhận hash khác nếu bạn đã chủ động sửa |
📌 Tóm tắt nhanh
- Đọc email theo danh sách cố định: nguồn gốc, xác thực, tên miền khớp nhau, liên kết, tệp đính kèm.
Fromcó thể giả. Hãy xemReceived,Return-Path,Reply-Tovà kết quả SPF, DKIM, DMARC.- Chữ hiển thị của liên kết có thể khác đích thật. Đích là IP trần hoặc tên miền na ná thương hiệu là dấu hiệu xấu.
- Đuôi kép (
.pdf.exe) là dấu hiệu tệp thực thi giả dạng tài liệu. - IoC cần được defang trước khi chia sẻ và chuyển cho đội phòng thủ: chặn, tìm trong nhật ký, báo cáo.
💬 Hỏi & Đáp nhanh
❓ SPF, DKIM, DMARC đều đạt thì thư an toàn chưa? Chưa chắc. Chúng chứng minh thư đến từ tên miền đó và không bị sửa, không chứng minh nội dung lành. Kẻ tấn công có thể dùng tên miền của chính họ (hợp lệ nhưng giả mạo thương hiệu), hoặc chiếm tài khoản thật. Phải xem thêm liên kết, tệp đính kèm và bối cảnh.
❓ Vì sao phải defang IoC? Để không ai vô tình bấm hoặc để công cụ tự động không truy cập vào liên kết nguy hiểm khi bạn dán vào báo cáo, chat hay email.
❓ Nên làm gì khi nhân viên đã lỡ bấm vào liên kết? Báo ngay cho bộ phận bảo mật, đổi mật khẩu và thu hồi phiên của tài khoản, bật hoặc kiểm tra MFA, quét máy, và tìm trong nhật ký xem liên kết đó có bị truy cập từ máy khác không. Báo sớm quan trọng hơn là sợ bị trách.
📝 Bài tập đánh giá
Tự chọn đáp án cho từng câu, rồi đối chiếu với phần đáp án ở cuối bài.
Câu 1. Trong email mẫu, Reply-To và Return-Path khác miền với From. Điều này gợi ý gì?
- A. Thư có thể bị giả mạo người gửi
- B. Thư được mã hóa tốt
- C. Thư đã qua kiểm tra DMARC
- D. Thư sẽ tự xóa sau 24 giờ
Câu 2. Chữ hiển thị của liên kết là https://ngan-hang-abc.example/xac-minh nhưng đích thật là http://203.0.113.45/login/abc. Nhận định đúng nhất là gì?
- A. Liên kết an toàn vì chữ hiển thị là HTTPS
- B. Liên kết đáng ngờ vì chữ hiển thị khác đích thật và đích là địa chỉ IP
- C. Liên kết bị hỏng
- D. Chỉ cần đổi sang HTTPS là an toàn
Câu 3. Tệp đính kèm tên HoaDon_T10.pdf.exe cho biết điều gì?
- A. Đây là tài liệu PDF bình thường
- B. Đây là tệp thực thi giả dạng tài liệu bằng đuôi kép
- C. Đây là ảnh
- D. Tệp bị nén
Câu 4. Vì sao khi ghi IoC vào báo cáo nên viết hxxp://203[.]0[.]113[.]45?
- A. Để tăng tốc truy cập
- B. Để mã hóa địa chỉ
- C. Để không ai vô tình bấm được và công cụ tự động không truy cập
- D. Vì máy chủ chỉ nhận định dạng này
Câu 5. SPF và DKIM đều đạt nhưng thư vẫn chứa liên kết tới trang đăng nhập giả. Kết luận hợp lý nhất là gì?
- A. Thư chắc chắn an toàn
- B. Các kiểm tra xác thực không phát hiện nội dung lừa đảo, cần xem thêm liên kết, tệp và bối cảnh
- C. DKIM bị lỗi
- D. Không bao giờ cần xem liên kết
👉 Đáp án
Câu 1: A — Reply-To và Return-Path khác miền From là dấu hiệu giả mạo người gửi rất thường gặp.
Câu 2: B — Chữ hiển thị khác đích thật và đích là IP trần là dấu hiệu lừa đảo. HTTPS trong chữ hiển thị không có ý nghĩa gì.
Câu 3: B — .pdf.exe là tệp thực thi giả dạng PDF bằng đuôi kép, dấu hiệu của trojan.
Câu 4: C — Defang giúp tránh bấm nhầm và tránh công cụ tự động truy cập vào liên kết nguy hiểm.
Câu 5: B — SPF, DKIM chỉ chứng minh nguồn và tính toàn vẹn, không chứng minh nội dung lành. Cần kết hợp nhiều dấu hiệu.
📚 Bài viết thuộc khóa học CompTIA Security+ của VNExperts