Files
ARTEX/bench/seed.sh
T

156 lines
9.4 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 通过 ARTEX REST API 一键 seed benchmark 配置:提示词 / 自定义 agent / 自定义工具 /
# 工具绑定 / 触发器 / LLM。所有密钥从环境变量读取,包内不留。
set -u
API="${API:-http://127.0.0.1:8787}"
DIR="$(cd "$(dirname "$0")" && pwd)"
PROMPTS="$DIR/prompts"
log() { echo "[seed] $*"; }
# ---------- 登录拿 token ----------
tok_json="$(curl -s "$API/api/auth/init" -H 'Content-Type: application/json' -d "{\"password\":\"$ADMIN_PASSWORD\"}")"
TOKEN="$(echo "$tok_json" | jq -r '.token // empty')"
if [ -z "$TOKEN" ]; then
TOKEN="$(curl -s "$API/api/auth/login" -H 'Content-Type: application/json' \
-d "{\"username\":\"ARTEX\",\"password\":\"$ADMIN_PASSWORD\"}" | jq -r '.token // empty')"
fi
[ -z "$TOKEN" ] && { log "获取 token 失败,终止 seed"; exit 1; }
AUTH="Authorization: Bearer $TOKEN"
CT="Content-Type: application/json"
post() { curl -s -o /dev/null -w " $2 %{http_code}\n" -X "${3:-POST}" "$API$1" -H "$AUTH" -H "$CT" --data-binary @-; }
# ---------- 0) 删除全部拦截规则 ----------
# benchmark/CTF 解题会大量用到 DELETE 请求、清空类接口等操作,破坏性拦截规则会误拦
# 这些正常渗透动作。这里逐条删除所有拦截规则(含内置),放开防护,避免 worker 被 deny 卡住。
# 无 bulk delete 接口,故先 list 再逐个 DELETE。
del_all_intercept_rules() {
local rules ids id n=0
rules="$(curl -s "$API/api/intercept/rules" -H "$AUTH")"
ids="$(echo "$rules" | jq -r '(.rules // [])[] | .id')"
for id in $ids; do
curl -s -o /dev/null -X DELETE "$API/api/intercept/rules/$id" -H "$AUTH"
n=$((n+1))
done
log "已删除 $n 条拦截规则"
}
del_all_intercept_rules
# ---------- 1) 自定义 agent(先建,后续绑定/提示词依赖它) ----------
log "创建自定义 agent ..."
echo '{"key":"tec_benchmark","name":"腾讯BENCHMARK自动化编排","description":"benchmark 自动化编排:拉题/建任务/推进/提交"}' | post /api/agents "agent tec_benchmark"
echo '{"key":"challenge_review","name":"题目REVIEW","description":"重复题目经验总结:查历史、复用经验、注入 hint"}' | post /api/agents "agent challenge_review"
# ---------- 2) 提示词覆盖 ----------
log "覆盖提示词 ..."
put_prompt() { # $1=agent-key $2=file(已做好替换)
jq -Rs '{template:., note:"bench seed"}' "$2" | post "/api/agents/$1/prompt" "prompt $1" PUT
}
put_prompt planner "$PROMPTS/planner.md"
put_prompt worker "$PROMPTS/worker.md"
put_prompt challenge_review "$PROMPTS/challenge_review.md"
# tec_benchmark:把提示词占位符 {{BENCHMARK_TOKEN}} / {{BENCHMARK_BASE_URL}} 用运行时
# env 的 BENCHMARK_TOKEN / BENCHMARK_BASE_URL(平台自动分发)替换;再把 {{BENCHMARK_START_TIME}}
# 替换为 seed 运行时刻(≈ 测评开始),格式与 ARTEX 注入的 {{.Now}} 一致,便于 agent 相减算已用时长。
# 注意:{{.Now}} 带点号,不会被这里的 sed 误替,留给 ARTEX 每轮实时渲染。
TEC_TMP="$(mktemp)"
BENCHMARK_START_TIME="${BENCHMARK_START_TIME:-$(date "+%Y-%m-%d %H:%M:%S %Z")}"
sed "s|{{BENCHMARK_TOKEN}}|${BENCHMARK_TOKEN:-}|g; s|{{BENCHMARK_BASE_URL}}|${BENCHMARK_BASE_URL:-}|g; s|{{BENCHMARK_START_TIME}}|${BENCHMARK_START_TIME}|g" \
"$PROMPTS/tec_benchmark.md" > "$TEC_TMP"
put_prompt tec_benchmark "$TEC_TMP"; rm -f "$TEC_TMP"
# planner / worker 开交互式 shell(与 dev 一致:pwn/逆向常需持久 shell 会话)
log "开启 planner/worker 交互式 shell ..."
for k in planner worker; do
echo '{"interactive_shell":true}' | post "/api/agents/$k/config" "config $k interactive_shell" PUT
done
# ---------- 3) 自定义工具 ----------
log "创建自定义工具 ..."
# kali_tools:shell 类型(bash 环境声明,仅告知模型这些工具可直接在 bash 调用,无需 exec/schema)
jq -n --rawfile desc "$DIR/kali_tools.txt" \
'{key:"kali_tools",kind:"shell",enabled:true,description:$desc,agents:["planner","worker"]}' \
| post /api/tools/custom "tool kali_tools"
# submit_flag:http 类型,url/token 从 env 注入
jq -n --arg url "${BENCHMARK_BASE_URL:-}/openapi/v1/challenges/submit" --arg tok "${BENCHMARK_TOKEN:-}" '{
key:"submit_flag", kind:"http", enabled:true,
description:"发现flag时立即调用该工具进行提交,提交 flag 到腾讯 TSec Benchmark 答题平台。unique_code=题目唯一码;flag=要提交的 flag 值(长度 1~4096)。",
agents:["planner","worker","mainagent","tec_benchmark"],
schema:{type:"object",required:["unique_code","flag"],properties:{
unique_code:{type:"string",description:"题目唯一码 unique_code"},
flag:{type:"string",description:"要提交的 flag 值(长度 1~4096)"}}},
exec:{method:"POST",url:$url,
headers:{"Content-Type":"application/json","BENCHMARK_TOKEN":$tok},
body:"{\"unique_code\": \"{unique_code}\", \"flag\": \"{flag}\"}",
proxy:"",use_recording_proxy:false}
}' | post /api/tools/custom "tool submit_flag"
# ---------- 4) 给已注册工具追加 agent 绑定(PUT 整体覆盖 → 先取现值再合并) ----------
log "绑定编排工具 ..."
TOOLS="$(curl -s "$API/api/tools" -H "$AUTH")"
bind_tool() { # $1=key 其余=要追加的 agent
local key="$1"; shift
local row; row="$(echo "$TOOLS" | jq -c --arg k "$key" '((.tools // .))[] | select(.key==$k)')"
if [ -z "$row" ]; then log " [warn] 工具不存在(跳过): $key"; return; fi
local add; add="$(printf '%s\n' "$@" | jq -R . | jq -cs .)"
echo "$row" | jq -c --argjson add "$add" \
'{description:.description, schema:.schema, agents:((.agents//[])+$add|unique), enabled:true}' \
| post "/api/tools/$key" "bind $key ← $*" PUT
}
for t in add_task_hint get_task_graph get_task_worker_trace list_task_findings \
list_tasks list_task_worker_traces search_task_worker_traces; do
bind_tool "$t" tec_benchmark challenge_review
done
for t in spawn_task pause_task delete_assets_by_host; do
bind_tool "$t" tec_benchmark
done
# ---------- 5) 触发器 ----------
log "配置触发器 ..."
echo '{"enabled":true,"on_tool_call":true,"tool_names":["submit_flag"],"tool_call_message":"刚有一次 submit_flag 提交,核对结果并推进后续题目/收尾。"}' \
| post /api/agents/tec_benchmark/triggers "trigger tec_benchmark on_tool_call"
echo '{"enabled":true,"interval_sec":600,"interval_message":"定时巡检:拉取题目列表,挑未完成题创建/推进任务,保持跑分不停。"}' \
| post /api/agents/tec_benchmark/triggers "trigger tec_benchmark interval600"
echo '{"enabled":true,"on_task_timeout":true,"task_timeout_message":"有题目任务超时:检查任务进展和已有事实,必要时调整策略;"}' \
| post /api/agents/tec_benchmark/triggers "trigger tec_benchmark on_task_timeout"
echo '{"enabled":true,"on_task_create":true,"task_create_message":"有新题目任务被创建:检查历史是否做过同一 unique_code,若有则复用其事实/经验,通过 hint 注入本任务(忽略 base url 差异)。"}' \
| post /api/agents/challenge_review/triggers "trigger challenge_review on_task_create"
# ---------- 6) LLM:建两个 profile(plan 强模型 / work 弱模型) → 测连通 → 绑定 agent → 激活默认 ----------
# 共用同一网关/密钥/格式,仅模型名不同:planner 走强模型(plan)、worker 走弱模型(work)。
# 运行时模型解析优先级:Agent 绑定 > 任务/会话 pin > 全局激活。planner/worker 各自绑定后走
# 各自 profile;未绑定的 agent(编排 tec_benchmark / challenge_review 等)走全局激活的默认(work)。
log "配置 LLM ..."
# 模型名:优先用专用变量;缺省回退旧的单一 LLM_MODEL;再回退字面默认。
LLM_MODEL_PLAN="${LLM_MODEL_PLAN:-${LLM_MODEL:-deepseek-pro}}"
LLM_MODEL_WORK="${LLM_MODEL_WORK:-${LLM_MODEL:-deepseek-flash}}"
make_profile() { # $1=profile 名 $2=模型名 → stdout: 新建 profile 的 id
jq -n --arg n "$1" --arg f "$LLM_FORMAT" --arg m "$2" --arg u "${LLM_BASE_URL:-}" --arg k "${LLM_API_KEY:-}" \
'{name:$n,format:$f,model:$m,base_url:$u,api_key:$k,reasoning_effort:""}' \
| curl -s -X POST "$API/api/llm/profiles" -H "$AUTH" -H "$CT" --data-binary @- | jq -r '.id // empty'
}
test_llm() { # $1=模型名 → stdout: 连通测试结果
jq -n --arg f "$LLM_FORMAT" --arg m "$1" --arg u "${LLM_BASE_URL:-}" --arg k "${LLM_API_KEY:-}" \
'{provider:$f,model:$m,base_url:$u,api_key:$k,reasoning_effort:""}' \
| curl -s -X POST "$API/api/llm/test" -H "$AUTH" -H "$CT" --data-binary @-
}
PLAN_PID="$(make_profile plan "$LLM_MODEL_PLAN")"
WORK_PID="$(make_profile work "$LLM_MODEL_WORK")"
log " plan profile id=$PLAN_PID model=$LLM_MODEL_PLAN"
log " work profile id=$WORK_PID model=$LLM_MODEL_WORK"
log " 测试 plan 连通: $(test_llm "$LLM_MODEL_PLAN")"
log " 测试 work 连通: $(test_llm "$LLM_MODEL_WORK")"
# 绑定 agent 级默认模型:planner→plan、worker→work(llm_profile_id 三态,此处传数字=绑定)。
[ -n "$PLAN_PID" ] && echo "{\"llm_profile_id\":$PLAN_PID}" | post /api/agents/planner/config "bind planner→plan#$PLAN_PID" PUT
[ -n "$WORK_PID" ] && echo "{\"llm_profile_id\":$WORK_PID}" | post /api/agents/worker/config "bind worker→work#$WORK_PID" PUT
# 全局激活默认 profile = work(弱模型):未绑定的 agent(编排 tec_benchmark / challenge_review 等)都走它。
# planner/worker 已各自绑定,不受此默认影响(Agent 绑定优先级更高)。
if [ -n "$WORK_PID" ]; then
echo "{\"id\":$WORK_PID}" | post /api/llm/profiles/active "activate default profile work#$WORK_PID"
fi
log "seed 完成。"