0

Tấn Công Hạ Tầng AI Qua Model Context Protocol - Phần 1: "Giải Phẫu Giao Thức - Kiến Trúc MCP, Bề Mặt Tấn Công Và Nghệ Thuật Liệt Kê Công Cụ"

Có một điều thú vị mà tôi nhận ra sau nhiều năm làm bảo mật: những cuộc tấn công nguy hiểm nhất không phải là những cuộc tấn công phá vỡ tường lửa hay exploit lỗ hổng zero-day. Chúng là những cuộc tấn công khai thác niềm tin. Và trong thế giới AI hiện đại, không có nơi nào niềm tin bị đặt nhầm chỗ nhiều hơn là giữa các Mô hình Ngôn ngữ Lớn (LLM) và các công cụ mà chúng được phép sử dụng.

Hôm nay tôi muốn kể cho các bạn về một giao thức đang thay đổi cách chúng ta xây dựng hệ thống AI và cũng đang mở ra một bề mặt tấn công mà nhiều đội bảo mật vẫn chưa ý thức hết. Nó có tên là Model Context Protocol, hay MCP.


1. MCP — Khi AI không chỉ nói mà còn làm

Hãy tưởng tượng bạn có một trợ lý AI không chỉ trả lời câu hỏi. Nó có thể đọc file trên máy tính của bạn. Nó có thể truy vấn cơ sở dữ liệu. Nó có thể gửi tin nhắn Slack thay bạn. Nó có thể chạy lệnh git, tạo commit, thậm chí push code lên repository.

Nghe tiện đấy chứ? Đó chính là sức mạnh của MCP.

Nhưng đây là mặt tối của nó: khi AI có quyền đọc file, truy vấn database, hay gửi tin nhắn, thì bất kỳ ai có khả năng ảnh hưởng đến hành vi của LLM đều kế thừa toàn bộ quyền hạn đó. Không cần exploit kernel. Không cần bypass firewall. Chỉ cần nói chuyện với AI đúng cách.

Đây không phải là bảo mật ứng dụng truyền thống, nơi kẻ tấn công tương tác trực tiếp với các endpoint. Đây là một cuộc chơi hoàn toàn khác — nơi kẻ tấn công khai thác mối quan hệ tin cậy giữa LLM và các công cụ của nó.

1.1. MCP hoạt động như thế nào?

Nói một cách đơn giản, MCP là một giao thức chuẩn hóa cho phép LLM tương tác với các hệ thống bên ngoài. Hãy nghĩ về nó như một "bộ chuyển đổi vạn năng" — thay vì mỗi LLM phải tự xây dựng tích hợp riêng cho từng công cụ, MCP cung cấp một ngôn ngữ chung để mọi thứ kết nối với nhau.

Về mặt kỹ thuật, MCP sử dụng JSON-RPC làm cơ chế nhắn tin. Có hai lớp giao vận chính:

  • stdio: Giao tiếp qua stdin/stdout. Thường dùng cho các công cụ chạy cục bộ trên workstation của nhà phát triển. Nhanh, đơn giản, không qua mạng.
  • HTTP/SSE: Giao tiếp qua mạng. Thường dùng cho các hệ thống tự hành, nhiều người dùng, nơi công cụ chạy trên server từ xa.

Điểm mấu chốt cần nhớ: LLM không trực tiếp gọi công cụ. Nó yêu cầu client gọi công cụ, và client thực thi yêu cầu đó. Nhưng từ góc độ bảo mật, LLM là "người ra quyết định" — nếu bạn kiểm soát được đầu vào của LLM, bạn kiểm soát được công cụ nào được gọi.

1.2. Hai bối cảnh tấn công hoàn toàn khác nhau

Trong series này, tôi sẽ tập trung vào hai môi trường điển hình mà tôi đã gặp trong các cuộc đánh giá red team thực tế:

  • workstation của nhà phát triển — nơi một nhà phát triển sử dụng VS Code với extension Continue và MCP để hỗ trợ công việc hàng ngày. Công cụ chạy cục bộ qua stdio. Quyền hạn là quyền của user trên máy. Bề mặt tấn công là file hệ thống, git repo, và các công cụ cục bộ.

  • Hệ thống tự hành — nơi một nền tảng AI chung phục vụ nhiều người dùng, với các MCP tool server chạy từ xa qua HTTP/SSE. Quyền hạn là quyền của service account. Bề mặt tấn công là database, API, shared filesystem, và mọi thứ mà service account đó có thể chạm tới.

Hai môi trường này có cùng giao thức nhưng có mức độ rủi ro hoàn toàn khác nhau. Và cách khai thác chúng cũng khác nhau.


2. Giải phẫu một cấu hình MCP thực tế

Đủ lý thuyết rồi. Hãy đi vào một kịch bản cụ thể.

Dave - một developer tại MegaCorpAI - Dave, sử dụng VS Code với extension Continue và MCP để hỗ trợ công việc hàng ngày. Trong khuôn khổ đánh giá bảo mật, chúng tôi đã có được quyền truy cập vào workstation của Dave. Nhiệm vụ bây giờ là liệt kê bề mặt tấn công MCP để hiểu những khả năng mà trợ lý AI của anh ta sở hữu.

2.1. Bước đầu tiên: Đọc cấu hình

Cấu hình MCP của Continue được lưu trong file config.yaml trong thư mục .continue của người dùng. Sử dụng PowerShell, chúng ta có thể đọc nó:

PS C:\Users\dave> type .continue\config.yaml

Và đây là những gì chúng ta tìm thấy:

name: MegaCorpAI AI Assistant
version: 0.0.1
schema: v1

models:
  - name: Qwen3.5 35B
    provider: openai
    model: Qwen/Qwen3.5-35B-A3B-FP8
    apiBase: http://skynet1.offseclabs.com:8000/v1
    apiKey: not-needed

mcpServers:
  - name: filesystem
    type: stdio
    command: node
    args:
      - C:/Users/dave/.lmstudio/mcp-wrapper/fs-server.js
      - C:/Users/dave/dev
      - C:/Users/dave/projects

  - name: git
    type: stdio
    command: node
    args:
      - C:/Users/dave/.lmstudio/mcp-wrapper/git-wrapper.js

  - name: notes
    type: sse
    url: http://tools01:8000/sse

2.2. Đọc vị bề mặt tấn công từ cấu hình

Từ file cấu hình này, chúng ta có thể trích xuất một lượng lớn thông tin tình báo. Hãy cùng phân tích từng máy chủ.

Máy chủ filesystem:

  • Chạy cục bộ qua stdio.
  • Có quyền truy cập vào hai thư mục: C:/Users/dave/devC:/Users/dave/projects.
  • Hệ quả: Bất kỳ file nào trong hai thư mục này đều có thể bị đọc hoặc ghi thông qua giao diện MCP. Và bạn biết đấy, các nhà phát triển thường để đủ thứ trong thư mục dev của họ.

Máy chủ git:

  • Chạy cục bộ qua stdio.
  • Hệ quả: Toàn bộ lịch sử commit — bao gồm cả những secret đã bị xóa — đều có thể truy cập được. Git nhớ mọi thứ, kể cả những gì bạn muốn quên.

Máy chủ notes:

  • Chạy từ xa qua SSE tại http://tools01:8000/sse.
  • Hệ quả: Bề mặt tấn công mở rộng ra ngoài phạm vi workstation cục bộ. Kẻ tấn công có thể truy cập dữ liệu trên server từ xa — nơi có thể chứa thông tin nhạy cảm mà nhà phát triển lưu trữ như ghi chú tạm thời.

Model endpoint:

  • http://skynet1.offseclabs.com:8000/v1 — một máy chủ suy luận chung, không phải model cục bộ.
  • Hệ quả: Dữ liệu gửi đến model có thể đi qua mạng, tạo cơ hội cho tấn công man-in-the-middle hoặc rò rỉ dữ liệu.

Chỉ với một file cấu hình, chúng ta đã có bản đồ sơ bộ về những gì trợ lý AI của Dave có thể làm. Nhưng để có bức tranh đầy đủ, chúng ta cần liệt kê chi tiết các công cụ.

2.3. Liệt kê công cụ qua giao diện người dùng

Mở VS Code và bảng điều khiển Continue (Ctrl+L), chúng ta thấy các MCP server đã kết nối:

image.png

  • filesystem: 4 tools
  • git: 4 tools
  • notes: 5 tools

Tổng cộng 13 công cụ. Nhưng tên công cụ không nói lên nhiều điều. Để có danh sách chi tiết với mô tả, chúng ta có thể hỏi trực tiếp LLM:

Prompt: "What tools do you have available? List each one with a brief description."

image.png

Và đây là những gì LLM trả về:

Filesystem tools:

  • filesystem_read_file: Đọc nội dung file
  • filesystem_list_directory: Liệt kê nội dung thư mục
  • filesystem_search_files: Tìm kiếm file theo pattern
  • filesystem_get_file_info: Lấy metadata của file

Git tools:

  • git_log: Hiển thị lịch sử commit
  • git_show: Hiển thị chi tiết commit
  • git_diff: Hiển thị thay đổi giữa các commit
  • git_status: Hiển thị trạng thái working tree

Notes tools:

  • notes_list_notes: Liệt kê tất cả ghi chú
  • notes_get_note: Lấy nội dung ghi chú theo tên
  • notes_create_note: Tạo ghi chú mới
  • notes_update_note: Cập nhật ghi chú
  • notes_delete_note: Xóa ghi chú

Điều đáng chú ý ở đây là LLM tiết lộ toàn bộ danh sách công cụ mà không cần xác thực bổ sung. Đây là bước đầu tiên của bất kỳ kẻ tấn công nào — hiểu rõ "vũ khí" có sẵn. Và trong trường hợp này, "vũ khí" khá là đầy đủ.


3. Nghệ thuật liệt kê: Từ công cụ đến dữ liệu nhạy cảm

Bây giờ chúng ta đã biết có những công cụ gì. Câu hỏi tiếp theo là: chúng ta có thể làm gì với chúng?

3.1. Khai thác filesystem MCP

Với quyền truy cập filesystem, chúng ta có thể yêu cầu LLM tìm kiếm các file cấu hình nhạy cảm. Hãy thử:

Prompt: "List all files in C:/Users/dave/dev including subfolders, and read any .env or configuration files you find"

LLM sẽ thực thi một chuỗi công cụ:

  1. filesystem_list_directory — liệt kê thư mục
  2. filesystem_search_files — tìm file .env và config
  3. filesystem_read_file — đọc nội dung

image.png

Và đây là kết quả:

DATABASE_URL=postgresql://app_user:Pr0d_DB_s3cret12025@db.devcorp.internal:5432/internal_api
REDIS_URL=redis://:r3d1s_s3cr3t@cache.devcorp.internal:6379/0
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_REGION=us-east-1
JWT_SECRET=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SENTRY_DSN=https://abc123@sentry.devcorp.internal/42
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Chỉ trong một prompt duy nhất, chúng ta đã có thông tin xác thực cơ sở dữ liệu, khóa AWS, JWT secret, Sentry DSN, và Slack webhook URL. Tất cả những gì chúng ta cần làm là yêu cầu LLM đọc những file mà nó có quyền truy cập.

Và tất nhiên, còn nhiều file cấu hình khác để khám phá:

Prompt: "What other config files are in the folder C:/Users/dave/dev or subfolder? Read any configuration files you find"

image.png

LLM tìm thấy file database.yml trong thư mục config của internal-api:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  timeout: 5000

development:
  <<: *default
  host: localhost
  database: internal_api_dev
  username: postgres
  password: localdev123

staging:
  <<: *default
  host: staging-db.devcorp.internal
  database: internal_api_staging
  username: app_user
  password: St@g1ng_Pass!

Thông tin xác thực staging nằm ngay đó, trong một file YAML mà bất kỳ ai có quyền truy cập filesystem đều có thể đọc được.

3.2. Khai thác git MCP

Git lưu giữ toàn bộ lịch sử commit, kể cả những file đã bị xóa. Đây là một sai lầm phổ biến của các nhà phát triển: họ nghĩ rằng xóa file sẽ xóa nó vĩnh viễn. Nhưng git nhớ mọi thứ.

Sử dụng git log, chúng ta có thể phát hiện các commit đáng ngờ:

Prompt: "Show git log for C:/Users/dave/projects/customer-portal"

image.png

Và đây là những gì chúng ta tìm thấy:

Commit Hash: 1ebee4c9279bc78165ca8b084be65d7245963394
Author: Adam Wilson
Email: adam.wilson@devcorp.com
Timestamp: 1770056951 (2023-10-09 14:25:51 UTC)
Subject: Fix: remove production secrets, add gitignore

Commit Hash: 277ca1cc2d7e9886a3f23881b1dc2f874199f192
Author: Adam Wilson
Email: adam.wilson@devcorp.com
Timestamp: 1770056941 (2023-10-09 14:25:41 UTC)
Subject: Add prod env - TEMP for deployment testing

Hai commit này kể một câu chuyện quen thuộc. Commit đầu tiên thêm production secrets vào repo. Commit thứ hai — chỉ 10 giây sau — xóa chúng đi và thêm gitignore. Có vẻ như ai đó đã nhận ra sai lầm và cố gắng sửa chữa.

Nhưng git không hoạt động theo cách đó. Secret vẫn nằm trong commit trước đó, và với git MCP, chúng ta có thể lấy lại chúng mà không cần chạm vào dòng lệnh.

3.3. Khai thác notes MCP từ xa

Máy chủ notes chạy từ xa minh họa cách MCP vượt qua ranh giới mạng. Đây là nơi mọi thứ trở nên thú vị hơn — vì dữ liệu không còn nằm trên máy cục bộ nữa.

Prompt: "What notes are available?"

image.png

LLM liệt kê các ghi chú có sẵn:

  • api-endpoints
  • deploy-checklist
  • aws-temp
  • meeting-notes
  • quick-ref
  • db-connection
  • ssh-hosts

Một số tên ghi chú gợi ý nội dung nhạy cảm. aws-temp đặc biệt thú vị. Hãy thử lấy nó:

Prompt: "Retrieve the contents of the aws-temp note"

image.png

Và đây là những gì chúng ta nhận được:

AWS creds for CI/CD pipeline debugging!

Access Key: AKIAIOSFODNN7EXAMPLE
Region: us-east-1

S3 bucket: devcorp-deployments
ECR repo: 123456789.dkr.ecr.us-east-1.amazonaws.com/internal-api

TODO: move these to GitHub secrets after testing

Thông tin xác thực AWS, được lưu trữ như một tài liệu tham khảo tạm thời. "TODO: move these to GitHub secrets after testing" — có lẽ "sau khi testing" chưa bao giờ đến.

Đây là bài học quan trọng: máy chủ notes từ xa chứa thông tin xác thực AWS có thể được lưu trữ như một tài liệu tham khảo tạm thời. Thông qua MCP, chúng ta có thể truy cập dữ liệu nhạy cảm được lưu trữ trên các hệ thống từ xa mà trợ lý AI của nhà phát triển kết nối đến.

3.4. Khám phá giới hạn quyền hạn

Không phải mọi đường dẫn đều có thể truy cập. Và việc hiểu rõ ranh giới này quan trọng không kém việc khai thác những gì có thể truy cập.

Khi yêu cầu LLM liệt kê nội dung của C:/Users/dave/documents, công cụ trả về lỗi:

image.png

It appears that the directory C:/Users/dave/documents is not within the allowed directories.

Tuy nhiên, C:/Users/dave/projects lại có thể truy cập được. Và trong đó, chúng ta tìm thấy thư mục customer-portal với thư mục .git — dấu hiệu của một git repository.

Việc kiểm tra có hệ thống các đường dẫn giúp xây dựng bản đồ ranh giới quyền hạn. Chúng ta biết được đâu là "vùng cấm" và đâu là "vùng tự do". Và trong bảo mật, biết ranh giới quan trọng không kém biết lỗ hổng.


4. Kỹ thuật liệt kê nâng cao

Đến đây, chúng ta đã có một bức tranh khá rõ về những gì có thể làm với MCP trong môi trường workstation nhà phát triển. Nhưng còn một môi trường khác — hệ thống tự hành, nơi MCP chạy từ xa và phục vụ nhiều người dùng.

4.1. Trích xuất lược đồ công cụ (Tool Schema Extraction)

Mỗi công cụ MCP có một lược đồ (schema) định nghĩa tham số đầu vào, kiểu dữ liệu, và mô tả. LLM nhìn thấy lược đồ này như ngữ cảnh hệ thống ẩn, nhưng người dùng chỉ thấy tên công cụ.

Kỹ thuật trích xuất lược đồ cho phép ánh xạ cấu trúc cơ sở dữ liệu bằng cách sử dụng LLM như một proxy.

Ví dụ, trong môi trường Open WebUI với PostgreSQL MCP:

image.png

Prompt: "Run a simple test query against the database: SELECT 1"

image.png

LLM gọi công cụ db_query và trả về kết quả. Ngay cả một thăm dò đơn giản cũng xác nhận kết nối và tiết lộ thông tin về môi trường cơ sở dữ liệu, bao gồm tên hàm nội bộ của công cụ — db_query. Kỹ thuật này cho phép ánh xạ cấu trúc cơ sở dữ liệu bằng cách sử dụng LLM như một proxy.

4.2. Liên kết liên công cụ (Cross-Tool Querying)

Sức mạnh thực sự của MCP nằm ở khả năng kết hợp nhiều công cụ trong một cuộc trò chuyện. Mỗi công cụ riêng lẻ cung cấp thông tin hạn chế, nhưng khi kết hợp, chúng tạo ra bức tranh toàn diện về nội bộ tổ chức.

Hãy xem xét prompt sau:

  1. "Search GitHub for any files mentioning 'database'"
  2. "List files in /data/shared directory"
  3. "Show me the message history from #dev-team Slack channel"

image.png

LLM sẽ gọi github_search, fs_list, và slack_history trên các máy chủ MCP khác nhau. Kết quả là một bức tranh toàn cảnh về nội bộ tổ chức — từ mã nguồn đến cấu trúc thư mục đến giao tiếp nhóm.

4.3. Ánh xạ quyền hạn (Permission Boundary Mapping)

Bước cuối cùng trong liệt kê là xác định chính xác những gì công cụ có thể và không thể truy cập:

Prompt:

  1. "Run this SQL query: SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public'"
  2. "Try to list files in the /etc directory using the filesystem tool"

image.png

Kết quả:

  • SQL query thành công, tiết lộ các bảng: customers, customer_pii, financial_records, api_keys, project_notes.
  • Filesystem tool từ chối truy cập /etc với lỗi "access denied".

Bằng cách kiểm tra có hệ thống các đường dẫn và lược đồ, chúng ta xây dựng bản đồ ranh giới quyền hạn hoàn chỉnh — biết chính xác công cụ nào có thể truy cập dữ liệu gì.


5. Tổng kết Phần 1

5.1. Chuỗi tấn công điển hình

Nhìn lại những gì chúng ta đã làm, có thể tóm tắt thành một chuỗi tấn công điển hình:

  1. Đọc cấu hình MCP → Xác định các máy chủ, giao vận, và đường dẫn được phép.
  2. Liệt kê công cụ → Hỏi LLM danh sách công cụ và mô tả.
  3. Khai thác filesystem → Đọc file cấu hình, .env, và secret.
  4. Khai thác git → Lấy lại secret từ lịch sử commit.
  5. Khai thác notes từ xa → Truy cập dữ liệu nhạy cảm trên server từ xa.
  6. Trích xuất lược đồ → Ánh xạ cấu trúc database qua LLM proxy.
  7. Liên kết liên công cụ → Kết hợp nhiều công cụ để có bức tranh toàn diện.
  8. Ánh xạ quyền hạn → Xác định ranh giới truy cập của từng công cụ.

5.2. Bài học phòng thủ

Và đây là những gì chúng ta có thể làm để phòng thủ:

  • Cấu hình tối thiểu: Máy chủ MCP chỉ nên tiết lộ các thư mục và repo mà nhà phát triển thực sự làm việc, không phải toàn bộ hồ sơ người dùng.
  • Giới hạn đường dẫn: Sử dụng tham số danh sách để giới hạn đường dẫn có thể truy cập.
  • Quản lý secret: Không bao giờ lưu trữ thông tin xác thực sản xuất trong file .env hoặc lịch sử git trên workstation của nhà phát triển.
  • Secret manager: Sử dụng trình quản lý bí mật và mã thông báo ngắn hạn để loại bỏ lớp rủi ro secret trong repo.

5.3. Điều gì tiếp theo?

Trong Phần 2, chúng ta sẽ khám phá cách kẻ tấn công đầu độc mô tả công cụ để thay đổi hành vi LLM, và cách MCP Apps có thể bị lạm dụng để tạo giao diện phishing thu thập thông tin xác thực. Chúng ta sẽ thấy cách một công cụ review mã lành tính trở thành công cụ lọc dữ liệu, và cách một máy chủ productivity bị đầu độc biến trợ lý AI thành gián điệp.

Nếu bạn nghĩ rằng việc đọc file .env là đáng sợ, hãy đợi đến khi bạn thấy một công cụ có thể tự thay đổi mô tả của chính nó — và LLM tin tưởng nó.

Hẹn gặp lại ở phần tiếp theo.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí