chaitin / xray

一款完善的安全评估工具,支持常见 web 安全问题扫描和自定义 poc | 使用之前务必先阅读文档
https://docs.xray.cool
Other
10.41k stars 1.83k forks source link

[Bugs] xray 问题反馈 #1493

Closed zema1 closed 7 months ago

zema1 commented 3 years ago

最近几天我做了一个神秘的工具,无意间发现了一些 xray 当前版本中存在的问题,希望有好心人能看下 版本: windows 1.8.2

poc 问题

跳转问题

run poc poc-yaml-sangfor-edr-arbitrary-admin-login err: execute r0() err: Get "http://127.0.0.1:7788/ui/login.php?user=admin": 302 response missing Location header

这个 poc 判断条件是 302 且不允许跳转,判断条件中也没有 Location 的判断,我猜是没处理好 follow_redirects

multipart 问题

目前 mutlipart 的 poc 发出去的包有问题,\r\n 不太对。我看了一下并非是新版引入的问题,至少 1.7 也是有问题的... image

phith0n commented 3 years ago

r0() || r1() 这个问题好像之前说过,Go的实现也有问题么?

likewhite commented 3 years ago

multipart 问题 我也发现了,缺少\r后端无法识别该请求包

zema1 commented 3 years ago

运行逻辑那个好像没啥问题,我又复现不了了。。可以再确认下

假设外层的 expression 是 r0() || r1() ,那么即使 r0 成功了,r1 也会执行,我猜这个和 cel 的执行有关,cel 没有对这类情况做优化。但理论上来说应该提前结束。

yywing commented 2 years ago

这个 poc 判断条件是 302 且不允许跳转,判断条件中也没有 Location 的判断,我猜是没处理好 follow_redirects

这个我本地测试没啥问题呀

求提供一个复现环境

yywing commented 2 years ago

运行逻辑那个好像没啥问题,我又复现不了了。。可以再确认下

假设外层的 expression 是 r0() || r1() ,那么即使 r0 成功了,r1 也会执行,我猜这个和 cel 的执行有关,cel 没有对这类情况做优化。但理论上来说应该提前结束。

下个版本添加一个 GAMMA_LOG_LEVEL 的环境变量可以打印 rule 执行的最后结果,可以看一下

yywing commented 2 years ago

目前 mutlipart 的 poc 发出去的包有问题,\r\n 不太对。我看了一下并非是新版引入的问题,至少 1.7 也是有问题的...

以 poc-yaml-apache-flink-upload-rce 为例

目前 body 里面内容是 \n 换行的,poc 框架这边没有做任何特殊的处理

目前可以有 2 种方案:

  1. 如果 content type 为 form data 的话,自动把 \n 替换成 \r\n
  2. 要求写 poc 的人 写为 \r\n

个人倾向于第二种

zema1 commented 2 years ago

第一种确实好一些,只是现在的 poc 格式需要批量改一波,而且比较简易 multipart 的 poc 的 body 直接用 str 表示,就是下面这种格式

body: "boundary\r\n\x89"

跳转那个你花一分钟写个 server 就是了

func main() {
    http.HandleFunc("/ui/login.php", func(writer http.ResponseWriter, request *http.Request) {
        // response.status == 302 && response.body.bcontains(b"/download/edr_installer_") && response.headers["Set-Cookie"] != ""
        writer.Header().Set("Set-Cookie", "rand-value")
        writer.WriteHeader(302)
        writer.Write([]byte("/download/edr_installer_"))
    })
    fmt.Println(http.ListenAndServe("127.0.0.1:7788", http.DefaultServeMux))
}
.\xray_windows_amd64.exe --log-level debug webscan --plugins phantasm --poc "*sangfor-edr-arbitrary-admin-login" --url http://127.0.0.1:7788

[DBUG] 2021-11-16 11:04:20 [phantasm:yaml_finger.go:89] run poc poc-yaml-sangfor-edr-arbitrary-admin-login err: execute r0() err: Get "http://127.0.0.1:7788/ui/login.php?user=admin": 302 response missing Location header
zema1 commented 2 years ago

https://github.com/chaitin/xray/pull/1542

yywing commented 2 years ago

https://github.com/chaitin/xray/issues/1493#issuecomment-968690547

对于这个 commit 中说的 multipart/form-data 的处理决定还是不自动进行处理。

理由:

  1. 之前的实现是没有处理
  2. 尽量不要再引入规定和定义了,如果处理了,遇到真的想构造 全是 \n 的怎么包,还要再定义一套表示方式?这样不优雅

那么如何让这种请求写得更优雅一点呢?

yaml 本身提供的字符串输入格式还是很强的:

还是以 apache-flink-upload-rce.yml 这个 yaml 为例, 其中需要发送 multipart/form-data 的包。它的每一行是要以 \r\n(hex 0d 0a) 结尾的。

目前错误的写法:(可以关注其中的 0a)

data: |-
    --8ce4b16b22b58894aa86c421e8759df3
    Content-Disposition: form-data; name="jarfile";filename="{{r2}}.jar"
    Content-Type:application/octet-stream

    {{r1}}
    --8ce4b16b22b58894aa86c421e8759df3--
# 00000000  2d 2d 38 63 65 34 62 31  36 62 32 32 62 35 38 38  |--8ce4b16b22b588|
# 00000010  39 34 61 61 38 36 63 34  32 31 65 38 37 35 39 64  |94aa86c421e8759d|
# 00000020  66 33 0a 43 6f 6e 74 65  6e 74 2d 44 69 73 70 6f  |f3.Content-Dispo|
# 00000030  73 69 74 69 6f 6e 3a 20  66 6f 72 6d 2d 64 61 74  |sition: form-dat|
# 00000040  61 3b 20 6e 61 6d 65 3d  22 6a 61 72 66 69 6c 65  |a; name="jarfile|
# 00000050  22 3b 66 69 6c 65 6e 61  6d 65 3d 22 7b 7b 72 32  |";filename="{{r2|
# 00000060  7d 7d 2e 6a 61 72 22 0a  43 6f 6e 74 65 6e 74 2d  |}}.jar".Content-|
# 00000070  54 79 70 65 3a 61 70 70  6c 69 63 61 74 69 6f 6e  |Type:application|
# 00000080  2f 6f 63 74 65 74 2d 73  74 72 65 61 6d 0a 0a 7b  |/octet-stream..{|
# 00000090  7b 72 31 7d 7d 0a 2d 2d  38 63 65 34 62 31 36 62  |{r1}}.--8ce4b16b|
# 000000a0  32 32 62 35 38 38 39 34  61 61 38 36 63 34 32 31  |22b58894aa86c421|
# 000000b0  65 38 37 35 39 64 66 33  2d 2d                    |e8759df3--|

我们可以用 " 来表示此包。需要做的事情是:

  1. 转义掉其中的 "
  2. 正确的处理换行,该格式下对于换行的处理:
    1. 换行会变成空格, 如果想不变成空格,需要结尾加 \
    2. 2 连换行会变成换行, \n 会变成换行
    3. 支持转义, " 需要转义

比较适宜阅读的写法为:

data: "\
    --8ce4b16b22b58894aa86c421e8759df3\r\n\ 
    Content-Disposition: form-data; name=\"jarfile\";filename=\"{{r2}}.jar\"\r\n\
    Content-Type:application/octet-stream\r\n\
    \r\n\
    {{r1}}\r\n\
    --8ce4b16b22b58894aa86c421e8759df3--\
    "
# 00000000  2d 2d 38 63 65 34 62 31  36 62 32 32 62 35 38 38  |--8ce4b16b22b588|
# 00000010  39 34 61 61 38 36 63 34  32 31 65 38 37 35 39 64  |94aa86c421e8759d|
# 00000020  66 33 0d 0a 43 6f 6e 74  65 6e 74 2d 44 69 73 70  |f3..Content-Disp|
# 00000030  6f 73 69 74 69 6f 6e 3a  20 66 6f 72 6d 2d 64 61  |osition: form-da|
# 00000040  74 61 3b 20 6e 61 6d 65  3d 22 6a 61 72 66 69 6c  |ta; name="jarfil|
# 00000050  65 22 3b 66 69 6c 65 6e  61 6d 65 3d 22 7b 7b 72  |e";filename="{{r|
# 00000060  32 7d 7d 2e 6a 61 72 22  0d 0a 43 6f 6e 74 65 6e  |2}}.jar"..Conten|
# 00000070  74 2d 54 79 70 65 3a 61  70 70 6c 69 63 61 74 69  |t-Type:applicati|
# 00000080  6f 6e 2f 6f 63 74 65 74  2d 73 74 72 65 61 6d 0d  |on/octet-stream.|
# 00000090  0a 0d 0a 7b 7b 72 31 7d  7d 0d 0a 2d 2d 38 63 65  |...{{r1}}..--8ce|
# 000000a0  34 62 31 36 62 32 32 62  35 38 38 39 34 61 61 38  |4b16b22b58894aa8|
# 000000b0  36 63 34 32 31 65 38 37  35 39 64 66 33 2d 2d     |6c421e8759df3--|

PS:也可以写在一行,就是比较难读 PSS: 要是愿意的话,也可以用 2 连换行来表示 \n 不过也有点难看就是了 -_-

yywing commented 2 years ago

https://github.com/chaitin/xray/pull/1574/

修改了:

yywing commented 2 years ago

poc-yaml-seeyon-a6-test-jsp-sql and poc-yaml-yongyou-u8-oa-sqli 重复,建议删掉一个

1580

yywing commented 2 years ago

这个 poc 判断条件是 302 且不允许跳转,判断条件中也没有 Location 的判断,我猜是没处理好 follow_redirects

仔细研究了一下 是 go 的锅, go 的http 库:

  1. 先请求一下,然后会调用 redirectBehavior 这个方法
  2. 发现需要被重定向的时候会先创建出 重定向的请求(在这报错的)
  3. 然后调用 CheckRedirect

真蠢呀 - -

https://github.com/golang/go/issues/49281

看有人已经提交了一个修复了,等合并之后更新一下 go 的版本就能解决这个问题了