前言
以前也有用xray扫扫学校的漏洞,最近有在开发自己的扫描平台,估借此机会再学习。
VulnType的复现在最后边。
三种基本模式
代理模式
初始配置证书部分看官方文档吧Orz, 代理模式进行扫描 - xray 安全评估工具文档
建议配合 SwitchyOmega 这个插件使用,可以随意切换代理服务器及端口。
config.yaml
配置好
mitm:
restriction: # 代理能够访问的资源限制, 以下各项为空表示不限制
hostname_allowed: ['*.web-security-academy.net','192.168.3.188'] # 允许访问的 Hostname,支持格式如 t.com、*.t.com、1.1.1.1、1.1.1.1/24、1.1-4.1.1-8
然后游览页面即可,若没有config.yaml
则先运行一次xray
基础爬虫模式
爬虫模式是模拟人工去点击网页的链接,然后去分析扫描,爬虫不需要人工的介入,访问速度要快很多,但是也有一些缺点
- xray 的基础爬虫不能处理 js 渲染的页面
./xray webscan --basic-crawler http://testphp.vulnweb.com/ --html-output xray-crawler-testphp.html
配置Cookie
配置文件config.yaml
里,http
配置部分的 headers
项:
添加一条Cookie,如
headers:
Cookie: key=value
例子
http:
...
headers:
Cookie: sysauth=xxxxx
服务扫描
目前主要是服务扫描相关的poc,目前只有一个 tomcat-cve-2020-1938 ajp 协议任意文件检测 poc。
target参数支持ip:port方式,和 xxx.file方式
./xray servicescan --target 127.0.0.1:8009
./xray servicescan --target xxx.file
xxx.file格式,一行一个ip:port目标,进行批量导入
127.0.0.1:8009
10.1.1.1:8099
可以使用如下不同的导出方式
NAME:
servicescan - Run a service scan task
USAGE:
servicescan [command options] [arguments...]
OPTIONS:
--target value 指定单一目标,例子: host:8009
--target-file value 从文件加载目标,一目标一行
--json-output FILE 使用json格式导出xray结果
--webhook-output value 用json格式post xray结果到某url
--html-output FILE 用html格式导出报告
配置文件
HTTP 配置
http:
proxy: "" # 漏洞扫描时使用的代理,如: http://127.0.0.1:8080。 如需设置多个代理,请使用 proxy_rule 或自行创建上层代理
proxy_rule: [] # 漏洞扫描使用多个代理的配置规则, 具体请参照文档
代理配置
支持 http
, https
和 socks5
三种格式,如:
http://127.0.0.1:1111
https://127.0.0.1:1111
socks5://127.0.0.1:1080
如果代理需要认证,可以使用下面的格式 http://user:password@127.0.0.1:1111
多代理配置
不同的域名使用不同的代理,设置多个代理切换等,可以通过 proxy_rule
字段来配置。==Proxy 配置将优先于本配置。==
proxy_rule:
- match: "*host1"
servers:
- addr: "http://127.0.0.1:8001"
weight: 1
- addr: "http://127.0.0.1:8002"
weight: 2
- match: "*"
servers:
- addr: "http://127.0.0.1:8003"
weight: 1
- addr: "http://127.0.0.1:8004"
weight: 5
- match: 请求的 url 的主机名如果匹配,就使用本条规则。
- 如果是
*
,则代表可以匹配所有。所以一定要将*
放在最后面,上面没有匹配到的域名都将使用这个配置。 - 如果没有任何一条可以匹配,这个请求将不会使用代理。
- 如果是
- addr: 代理服务器的地址,同
proxy
的配置。 - weight: 代理服务器的权重,如果
servers
中配置了多个代理服务器,设置权重可以均衡负载,比如权重是3:7
,则代表每 10 个请求,有 3 个选择 server1,有 7 个选择 server2。要注意的是,这里是 round bin 算法,前 3 个一定发往 server1,后面 7 个一定发往 server2,然后继续循环,不是每个请求都是基于权重随机的。
插件配置
dirscan
depth
深度限制dictionary
配置目录字典, 需要是绝对路径, 配置后将与内置字典合并
depth
是探测深度, 默认为 1, 即只在 URL 深度为 0, 和深度为 1 时运行该插件(前提是启用了该插件)
定义 http://example.com/
,深度为 0,定义 http://example.com/a/
, 深度为 1。 在这种配置下,dirscan 将对
http://example.com/
和 http://example.com/a/
做两次扫描,如果存在 http://example.com/a/example.zip
那么就能将其扫描出来。
sqldet
下面这个选项很危险,开启之后可以增加检测率,但是有破坏数据库数据的可能性,请务必了解工作原理之后再开启
dangerously_use_comment_in_sql
允许检查注入的时候使用注释
phantasm
xray 的 poc 框架,在其下运行着许多 yaml 和 go 写的 poc,用户可以通过该模块编写自己的 poc 并让 xray 加载,具体见 自定义POC语法
两个重点配置:
depth: 1 # 与 dirscan 一样,不再赘述
exclude_poc: [] # 排除哪些 poc, 支持 glob 语法, 如: /home/poc/*thinkphp* 或 poc-yaml-weblogic*
local_poc: [] # 加载本地的 poc, 支持 glob 语法, 如: /home/poc/*
exclude_poc
用于去除加载哪些 poc。
plugins:
...
phantasm:
enabled: true
exclude_poc:
- poc-yaml-bad-poc
- *bad-poc*
local_poc
是用于加载本地的 poc 的配置,最好指定绝对路径,且同样支持 glob 语法。
一个稍微复杂的情况是将这两个搭配起来使用,比如:
plugins:
...
phantasm:
enabled: true
exclude_poc:
- /home/poc/poc-fake-good-poc
local_poc:
- /home/poc/*good-poc*
上述配置的意思是加载 /home/poc/
目录下所有符合 *good-poc*
这个pattern 的poc,同时去掉同样目录下的 poc-fake-good-poc
被动代理配置
这部分是代理模式的配置
代理启用密码保护
对应于 auth
中的配置。
支持给代理配置基础认证的密码,当设置好 auth
中的 username
和 password
后,使用代理时浏览器会弹框要求输出用户名密码,输入成功后代理才可正常使用。
限制允许使用该代理的ip
allow_ip_range
,限制哪些ip可以使用该代理。支持单个 IP 和 CIDR 格式的地址,如:
allow_ip_range: ["127.0.0.1","192.168.1.1/24"]
留空则允许所有地址访问
限制扫描范围
restriction
中,allowed即为允许访问的,disallowed即为不允许的。如
hostname_allowed: [] # 允许访问的 Hostname,支持格式如 t.com、*.t.com、1.1.1.1、1.1.1.1/24、1.1-4.1.1-8
hostname_disallowed: # 不允许访问的 Hostname,支持格式如 t.com、*.t.com、1.1.1.1、1.1.1.1/24、1.1-4.1.1-8
- '*google*'
代理请求头配置 proxy_header
proxy_header:
via: "" # 如果不为空,proxy 将添加类似 Via: 1.1 $some-value-$random 的 http 头
x_forwarded: false # 是否添加 X-Forwarded-{For,Host,Proto,Url} 四个 http 头
如果开启 proxy_header,代理会添加 via
头和 X-Forwarded-*
系列头。
比如 curl http://127.0.0.1:1234 -H "Via: test" -H "X-Forwarded-For: 1.2.3.4" -v
,后端实际收到的请求将会是
GET / HTTP/1.1
Host: 127.0.0.1:1234
User-Agent: curl/7.54.0
Accept: */*
Via: test, 1.1 xray-1fe7f9e5241b2b150f32
X-Forwarded-For: 1.2.3.4, 127.0.0.1
X-Forwarded-Host: 127.0.0.1:1234
X-Forwarded-Proto: http
X-Forwarded-Url: http://127.0.0.1:1234/
Accept-Encoding: gzip
http的代理 upstream_proxy
该项配置仅对 http 代理本身生效,不对漏洞扫描发出的请求生效。漏扫的代理配置HTTP部分
基础爬虫配置
看配置就行
basic-crawler:
max_depth: 0 # 最大爬取深度, 0 为无限制
max_count_of_links: 0 # 本次爬取收集的最大链接数, 0 为无限制
allow_visit_parent_path: false # 是否允许爬取父目录, 如果扫描目标为 t.com/a/且该项为 false, 那么就不会爬取 t.com/ 这级的内容
restriction: # 爬虫的允许爬取的资源限制, 为空表示不限制。爬虫会自动添加扫描目标到 Hostname_allowed。
hostname_allowed: [] # 允许访问的 Hostname,支持格式如 t.com、*.t.com、1.1.1.1、1.1.1.1/24、1.1-4.1.1-8
hostname_disallowed: # 不允许访问的 Hostname,支持格式如 t.com、*.t.com、1.1.1.1、1.1.1.1/24、1.1-4.1.1-8
- '*google*'
- '*github*'
- '*.gov.cn'
- '*.edu.cn'
- '*chaitin*'
- '*.xray.cool'
port_allowed: [] # 允许访问的端口, 支持的格式如: 80、80-85
port_disallowed: [] # 不允许访问的端口, 支持的格式如: 80、80-85
path_allowed: [] # 允许访问的路径,支持的格式如: test、*test*
path_disallowed: [] # 不允许访问的路径, 支持的格式如: test、*test*
query_key_allowed: [] # 允许访问的 Query Key,支持的格式如: test、*test*
query_key_disallowed: [] # 不允许访问的 Query Key, 支持的格式如: test、*test*
fragment_allowed: [] # 允许访问的 Fragment, 支持的格式如: test、*test*
fragment_disallowed: [] # 不允许访问的 Fragment, 支持的格式如: test、*test*
post_key_allowed: [] # 允许访问的 Post Body 中的参数, 支持的格式如: test、*test*
post_key_disallowed: [] # 不允许访问的 Post Body 中的参数, 支持的格式如: test、*test*
basic_auth: # 基础认证信息
username: ""
password: ""
反连平台
反连平台默认不启用,因为这里面有些配置没有办法自动化,必须由人工配置完成才可使用。需要反连平台才可以检测出来的漏洞包括但不限于:
- ssrf
- fastjson
- s2-052
- xxe 盲打
- 所有依赖反连平台的 poc
reverse:
db_file_path: "" # 反连平台数据库文件位置, 这是一个 KV 数据库
token: "" # 反连平台认证的 Token, 独立部署时不能为空
http:
enabled: false
listen_ip: 0.0.0.0
listen_port: ""
ip_header: "" # 在哪个 http header 中取 ip,为空代表从 REMOTE_ADDR 中取
dns:
enabled: false
listen_ip: 0.0.0.0
domain: "" # DNS 域名配置
is_domain_name_server: false # 是否修改了域名的 ns 为反连平台,如果是,那 nslookup 等就不需要指定 dns 了
resolve: # DNS 静态解析规则
- type: A # A, AAAA, TXT 三种
record: localhost
value: 127.0.0.1
ttl: 60
client:
remote_server: false # 是否是独立的远程 server,如果是要在下面配置好远程的服务端地址
http_base_url: "" # 默认将根据 ListenIP 和 ListenPort 生成,该地址是存在漏洞的目标反连回来的地址, 当反连平台前面有反代、绑定域名、端口映射时需要自行配置
dns_server_ip: "" # 和 http_base_url 类似,实际用来访问 dns 服务器的地址
例子
xray和目标可以用ip双向互联
假设 192.168.1.2 是 xray 所在机器的地址
reverse:
http:
enabled: true
listen_ip: 192.168.1.2
这里的 192.168.1.2 是 xray 所在的机器的地址, 也是扫描目标反连时所使用的地址。也就是,目标存在漏洞的时候,会访问 http://192.168.1.2/xxxx 携带漏洞结果和数据
xray 和目标可以使用 ip 双向互联,但 listen 的地址和目标反连访问的地址不一样
这种情况经常出现在云主机中,比如腾讯云的 linux 机器网卡地址时 10.xxx,但实际公网假设是 221.xxx
reverse:
http:
enabled: true
listen_ip: 0.0.0.0
client:
http_base_url: "http://221.xxx:${port}"
${port}
是一个预定义的宏,在运行时将被替换为实际监听的端口, 当然你也可以使用这种方式固定监听的端口:
reverse:
http:
enabled: true
listen_ip: 0.0.0.0
listen_port: 8888
client:
http_base_url: "http://221.xxx:8888"
单独布置反连平台
xray 自带了一个 reverse
命令,可以启动反连平台作为一个远程服务运行,给多个客户端使用。
在启动之前,需要配置好配置文件的 db_file_path
和 token
,前者用于存储数据,后者用于服务端和客户端通信的秘钥。
一个示例的服务端配置是:
reverse:
db_file_path: "reverse.db"
token: "please_change_me_to_a_new_token"
http:
listen_ip: 0.0.0.0
listen_port: "80"
与之对应的客户端配置是:
reverse:
token: "please_change_me_to_a_new_token"
client:
remote_server: true
http_base_url: "http://YOUR_REVERSE_SERVER_IP:80"
需要客户端和服务端版本相同
管理界面
反连平台贴心的内置了一个管理界面,可以访问反连平台 http 地址,url 为 /cland/
。
功能包括
- 生成自定义 url,并记录访问记录
- 生成自定义域名,并记录解析记录
- 使用平台预制 payload,记录抓取的数据
mac 下的 docker 由于网络环境特殊,其实无法双向互联,建议使用远程部署的模式或使用
host.docker.internal
作为 http_base_url 的 host
子域名配置
subdomain:
max_parallel: 30 # 子域名探测的并发度
allow_recursion: false # 是否允许递归探测, 开启后,扫描完一级域名后,会自动将一级的每个域名作为新的目标
max_recursion_depth: 3 # 最大允许的递归深度, 3 表示 3 级子域名 仅当 allow_recursion 开启时才有意义
web_only: false # 结果中仅显示有 web 应用的, 没有 web 应用的将被丢弃
ip_only: false # 结果中仅展示解析出 IP 的,没有解析成功的将被丢弃
servers: # 子域名扫描过程中使用的 DNS Server
- 8.8.8.8
- 8.8.4.4
- 223.5.5.5
- 223.6.6.6
- 114.114.114.114
sources:
brute:
enabled: true
main_dict: "" # 一级大字典路径,为空将使用内置的 TOP 30000 字典
sub_dict: "" # 其他级小字典路径,为空将使用内置过的 TOP 100 字典
httpfinder:
enabled: true # 使用 http 的一些方式来抓取子域名,包括 js, 配置文件,http header 等等
dnsfinder:
enabled: true # 使用 dns 的一些错误配置来找寻子域名,如区域传送(zone transfer)
certspotter: # 下面的通过 api 获取的了
enabled: true
crt:
enabled: true
hackertarget:
enabled: true
qianxun:
enabled: true
rapiddns:
enabled: true
sublist3r:
enabled: true
threatminer:
enabled: true
virusTotal:
enabled: true
检查更新配置
添加如下即可禁用更新检查
update:
check: false
并发配置
parallel: 30 # 漏洞探测的 worker 数量,可以简单理解为同时有 30 个 POC 在运行
默认基本足够
高级用法
优化扫描速度
在 xray 的默认配置中,影响扫描速度的主要有两个参数
max_qps
每秒最大请求数,默认值为 500max_parallel
插件调度并发数,默认值为 30
即使到了 2000 qps,也还没有达到配置的检测最大并发,所以
max_parallel
一般情况下不需要修改。max_qps
在非测试场景下,也很难打满,一般情况下只会改低,防止影响业务,而不需要再调高。
总结
限制 xray 扫描速度的主要原因为
- xray 与被扫描目标之间的网络情况
- 被扫描目标的性能;否则网络再好,扫描速度也无法提升
这两点可以从 latency
和 failedRatio
字段评估。latency
比较大,超过 100ms,说明网络比较慢,或者被扫描的目标响应比较慢。failedRatio
比较大,说明网络比较差,或者被扫描目标负载高而失去了响应等。
在网络情况稳定的情况下,可以考虑
- 降低
max_qps
,防止业务方负载过高 - 关闭特定模块和禁用部分 poc,减少请求量
- 不要性能比较差的代理作为 xray 的扫描代理,比如 burp 的代理通过请求的速度基本只有几十 qps,这样整个扫描的瓶颈就在 burp 上了。
自定义POC语法和编写高质量POC
webhook
--webhook-output
统一的格式为:
{
"type": "xxx",
"data": {}
}
type 的 enum 为 :
- “web_statistic” web 扫描统计信息
- “web_vuln” web 漏洞
- “host_vuln” 服务漏洞
- “subdomain” 子域名
漏洞信息
{
"type": "web_vuln",
"data": {
"create_time": 1604736253090,
"detail": {
"addr": "http://127.0.0.1:9000/xss/example1.php?name=hacker",
"extra": {
"param": {
"key": "name",
"position": "query",
"value": "pkbnekwkjhwzabxnfjwh"
}
},
"payload": "<sCrIpT>alert(1)</ScRiPt>",
"snapshot": [
[
"GET /xxx",
"HTTP/1.1 200 OK"
]
]
},
"plugin": "xss/reflected/default",
"target": {
"params": [],
"url": "http://127.0.0.1:9000/xss/example1.php"
}
}
}
- type 是
web_vuln
或host_vuln
- snapshot 是漏洞探测的请求流,定义是
[][2]string
, 即每一组有两部分,对应于请求和响应。对于 sql 注入这种就会有多组请求响应。 - target 实际意义不大, 主要是 detail 中的部分, detail 的定义为:
type VulnDetail struct {
Addr string `json:"addr" yaml:"addr"`
Payload string `json:"payload" yaml:"payload"`
SnapShot []interface{} `json:"snapshot" yaml:"snapshot"`
Extra map[string]interface{} `json:"extra" yaml:"extra"`
}
web统计信息
{
"type": "web_statistic",
"data": {
"num_found_urls": 1,
"num_scanned_urls": 1,
"num_sent_http_requests": 3,
"average_response_time": 0,
"ratio_failed_http_requests": 0,
}
}
num_found_urls
发现的扫描目标数量num_scanned_urls
已扫描完成的扫描目标数量num_sent_http_requests
已经发出的漏洞探测请求数量average_response_time
近 30s 请求平均响应时间ratio_failed_http_requests
近 30s 请求失败率
这些信息除了表面意思,还有其他隐藏含义:
- pending 的数量等于
num_found_urls
-num_scanned_urls
, 如果 pending = 0,那么就意味着扫描完成了 average_response_time
比较高 (>200ms) 意味着网络延迟比较大ratio_failed_http_requests
比较高(>5%) 意味着可能有 waf, 反正就是很多请求失败了
子域名消息格式
{
"type": "subdomain",
"data": {
"cname": [],
"domain": "example.com",
"extra": "",
"ip": [
{
"asn": "EDGECAST (ASN15133)",
"country": "北美洲 美国",
"ip": "93.184.216.34"
},
{
"asn": "EDGECAST (ASN15133)",
"country": "北美洲 美国",
"ip": "2606:2800:220:1:248:1893:25c8:1946"
}
],
"parent": "example.com",
"verbose_name": "initial",
"web": [
{
"link": "http://example.com/",
"server": "ECS (sjc/4FB8)",
"status": 200,
"title": "Example Domain"
},
{
"link": "https://example.com/",
"server": "ECS (sjc/4E8D)",
"status": 200,
"title": "Example Domain"
}
]
}
}
VulnType大类复现
Server-error
使用bp的Repeater,设置目标复制Request即可。由于是概率引发error,多次刷新才行。
crossdomain
config/ide
其中,FileEditorManager包含文件名及相对路径
<component name="FileEditorManager">
...
<file leaf-file-name="cart.php" pinned="false" current="true" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/cart.php">
Git.Settings包含Git的一些设置
<component name="Git.Settings">
<option name="CHECKOUT_INCLUDE_TAGS" value="false"/>
<option name="UPDATE_CHANGES_POLICY" value="STASH"/>
<option name="LINE_SEPARATORS_CONVERSION" value="ASK"/>
</component>
ide文件历史记录
<component name="IdeDocumentHistory">
<option name="changedFiles">
<list>
<option value="$PROJECT_DIR$/.htaccess"/>
<option value="$PROJECT_DIR$/cart.php"/>
</list>
</option>
</component>
修改历史记录
<component name="ChangeListManager">
<list default="true" id="190e5f86-a42c-4cc9-a03a-80ac0d47d6d2" name="Default" comment=""/>
<ignored path="acuart.iws"/>
<ignored path=".idea/workspace.xml"/>
<option name="TRACKING_ENABLED" value="true"/>
<option name="SHOW_DIALOG" value="false"/>
<option name="HIGHLIGHT_CONFLICTS" value="true"/>
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false"/>
<option name="LAST_RESOLUTION" value="IGNORE"/>
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/.htaccess">
<provider selected="true" editor-type-id="text-editor">
<state line="6" column="0" selection-start="213" selection-end="222" vertical-scroll-proportion="0.124847">
...
<entry file="file://$PROJECT_DIR$/cart.php">
<provider selected="true" editor-type-id="text-editor">
<state line="60" column="26" selection-start="2336" selection-end="2336" vertical-scroll-proportion="-0.41645244">
...
</component>
poc-yaml-phpstudy-nginx-wrong-resolve
请求了
94561621.php
index.php
index.php/.php
index.php/.xxx
只有index.php
和index.php/.php
请求成功了,并且都返回的是index.php的页面。但由于网页使用相对路径加载图片,所以在index.php/.php
时图片都无法正常加载。
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付