脚本编写

  • 建议先过一遍参考文档:https://docs.xray.cool/#/guide/poc/v2

    YAML

    一种可读的序列化数据,类似JSON。参考:YAML - Wiki

  • 特点:

    • 大小写敏感
    • 可以使用#号注释
    • 使用缩进表示层级关系,缩进不允许使用Tab,可以用空格
  • 关于YAML字符串转义:https://stackoverflow.com/questions/3790454/

    基本信息

  • 文件命名格式为:组件-编号-漏洞类型.yml,如:node-cve-2017-14849-fileread.yml ```yaml

    基本信息

    POC名称,一般格式为 poc-yaml-<组件名>-<漏洞编号>-<漏洞类型>

    name: poc-yaml-test

    区分是否手工编写,Xray有一些poc是自动生成的

    manual: true

  1. <a name="fglJV"></a>
  2. ### 脚本部分
  3. - `set`:定义全局变量
  4. - 随机整数:`变量名: randomInt(min, max)`
  5. - 随机字符:`变量名: randomLowercase(length)`
  6. - `transport`:通信协议,`tcp/udp/http`
  7. - `rules`:语法规则
  8. - `request`字段:定义请求方式和目标路径
  9. - `expression`字段:判断规则是否命中,返回`true/false`
  10. - `out`字段:可以从响应包中获取数据
  11. - `search`字段定义匹配的正则表达式,返回一个字典
  12. - `info:search["info"]`:
  13. - `info`是自定义的变量名,后面可以用`{{info}}`进行调
  14. - `search["info"]`:`search`字典中Key为`info`的值
  15. - `expression`:全部`rule`的执行顺序,遵循短路求值
  16. - 短路求值:即`r1() || r2()`,如果`r1()`的结果为`true`,那么`r2()`不会执行
  17. - 示例:
  18. - `r1() && r2() && r3()`,全部规则命中时返回`true`
  19. - `r1() || r2() || r3()`,任一规则命中时返回`true`
  20. - `r1() || (r2() && r3())`,`r1`规则命中,或者`r2、r3`规则同时命中时返回`true`
  21. ```yaml
  22. # 脚本部分
  23. # 全局变量
  24. set:
  25. # 范围随机整数/字符
  26. randInt0: randomInt(1000, 9999)
  27. randStr1: randomLowercase(10)
  28. # 通信协议
  29. transport: http
  30. # 匹配规则
  31. rules:
  32. r1:
  33. # 请求方式
  34. request:
  35. method: GET
  36. path: "/"
  37. # 最终执行结果
  38. expression: |
  39. response.status == 200 && response.body.bcontains(b"example")
  40. # 从响应包获取数据
  41. output:
  42. # search,指定搜索语法
  43. search: |
  44. r'(?P<info>\|.*\|)'.bsubmatch(response.raw)'
  45. # 变量名:匹配规则
  46. info: search["info"]
  47. # rule执行顺序
  48. expression:
  49. r1()

信息部分

  1. - 完整POC
  2. ```yaml
  3. # 基本信息
  4. # POC名称,一般格式为 poc-yaml-[框架名]-<漏洞编号>
  5. name: poc-yaml-test
  6. # 区分是否手工编写,Xray有一些poc是自动生成的
  7. manual: true
  8. # 脚本部分
  9. # 全局变量
  10. set:
  11. # 范围随机整数/字符
  12. randInt0: randomInt(1000, 9999)
  13. randStr1: randomLowercase(10)
  14. # 通信协议
  15. transport: http
  16. # 匹配规则
  17. rules:
  18. r1:
  19. # 请求方式
  20. request:
  21. method: GET
  22. path: "/"
  23. # 最终执行结果
  24. expression: |
  25. response.status == 200 && response.body.bcontains(b"example")
  26. # 从响应包获取数据
  27. output:
  28. # search,指定搜索语法
  29. search: |
  30. r'(?P<info>\|.*\|)'.bsubmatch(response.raw)'
  31. # 变量名:匹配规则
  32. info: search["info"]
  33. # rule执行顺序
  34. expression:
  35. r1()
  36. # 信息部分,非必填内容
  37. detail:
  38. author: Chaitin(https://chaitin.com/)
  39. links:
  40. - https://docs.xray.cool/
  41. # 还有一些指纹和漏洞信息,可以参考文档

expression

  • 匹配响应包 ```yaml expression: response.status == 200 # Status-Code expression: “zbx_session” in response.headers # Header expression: response.body.bcontains(b”verify_string”) # Body
  1. - 搜索
  2. ```yaml
  3. # 搜索Body
  4. search: |
  5. "\"verify_string\":\"(?P<token>\\w+)\"".bsubmatch(response.body)

常用字段

output - rule完成后的全局变量

定义了这条 rule 运行完成之后的一些变量,该字段定义的变量会被添加到全局变量。

  • out字段下的变量是全局变量,如果2条rule里在匹配正则时,都用到search变量,后面的search的内容会和前面的search一样,也就是说第2条正则不会生效,所以后面info2自然和前面info1一样。不会覆盖也不会报错,第一次遇到的时候排查了很久,记录一下 ```yaml

    错误示例

r0: request: method: GET path: / expression: response.status == 200 output: search: “?P\w+”.bsubmatch(response.body) info1: search[“info”] r1: request: method: GET path: /test.php expression: response.status == 200 output: search: “?P\w+”.bsubmatch(response.body) info2: search[“info”]

  1. - 正确写法应该是命名不同的变量
  2. ```yaml
  3. # 正确示例
  4. r0:
  5. request:
  6. method: GET
  7. path: /
  8. expression: response.status == 200
  9. output:
  10. r0search: "?P<info>\\w+".bsubmatch(response.body)
  11. info1: r0search["info"]
  12. r1:
  13. request:
  14. method: GET
  15. path: /test.php
  16. expression: response.status == 200
  17. output:
  18. r1search: "?P<info>\\w+".bsubmatch(response.body)
  19. info2: r1search["info"]

follow_redirects - 跟随跳转

  • 可以通过设置follow_redirects: bool来判断是否允许跟随30X跳转
  • 举例场景:

    • 如果需要从一个302跳转的包中取值并设置到Cookie中,这个时候就需要显式设置follow_redirects为´false,然后再手动发起一次新的请求包。否则如果跟随跳转的话,则会携带原来Cookie

      payload - 全局变量载荷

      该字段用于定义多个 payload,来实现发送不同 payload 的效果。

  • 这个字段是POCv2版本新增的,Gamma语法检查时会报错,但是实际可以运行 | 变量名/函数名 | 类型 | 说明 | | —- | —- | —- | | continue | bool | 命中一个之后是否继续,默认false命中即停 | | payloads | map[string]Set | 和 set 一样的结构和语法 |

  • 每个 payload 中的 key 必须严格一致 ```shell payloads: payloads: ping:

    1. cmd: r"ping test.com"

    curl:

    1. cmd: r"curl test.com"
  1. <a name="ndzce"></a>
  2. ### reverse - 反连平台
  3. - 设变量名为`reverse`,需要先使用`newReverse()`生成实例)
  4. | **变量名/函数名** | **类型** | **说明** |
  5. | --- | --- | --- |
  6. | reverse.url | urlType | 反连平台的 url |
  7. | reverse.domain | string | 反连平台的域名 |
  8. | reverse.ip | string | 反连平台的 ip 地址 |
  9. | reverse.is_domain_name_server | bool | 反连平台的 domain 是否同时是 nameserver |
  10. | reverse.wait(timeout) | func (timeout int) bool | 等待 timeout 秒,并返回是否在改时间内获得了信息 |
  11. ```yaml
  12. set:
  13. reverse: newReverse()
  14. reverseURL: reverse.url
  15. rules:
  16. r1:
  17. request:
  18. method: POST
  19. path: "/xxx/{{reverseURL}}"
  20. expression: |
  21. reverse.wait(5)

参考知识

CEL

  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/520228/1645687966683-80b0aa97-9e6d-4bd8-8885-a2e963d61f92.png#clientId=ub141f219-a495-4&from=paste&height=426&id=LhSZR&margin=%5Bobject%20Object%5D&name=image.png&originHeight=852&originWidth=1087&originalType=binary&ratio=1&size=249794&status=done&style=none&taskId=ufb0e0e26-b76f-4d57-881b-d95714012e8&width=543.5)
  2. - [Gamma](https://github.com/chaitin/gamma):提供YAML脚本运行环境,请求响应会以Base64编码形式返回,可以使用`--http-proxy`参数代理到Burp中
  3. ```shell
  4. # 语法检查
  5. $ gamma lint --script xxx.yml
  6. # 运行
  7. $ gamma run --target "http://xxx.com" --script xxx.yml
  8. # 调试运行
  9. $ GAMMA_LOG_LEVEL=debug ./gamma run --no-cache --target "http://xxx.com" --script xxx.yml
  10. # 搭配Burp调试
  11. $ gamma run --target "http://xxx.com" --script xxx.yml --http-proxy http://127.0.0.1:8080

image.png
image.png

作业