Khai thác lỗ hổng web tự động bằng AI



This content originally appeared on DEV Community and was authored by Mo0n Sha𝄞ow

Bài viết được dựa trên bài nghiên cứu https://arxiv.org/html/2402.06664v1
Đây là lần đầu tiên mình nghiên cứu về LLM nên có thể có sai sót, mong bạn đọc có thể góp ý bằng cách comment bên dưới hoặc mail về kyhungchien@gmail.com. Xin cảm ơn!

1. Các khái niệm cơ bản

  • AI là viết tắt của từ Artifical Intelligence hay được gọi là trí thông minh nhân tạo.
  • Các mô hình ngôn ngữ lớn (LLM) là các mô hình học sâu rất lớn, được đào tạo trước dựa trên một lượng dữ liệu khổng lồ. https://inwedo.com/blog/llm-ml-models-in-business/
  • ChatGPT (Chat Generative Pre-training Transformer) là một chatbot do OpenAI phát triển dựa trên mô hình Transformer của Google. Đây là một AI (trí tuệ nhân tạo) giúp tạo các cuộc trò chuyện tự động và trả lời các câu hỏi về nhiều chủ đề và lĩnh vực khác nhau. ChatGPT có thể trò chuyện như con người, và điều đặc biệt hơn là nó có khả năng tương tác ở dạng các cuộc hội thoại, đàm thoại tương tự như cách hai con người với nhau. ChatGPT website Mặc dù công cụ này phổ biến, tuy nhiên nó vẫn tồn tại nhiều hạn chế (xin trích lại từ https://viblo.asia/p/langchain-1-diem-qua-cac-chuc-nang-sung-so-nhat-cua-langchain-mot-framework-cuc-ba-dao-khi-lam-viec-voi-llm-BQyJKmrqVMe): Không có tính realtime: Bạn thử lên ChatGPT và hỏi nó về thời tiết ngày hôm nay xem. Nó sẽ không trả lời được đâu. Bởi đơn giản nó chỉ là một mô hình ngôn ngữ và chỉ có có thể trả lời được trên các thông tin nó đã được huấn luyện thôi chứ không thể cập nhật dữ liệu một cách real time được. Ví dụ như hình này luôn cho các bạn dễ hình dung nhé Ask weather Không truy cập được vào các dữ liệu cá nhân: Điều này là chắc chắn rồi. Nó mà trả lời được các thông tin liên quan đến dữ liệu cá nhân của mình thì quá đáng sợ phải không nào. Ví dụ nãy hỏi nó về tài khoản Facebook của bạn xem nó có biết không nhé Ask personal information Đương nhiên câu trả lời cũng là không rồi.

2. Đặt vấn đề và hướng giải quyết cơ bản

Tương tự như ChatGPT, liệu ta có thể tạo ra một phần mềm AI, chỉ cần ra lệnh là nó có thể tự động thu thập dữ liệu và khai thác lỗ hổng Website thông dụng được hay không? Câu trả lời là có thể (mặc dù đã có sẵn nhan nhản các sản phẩm cực kì nổi tiếng như Acunetix, Nessus, … 😂😂). Tuy nhiên để tạo ra nó ta sẽ phải giải quyết một số vấn đề sau:

  • Hệ thống nào sẽ quyết định chính về việc đưa ra logic khai thác và xử lí: chính là hệ thống LLM ở trên, ở đây có thể tự tạo hoặc sử dụng các hệ thống có sẵn. Trong bài viết này, mình sẽ sử dụng chính sản phẩm OpenAI vừa được giới thiệu ở trên, tuy nhiên dưới dạng api.
  • Làm thế nào để hệ thống này tương tác realtime (nếu cần) và truy cập được tới website, dữ liệu cá nhân (target): Điều này có thể tạm thời giải quyết bằng cách từ dữ liệu thu được ở ChatGPT, viết một đoạn code xử lý logic cho phù hợp ¯\_(ツ)_/¯.
  • Tự động hóa quá trình kiểm thử trên front-end: thường thì chúng ta hay dùng Selenium, tuy nhiên trong bài viết này, mình sẽ Playwright vì nó được “hỗ trợ”.
  • Cuối cùng, mình vẫn muốn tự động hóa quá trình xử lý logic từ response của ChatGPT tới Playwright hoặc các logic tương tự khác: điều này là hoàn toàn “có thể”, với sự giúp đỡ của một nhân tố mới “LLM Agents”. Nó là một hệ thống có thể sử dụng LLM để giải quyết vấn đề, lập kế hoạch giải quyết vấn đề và thực hiện chúng với sự trợ giúp của các công cụ đi kèm. Hay nói cách khác, chúng chính là đầu mối trung gian giữa input của người dùng với hệ thống dữ liệu sẵn có LLM. ChatGPT đã làm tốt điều này, tuy nhiên ta cần một bộ công cụ tuyệt vời hơn nữa để tự động hóa luôn cả “hành động” cần làm, thay vì lý thuyết suông như ChatGPT. Ở đây ta sẽ sử dụng một framework có tên là LangChain. LangChain Logo Ngoài ra thư viện này còn cung cấp thêm một số tính năng khác nữa:
  • Cung cấp các component đa dạng: LangChain cung cấp một loạt các component cần thiết cho việc tương tác với các language model. Các component này được thiết kế dễ dàng sử dụng, mở rộng và tuỳ biến cho nhiều bài toán khác nhau. Nôm na có thể hiểu là nó sẽ cung cấp một bộ converter-connector từ các tool thông dụng tới OpenAI.
  • Cung cấp các chains cho các use-case cụ thể: Một chains được hiểu là một chuỗi các component ghép nối lại với nhau theo thứ tự nhất định để từ đó có thể giải quyết được các trường hợp sử dụng trong thực tế. Các use-case mà langchain cung cấp như trợ lý ảo, hỏi đáp dựa trên các tài liệu, chatbot, hỗ trợ truy vấn dữ liệu bảng biểu, tương tác với các API, trích xuất đặc trưng của văn bản, đánh giá văn bản, tóm tắt văn bản. Ở đây có thể hiểu là chi tiết hóa kỹ thuật Prompt Engineering.

3. Xây dựng chương trình

3.1 Nguyên lý hoạt động

Nguyên lý hoạt động
Về căn bản, framework này hoạt động giống như ChatGPT. Tuy nhiên có một số điểm vượt trội:

  • Sau khi nhận được yêu cầu của người dùng, framework sử dụng Prompt Engineering để tái cấu trúc hóa dữ liệu này và đưa dữ liệu vào trong context mà các function của framework hỗ trợ.
  • Sau khi nhận được câu trả lời từ AI, framework sẽ tiến hành chạy các hàm, hoặc xử lý các lệnh, tùy ngữ cảnh cụ thể.

3.2 Xây dựng chương trình

– Chuẩn bị:
+, Python + LangChain + PlayWright LangChain ¯\_(ツ)_/¯
+, Web server chứa lỗ hổng. Ở đây mình dùng lab DVWA. Xem hướng dẫn cài đặt tại https://cehvietnam.com/2022/03/05/dung-nhanh-lab-hack-pentest-web-dvwamutillidae-bwapp-voi-docker-tren-kali-linux/.
+, ChatGPT 4.

– Các bước tiến hành:
+, Đầu tiên import ChatGPT key vảo biến môi trường.

os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY

+, Xác định mục tiêu: Ở đây ta muốn khai thác lỗ hổng SQL injection tại lab vừa tạo có địa chỉ là 127.0.0.1:8088.

command = {
    "input": "Penetration testing 'http://127.0.0.1:8088/vulnerabilities/sqli/' with SQL injection"
}

+, Sau đó ta sẽ phải tạo “Agents”. Nhiệm vụ chính của nó, như đã nói ở trên, là đưa dữ liệu nhập vào thành format đúng định dạng và ngữ cảnh để kết quả trả về có thể thực thi trên các tool có sẵn.

prompt = hub.pull("hwchase17/openai-tools-agent")

Ngoài ra thì thư viện còn có “Agents” hỗ trợ giúp cho AI trả về định dạng JSON, XML, … (https://python.langchain.com/v0.1/docs/modules/agents/agent_types/). Có thể coi đây chính là “thợ đọc lệnh” cho AI (Prompt Engineering). Kết quả là, sau khi thực thi, framework sẽ sinh request tương ứng như sau:

{
    "messages": [
        {
            "content": "You are a helpful assistant",
            "role": "system"
        },
        {
            "content": "Penetration testing 'http://127.0.0.1:8088/vulnerabilities/sqli/' with SQL injection",
            "role": "user"
        }
    ]
}

Tiếp theo xác định các công cụ mà ta muốn AI sử dụng để xử lí yêu cầu. Ở đây ta muốn AI mô phỏng lại quá trình pentest, nên sẽ sử dụng công cụ PlayWright cùng với những hàm mà thư viện này có sẵn để sử dụng.

sync_browser = create_sync_playwright_browser(headless=False)
toolkit = PlayWrightBrowserToolkit.from_browser(sync_browser=sync_browser)
tools = toolkit.get_tools()

Kết hợp với agent ở trên, thì request sẽ có thêm đoạn sau:

{
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "click_element",
                "description": "Click on an element with the given CSS selector",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "selector": {
                            "description": "CSS selector for the element to click",
                            "type": "string"
                        }
                    },
                    "required": [
                        "selector"
                    ]
                }
            }
        },
        {
            "type": "function",
            "function": {
                "name": "navigate_browser",
                "description": "Navigate a browser to the specified URL",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "url": {
                            "description": "url to navigate to",
                            "type": "string"
                        }
                    },
                    "required": [
                        "url"
                    ]
                }
            }
        },
        {
            "type": "function",
            "function": {
                "name": "get_elements",
                "description": "Retrieve elements in the current web page matching the given CSS selector",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "selector": {
                            "description": "CSS selector, such as '*', 'div', 'p', 'a', #id, .classname",
                            "type": "string"
                        },
                        "attributes": {
                            "description": "Set of attributes to retrieve for each element",
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    },
                    "required": [
                        "selector"
                    ]
                }
            }
        },
        ...
    ]
}

Từ đó giúp AI chỉ trả về các dữ liệu trong những action bên trên!
+, Chọn loại AI và model AI (lưu ý phải được hỗ trợ bằng framework trên)

llm = ChatOpenAI(model="gpt-4o", temperature=0)

Các bạn có thể chọn loại AI khác :v
Chat models
Qua đó framework xác định được địa chỉ api tương ứng để gọi, ở đây mình dùng ChatOpenAI nên sẽ là https://api.openai.com/v1/chat/completions. Tùy thuộc vào model tương ứng, các tùy chọn bên trên sẽ biểu thị khác nhau, nhưng ở đây sẽ là:

{
    "model": "gpt-4o",
    "n": 1,
    "stream": true,
    "temperature": 0
}

+, Những thông tin ở trên đã đủ để tạo ra một agent. Tiến hành chạy nó thôi ~~

agent = create_openai_tools_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke(command)

Thật bất ngờ, server sẽ gửi trả về tên các hàm và tham số tương ứng để client có thể thực thi!

data: {
    "id": "chatcmpl-...",
    "object": "chat.completion.chunk",
    "model": "gpt-4o-2024-05-13",
    "system_fingerprint": "fp_...",
    "choices": [
        {
            "index": 0,
            "delta": {
                "role": "assistant",
                "content": null,
                "tool_calls": [
                    {
                        "index": 0,
                        "id": "call_...",
                        "type": "function",
                        "function": {
                            "name": "navigate_browser",
                            "arguments": ""
                        }
                    }
                ]
            },
            "logprobs": null,
            "finish_reason": null
        }
    ]
}
data: {
    "id": "chatcmpl-...",
    "object": "chat.completion.chunk",
    "model": "gpt-4o-2024-05-13",
    "system_fingerprint": "fp_...",
    "choices": [
        {
            "index": 0,
            "delta": {
                "tool_calls": [
                    {
                        "index": 0,
                        "function": {
                            "arguments": "{\""
                        }
                    }
                ]
            },
            "logprobs": null,
            "finish_reason": null
        }
    ]
}
data: {
    "id": "chatcmpl-...",
    "object": "chat.completion.chunk",
    "model": "gpt-4o-2024-05-13",
    "system_fingerprint": "fp_...",
    "choices": [
        {
            "index": 0,
            "delta": {
                "tool_calls": [
                    {
                        "index": 0,
                        "function": {
                            "arguments": "url"
                        }
                    }
                ]
            },
            "logprobs": null,
            "finish_reason": null
        }
    ]
...
}

openai_tools_agent
Từ response trên, framework sẽ gọi hàm navigate_browser, mở trình duyệt với địa chỉ trả về (chính là địa chỉ mà ta yêu cầu).
Tuy nhiên điều này cũng có thể dẫn tới rủi ro về bảo mật, do OpenAI có thể trả về các hàm độc hại tới máy tính. Nếu sử dụng các công cụ Python REPL, framework còn cảnh báo cụ thể tới người dùng
CAUTION
Sau khi trang web được loading xong, framework tiếp tục gọi api đến server với kết quả thu được và chờ lệnh tiếp theo.

{
    "messages": [
        {
            "content": "You are a helpful assistant",
            "role": "system"
        },
        {
            "content": "Penetration testing 'http://127.0.0.1:8088/vulnerabilities/sqli/' with SQL injection",
            "role": "user"
        },
        {
            "content": null,
            "role": "assistant",
            "tool_calls": [
                {
                    "type": "function",
                    "id": "call_...",
                    "function": {
                        "name": "navigate_browser",
                        "arguments": "{\"url\": \"http://127.0.0.1:8088/vulnerabilities/sqli/\"}"
                    }
                }
            ]
        },
        {
            "content": "Navigating to http://127.0.0.1:8088/vulnerabilities/sqli/ returned status code 200",
            "role": "tool",
            "tool_call_id": "call_..."
        }
    ]
}

Cứ tiếp tục như vậy cho đến khi server trả về tín hiệu dừng, ở đây sẽ là đoạn bán json như sau

data: {
    "id": "chatcmpl-...",
    "object": "chat.completion.chunk",
    "model": "gpt-4o-2024-05-13",
    "system_fingerprint": "fp_...",
    "choices": [
        {
            "index": 0,
            "delta": {

            },
            "logprobs": null,
            "finish_reason": "stop"
        }
    ]
}

thì framework sẽ dừng lại. Hoặc ta có thể cấu hình điều kiện nâng cao ở bên trên để dừng lại.
Kết quả thực tế cho thấy, sau đó, AI sẽ parse và đọc nội dung của HTML, tìm xem có dấu hiệu khả nghi, check SQLi chỉ bằng một payload rất đơn giản rồi sau đó kết luận luôn.

The SQL injection payload `' OR '1'='1` was successful. The page returned multiple user records, indicating that the application is vulnerable to SQL injection....
This confirms that the application is vulnerable to SQL injection attacks.
> Finished chain.

Như vậy có thể thấy, model AI này cũng khá thông minh và đã kết luận đúng.
Video demo:

Ngoài ra chúng ta còn có thể đưa thêm tài liệu cho AI hoặc thêm các custom Prompt Engineering để tạo hướng dẫn chi tiết các bước cho một yêu cầu nào đó, …. Tất cả điều này đều làm tăng độ chính xác và hiệu quả cho quá trình tự động hóa này. Mình sẽ không đi sâu vào phần này ¯\_(ツ)_/¯.

4. Ứng dụng

4.1 Tích hợp nuclei

nuclei
Ở đây mình đang hiểu là tích hợp nuclei vào quá trình tự động hóa này, hay nói cách khác, là chỉ cần ra lệnh cho AI thì nó sẽ chạy nuclei với điều kiện thích hợp. Điều này hoàn toàn có thể làm được. Tuy nhiên so với ví dụ trên, ta sẽ phải sử dụng công cụ khác, không phải là PlayWright nữa, mà là PythonREPL, do LangChain chưa hỗ trợ các hàm của nuclei. Hoặc có thể sử dụng tool nuclei_gpt (mình chưa test thử xem có uy tín hay không :v). Bản chất của thư viện PythonREPL chính là thực thi các đoạn mã python do OpenAI trả về. Ta dựa vào đó gọi command nuclei thôi.
Như vậy phải chỉnh lại đoạn code một chút

llm = OpenAI(temperature=0, max_tokens=100)
agent_executor = create_python_agent(llm=llm, tool=PythonREPLTool(), verbose=True, agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION)
agent_executor.run("""Using nuclei tool, -automatic-scan option this url 'http://127.0.0.1:8088/vulnerabilities/sqli/'""")

Kết quả cũng không được khả quan lắm (do dùng ChatGPT 3.5 chăng 🤔)
nuclei
Tương tự, có thể dùng ShellTool để xử lý yêu cầu này.

4.2 Truy vấn dữ liệu realtime

Bài toán đặt ra ở đây là liệt kê danh sách các subdomain của [reacted] để tiến hành xử lý sau này.

  • Đã test với các công cụ như SearchApiAPIWrapper, GoogleSerperAPIWrapper, SerpAPI,… tuy nhiên kết quả thu được lại rất chung chung. Ở đây ta sẽ sử dụng thử công cụ Tavily kết hợp với OpenAI để xử lý.
tools = [TavilySearchResults(max_results=1)]
prompt = hub.pull("hwchase17/openai-tools-agent")
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
agent = create_openai_tools_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke({"input": "List all [reacted] subdomains"})

Ở đây bản chất luồng thực hiện như sau: đầu tiên framework sẽ gọi lên OpenAI xem với yêu cầu này sẽ phải dùng hàm gì với tham số như nào?

{
    "messages": [
        {
            "content": "You are a helpful assistant",
            "role": "system"
        },
        {
            "content": "List all [reacted] subdomains",
            "role": "user"
        }
    ],
    "model": "gpt-4-turbo",
    "n": 1,
    "stream": true,
    "temperature": 0,
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "tavily_search_results_json",
                "description": "A search engine optimized for comprehensive, accurate, and trusted results. Useful for when you need to answer questions about current events. Input should be a search query.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "query": {
                            "description": "search query to look up",
                            "type": "string"
                        }
                    },
                    "required": [
                        "query"
                    ]
                }
            }
        }
    ]
}

Sau đó server sẽ trả về hàm nên sử dụng
Image description
Sau khi thực hiện hàm đó và gửi kết quả lên server, framework sẽ chờ kết quả trả về và tiếp tục lặp lại như vậy cho đến khi nào server gửi tín hiệu dừng lại. Sau khi chạy trên thực tế, kết quả là AI có thực hiện tìm kiếm subdomain nhưng trả về dữ liệu chung chung.
tavily (2)
Tuy nhiên trên đường link trả về đúng là có dữ liệu thật
tavily (3)
Để tăng hiệu quả và tính tự động hóa thì ở đây chúng ta lại dùng tool PythonREPL để call các thư viện khác mà có trả về kết quả luôn. Nguyên lý hoạt động thì giống như bên trên nên ta sẽ không phân tích lại nữa. Kết quả như sau:
PythonREPL
Mặc dù kết quả chưa được ổn lắm, và AI chưa tìm và sử dụng được công cụ phù hợp nhất, tuy nhiên những thông tin này được lấy dựa trên kết quả realtime. Thêm vào đó, framework hỗ trợ tự sửa sai và chỉnh lại đoạn code để có thể thực thi được.

4. Một số nhận xét chung

Do mình mới sử dụng framework này và mới tìm hiểu về LLM nên chưa có nhiều kỹ thuật để sử dụng nó, nên những lời nhận xét sau có thể mang tính cá nhân. Mặc dù đúng là luôn có cách để AI tự động hóa quá trình khai thác lỗ hổng website, theo lệnh của ngôn ngữ con người, tuy nhiên nó lại tồn tại khá nhiều nhược điểm:

  • Hiệu quả làm việc không cao (qua nhiều bài demo ở trên). Muốn cải thiện thì phải bổ sung thêm tài liệu cho AI, hoặc hướng dẫn chi tiết cho nó (Prompt Engineering),…
  • Rủi ro trong chính quá trình sử dụng. Do framework trực tiếp thực thi các hàm được trả về, nên không loại trừ việc AI “vô tình” trả về hàm độc hại cho client.
  • Chi phí cao. Hầu hết các dịch vụ API ở trên đều chỉ ở mức dùng thử và bị giới hạn.
  • Bài nghiên cúu được giới thiệu ở phần mở đầu đã có bài phản biện phê bình.

Mặc dù vậy, có thể tương lai của nó sẽ hoàn hảo hơn. Các bạn có thể tải về và dùng thử.


This content originally appeared on DEV Community and was authored by Mo0n Sha𝄞ow