94 lines
3.8 KiB
Bash
Executable File
94 lines
3.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# gist.sh — GitHub Gist 扫描模块
|
|
# 公开 Gist 是 API key 泄露重灾区,尤其是 Jupyter notebook dump
|
|
# ═══════════════════════════════════════════════════════════════
|
|
set -euo pipefail
|
|
|
|
TOKEN=""
|
|
REPORT_DIR="./results"
|
|
LIMIT=1000
|
|
|
|
CYAN='\033[0;36m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${CYAN}[*]${NC} $1"; }
|
|
log_found() { echo -e "${GREEN}[+]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--token) TOKEN="$2"; shift 2 ;;
|
|
--report) REPORT_DIR="$2"; shift 2 ;;
|
|
--limit) LIMIT="$2"; shift 2 ;;
|
|
*) shift ;;
|
|
esac
|
|
done
|
|
|
|
mkdir -p "$REPORT_DIR"
|
|
RESULTS_FILE="${REPORT_DIR}/gist_keys.txt"
|
|
> "$RESULTS_FILE"
|
|
|
|
# 正则模式
|
|
REGEX='(sk-[a-zA-Z0-9]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}|sk-ant-[a-zA-Z0-9-]{20,}|AIza[0-9A-Za-z\-_]{35}|hf_[a-zA-Z0-9]{34}|gsk_[a-zA-Z0-9]{52}|r8_[a-zA-Z0-9]{37}|sk-or-[a-zA-Z0-9-]{20,}|pplx-[a-zA-Z0-9]{48,})'
|
|
|
|
# ── 扫描公开 gist ────────────────────────────────────────
|
|
log_info "列出公开 Gist (limit: $LIMIT)..."
|
|
|
|
# 用 gh 列出 gist
|
|
GIST_IDS=$(gh gist list --public --limit "$LIMIT" 2>/dev/null | awk '{print $1}')
|
|
|
|
if [[ -z "$GIST_IDS" ]]; then
|
|
log_warn "未找到公开 gist,尝试用 API 搜索..."
|
|
|
|
# 用 GitHub search API 搜 gist 中的 key
|
|
for query in "sk-proj-" "sk-ant-" "OPENAI_API_KEY" "ANTHROPIC_API_KEY" "GROQ_API_KEY" "HUGGINGFACE"; do
|
|
log_info "搜索 gist: $query"
|
|
gh api "search/code?q=${query}+extension:ipynb" --jq '.items[].html_url' 2>/dev/null | while read -r url; do
|
|
raw_url=$(echo "$url" | sed 's|github.com|raw.githubusercontent.com|;s|/blob/||')
|
|
content=$(curl -sL --max-time 10 "$raw_url" 2>/dev/null) || continue
|
|
[[ -z "$content" ]] && continue
|
|
|
|
echo "$content" | grep -oE "$REGEX" 2>/dev/null | while read -r key; do
|
|
echo "GistMatch|${key}|${url}|Gist leak" >> "$RESULTS_FILE"
|
|
log_found "Gist key: $key"
|
|
done
|
|
done
|
|
done
|
|
else
|
|
log_info "扫描 $(echo "$GIST_IDS" | wc -l | tr -d ' ') 个 gist..."
|
|
|
|
while read -r gist_id; do
|
|
[[ -z "$gist_id" ]] && continue
|
|
|
|
content=$(gh gist view "$gist_id" 2>/dev/null) || continue
|
|
[[ -z "$content" ]] && continue
|
|
|
|
echo "$content" | grep -oE "$REGEX" 2>/dev/null | while read -r key; do
|
|
echo "GistMatch|${key}|gist:${gist_id}|Gist leak" >> "$RESULTS_FILE"
|
|
log_found "Gist key: $key (gist: $gist_id)"
|
|
done
|
|
done <<< "$GIST_IDS"
|
|
fi
|
|
|
|
# ── 搜索 GitHub Gist API ─────────────────────────────────
|
|
log_info "通过 GitHub API 搜索 gist 中的 key 模式..."
|
|
for pattern in "sk-proj-" "sk-ant-" "AIza" "hf_" "gsk_" "r8_"; do
|
|
gh api "/gists/public" --paginate --jq '.[].id' 2>/dev/null | head -200 | while read -r gid; do
|
|
[[ -z "$gid" ]] && continue
|
|
content=$(gh gist view "$gid" 2>/dev/null) || continue
|
|
echo "$content" | grep -oE "$REGEX" 2>/dev/null | while read -r key; do
|
|
grep -q "${key}" "$RESULTS_FILE" 2>/dev/null || {
|
|
echo "GistAPI|${key}|gist:${gid}|Gist API leak" >> "$RESULTS_FILE"
|
|
log_found "Gist API key: $key"
|
|
}
|
|
done
|
|
done
|
|
done
|
|
|
|
count=$(wc -l < "$RESULTS_FILE" | tr -d ' ')
|
|
log_found "Gist 扫描完成: $count 个 key"
|
|
log_info "结果保存至: $RESULTS_FILE"
|