Tấn Công Embedding Trong Hệ Thống RAG - Phần 3: "Đảo Ngược Zero-Shot - Khi Mẫu Dò Và Tìm Kiếm Chùm Lên Tiếng"
Mở đầu: Bạn đã có chìa khóa, giờ làm sao mở ổ?
Tiếp tục câu chuyện từ Phần 2.
Bạn đã có trong tay embeddings.npy - kho báu gồm 31 vector số. Bạn đã xác định được "nhà sản xuất" của chiếc khóa - mô hình all-MiniLM-L6-v2. Bạn đã dùng pipeline phân loại 3 tầng để thu hẹp từ 31 xuống chỉ 3 mục tiêu đáng tấn công. Và bạn đã trích xuất riêng Chunk #23 - mục tiêu mà chúng ta sẽ tập trung vào.
Bây giờ đến phần thú vị nhất: làm thế nào để biến một mảng số float32 trở lại thành văn bản tiếng Anh có nghĩa?
Hãy tưởng tượng bạn tìm thấy một két sắt. Bạn biết nhà sản xuất (đã xác định mô hình). Bạn có bản thiết kế của két (embedding). Nhưng bạn không có mật khẩu. Làm sao để mở nó?
Có hai cách tiếp cận, giống như hai người thợ khóa với hai phương pháp khác nhau:
Cách 1 - Dùng "sách mã mẫu": Bạn có một cuốn sách dày chứa hàng trăm nghìn mật khẩu mẫu cho các loại két khác nhau. Bạn so sánh "dấu vân tay" của từng mật khẩu mẫu với dấu vân tay của két cần mở. Mật khẩu nào có dấu vân tay giống nhất - đó là mật khẩu đúng. Nhanh, nhưng nếu cuốn sách không có mật khẩu nào giống, bạn bó tay.
Cách 2 - Mò từng số một: Bạn bắt đầu với số đầu tiên, thử từ 0 đến 9, xem số nào làm cho "dấu vân tay" gần nhất. Sau đó số thứ hai, rồi số thứ ba... Cứ thế cho đến khi có cả dãy số. Chậm hơn, tốn sức hơn, nhưng không cần cuốn sách nào cả.
Cả hai cách đều không cần huấn luyện trước (zero-shot). Cả hai đều có thể giúp bạn mở két. Nhưng tùy tình huống, bạn sẽ chọn cách phù hợp. Phần này sẽ hướng dẫn bạn cả hai.
1. Tạo ngân hàng mẫu (Template Bank) - "Cuốn sách vàng" của kẻ tấn công
1.1. Tạo cuốn sách - Tự động sinh 500.000 câu mẫu
Ý tưởng rất đơn giản: Nếu bạn có đủ các câu mẫu bao phủ mọi chủ đề có thể, một trong số chúng sẽ có embedding gần với embedding mục tiêu.
Phát hiện chủ đề - "Bắt mạch" embedding mục tiêu:
Trước khi tạo mẫu, script cần biết chunk đang nói về chủ đề gì. Làm sao để biết?
Hãy tưởng tượng bạn có 20 "thẻ đánh dấu" (anchors) cho 20 chủ đề khác nhau. Mỗi thẻ là một cụm từ đặc trưng cho chủ đề đó:
- Chủ đề "đặt lại mật khẩu": "reset your password", "login portal"
- Chủ đề "kết nối database": "connection string", "postgresql://"
- Chủ đề "khóa API": "API key", "bearer token"
Script nhúng (embed) tất cả các thẻ này, rồi tính Cosine Similarity giữa embedding của chunk mục tiêu với từng thẻ. Chủ đề nào có độ tương đồng cao nhất - đó là chủ đề của chunk. Giống như bạn đưa một mùi hương lạ cho một chú chó nghiệp vụ, nó đánh hơi và chỉ ra đúng loại hoa. Phép thuật ở đây không phải phép thuật, mà là phép toán vector đơn giản: so sánh độ giống nhau giữa các vector số.
Trong trường hợp của chúng ta, chunk #23 có độ tương đồng 0.4618 với chủ đề "đặt lại mật khẩu" - cao nhất trong 20 chủ đề. Script kết luận: "Đây là chunk về đặt lại mật khẩu!"
Trước khi tạo mẫu, script sẽ tự động phát hiện chủ đề của chunk mục tiêu bằng cách so sánh embedding của nó với các "mẫu chữ ký" của 20 miền doanh nghiệp khác nhau.
Bước 1: Tạo file generate_templates.py (link source code) để tự động sinh 500.000 câu mẫu:
Bước 2: Tải danh sách từ cho suy luận thành viên:
attacker@rag:~$ wget -O passwords.txt https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt
Bước 3: Chạy script tạo mẫu:
attacker@rag:~$ python3 emb_fin.py chunk_23.npy --chunk 0 --templates templates.json --wordlist passwords.txt --slots PASSWORD --default-URL https://login.megacorpone.ai --max-templates 500000
Kết quả mong đợi:

Giải thích: Script này phát hiện chunk đang nói về chủ đề "đặt lại mật khẩu", sau đó từ 7 câu mẫu cơ bản, dùng 4 chiến thuật để mở rộng thành 500.000 câu độc nhất.
💡 Tại sao z-score quan trọng? Z-score đo mức độ ứng viên chiến thắng vượt trội so với ứng viên tiếp theo. Z-score 6.50 có nghĩa là ứng viên chiến thắng cách ứng viên tiếp theo 6.5 độ lệch chuẩn - rất đáng tin cậy.
1.2. Mở két - Dùng ngân hàng mẫu và suy luận thành viên
Bây giờ chúng ta đã có "cuốn sách" với 500.000 câu mẫu. Công việc tiếp theo: so sánh embedding mục tiêu với tất cả mẫu, tìm mẫu khớp nhất, và dùng suy luận thành viên để điền vào vị trí {PASSWORD}.
Bước 1: Tạo file emb_fin.py (link):
Bước 4: Chạy pipeline:
attacker@rag:~$ python3 emb_fin.py chunk_23.npy --chunk 0 --templates templates.json --wordlist passwords.txt --slots PASSWORD --default-URL https://login.megacorpone.ai --max-templates 500000
Kết quả mong đợi:

Giải thích: Pipeline này:
- Mã hóa tất cả 500.000 mẫu và tính độ tương tự với embedding mục tiêu
- Chọn 20 mẫu đa dạng nhất có điểm cao nhất (giống như chọn 20 nhân chứng đáng tin nhất)
- Với mỗi mẫu, thử từng mật khẩu trong danh sách 99.839 từ
- Các mẫu bỏ phiếu, N0=Acc3ss thắng với 18/20 đồng thuận
- Z-score 6.50 nghĩa là ứng viên chiến thắng cách ứng viên tiếp theo 6.5 độ lệch chuẩn - rất đáng tin cậy
Như vậy, chúng ta đã mở được két bằng Cách 1!
2. Khi "cuốn sách" không đủ tốt
Nhưng có tình huống mà ngay cả 500.000 câu mẫu cũng không đủ.
Hãy tưởng tượng câu gốc có cấu trúc bất thường: "Attention: user mwilliams must change password to N0=Acc3ss before accessing mainframe" - cấu trúc này có thể không nằm trong 500.000 mẫu của bạn.
Trong trường hợp đó, Cách 1 sẽ cho độ tin cậy "YẾU" hoặc "KHÔNG CHẮC CHẮN". Đó là lúc Cách 2 xuất hiện.
3. Khi ngân hàng mẫu thất bại - Tìm kiếm theo chùm (Beam Search)
Nhưng nếu ngân hàng mẫu của bạn không có cấu trúc nào khớp với văn bản gốc? Ví dụ, văn bản gốc là một cấu trúc bất thường không nằm trong 500,000 mẫu bạn đã tạo?
Đó là lúc tìm kiếm theo chùm xuất hiện. Thay vì dùng mẫu có sẵn, bạn xây dựng văn bản từ đầu, token-by-token.
Ý tưởng: Bắt đầu với một token, thử nhiều token tiếp theo, giữ lại những token làm cho embedding gần với mục tiêu nhất. Lặp lại 30-40 bước.
Nghiên cứu Zero2Text (arXiv 2602.01757v2) đã chứng minh rằng cách tiếp cận này có thể phục hồi văn bản có nghĩa từ embeddings mà không cần bất kỳ huấn luyện nào . Phương pháp này sử dụng một mô hình ngôn ngữ như GPT-2 hoặc Qwen3-0.6B để đề xuất token tiếp theo, và mô hình embedding mục tiêu để chấm điểm .
3.1. Xây dựng từng chữ một
Thay vì dùng mẫu có sẵn, Cách 2 xây dựng văn bản từ đầu, token-by-token, sử dụng GPT-2 để đề xuất các token tiếp theo và embedding model để chấm điểm.
Bước 1: Tạo file zero2text_impl.py (link):
Bước 2: Chạy script:
attacker@rag:~$ python3 zero2text_impl.py chunk_23.npy --chunk 0 --templates templates.json --wordlist passwords.txt --slots PASSWORD --default-URL https://login.megacorpone.ai --max-steps 40 --beam-width 10 --device cuda
Kết quả mong đợi:

Giải thích: Beam search:
- Bắt đầu với token đầu tiên, thử 100 khả năng
- Giữ lại 10 khả năng tốt nhất (beam width=10)
- Tại mỗi bước, mở rộng mỗi khả năng với token tiếp theo
- Chấm điểm bằng độ tương tự cosine với embedding mục tiêu
- Sau 27 bước, hội tụ về văn bản có cấu trúc khớp 91.6%
- Phát hiện vùng entropy cao (
N0=Acc3ss) và dùng membership inference để xác nhận
4. So sánh hai cách tiếp cận
| Tiêu chí | Cách 1: Ngân hàng mẫu | Cách 2: Tìm kiếm theo chùm |
|---|---|---|
| Cách làm | So sánh với cuốn sách 500.000 mẫu | Xây dựng lại từng chữ |
| Thời gian | Vài phút (nhanh) | Vài phút đến vài giờ (chậm hơn) |
| Cần GPU? | Không | Có (bắt buộc) |
| Cần cuốn sách mẫu? | Có | Không |
| Thành công khi | Cuốn sách có câu tương tự | Câu không quá bất thường |
| Thất bại khi | Không có mẫu nào khớp | Văn bản quá dài (>32 token) |
| Khi nào dùng | Ưu tiên dùng trước | Dùng khi Cách 1 cho kết quả yếu |
5. Một thực tế cần nhớ
Cả hai cách đều có giới hạn:
1. Độ dài token: Cả hai đều hoạt động tốt với văn bản ngắn (32-64 token). Với văn bản dài (256-512 token), kết quả kém chính xác hơn. Tin tốt: Mật khẩu, khóa API thường ngắn.
2. Mật khẩu ngẫu nhiên: N0=Acc3ss có nghĩa, nên mô hình có thể đoán được. 1qaz2wsx3edc4rfv ngẫu nhiên thuần túy - cả hai cách đều bó tay vì mô hình coi nó như nhiễu.
3. Cần biết mô hình embedding: Cả hai cách đều yêu cầu bạn biết mô hình nào tạo ra embedding. Nếu không, hãy chờ Phần 4.
6. Tóm tắt: 3 bài học từ phần này
-
Ngân hàng mẫu là cách nhanh và đơn giản nhất. Tạo 500.000 mẫu tự động, so sánh và bỏ phiếu. Phù hợp với các chủ đề phổ biến.
-
Tìm kiếm theo chùm là cách mạnh mẽ hơn. Không cần mẫu có sẵn, xây dựng văn bản từ đầu. Nhưng chậm hơn và cần GPU.
-
Cả hai đều là zero-shot - không cần huấn luyện trước. Nhưng vẫn cần biết mô hình embedding. Nếu không, phải đợi đến Phần 4.
7. Preview Phần 4
Trong phần tiếp theo - "Đảo Ngược Có Huấn Luyện - ALGEN Và Vec2Text" - chúng ta sẽ:
- Dùng ALGEN (Few-Shot) để căn chỉnh không gian embedding mà không cần biết mô hình mục tiêu
- Kỹ thuật Canary Injection - tiêm dữ liệu vào vector store để tạo cặp căn chỉnh
- Vec2Text (Supervised) - huấn luyện với 60 giờ GPU để đạt độ chính xác cao nhất
- So sánh 4 phương pháp và hướng dẫn chọn vũ khí phù hợp
Hãy sẵn sàng cho những vũ khí hạng nặng. 🚀
"Zero-shot không có nghĩa là không chuẩn bị. Nó có nghĩa là bạn đã chuẩn bị đủ tốt để không cần huấn luyện lại."
Hẹn gặp lại ở Phần 4.
All rights reserved