大模型安全测试garak工具搭建配置"

admin 2026-10-22 13:34:39 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

大模型安全测试garak工具搭建配置

原创

F1rstb100d
F1rstb100d

智佳网络安全

2026年10月18日 15:58
北京

去阅读

基础环境配置

https://github.com/ggml-org/llama.cpp/releases

下载对应cuda版本的exe和后面对应的DLLs 至于如何看cuda版本,命令nvidia-smi也行,去nvidia控制面板看也行

modelscope download --model diodel/Qwen3.5-4B-Q4_K_M-GGUF --local_dir ./

llama-server.exe -m D:\\llama_cpp\\llama-b10995-bin-win-cuda-13.4-x64\\models\\qwen3-5-4B-Q4_K_M.gguf -c 4096 --host 127.0.0.1 --port 9090 -ngl 99

curl http://127.0.0.1:9090/v1/models

大模型就跑起来了

安装garak

conda create --name garak_env \"python>=3.10,<=3.12\"
conda activate garak_env
python -m pip install -U garak

set OPENAI_API_KEY=sk-no-key-required
set OPENAI_BASE_URL=http://127.0.0.1:9090/v1

garak --target_type openai --target_name qwen3-5-4B-Q4_K_M.gguf --probes encoding --parallel_attempts 1 --generations 1

参数 缩写 默认值 作用与说明
--target_type -t / -m 无(必填) 指定生成器类型,如 openai、rest、huggingface、ollama
--target_name -n 无(必填) 目标模型或服务名称,如 qwen3-5-4B-Q4_K_M.gguf
--probes -p all 探针列表,可指定 encoding、dan、promptinject、 all 或 garak --list_probes(建议新版本使用--spec)
--probe_tags 无 无 按标签筛选探针,如 owasp:llm01
--detectors -d all 检测器列表,默认使用各探针推荐的检测器
--generations -g 5 每个提示生成几个响应。本地模型建议设为 1
--parallel_attempts 无 5 并行执行的探测尝试数。本地模型建议设为 1
--parallel_requests 无 1 同一提示的并行请求数,对不支持多生成的模型会被忽略
--config 无 无 指定 YAML/JSON 配置文件路径
--generator_option_file -G 无 指定生成器配置文件路径(用于自定义 REST 接口)
--detector_option_file 无 无 指定检测器配置文件路径(用于配置裁判模型)
--eval_threshold 无 0.5 判定为“成功攻击”的最低阈值
--timeout 无 视生成器而定 请求超时时间(秒),本地模型建议设大一些
--report_prefix 无 garak 报告文件的前缀名
--seed -s 随机 随机种子,用于结果可复现
--verbose -v 0 增加日志详细程度,可叠加使用

坑1: 跑完之后发现模型的返回是空

经过检查发现是Qwen3.5自带思考,设置的窗口4096还没完成思考过程就截断了,导致garak没有收到完整的结果,也就默认判断为了通过

现在换成qwen2.5-3b-instruct-q4_k_m.gguf,这个没有思考过程,可以直接在content里返回模型输出结果

llama-server.exe -m ./models/qwen2.5-3b-instruct-q4_k_m.gguf -c 4096 --host 127.0.0.1 --port 9090 -ngl 99

garak --target_type openai --target_name qwen2.5-3b-instruct-q4_k_m.gguf --spec probes.promptinject --parallel_attempts 1 --generations 1

查看生成的jsonl结果文件,可以看到每个请求和响应

如果大模型提供接口和请求不是标准的格式,那么可能需要自己写对应的配置文件或Generator插件,相见下文,分别对应流式和非流式以及配置文件或插件处理方式

流式返回

方案一:使用RestGenerator配置文件

创建my_config.yaml

plugins:
  generators:
    rest:
      RestGenerator:
        name:\"MyAgent\"
        uri:\"http://xxxx:8080/api/chat/stream\"
        method:post
        headers:
          Content-Type:\"application/json\"
          Accept:\"text/event-stream\"# 明确要求返回SSE流
          User-Agent:\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\"
        req_template_json_object:
          message:\"$INPUT\"
          session_id:\"garak_session_default\"
          user_orgid:\"123456\"
          user_orgnm:\"机构1\"
        # 注意:因为返回是 text/event-stream,此处无法用 response_json 提取字段
        response_json:false

执行

garak --target_type rest -G my_config.yaml --spec probes.encoding --parallel_attempts 1

方案二:编写自定义Generator插件

新建my_generator.py

import json
import requests
from garak.generators.base import Generator

class MyGenerator(Generator):
    \"\"\"专门用于对接MyAgent自定义接口的生成器\"\"\"

    # 声明支持的生成数量
    supports_multiple_generations = False

    # 默认参数,可在配置文件中覆盖
    DEFAULT_PARAMS = Generator.DEFAULT_PARAMS | {
        \"uri\": \"http://xxxxx:8080/api/chat/stream\",
        \"headers\": {
            \"Content-Type\": \"application/json\",
            \"Accept\": \"text/event-stream\",
            \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\"
        }
    }

    def _call_model(self, prompt, generations_this_call=1):
        # 构造请求体,替换 message 字段
        payload = {
            \"message\": prompt,
            \"session_id\": \"garak_session_123\",
            \"user_orgid\": \"123456\",
            \"user_orgnm\": \"机构1\"
        }

        try:
            # 发送请求,开启流式读取
            response = requests.post(
                self.uri,
                headers=self.headers,
                json=payload,
                stream=True,
                timeout=60
            )
            response.raise_for_status()

            # 解析 SSE 流,寻找 type 为 message 的 data
            final_message = \"\"
            for line in response.iter_lines():
                if line:
                    decoded_line = line.decode('utf-8')
                    if decoded_line.startswith(\"data:\"):
                        json_str = decoded_line[5:].strip()  # 去掉 \"data:\" 前缀
                        try:
                            data_obj = json.loads(json_str)
                            if data_obj.get(\"type\") == \"message\":
                                final_message = data_obj.get(\"data\", \"\")
                                # 因为只有一条真正的 message,找到后可以 break(或者继续读取直到流结束)
                                break
                        except json.JSONDecodeError:
                            continue

            # 如果没找到 message 类型的回复,返回兜底内容
            ifnot final_message:
                final_message = \"ERROR: No 'message' type found in SSE response.\"

            return [final_message]

        except Exception as e:
            return [f\"ERROR: {str(e)}\"]

把这个文件放到garak安装目录下,比如:D:\\env\\anaconda3\\envs\\garak_env\\Lib\\site-packages\\garak\\generators\\my_generator.py

复制过去后,运行garak --list_generators,如果看到my_generator.MyGenerator,说明加载成功。

执行命令

garak --target_type my_generator --target_name qwen-agent --spec probes.promptinject --parallel_attempts 1 --generations 1

非流式返回

方案一:使用 RestGenerator 配置文件

创建my_json_config.yaml

plugins:
  generators:
    rest:
      RestGenerator:
        name:\"MyAgent普通接口\"
        uri:\"http://xxxxx:8080/api/chat/stream\"# 换成实际接口地址
        method:post
        headers:
          Content-Type:\"application/json\"
          Accept:\"application/json\"
          User-Agent:\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\"
        req_template_json_object:
          message:\"$INPUT\"
          session_id:\"garak_session_default\"
          user_orgid:\"123456\"
          user_orgnm:\"机构1\"
        response_json:true
        # 重点:根据你的实际返回结构改写 JSONPath
        # 假设返回的是 {\"data\": {\"content\": \"...\"}}
        response_json_field:\"$.data.content\"

执行命令和流式一样:

garak --target_type rest -G my_json_config.yaml --spec probes.promptinject --parallel_attempts 1

方案二:编写自定义 Generator 插件

新建my_json_generator.py

import json
import requests
from garak.generators.base import Generator

class MyJsonGenerator(Generator):
    \"\"\"用于对接返回普通 JSON 的MyAgent接口\"\"\"

    supports_multiple_generations = False

    DEFAULT_PARAMS = Generator.DEFAULT_PARAMS | {
        \"uri\": \"http://xxxx:8080/api/chat/stream\",
        \"headers\": {
            \"Content-Type\": \"application/json\",
            \"Accept\": \"application/json\",
            \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\"
        }
    }

    def _call_model(self, prompt, generations_this_call=1):
        # 构造请求体,替换 message 字段
        payload = {
            \"message\": prompt,
            \"session_id\": \"garak_session_123\",
            \"user_orgid\": \"123456\",
            \"user_orgnm\": \"机构1\"
        }

        try:
            # 1. 发送请求,注意去掉了 stream=True
            response = requests.post(
                self.uri,
                headers=self.headers,
                json=payload,
                timeout=60
            )
            response.raise_for_status()

            # 2. 直接将整个响应解析为 JSON
            resp_json = response.json()

            # 3. 根据返回结构提取需要的字段
            final_message = \"\"

            # 假设普通 JSON 返回是类似 {\"code\":200, \"data\": [{\"type\":\"thought\", ...}, {\"type\":\"message\", \"data\":\"...\"}]}
            data_list = resp_json.get(\"data\", [])
            if isinstance(data_list, list):
                for item in data_list:
                    if item.get(\"type\") == \"message\":
                        final_message = item.get(\"data\", \"\")
                        break# 找到就跳出循环
            elif isinstance(data_list, dict):
                # 如果是 {\"data\": {\"type\": \"message\", \"data\": \"...\"}}
                if data_list.get(\"type\") == \"message\":
                    final_message = data_list.get(\"data\", \"\")

            # 兜底:如果没找到对应字段,返回整个 JSON 字符串
            ifnot final_message:
                final_message = json.dumps(resp_json, ensure_ascii=False)

            return [final_message]

        except Exception as e:
            return [f\"ERROR: {str(e)}\"]

同样复制到garak安装目录下,执行:

garak --target_type my_json_generator --target_name qwen-agent --spec probes.promptinject --parallel_attempts 1

大模型安全测试garak工具搭建配置" 网络安全文章

大模型安全测试garak工具搭建配置"

本文档介绍大模型安全测试工具garak的搭建配置流程,包括使用llama.cpp部署本地模型、安装garak工具、配置参数及执行安全测试。文档详细说明了流式与非流式返回的处理方案,以及通过配置文件或自定义Generator插件对接非标准接口的方法。同时指出使用带思考过程的模型可能导致测试结果为空的问题,建议使用无思考过程的instruct模型。
俄关联组织UAC-0099据报以新型ASHVEIN远控木马攻击乌政府人员,警惕HTML隐蔽指令及初始访问转售手法被复用于针对我政企网络的攻击" 网络安全文章

俄关联组织UAC-0099据报以新型ASHVEIN远控木马攻击乌政府人员,警惕HTML隐蔽指令及初始访问转售手法被复用于针对我政企网络的攻击"

俄关联组织UAC-0099使用新型ASHVEIN远控木马攻击乌克兰政府人员,该木马能提取浏览器凭据、截屏、检索文件,通过HTML隐蔽指令和GitHub备用渠道接收任务。文章指出这是持续获取入口、筛选目标并移交的前端作业系统,四年更换十余种工具,目标覆盖乌克兰政府、防务、边防和物流等领域。对我风险主要来自手法迁移,驻外机构、物流企业等可能成为目标,建议关注非浏览器进程读取凭据库等组合信号,并核查身份令牌、VPN会话等环境。
关于双十一期间暂停授权测试及漏洞收录的通知" 网络安全文章

关于双十一期间暂停授权测试及漏洞收录的通知"

中通安全应急响应中心发布通知,因双十一业务高峰,于2026年10月19日至11月14日暂停外部授权测试及漏洞收录。期间未经授权的测试将被视为违规,可能面临取消奖励、账号封禁等处置,严重者保留追责权利。暂停期结束后恢复正常收录,建议白帽子遵守规定,保障业务安全稳定。
评论:0   参与:  0