漏洞验证框架的构思与实现(二)
字数 1253 2025-08-05 08:19:29
漏洞验证框架规则体系设计与实现
1. 规则体系概述
本文档详细介绍了基于xray规则体系扩展的漏洞验证框架核心模块——规则体系的设计与实现。该体系兼容xray的POC规则,同时增加了更细致的请求变形分类,提高了漏洞检测的灵活性和准确性。
2. 原始请求来源处理
框架支持三种原始请求来源方式:
2.1 从URL生成请求
func GenOriginalReq(url string) (*http.Request, error) {
// 生成原始请求,如果没有协议默认使用http
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "http://" + url
}
originalReq, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Error("util/requests.go:GenOriginalReq original request gen error", url, err)
return nil, err
}
// 设置默认请求头
originalReq.Header.Set("Host", originalReq.Host)
originalReq.Header.Set("Accept-Encoding", "gzip, deflate")
originalReq.Header.Set("Accept", "*/*")
originalReq.Header.Set("User-Agent", conf.GlobalConfig.HttpConfig.Headers.UserAgent)
originalReq.Header.Set("Accept-Language", "en")
originalReq.Header.Set("Connection", "close")
return originalReq, nil
}
2.2 从HTTP报文文件生成请求
func GenOriginalReqFromRaw(filePath string) (*http.Request, error) {
raw, err := ioutil.ReadFile(filePath)
if err != nil {
c.JSON(msg.ErrResp("请求报文文件解析失败"))
return nil, err
}
oreq, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(raw)))
if err != nil {
return nil, err
}
if !oreq.URL.IsAbs() {
scheme := "http"
oreq.URL.Scheme = scheme
oreq.URL.Host = oreq.Host
}
return oreq, nil
}
2.3 通过代理监听获取请求
第三种方式是通过代理形式监听获取请求(如xray浏览器代理模式)。
3. xray规则兼容实现
3.1 CEL表达式处理
xray的规则体系基于Common Expression Language (CEL)实现,使用cel-go包处理表达式。
CEL表达式运行流程:
- 构建CEL环境(cel.Env)
- 向环境中注入类型和方法
- 计算表达式
3.1.1 变量和方法注入
需要实现xray规则中所有的变量和方法,包括:
- UrlType
- Request
- Response
- Reverse
- 文档未提及的icontains方法
3.1.2 Set变量处理
Set中自定义变量可能引用之前的变量,因此必须有序加载。建议使用yaml.v2包的MapSlice而非原生map保存Set变量。
3.2 请求构造过程
POC运行阶段有两个请求:
- 原始请求
- 根据规则变形的请求
以airflow未授权访问漏洞POC为例:
name: poc-yaml-airflow-unauth
rules:
- method: GET
path: /admin/
expression: |
response.status == 200 &&
response.body.bcontains(b"<title>Airflow - DAGs</title>") &&
response.body.bcontains(b"<h2>DAGs</h2>")
请求变形逻辑:
- 获取原始请求路径(如/test/)
- 将POC中的path(/admin/)拼接到原始路径后(/test/admin/)
- 保持原始请求头不变
为提高性能,使用fasthttp替换原生http包:
// 定义fasthttp.Request保存构造的请求
fastReq := controller.Request.Fast
fixedFastReq := fasthttp.AcquireRequest()
fastReq.CopyTo(fixedFastReq)
3.3 检测链控制
xray支持两种检测链格式:
-
rules:rule组成的有序列表([]rule)
- 值为true的rule继续执行后续rule
- 所有rule执行成功则POC结果为true
-
groups:rules组成的列表(map[string]rules)
- 任意一组rules执行成功则POC结果为true
执行逻辑:
func ExecExpressionHandle(ctx controllerContext) {
var result bool
var err error
poc := ctx.GetPoc()
if poc == nil {
log.Error("[rule/handle.go:ExecExpressionHandle error]", "poc is nil")
return
}
if poc.Groups != nil {
result, err = ctx.Groups(ctx.IsDebug())
} else {
result, err = ctx.Rules(poc.Rules, ctx.IsDebug())
}
if err != nil {
log.Error("[rule/handle.go:ExecExpressionHandle error]", err)
return
}
if result {
ctx.Abort()
}
return
}
3.4 POC运行流程
- 获取原始请求,根据规则变形构造新请求
- 初始化CEL环境:注入变量和方法
- 初始化CEL变量列表:注入Set定义的自定义变量和当前请求
- 发起构造后的请求,将响应写入CEL变量列表
- 执行表达式判断结果
4. xray规则扩展
在xray基础上增加了更细致的请求变形分类:
4.1 规则类型扩展
新增规则类型字段,根据不同类型执行不同变形逻辑:
func (controller *PocController) DoSingleRuleRequest(rule *Rule) (*proto.Response, error) {
fastReq := controller.Request.Fast
fixedFastReq := fasthttp.AcquireRequest()
fastReq.CopyTo(fixedFastReq)
curPath := string(fixedFastReq.URI().Path())
affects := controller.Plugin.Affects
switch affects {
// 情况4 参数级
case AffectAppendParameter, AffectReplaceParameter:
for k, v := range rule.Headers {
fixedFastReq.Header.Set(k, v)
}
return util.DoFasthttpRequest(fixedFastReq, rule.FollowRedirects)
// 情况3 content级
case AffectContent:
return util.DoFasthttpRequest(fixedFastReq, rule.FollowRedirects)
// 情况1 dir级
case AffectDirectory:
// 目录级漏洞检测 判断是否以"/"结尾
if curPath != "" && strings.HasSuffix(curPath, "/") {
// 去掉规则中的的"/" 再拼
curPath = fmt.Sprint(curPath, strings.TrimPrefix(rule.Path, "/"))
} else {
curPath = fmt.Sprint(curPath, "/", strings.TrimPrefix(rule.Path, "/"))
}
// 情况2
case AffectServer:
curPath = rule.Path
// url级(直接使用原始请求头,只替换路径和完整post参数)
case AffectURL:
//curPath = curPath, strings.TrimPrefix(rule.Path, "/"))
default:
}
// 兼容xray: 某些POC没有区分path和query
curPath = strings.ReplaceAll(curPath, " ", "%20")
curPath = strings.ReplaceAll(curPath, "+", "%20")
fixedFastReq.URI().DisablePathNormalizing = true
fixedFastReq.URI().Update(curPath)
for k, v := range rule.Headers {
fixedFastReq.Header.Set(k, v)
}
fixedFastReq.Header.SetMethod(rule.Method)
// 处理multipart
contentType := string(fixedFastReq.Header.ContentType())
if strings.HasPrefix(strings.ToLower(contentType), "multipart/form-Data") &&
strings.Contains(rule.Body, "\n\n") {
multipartBody, err := util.DealMultipart(contentType, rule.Body)
if err != nil {
return nil, err
}
fixedFastReq.SetBody([]byte(multipartBody))
} else {
fixedFastReq.SetBody([]byte(rule.Body))
}
return util.DoFasthttpRequest(fixedFastReq, rule.FollowRedirects)
}
4.2 Multipart处理
对于文件上传等需要multipart格式的POC,需要按照RFC规定处理换行符:
func DealMultipart(contentType string, ruleBody string) (result string, err error) {
errMsg := ""
// 处理multipart的/n
re := regexp.MustCompile(`(?m)multipart\/form-Data; boundary=(.*)`)
match := re.FindStringSubmatch(contentType)
if len(match) != 2 {
errMsg = "no boundary in content-type"
return "", errors.New(errMsg)
}
boundary := "--" + match[1]
multiPartContent := ""
// 处理rule
multiFile := strings.Split(ruleBody, boundary)
if len(multiFile) == 0 {
errMsg = "ruleBody.Body multi content format err"
return multiPartContent, errors.New(errMsg)
}
for _, singleFile := range multiFile {
// 处理单个文件
// 文件头和文件响应
spliteTmp := strings.Split(singleFile, "\n\n")
if len(spliteTmp) == 2 {
fileHeader := spliteTmp[0]
fileBody := spliteTmp[1]
fileHeader = strings.Replace(fileHeader, "\n", "\r\n", -1)
multiPartContent += boundary + fileHeader + "\r\n\r\n" +
strings.TrimRight(fileBody, "\n") + "\r\n"
}
}
multiPartContent += boundary + "--" + "\r\n"
return multiPartContent, nil
}
5. 总结
本文详细介绍了漏洞验证框架规则体系的设计与实现,包括:
- 原始请求的多种来源处理
- 兼容xray CEL表达式规则体系
- 请求变形和检测链控制
- 在xray基础上扩展的更细致请求变形分类
该规则体系既保持了与xray POC规则的兼容性,又增加了更灵活的检测方式,提高了漏洞验证的准确性和效率。