DEV Community

EME GUG
EME GUG

Posted on

Honeytokens in Practice: Catching Credential Theft When Malware Uses LLMs to Triage Your Secrets

Tuần này trên Hacker News có một bài khá đáng lo: malware mới dùng LLM để xếp hạng nạn nhân theo giá trị. Thay vì exfiltrate cả ổ cứng rồi để người ngồi lọc, con malware gom file .env, ~/.aws/credentials, lịch sử shell, config Kubernetes, rồi đưa cho một LLM đánh giá: máy này có đáng khai thác không, key nào là production, wallet nào có tiền. Tức là attacker giờ lọc chiến lợi phẩm nhanh hơn bạn kịp phát hiện mình bị dính.

Tin tốt là chính chuyện đó lại tạo ra một điểm yếu để mình tận dụng: càng tự động, attacker càng dễ ăn phải mồi. Một LLM thấy file prod-admin.env có AWS_ACCESS_KEY_ID thì gần như chắc chắn sẽ chấm điểm cao, và script phía sau sẽ thử dùng key đó. Đó là lúc honeytoken (hay canary token) phát huy tác dụng. Bài này mình chia sẻ cách tự dựng honeytoken cho máy dev và server, không phụ thuộc dịch vụ bên thứ ba.

Honeytoken là gì và vì sao nó hợp với thời LLM

Honeytoken là một credential, file hoặc URL giả nhưng trông thật, không ai trong team có lý do hợp lệ để chạm vào. Hễ nó bị dùng là có chuyện. Khác với IDS hay EDR phải đoán xem hành vi nào là xấu, honeytoken gần như không có false positive: không ai dùng AWS key tên backup-admin-legacy cả, nên nó mà được gọi thì chắc chắn có người đang lục máy bạn.

Với malware dùng LLM để triage, có ba điểm hay:

  • LLM được prompt để ưu tiên thứ trông có giá trị, nên bạn có thể thiết kế mồi đúng gu nó: tên file có prod, admin, root, comment kiểu # DO NOT COMMIT.
  • Pipeline tự động thường validate key ngay để chấm điểm, nên bạn biết sớm, nhiều khi chỉ vài phút sau khi bị lấy.
  • Chi phí gần như bằng 0: một IAM user không có quyền, một endpoint HTTP, vài dòng bash.
flowchart LR
    A[Malware trên máy dev] --> B[Gom .env, ~/.aws, kubeconfig]
    B --> C[LLM chấm điểm giá trị]
    C --> D{Key trông như production?}
    D -->|Có| E[Script thử gọi API bằng key]
    E --> F[CloudTrail / Webhook ghi nhận]
    F --> G[Alert Telegram/Slack]
    G --> H[Rotate key thật, cách ly máy]

Lớp 1: AWS key mồi với IAM user không có quyền gì

Đây là loại mồi hiệu quả nhất vì AWS key là thứ attacker thèm nhất. Ý tưởng: tạo một IAM user thật, gắn policy deny toàn bộ, lấy access key, rồi cài vào các chỗ attacker hay tìm.

# AWS CLI v2.x
USER=backup-admin-legacy

aws iam create-user --user-name $USER

# Deny tất cả, key có tồn tại nhưng không làm được gì
aws iam put-user-policy --user-name $USER \
  --policy-name deny-all \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}]
  }'

aws iam create-access-key --user-name $USER \
  --query 'AccessKey.[AccessKeyId,SecretAccessKey]' --output text
Enter fullscreen mode Exit fullscreen mode

Sau đó thêm vào ~/.aws/credentials một profile tên hấp dẫn:

[prod-admin]
aws_access_key_id = AKIA...
aws_secret_access_key = ...
region = ap-southeast-1
Enter fullscreen mode Exit fullscreen mode

Để phát hiện, bạn cần một CloudTrail trail đẩy log về CloudWatch Logs, rồi tạo metric filter theo access key ID:

aws logs put-metric-filter \
  --log-group-name cloudtrail-logs \
  --filter-name honeytoken-prod-admin \
  --filter-pattern '{ $.userIdentity.accessKeyId = "AKIA_YOUR_CANARY_ID" }' \
  --metric-transformations \
    metricName=HoneytokenUsed,metricNamespace=Security,metricValue=1
Enter fullscreen mode Exit fullscreen mode

Gắn một CloudWatch Alarm với ngưỡng >= 1 rồi đẩy qua SNS là xong. Có hai lưu ý thực tế. Thứ nhất, đừng đặt honeytoken trong account production, hãy dùng một account riêng cho security để không ai lỡ tay xoá. Thứ hai, attacker có kinh nghiệm biết vài cách kiểm tra key mà không để lại nhiều log. Vì vậy honeytoken là một lớp cảnh báo sớm, không phải lá chắn duy nhất.

Lớp 2: Canary URL trong file .env và tài liệu nội bộ

Không phải cái gì cũng là AWS key. Pipeline LLM thường đọc cả file .env, README nội bộ, note trong Obsidian. Mình nhét vào đó một URL độc nhất, bất kỳ request nào tới URL đó đều là tín hiệu. Đây là một webhook receiver tối giản viết bằng Python 3.12 + Flask 3.0:

# canary_server.py
import os, json, time, secrets
import requests
from flask import Flask, request, abort

app = Flask(__name__)
TG_TOKEN = os.environ['TG_TOKEN']
TG_CHAT = os.environ['TG_CHAT']

# Mỗi token gắn với một vị trí cài mồi, để biết máy nào bị lộ
TOKENS = json.load(open('tokens.json'))  # {'a1b2...': 'laptop-andy:.env.production'}

def alert(where: str):
    msg = (f'HONEYTOKEN TRIGGERED\n'
           f'Vị trí: {where}\n'
           f'IP: {request.headers.get("X-Forwarded-For", request.remote_addr)}\n'
           f'UA: {request.headers.get("User-Agent", "-")}\n'
           f'Time: {time.strftime("%Y-%m-%d %H:%M:%S")}')
    requests.post(f'https://api.telegram.org/bot{TG_TOKEN}/sendMessage',
                  json={'chat_id': TG_CHAT, 'text': msg}, timeout=5)

@app.route('/v1/<token>', methods=['GET', 'POST'])
def hit(token):
    where = TOKENS.get(token)
    if where:
        alert(where)
    # Trả 401 cho giống API thật, attacker tưởng key sai chứ không nghĩ là bẫy
    abort(401)

def new_token(location: str) -> str:
    t = secrets.token_hex(16)
    TOKENS[t] = location
    json.dump(TOKENS, open('tokens.json', 'w'), indent=2)
    return t
Enter fullscreen mode Exit fullscreen mode

Rồi cài vào file mồi:

# .env.production (file mồi, KHÔNG phải file thật)
INTERNAL_BILLING_API=https://api-billing.yourdomain.dev/v1/a1b2c3d4e5f6...
INTERNAL_BILLING_KEY=sk_live_51Hx...fake
Enter fullscreen mode Exit fullscreen mode

Mẹo nhỏ: đặt domain trông như internal API (api-billing, vault-internal), đừng dùng tên kiểu canary.yourdomain.dev. LLM đọc được chữ canary và có thể được prompt để bỏ qua. Bạn đang chơi trò tâm lý với một model, nên đặt tên mồi cho đúng kiểu thứ nó được dặn đi tìm.

Lớp 3: Theo dõi việc đọc file mồi trên chính máy

Hai lớp trên chỉ báo khi mồi được dùng. Muốn biết sớm hơn, lúc file vừa bị đọc, trên Linux dùng inotifywait (gói inotify-tools 3.22+):

#!/usr/bin/env bash
# watch_decoys.sh: chạy bằng systemd user service
DECOYS=(
  "$HOME/.aws/credentials.bak"
  "$HOME/projects/legacy/.env.production"
  "$HOME/.ssh/id_rsa_prod_old"
)

inotifywait -m -e open,access --format '%w %e' "${DECOYS[@]}" |
while read -r file event; do
  PROC=$(lsof -t "$file" 2>/dev/null | head -1)
  CMD=$(ps -o comm= -p "$PROC" 2>/dev/null)
  curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
    -d chat_id="$TG_CHAT" \
    -d text="Decoy opened: $file ($event) by ${CMD:-unknown} on $(hostname)"
done
Enter fullscreen mode Exit fullscreen mode

Trên server production, mình khuyên dùng auditd thay vì inotify vì nó ghi được PID, UID và executable đầy đủ hơn:

sudo auditctl -w /opt/app/.env.backup -p r -k honeytoken
sudo ausearch -k honeytoken --format text
Enter fullscreen mode Exit fullscreen mode

Có một cái bẫy hay gặp: backup tool, Spotlight hay indexer của IDE cũng đọc file và gây false positive. Đặt file mồi ở thư mục bị exclude khỏi backup và indexer, hoặc lọc theo tên process trong script.

sequenceDiagram
    participant M as Malware
    participant F as File mồi
    participant W as inotify/auditd
    participant API as Canary API / AWS
    participant A as Alert
    M->>F: Đọc .env.production
    F-->>W: Event open/read
    W->>A: Cảnh báo sớm (giây)
    M->>API: Thử dùng key/URL
    API->>A: Cảnh báo xác nhận

Kết luận

Malware dùng LLM giúp attacker nhanh hơn, nhưng cũng làm chúng đoán trước được hơn: chúng ưu tiên đúng những thứ bạn có thể làm giả. Một số việc nên làm ngay trong tuần này:

  1. Tạo 1 AWS honeytoken trong một account riêng, policy deny-all, gắn CloudWatch alarm. Mất khoảng 20 phút.
  2. Cài mồi lên máy của từng dev, mỗi máy một token riêng để khi có alert là biết ngay máy nào bị lộ.
  3. Đặt tên mồi theo gu của LLM: có prod, admin, legacy, backup, tuyệt đối không dùng chữ canary hay honey.
  4. Thêm inotify/auditd cho file mồi để có cảnh báo từ lúc bị đọc, không phải đợi tới lúc bị dùng.
  5. Viết sẵn runbook: có alert thì rotate key thật nào, cách ly máy ra sao, ai chịu trách nhiệm. Alert mà không ai biết phải làm gì thì cũng vô ích.

Honeytoken không thay được secret manager, MFA hay việc không để credential nằm plaintext trên laptop. Nhưng nó là lớp phòng thủ rẻ nhất mà mình biết, nó báo đúng tới mức bạn có thể tin từng cái alert, và nó biến chính sự tự động của attacker thành thứ tố cáo chúng.

Top comments (0)