Dùng LLM đọc 50k dòng log IIS: cái gì hiệu quả, cái gì là ảo tưởng
Thử dùng LLM để đọc qua log IIS của một web server nghi bị dò webshell. Kết quả: nó giỏi hơn mình tưởng ở một số việc, và ảo tưởng đáng sợ ở những việc khác. Đây là những gì thực sự hiệu quả.
Một web server nội bộ bị nghi có webshell sau khi phát hiện traffic bất thường. Log IIS trong 7 ngày: hơn 50,000 dòng. Đọc tay là không khả thi trong thời gian cho phép — đây là lúc mình thử nghiêm túc dùng LLM như một trợ lý triage, thay vì chỉ nói chuyện chơi.
Bước lọc thô — LLM không nên làm việc mà regex làm tốt hơn
import re
SUSPICIOUS_EXT = re.compile(r"\.(aspx|asp|jsp|php)\?", re.IGNORECASE)
LONG_QUERYSTRING = 300 # ký tự
def is_suspicious(line: str) -> bool:
parts = line.split()
if len(parts) < 10:
return False
uri, query = parts[6], parts[7] if len(parts) > 7 else ""
return bool(SUSPICIOUS_EXT.search(uri)) or len(query) > LONG_QUERYSTRING
with open("iis_log_7days.log") as f:
suspicious = [line for line in f if is_suspicious(line)]
print(f"Còn lại {len(suspicious)} / tổng số dòng sau khi lọc thô")Kết quả: 50,000 dòng xuống còn 340 dòng. Đây là bước quan trọng nhất của cả quy trình, và nó không cần LLM — regex và domain knowledge cơ bản làm việc này rẻ hơn, nhanh hơn, và đáng tin cậy hơn.
Việc LLM làm tốt: tóm tắt pattern và gợi ý hướng điều tra
Đưa 340 dòng đã lọc (chia batch 50 dòng/lần) vào LLM với prompt có cấu trúc:
Đây là các dòng log IIS đã được lọc vì chứa extension thực thi hoặc
query string dài bất thường. Với mỗi dòng, hãy:
1. Nhóm các request có pattern giống nhau (cùng IP, cùng path, cùng
kiểu payload trong query string)
2. Với mỗi nhóm, mô tả ngắn gọn pattern đó là gì
3. KHÔNG kết luận đây có phải webshell hay không — chỉ mô tả pattern
[dán 50 dòng log]Cái LLM làm tốt bất ngờ: nhóm 340 dòng thành 12 cụm pattern trong vài giây, và mô tả chính xác một cụm là "các request POST liên tục tới /images/logo.aspx với query string chứa base64, từ cùng 3 địa chỉ IP, cách nhau vài giây" — đúng là dấu hiệu webshell đang được poll bởi attacker. Việc nhóm và tóm tắt hàng trăm dòng thành vài cụm có mô tả là việc LLM tiết kiệm được nhiều thời gian nhất — việc này vốn là lao động thủ công buồn tẻ, không cần khả năng suy luận sâu.
Việc LLM ảo tưởng: tự tin kết luận điều nó không thể biết
Khi mình đổi prompt, hỏi trực tiếp "dòng log này có phải webshell không?", LLM trả lời rất tự tin — và sai ở ít nhất hai trường hợp mình kiểm chứng lại thủ công:
Input: một request GET tới /admin/login.aspx?returnurl=%2fDashboard
LLM: "Đây có khả năng cao là webshell dựa trên tham số returnurl
đáng ngờ, khuyến nghị cách ly ngay."
Thực tế: đây là redirect chuẩn của ASP.NET Forms Authentication,
hoàn toàn hợp lệ, xảy ra hàng nghìn lần mỗi ngày trên
mọi ứng dụng .NET có login form.LLM không có ngữ cảnh về việc returnurl là một tham số chuẩn cực kỳ phổ biến trong ASP.NET — nó chỉ thấy "tham số chứa đường dẫn, trông giống thứ có thể lợi dụng" và suy luận theo hướng đó với vẻ tự tin y hệt khi nó đúng. Không có cách nào phân biệt câu trả lời LLM đúng và LLM sai chỉ bằng cách đọc văn phong của câu trả lời — cả hai đều tự tin như nhau.
Quy tắc mình áp dụng sau lần này
| Việc | Có nên dùng LLM? |
|---|---|
| Lọc thô hàng chục nghìn dòng theo tiêu chí rõ ràng | Không — regex/script rẻ hơn, đáng tin hơn |
| Nhóm cụm và tóm tắt pattern từ dữ liệu đã lọc | Có — tiết kiệm thời gian rõ rệt |
| Kết luận cuối cùng "đây có phải tấn công không" | Không — luôn tự verify bằng kiến thức domain |
| Gợi ý hướng điều tra tiếp theo ("nên kiểm tra thêm gì") | Có — hữu ích như một checklist tư duy, không phải câu trả lời |
Kết luận sau case này: LLM là một trợ lý đọc nhanh, không phải một analyst thứ hai. Nó rút ngắn thời gian từ "50,000 dòng log" xuống "12 cụm pattern cần xem xét" — một khoảng thời gian tiết kiệm thật. Nhưng quyết định cuối cùng về webshell hay không vẫn phải đi qua một người hiểu ASP.NET đủ để biết returnurl là chuyện bình thường.