Xây dựng framework hỗ trợ phát hiện lỗ hổng WordPress bằng AI
Trong bối cảnh hệ sinh thái WordPress ngày càng mở rộng với hàng chục nghìn plugin và theme, việc rà soát bảo mật thủ công trở nên khó đáp ứng yêu cầu về tốc độ và quy mô. Chuyên gia an toàn thông tin Bùi Đức Tài (FPT IS) chia sẻ cách xây dựng một framework kết hợp phân tích tĩnh, AI đa tầng và xác minh thực tế nhằm hỗ trợ quá trình phát hiện lỗ hổng hiệu quả hơn.
Cách tôi xây dựng quy trình săn lỗ hổng WordPress
Trong hai tháng qua, tôi đã xây dựng và thử nghiệm một framework săn tìm lỗ hổng cho hệ sinh thái WordPress. Đây là một hệ thống giúp tôi sử dụng thời gian hiệu quả hơn, rà quét được nhiều mục tiêu hơn, loại bỏ false positive từ sớm, duy trì trạng thái đánh giá qua nhiều lần chạy và liên tục đưa ra những đầu mối tiềm năng nhất để tôi đánh giá và xác minh.
Ở mức độ tổng quan, công cụ kết hợp phân tích tĩnh quy trình đánh giá nhiều giai đoạn bằng AI , xác minh trên môi trường thử nghiệm và báo cáo kết quả. Mô hình này được áp dụng cho cả plugin và theme, dù mỗi loại đều có những đặc thù riêng.
Vì sao tôi xây dựng nó theo cách này
Hệ sinh thái plugin và theme WordPress quá lớn để có thể rà soát thủ công ở bất kỳ quy mô thực tế nào. Ngay cả khi tôi chỉ tập trung vào một số loại lỗ hổng cụ thể, vẫn có một lượng mã nguồn khổng lồ, cùng rất nhiều phát hiện ban đầu từ công cụ phân tích tĩnh trông đáng ngờ nhưng lại không thực sự dẫn đến lỗ hổng sau khi phân tích kỹ hơn .
SAST làm tốt trong việc tìm kiếm các pattern lỗi trong source code, nhưng đồng thời cũng đưa về quá nhiều kết quả false positive. Và việc giao cho một mô hình ngôn ngữ lớn (LLM) nhiệm vụ đánh giá toàn bộ mã nguồn” mà không theo một cấu trúc cụ thể vừa tốn kém vừa thiếu tin cậy. Vì vậy tôi lên ý tưởng xây dựng quy trình tìm lỗi theo từng giai đoạn.
Ý tưởng cơ bản là: thực hiện các bước kiểm tra dựa trên rule với chi phí thấp trước, chỉ dành các bước phân tích tốn tài nguyên cho những kết quả đã vượt qua vòng sàng lọc ban đầu ; và giữ human-in-the-loop ở các bước cuối cùng.
Quy trình tổng quan
1. Thu thập và quét tĩnh
Quy trình bắt đầu bằng việc quét mã nguồn ở quy mô lớn. Điều đó có nghĩa là liên tục tải xuống plugin và theme WordPress, sau đó đưa chúng qua một bước static analysis được thiết kế riêng cho môi trường WordPress.
Công cụ rà quét là Semgrep với bộ rule tùy chỉnh được tối ưu cho các pattern bảo mật đặc thù của WordPress, những attack surface mà tôi tập trung vào , chẳng hạn như dữ liệu được đưa vào vào các sink nguy hiểm, thiếu cơ chế phân quyền trên AJAX/REST handler, deserialization không an toàn, file inclusion, các sink XSS ….
Mục tiêu của vòng quét đầu tiên là bao quát rộng. Nhiệm vụ của nó không phải là kết luận “đây là một lỗ hổng”, mà là “Đây có phải là thứ đáng để xem xét kỹ hơn hay không?”.

2. Giai đoạn 0: Phân loại sơ bộ dựa trên Rule-Based Triage
Sau khi hoàn tất quá trình quét ban đầu, framework sẽ áp dụng thêm một lớp lọc dựa trên các rule đơn giản trước khi chuyển sang bất kỳ bước đánh giá chuyên sâu nào. Giai đoạn này tồn tại vì một lý do: phân tích tĩnh luôn tạo ra nhiều false positive, và không có lý do gì để tốn tài nguyên AI hoặc thời gian vào những kết quả rõ ràng là không có giá trị.
Giai đoạn này đảm nhiệm các công việc tuy đơn giản nhưng rất quan trọng :
- Gom các phát hiện thành những nhóm đánh giá nhỏ hơn thay vì xử lý từng kết quả một các độc lập một file mã nguồn có thể tạo ra hàng chục finding thuộc cùng một bug class).
- Loại bỏ các kết quả false positive rõ ràng như đường dẫn được sinh tự động hoặc các thành phần không liên quan đến quá trình đánh giá bảo mật.
- Lọc bỏ các phát hiện rõ ràng không thể khai thác dựa trên các kiểm tra regex đơn giản.
- Tách riêng các finding có độ tin cậy thấp — những trường hợp “có thể đáng để xem thủ công vào một thời điểm nào đó” — thay vì để chúng lẫn vào pipeline phân tích chính
Giai đoạnnày còn đóng vai trò như một cơ chế kiểm soát chất lượng cho toàn bộ pipeline phía sau. Nếu một finding không vượt qua được những bước kiểm tra cơ bản, thì sẽ không được chuyển tiếp đến các giai đoạn sau.

3. Loại bỏ trùng lặp và tái sử dụng trạng thái đánh giá trước đó
Quá trình quét plugin và theme WordPress thường tạo ra rất nhiều kết quả trùng lặp. Nhiều rule khác nhau có thể cùng đánh dấu một sink, một plugin có thể được quét lại nhiều lần dù phần lớn mã nguồn không thay đổi, và những finding mà tôi đã xem xét rồi loại bỏ trước đó vẫn tiếp tục xuất hiện trong các lần quét sau.
Nếu phải đánh giá lại toàn bộ những kết quả này từ đầu mỗi lần chạy, sẽ lãng phí rất nhiều token AI lẫn thời gian mà không mang lại thêm giá trị nào.
Vì vậy, trước khi một finding được chuyển sang các giai đoạn tiếp theo, framework sẽ hợp nhất các phát hiện chồng lặp, kiểm tra những gì đã được đánh giá trước đó. Chỉ những finding thực sự mới hoặc những trường hợp vẫn còn chưa đủ cơ sở để kết luận mới được chuyển tiếp sang các bước phân tích chuyên sâu tiếp theo

4. Giai đoạn 1: Phân loại AI theo nhóm
Sau khi các kết quả nhiễu rõ ràng đã được loại bỏ, những finding còn lại sẽ được đưa qua một vòng đánh giá bằng các model AI chi phí thấp.
Mục tiêu của giai đoạn này không phải là đưa ra kết luận chắc chắn, mà là phân loại và sắp xếp mức độ ưu tiên. Mỗi finding thường sẽ được xếp vào một trong ba nhóm :
- Đáng để phân tích sâu hơn .
- Có khả năng là false positive.
- Chưa đủ thông tin để kết luận .
Một điểm khác biệt trong framework này là tôi không đánh giá từng finding một cách độc lập. Thay vào đó, các finding thuộc cùng một file hoặc cùng một khu vực mã nguồn sẽ được nhóm lại và phân tích cùng nhau.
Lý do là bởi những yếu tố thực sự quyết định khả năng khai thác của một finding thường không nằm ở chính dòng mã bị đánh dấu, mà nằm trong phần ngữ cảnh xung quanh. Nếu chỉ nhìn vào một finding riêng lẻ, rất dễ bỏ sót những điều kiện quan trọng ảnh hưởng đến mức độ rủi ro thực tế.
Việc phân tích theo nhóm cho phép mô hình AI đặt ra những câu hỏi có giá trị hơn, chẳng hạn như :
- Sink đáng ngờ đó có thực sự có thể truy cập được hay không?
- Có cơ chế kiểm tra phân quyền hoặc xác thực nào ở gần đó mà static analysis không theo dõi được không
- Khi xem xét toàn bộ data flow trong ngữ cảnh xung quanh, dữ liệu này còn dẫn tới rủi ro bảo mật hay không ?
Kết thúc giai đoạn này, mục tiêu không phải là đạt độ chính xác hoàn hảo. Thay vào đó, mục tiêu là thu hẹp danh sách ban đầu thành một hàng đợi nhỏ hơn gồm những finding thực sự xứng đáng được phân tích chuyên sâu ở các bước tiếp theo

5. Giai đoạn 2: Đánh giá chuyên sâu theo ngữ cảnh
Đây là giai đoạn mà quá trình đánh giá trở nên chọn lọc hơn và tập trung vào bằng chứng thực tế thay vì chỉ dựa vào việc nhận diện các pattern đáng ngờ
Đối với mỗi finding vượt qua các vòng sàng lọc trước đó, hệ thống sẽ thu thập thêm mã nguồn và ngữ cảnh liên quan xung quanh để trả lời những câu hỏi mà tôi thực sự quan tâm khi đánh giá một lỗ hổng :
- Đây có khả năng thuộc nhóm lỗ hổng nào ?
- Cần mức quyền truy cập nào để khai thác ?
- Đường dẫn thực thi có khả năng khai thác trong thực tế hay không?
- Và quan trọng nhất: bằng chứng thực tế nào hỗ trợ cho kết luận đó?
Ở giai đoạn này, tôi cố gắng tránh việc đưa ra kết luận chỉ dựa trên những dấu hiệu ban đầu. Dù một finding có vẻ giống một lỗ hổng nghiêm trọng đến đâu, nó vẫn cần được chứng minh bằng các bằng chứng cụ thể trong mã nguồn.
Nếu bằng chứng yếu, không đầy đủ hoặc mâu thuẫn, câu trả lời đúng không phải là tự động nâng cấp mức độ chỉ vì nó trông hấp dẫn.
Điều này quan trọng bởi:
- Một sink không có source thực sự thì không phải lỗi.
- Một source mà không thể tác động tới bất kỳ sink có ý nghĩa nào cũng không phải là lỗ hổng.
- Một pattern ban đầu trông có vẻ nguy hiểm nhưng mất đi khả năng khai thác sau khi xem xét trạng thái của ứng dụng (application state), cơ chế sanitization hoặc kiểm soát phân quyền, thì cũng không nên được xem là một lỗ hổng bảo mật.
Hãy xem một vài ví dụ
Trong trường hợp này, như bạn có thể thấy sau khi chạy Giai đoạn 1 (Quick AI triage), AI rất tự tin rằng đây là một false positive finding và quyết định không chuyển nó sang Giai đoạn 2.

Trong trường hợp khác, phát hiện đó được chuyển sang Giai đoạn 2 và mô hình AI ở giai đoạn này rất tự tin rằng đây là một lỗ hổng thực sự.

Tuy nhiên, sau khi xác minh động trong môi trường thử nghiệm bằng Claude Code, kết quả cuối cùng cho thấy đây vẫn là một false positive finding.

Về cơ bản, finding nào từ Giai đoạn 2 với bằng chứng chắc chắn, tức những phát hiện mà tôi cho là có khả năng cao là lỗ hổng thực sự, sẽ được đưa vào quy trình xác minh với Claude code.
Quy trình đó có cấu trúc và các skills riêng cần tuân theo tùy thuộc vào loại lỗi, và đó là nội dung của phần tiếp theo.
6. Nâng cấp mức độ ưu tiên, xác minh cục bộ và báo cáo
Những finding có độ tin cậy cao sẽ được chuyển sang quy trình xử lý riêng
Ở giai đoạn này, tôi thường cân nhắc nhiều yếu tố khác nhau như loại lỗ hổng, mức độ ảnh hưởng tiềm năng, độ chắc chắn của các bằng chứng đã thu thập được, và đôi khi đơn giản là liệu finding đó có đủ thuyết phục để đáng bỏ thời gian hay không.
Khi quyết định xác minh một finding, tôi thường sử dụng Claude Code như một trợ lý hỗ trợ quá trình kiểm chứng. Tùy thuộc vào từng nhóm lỗ hổng, tôi có thể cung cấp cho nó các hướng dẫn hoặc kỹ năng chuyên biệt để tập trung vào những lĩnh vực cụ thể như XSS, SQL Injection, deserialization, file inclusion, … hoặc hỗ trợ viết báo cáo.

Xung quanh đó, tôi có các script hỗ trợ và quy trình phụ xử lý những công việc lặp đi lặp lại như chuẩn bị hoặc đặt lại môi trường WordPress cục bộ, cài đặt hoặc gỡ bỏ plugin mục tiêu, thu thập ngữ cảnh xác thực phù hợp và thực hiện các bước thăm dò quyền truy cập hoặc thiết lập khác một cách có cấu trúc.



Cấu trúc này giúp quá trình xác minh trở nên hiệu quả hơn đáng kể. Claude không phải bắt đầu từ con số không mỗi lần kiểm tra một finding mới. Thay vào đó, nó được cung cấp sẵn hướng dẫn phù hợp với loại lỗ hổng đang đánh giá cùng với một môi trường đã được chuẩn bị đúng ngữ cảnh.
Nhờ vậy, Claude có thể tập trung vào việc trả lời câu hỏi thực sự quan trọng — liệu finding này có thể khai thác được hay không — thay vì tiêu tốn thời gian và token cho việc thiết lập môi trường, khám phá mã nguồn hoặc cố gắng hiểu mình đang phân tích điều gì.
Phần báo cáo cũng tuân theo cùng một triết lý. Mỗi finding luôn đi kèm toàn bộ lịch sử đánh giá của nó: finding xuất phát từ đâu, tại sao nó vượt qua được các vòng sàng lọc trước đó, những bằng chứng nào đang hỗ trợ cho kết luận hiện tại, và những điểm nào vẫn cần con người xem xét hoặc đưa ra quyết định cuối cùng.
Một ý tưởng mà tôi đang cân nhắc cho tương lai là bổ sung một tầng điều phối riêng dựa trên Claude. Thành phần này sẽ theo dõi các finding mới, tự động chọn ra những trường hợp vừa có dấu hiệu đáng chú ý vừa có khả năng khai thác thực tế, sau đó chủ động khởi động quá trình xác minh khi tôi không có mặt trước máy tính hoặc đang ngủ.
Tôi vẫn khá thận trọng với hướng đi này vì nó đòi hỏi phải đặt nhiều niềm tin hơn vào khả năng đánh giá của AI. Tuy vậy, nếu hoạt động tốt, nó có thể giúp rút ngắn đáng kể khoảng thời gian từ lúc một finding tiềm năng xuất hiện cho đến khi tôi thực sự bắt tay vào đánh giá nó.
Góc nhìn xuyên suốt toàn bộ quy trình
Mỗi phần ở trên mô tả một thành phần riêng trong pipeline. Khi ghép tất cả lại với nhau, toàn bộ quy trình sẽ trông như sau:

Những điều Framework đã làm tốt
Tôi thực sự hài lòng với những gì hệ thống đã mang lại cho đến nay. Nó đã phát hiện được nhiều loại lỗ hổng khác nhau, bao gồm:
- PHP Object Injection nghiêm trọng không yêu cầu xác thực.
- Một số phát hiện SQL Injection có tác động lớn.
- Nhiều trường hợp Cross-Site Scripting (XSS)
- Broken Access Control đơn giản.
- Local File Inclusion và các lỗi liên quan đến đường dẫn.
Điểm mạnh lớn nhất của pipeline này là khả năng biến một khối lượng lớn mã nguồn đã được quét thành những dấu hiệu thực sự đáng để xem xét.
Nó cũng hữu ích về mặt vận hành đơn giản vì nó ghi nhớ mọi thứ. Thay vì hoạt động như một trình quét dùng một lần, nó mang trạng thái qua các lần chạy, cho phép tôi quay lại cùng một plugin hoặc cùng một hệ sinh thái sau nhiều tuần thay vì phải rà soát lại mọi thứ từ đầu.
Bằng chứng kết quả
Framework bắt đầu hoạt động từ cuối tháng 4. Sau khi gửi 9 báo cáo, tôi đạt vị trí thứ 19 trên bảng xếp hạng Patchstack tháng 4, trong đó có một lỗ hổng zero-day với điểm CVSS 9.8.

Bảng xếp hạng tháng 4
Đến tháng 5, kết quả tốt hơn đôi chút khi tôi lọt vào top 9.

Bảng xếp hạng tháng 5
Cho đến nay, tôi đã gửi tổng cộng 31 báo cáo tới PatchStack.

Những hạn chế
Tôi cũng muốn thẳng thắn về các hạn chế.
Về bản chất, đây là một hệ thống ưu tiên phân tích tĩnh, và điều đó đi kèm với những điểm mù. Nó gặp khó khăn với:
- Lỗi logic nghiệp vụ.
- Lỗi sở hữu hoặc phân quyền phụ thuộc vào trạng thái ứng dụng.
- Second-order vulnerabilities
- Chuỗi khai thác nhiều bước.
- Những trường hợp dữ liệu đi qua nhiều lớp wrapper, storage layer hoặc abstraction trước khi tới sink thực sự.
Nói ngắn gọn, nếu một lỗ hổng phụ thuộc nhiều vào cách ứng dụng vận hành trong thực tế thay vì chỉ thể hiện qua một đoạn mã cụ thể, thì độ tin cậy của framework sẽ giảm đi đáng kể
Trên thực tế, framework đã từng bỏ sót những lỗ hổng có mức độ ảnh hưởng cao, bao gồm cả các trường hợp deserialization và SQL Injection nghiêm trọng.
Khi nhìn lại những trường hợp đó, vấn đề thường không nằm ở việc lỗ hổng không thể phát hiện được. Thay vào đó, source và sink nằm quá xa nhau, hành vi nguy hiểm chỉ xuất hiện sau khi dữ liệu đi qua nhiều lớp xử lý, hoặc khả năng khai thác phụ thuộc vào những ngữ cảnh mà chỉ nhìn vào mã nguồn thì gần như không thể nhận ra.
Broken Access Control cũng là một lỗi mà tôi luôn giữ kỳ vọng thực tế. Những trường hợp đơn giản như thiếu kiểm tra quyền hạn thường dễ phát hiện. Các lỗi BAC thực sự thú vị hầu như không bao giờ như vậy. Chúng liên quan đến quyền sở hữu, phạm vi đối tượng hoặc các giả định trong quy trình làm việc, và framework thường không có đủ tín hiệu để phát hiện chúng.
Vì sao xác minh thủ công vẫn quan trọng
Nếu có một điều mà dự án này liên tục nhắc nhở tôi, thì đó là việc phát hiện một thứ gì đó và chứng minh nó là hai việc hoàn toàn khác nhau.
Rất nhiều phát hiện trông rất hứa hẹn trên lý thuyết nhưng không vượt qua được kiểm thử thực tế. Đôi khi WordPress core thay đổi cấu trúc dữ liệu vừa đủ để phá vỡ cách khai thác. Đôi khi sink là thật nhưng kẻ tấn công thực sự không kiểm soát được dữ liệu đầu vào. Đôi khi hướng phân tích đúng nhưng mức độ tác động bị đánh giá quá cao.
Vì vậy, với tôi, xác minh thủ công không phải là lựa chọn. Nó là cánh cổng cuối cùng trước khi tôi tin tưởng bất kỳ phát hiện nào. Framework giúp tôi tiếp cận đúng vấn đề nhanh hơn nhanh hơn, nhưng nó không thay tôi đưa ra kết luận.
Phần tôi thích nhất
Nếu phải chọn điều tôi đánh giá cao nhất trong toàn bộ hệ thống này, đó không phải là “nó tự động tìm ra lỗi”.
Điều tôi thích là nó mang lại cho tôi một cách tiếp cận có cấu trúc để săn lỗi ở quy mô lớn nhưng vẫn thừa nhận rằng những phần khó nhất của công việc vẫn cần con người giải quyết .
Trình quét đưa ra các phát hiện, quá trình đánh giá nhiều giai đoạn loại bỏ nhiễu, các bước phân tích chuyên sâu bổ sung ngữ cảnh, và lớp xác minh/báo cáo giúpchuẩn hóa những bước cuối cùng của quy trình
Thành thật mà nói, những lần bỏ sót các lỗ hổng đôi khi còn có giá trị không kém những lần phát hiện thành công. Chính chúng giúp tôi hiểu được phương pháp hiện tại còn yếu ở đâu và cần cải thiện điều gì.
Vòng phản hồi đó có lẽ là phần giá trị nhất của toàn bộ dự án. Mỗi false positive, mỗi lỗi bị bỏ sót và mỗi phát hiện được xác nhận trở thành dữ liệu phản hồi để cải thiện rule, quy trình review và cách tôi quyết định điều gì thực sự đáng để dành thời gian.
Bên cạnh đó, bước xác minh bằng Claude đã giúp tôi tiết kiệm rất nhiều thời gian trong quá trình tái hiện lỗi. Trong nhiều trường hợp, tôi đã biết chính xác hàm hoặc dòng mã chứa lỗ hổng. Điều tôi chưa biết là làm thế nào để thực sự tiếp cận nó: trang nào, hành động nào, thiết lập plugin nào hoặc yêu cầu nào sẽ kích hoạt đoạn mã bị lỗi.
Việc để Claude làm việc với plugin hoặc giao diện người dùng để tìm ra đường dẫn kích hoạt phù hợp đã giúp tôi tiết kiệm rất nhiều thời gian.
Kết luận
Tôi không xem framework này là sự thay thế cho hoạt động nghiên cứu bảo mật truyền thống. Với tôi, đây là một công cụ khuếch đại hiệu suất .
Khi hoạt động tốt, nó cho phép tôi bao quát nhiều mục tiêu hơn, dành ít thời gian hơn cho những ngõ cụt hiển nhiên và tập trung sự chú ý của bản thân vào những finding có khả năng mang lại kết quả nhất.
Khi nó không hoạt động, đó cũng là một lời nhắc nhở khá tốt về lý do công việc này cuối cùng vẫn phụ thuộc vào khả năng phán đoán, sự hoài nghi và việc thực sự xác minh mọi thứ.
Và khi nhìn vào các nền tảng bug bounty hiện nay như Patchstack, Wordfence và những nền tảng tương tự, việc gửi báo cáo bắt đầu giống như một cuộc đua.

Rất nhiều nhà nghiên cứu đang gửi các lỗ hổng tương tự với khối lượng lớn và tốc độ cao, điều đó cho tôi thấy họ có thể đang vận hành những framework tương tự hoặc thậm chí tiên tiến hơn.
Điều khiến tôi nhận ra rõ hơn là khi xem lại các báo cáo đã được công khai của những nhà nghiên cứu hàng đầu trên bảng xếp hạng Patchstack. Nhiều lỗi trong số đó thực sự phức tạp, thuộc loại rất khó, thậm chí gần như không thể phát hiện chỉ bằng phân tích tĩnh. Khi xem các báo cáo đó, tôi có thể thấy rõ framework của mình sẽ bỏ lỡ những gì.
Vì vậy, dù framework rất hữu ích để nhanh chóng bao quát diện rộng, tôi vẫn tin rằng còn rất nhiều dư địa, cả trong việc cải thiện công cụ lẫn nghiên cứu thủ công theo cách truyền thống, để tìm ra những lỗ hổng sâu hơn, có tác động lớn hơn, những thứ mà các phương pháp dựa trên phân tích tĩnh đơn thuần vốn không được thiết kế để phát hiện.
| Bài viết độc quyền của chuyên gia FPT IS, Tập đoàn FPT
Bùi Đức Tài – Trung tâm An toàn, bảo mật thông tin FPT |

