Skip to content

Instantly share code, notes, and snippets.

@Mr-xn
Last active December 12, 2022 03:04
Show Gist options
  • Save Mr-xn/f91c02c06bbd9a809d1c36de4e68e94d to your computer and use it in GitHub Desktop.
Save Mr-xn/f91c02c06bbd9a809d1c36de4e68e94d to your computer and use it in GitHub Desktop.
arl docker

docker 部署 arl 及其注意事项

安装 docker

这里选择安装 docker-ce 版本 根据不同的平台请参考官方教程

https://docs.docker.com/engine/install/

另外安装docker过程可能受国内网络环境影响会有点慢 可以选择添加清华的源来进行加速下载,具体修改源的方法请查看下面的URL

https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/

修改配置

  • 修改镜像源

如果是在国内机器,修改一下镜像源,加快部署速度

# 往 /etc/docker/daemon.json 文件写入下面的内容,配置docker镜像源
{
        "registry-mirrors":[
            "http://hub-mirror.c.163.com/",
            "https://docker.mirrors.ustc.edu.cn"
        ]
}
#重启docker守护进程让修改生效。
systemctl daemon-reload
systemctl restart docker
  • 配置 docker日志文件
# 设置日志个数和大小,防止过大的日志文件耗尽硬盘空间
新建/etc/docker/daemon.json,若有就不用新建了。添加log-dirver和log-opts参数,样例如下:

# vim /etc/docker/daemon.json

{
  "log-driver":"json-file",
  "log-opts": {"max-size":"100m", "max-file":"3"}
}

max-size=100m,意味着一个容器日志大小上限是100M, 
max-file=3,意味着一个容器有三个日志,分别是id+.json、id+1.json、id+2.json。

然后重启docker的守护线程
systemctl daemon-reload
systemctl restart docker

## 如果有需要可以修改 docker-compose.yaml 文件中的 Port 部分只监听本地,通过 nginx 反代
127.0.0.1:5003:443

安装 docker-compose

先安装pip, 新版本在python2下运行有点问题, 优先选择python3进行安装

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py  
pip3 install  -i https://pypi.tuna.tsinghua.edu.cn/simple docker-compose

安装ARL

可以选择在releases下载最新的docker.zip启动,docker环境的话只是需要docker-compose.yml文件和一些其他配置文件。

mkdir docker_arl
国内
wget -O docker_arl/docker2.5.2.zip https://github.com/TophantTechnology/ARL/releases/download/v2.5.2/docker.zip
cd docker_arl
unzip docker2.5.2.zip
docker volume create arl_db
docker-compose up -d

这里 git clone 只是为了获取docker-compose.yml 等文件,鉴于国内网速请选择上面的方法执行。

git clone https://github.com/TophantTechnology/ARL
cd ARL/docker
docker volume create arl_db
docker-compose up -d

查看是否正常启动
docker-compose ps
看下日志
tail -f *.log

arl的日志自清理

arl在运行后会在运行的根目录产生两个日志文件: arl_web.log 和 arl_worker.log ,时间长了和任务多了之后,这两个日志文件可以很快的达到数百兆或者数 G ,对于一些储存紧张的机器来说是一种负担,当达到一定的时候,影响系统本身的运行。

利用 Linux 系统的 logrotate 来实现自动压缩分割日志,其余的介绍可以参考Linux日志工具logrotate详解

通过在 /etc/logrotate.d/ 目录下新建一个 arl 清理用的配置,比如 arl_clean vim /etc/logrotate.d/arl_clean 将如下内容中的开头的 arl 安装路径替换成你自己的后,粘贴进去,保存即可,logrotate 默认每天执行

/root/docker_arl/arl_*.log {
    missingok
    notifempty
    daily
    create 0644 root root
    minsize 100M
    rotate 3
    dateext
    compress
}

执行效果如下,会生成压缩后的文件:

arl_web.log-20220911.gz arl_worker.log-20220911.gz

nginx 反向代理

#PROXY-START/
location ~* \.(gif|png|jpg|css|js|woff|woff2)$
{
	proxy_pass https://127.0.0.1:5003;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    expires 12h;
}
location /
{
    proxy_pass https://127.0.0.1:5003;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    
    add_header X-Cache $upstream_cache_status;
    
    #Set Nginx Cache
    
    	add_header Cache-Control no-cache;
}

#PROXY-END/

docker-compose 自启

#!/bin/bash
docker-compose -f /root/docker_arl/docker-compose.yml up -d

添加

vim /etc/init.d/start-docker-compose.sh
chmod +x /etc/init.d/start-docker-compose.sh

登录 ARL

URL:https://127.0.0.1:5003 密码: admin/arlpass

FAQ

F:密码忘记了怎么办? Q:可以执行下面的命令,然后使用admin/admin123就可以登录了。

docker exec -ti arl_mongodb mongo -u admin -p admin
use arl
db.user.drop()
db.user.insert({ username: 'admin',  password: hex_md5('arlsalt!@#'+'admin123') })

F: 如何修改任务并行数量? Q: 修改下面文件43行中的 -c 参数即可,默认为2, 重启容器生效。 https://github.com/TophantTechnology/ARL/blob/master/docker/docker-compose.yml#L43

F: 运行出现异常? Q: 可以执行下面的三条命令并尝试触发错误观察输出有什么异常。

docker-compose ps 
docker-compose logs -f  --tail=10
tail -f *.log

F: 容器一直重启,查看日志提示权限错误 Q: 排查下宿主机是否开启了selinux , 将selinux功能关闭即可。

F: Docker 环境的 ARL 如何更新? Q:git pull 是为了更新docker-compose.yml, docker-compose pull 是为了更新镜像

git pull
docker-compose pull 
docker-compose up -d

F: 任务结果为什么只有域名和IP结果? Q: 可能任务下发时开启了全端口扫描,对于金融、银行存在防护设备的情况大量端口扫描、服务报文探测会出现异常。 可以选择Top 10端口扫描,或者关闭端口扫描,将只会探测80,443端口。

F: 如何判断任务是否还在运行 Q:

  1. 任务状态长时间没有改变,并且后下发的多个(大于等于2)任务都已经执行了,当前任务肯定是异常了。
  2. 根据下面的异常任务原因排查看任务日志是否有持续输出。
  3. 根据网络带宽,CPU,内存占用情况判断任务是否还在运行。

F: 异常任务原因排查 Q: 一般错误异常到会写入到 arl_worker.log 日志中 下面是一个简单的例子.

  1. 先在后台找到Task ID cat arl_worker.log | grep 6288... image
  2. 可以找到对应的Celery ID cat arl_worker.log |grep eaa03c9b-3084-4777-bbaa-74188623fb04 image
  3. 再找到详细的堆栈错误信息 cat arl_worker.log |grep -A 20 "has no attribute" image

附录

查看最新10条日志

docker-compose logs -f  --tail=10
tail -f *.log

数据备份和迁移到存储卷

方法一:镜像的备份恢复迁移

#导出
docker save -o /root/mycentos7.tar mycentos:7
#恢复
docker load -i mycentos7.tar

方法二:备份恢复 mongodb 数据库

防止误删除mongo容器,导致数据丢失,现将数据存储到存储卷中,升级前需要手动执行下面的命令

#备份mongo数据到容器根目录下的arl.gz
docker-compose exec mongodb mongodump -u admin -p admin --authenticationDatabase=admin -d arl --gzip  --archive=/arl.gz

#从容器中将数据复制到当前目录
docker cp arl_mongodb:/arl.gz .

#创建存储卷
docker volume create arl_db

然后执行下面的命令进行更新升级 升级完启动后,用默认密码登录后数据都没有了。

#更新docker/docker-compose.yml 等
git pull

#获取最新的ARL镜像等, 这个过程可能有点缓慢
docker-compose pull

#删除容器并退出
docker-compose down

#重新启动
docker-compose up -d

查看存储卷挂载是否生效, 执行下面的命令看是否有输出

docker inspect arl_mongodb | grep '"arl_db:/data/db'
#输出
"arl_db:/data/db:rw"

将备份恢复到存储卷

#停止容器
docker-compose stop

#将备份恢复到存储卷
docker run --rm -v arl_db:/data/db -v  `pwd`/arl.gz:/arl.gz  mongo:4.0.27  bash -c "mongod --fork --logpath /var/log/mongodb/mongod.log;mongorestore -d arl --gzip  --archive=/arl.gz; mongod --shutdown"

# 启动
docker-compose up -d

#需要注意 arl 是用的 mongodb 版本  mongo:4.0.27
#可以通过如下命令来查询 arl mongodb 使用的版本
➜  docker git:(master) ✗ docker-compose images
Container           Repository          Tag                        Image Id            Size
arl_mongodb         mongo               4.0.27                     e305b5d51c0a        430MB
arl_rabbitmq        rabbitmq            3.8.19-management-alpine   cd80881c4e0e        173MB
arl_scheduler       tophant/arl         latest                     c10b4d9d7ead        1.1GB
arl_web             tophant/arl         latest                     c10b4d9d7ead        1.1GB
arl_worker          tophant/arl         latest                     c10b4d9d7ead        1.1GB

其中 mongodb 的版就是 4.0.27 修改上面命令中的版本为同一个版本就 OK

特别注意,按照上面的方法升级后,系统会多出一个默认用户(admin/arlpass), 可以登录系统点击右上角修改密码,也可以执行下面的命令,进行删除

docker exec -ti arl_mongodb mongo -u admin -p admin
use arl
db.user.remove({"username":"admin", "password":"fe0a9aeac7e5c03922067b40db984f0e"})

清空 volume image

docker stop $(docker ps -a -q)
docker rmi $(docker images -a -q)
docker volume prune

删除特定状态的任务

#删除 stop 状态的任务
docker exec -ti arl_mongodb mongo -u admin -p admin 
use arl
db.task.remove({"status":"stop"}) 

查询指定表返回指定字段

db.task.find({"status":"waiting"},{target:1,name:1}).limit(3)
{ "_id" : ObjectId("6197c1b4104c3c005aca0ff3"), "name" : "test", "target" : "www.xxx.com" }
{ "_id" : ObjectId("6197c1d4104c3c00603b3b8e"), "name" : "test", "target" : "www.xxx.com" }
{ "_id" : ObjectId("6197c206104c3c0038710b93"), "name" : "test", "target" : "www.xxx.com.cn" }
#可以使用 pretty()格式化
> db.task.find({"status":"waiting"},{target:1,name:1}).limit(3).pretty()
{
        "_id" : ObjectId("6197c1b4104c3c005aca0ff3"),
        "name" : "test",
        "target" : "www.xxx.com"
}
{
        "_id" : ObjectId("6197c1d4104c3c00603b3b8e"),
        "name" : "test",
        "target" : "www.xxx.com"
}
{
        "_id" : ObjectId("6197c206104c3c0038710b93"),
        "name" : "test",
        "target" : "www.xxx.com.cn"
}

备份/导出特定表和字段(压缩)

#备份停止状态的任务目标和名称
docker-compose exec mongodb mongodump -u admin -p admin --authenticationDatabase=admin -d arl -c task -q '{"status":"stop"}' --gzip  --archive=/arl_task_stop.gz
#从容器中将数据复制到当前目录
docker cp arl_mongodb:/arl_task_stop.gz .

导出特定表和字段

#导出停止状态的任务目标和名称
docker-compose exec mongodb mongoexport -u admin -p admin --authenticationDatabase=admin -d arl -c task --type=csv --noHeaderLine -f target,name,status -q '{"status":"stop"}' -o arl_task_stop.csv
#从容器中将数据复制到当前目录
docker cp arl_mongodb:/arl_task_stop.csv .
#比如导出 waiting 状态的所有任务的 target 和 name
➜  docker_arl docker-compose exec mongodb mongoexport -u admin -p admin --authenticationDatabase=admin -d arl -c task --type=csv --noHeaderLine -f target,name,status -q '{"status":"waiting"}' -o arl_task_waiting.csv
2022-09-07T11:48:39.885+0800    connected to: localhost
2022-09-07T11:48:40.855+0800    arl.task  0
2022-09-07T11:48:41.855+0800    arl.task  8000
2022-09-07T11:48:42.855+0800    arl.task  152000
2022-09-07T11:48:43.855+0800    arl.task  256000
2022-09-07T11:48:44.855+0800    arl.task  360000
2022-09-07T11:48:45.855+0800    arl.task  464000
2022-09-07T11:48:46.855+0800    arl.task  576000
2022-09-07T11:48:47.855+0800    arl.task  664000
2022-09-07T11:48:48.855+0800    arl.task  784000
2022-09-07T11:48:49.855+0800    arl.task  888000
2022-09-07T11:48:50.855+0800    arl.task  976000
2022-09-07T11:48:51.855+0800    arl.task  1104000
2022-09-07T11:48:52.855+0800    arl.task  1240000
2022-09-07T11:48:53.559+0800    arl.task  1340381
2022-09-07T11:48:53.560+0800    exported 1340381 records
➜  docker_arl ls -lh
total 1.5G
-rw-r--r-- 1 root root 1.4G Sep  7 04:00 arl.gz
-rw-r--r-- 1 root root  54M Sep  7 04:48 arl_task_waiting.csv
-rw-r--r-- 1 root root 114K Sep  7 04:11 arl_web.log
-rw-r--r-- 1 root root 2.2M Sep  6 19:29 arl_worker.log
-rw-r--r-- 1 root root 2.9K Sep  5 16:19 config-docker.yaml
-rw-r--r-- 1 root root 3.3K Aug 25 12:52 docker2.5.2.zip
-rw-r--r-- 1 root root 2.9K Sep  5 15:31 docker-compose.yml
drwxr-xr-x 2 root root 4.0K Sep  5 13:41 image
-rw-r--r-- 1 root root   97 Dec  9  2020 mongo-init.js
drwxr-xr-x 2 root root 4.0K Sep  5 13:41 poc
➜  docker_arl 

添加自定义PoC 和弱口令爆破

为了对通用应用漏洞进行扫描,灯塔中使用了个名为NPoC的框架,框架默认存在的PoC目录为 xing/plugins, 框架会动态加载该目录下的文件, 可以按照自己的需求在目录中添加相应的PoC代码文件, 注意不同子目录下的文件名不要出现重复情况。 由于运行环境为docker, 可以将写好的PoC代码文件手动Copy到容器。

点击灯塔后台系统中的【PoC信息】-【更新】即可查看到添加到框架中的PoC信息, 然后可以通过配置策略用于扫描

image

风险巡航任务下发

请先查看下PoC 信息看是否有信息,如果没有的话请点击更新,将会加载系统默认PoC 信息

对内网C段进行绕口令爆破

先进入【策略配置】【新建配置】输入名称【弱口令扫描】 域名和IP配置 可以根据自己的需要配置, 另外请务必勾选 【服务(python)识别】

image

【站点配置】这里保持默认, 【弱口令爆破配置】这里点击全选,然后点击确定

image

在刚刚添加的策略上点击【任务下发】,任务类型,选择资产侦查任务,目标可以填C段, 在运行过程中会进行端口扫描,服务识别,然后根据匹配的协议进行弱口令爆破。 目前不支持配置字典,相关的默认字典在容器内路径为/opt/ARL-NPoC/xing/dicts, 也可以到下面的链接查看 https://github.com/1c3z/ARL-NPoC/tree/master/xing/dicts

image

对特定目标进行弱口令爆破

在已知目标ip和开放端口是,可以选择风险巡航任务,然后目标直接填如, 10.0.0.2:2222 , 这个过程不会进行端口扫描。

对流行漏洞进行应急响应

先进入【策略配置】【新建配置】输入名称【exchange 扫描】 域名和IP配置 可以根据自己的需要配置, 这里保持默认,【站点配置】这里也保持默认 【PоC配置】勾选 Exchange 漏洞

image

【弱口令爆破配置】也保持默认

进入【资产搜索】点击站点,根据观察,发现Exchange服务的header都会出现X-FEServer字样,在标头输入筛选条件 X-FEServer, 可以快速将Exchange筛选出来,点击风险任务下发。

image

docker 相关配置文件

  • config-docker.yaml
CELERY:
  BROKER_URL : "amqp://arl:arlpassword@rabbitmq:5672/arlv2host"


MONGO:
  URI : 'mongodb://admin:admin@mongodb:27017/'
  DB : 'arl'



#GeoIP 数据库文件配置项
GEOIP:
  CITY: '/data/GeoLite2/GeoLite2-City.mmdb'
  ASN: '/data/GeoLite2/GeoLite2-ASN.mmdb'


#Fofa API 配置项
FOFA:
  URL: "https://fofa.info"
  EMAIL: ""
  KEY: ""


# 利用三方API进行域名收集
# 进入容器测试  docker-compose exec worker bash
# 测试命令 python3.6 -m test.test_query_plugin [source1] [source2]
QUERY_PLUGIN:
  passivetotal: #演示帐号有查询额度限制,请前往 https://community.riskiq.com/ 注册自己的key并替换
    auth_email: 
    auth_key: 
  hunter_qax:  # 网站 https://hunter.qianxin.com/
    api_key:
    page_size: 100
    max_page: 5
  securitytrails: # 网站 https://securitytrails.com/
    api_key: 
  virustotal: # 网站 https://www.virustotal.com/gui/
    api_key: 
  quake_360: # 网站 https://quake.360.cn/
    quake_token:
    max_size: 500
  certspotter: # 网站 https://www.certspotter.com/
    after_id: 0
    max_page: 3


#钉钉消息推送配置
#钉钉添加机器人,请查看
#https://github.com/TophantTechnology/ARL/wiki/ARL%202.3%20%E6%96%B0%E6%B7%BB%E5%8A%A0%E5%8A%9F%E8%83%BD%E8%AF%B4%E6%98%8E
DINGDING:
  SECRET: ""
  ACCESS_TOKEN: ""

#邮件推送配置
EMAIL:
  HOST: ""
  PORT: ""
  USERNAME: ""
  PASSWORD: ""
  TO: ""

# 监控任务 WEBHOOK 配置
# IP/域名监控和站点监控结束后会往下面的URL POST提交JSON数据
# 为了验证身份会在Header中带上Token 字段
# 进入容器测试  docker-compose exec worker bash
# 测试命令 python3.6 -m test.test_webhook <task_id> <scope_id>
WEBHOOK:
  URL: ""
  TOKEN: ""


#GITHUB 搜索 TOKEN
GITHUB:
  TOKEN: ""

#代理配置项,如"http://127.0.0.1:8080", 端口扫描不会走代理
PROXY:
  HTTP_URL: ""

ARL:
  AUTH: true
  #API 认证key, 可以访问api/doc查看文档
  API_KEY: ""
  BLACK_IPS:
    - 127.0.0.0/8
    - 0.0.0.0/8
    - 172.16.0.0/12
    - 100.64.0.0/10
    #- 10.0.0.0/8
    #- 192.168.0.0/16
  ## 禁止域名,不可为空数组
  FORBIDDEN_DOMAINS:
    #- edu.cn
    #- org.cn
    #- gov.cn
    - test.test
  #端口对应前端测试选项
  PORT_TOP_10: "22,80,81,88,443,800,3000,3306,3389,5000,5001,6379,7001,8001,8009,8080,8081,8085,8089,8090,8443,8888,9000,11211"
  #域名爆破字典前端大字典选项
  DOMAIN_DICT: "/code/app/dicts/domain_2w.txt"
  #文件泄漏字典
  FILE_LEAK_DICT: "/code/app/dicts/file_top_2000.txt"

  #域名爆破并发数
  DOMAIN_BRUTE_CONCURRENT: 300
  #组合生成的域名爆破并发数
  ALT_DNS_CONCURRENT: 1500
  • docker-compose.yml
version: '3'

volumes:
  arl_db:
    external: true

services:
    web:
        image: tophant/arl:latest
        container_name: arl_web
        restart: unless-stopped
        depends_on:
          - mongodb
          - rabbitmq
        ports:
          #http 服务,默认不映射出来
          #- "5003:80"
          - "5003:443"
        volumes:
          - ./arl_web.log:/code/arl_web.log
          - ./config-docker.yaml:/code/app/config.yaml
          - ./image:/code/app/tmp_screenshot
          - ./poc:/opt/ARL-NPoC/xing/plugins/upload_poc
        entrypoint: ["sh", "-c", "gen_crt.sh; nginx; wait-for-it.sh mongodb:27017; gunicorn -b 0.0.0.0:5003 app.main:arl_app -w 3 --access-logfile arl_web.log"]
        environment:
          - LANG=en_US.UTF-8
          - TZ=Asia/Shanghai

    worker:
        image: tophant/arl:latest
        container_name: arl_worker
        restart: unless-stopped
        depends_on:
          - mongodb
          - rabbitmq
        volumes:
          - ./arl_worker.log:/code/arl_worker.log
          - ./config-docker.yaml:/code/app/config.yaml
          - ./image:/code/app/tmp_screenshot
          - ./poc:/opt/ARL-NPoC/xing/plugins/upload_poc
        entrypoint: ["sh", "-c", "wait-for-it.sh mongodb:27017; wait-for-it.sh rabbitmq:5672;
        celery -A app.celerytask.celery worker -l info -Q arlgithub -n arlgithub -c 2 -O fair -f arl_worker.log &
         celery -A app.celerytask.celery worker -l info -Q arltask -n arltask -c 20 -O fair -f arl_worker.log"]

        environment:
          - LANG=en_US.UTF-8
          - TZ=Asia/Shanghai

    scheduler:
      image: tophant/arl:latest
      container_name: arl_scheduler
      restart: unless-stopped
      depends_on:
        - mongodb
        - rabbitmq
      volumes:
        - ./config-docker.yaml:/code/app/config.yaml
      entrypoint: [ "sh", "-c", "wait-for-it.sh mongodb:27017; python3.6 -m app.scheduler" ]
      environment:
        - LANG=en_US.UTF-8
        - TZ=Asia/Shanghai

    mongodb:
        image: mongo:4.0.27
        container_name: arl_mongodb
        restart: always
        volumes:
          - arl_db:/data/db
          - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
        environment:
          - MONGO_INITDB_DATABASE=arl
          - MONGO_INITDB_ROOT_USERNAME=admin
          - MONGO_INITDB_ROOT_PASSWORD=admin


    rabbitmq:
      image: rabbitmq:3.8.19-management-alpine
      container_name: arl_rabbitmq
      restart: always
      environment:
        - RABBITMQ_DEFAULT_PASS=arlpassword
        - RABBITMQ_DEFAULT_USER=arl
        - RABBITMQ_DEFAULT_VHOST=arlv2host
      logging:
        driver: "json-file"
        options:
          max-size: "1M"
          max-file: "10"

docker 更多操作-清理 volume container image

https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes

List:

docker images -a

Remove:

docker rmi $(docker images -a -q)

List:

docker ps -a

Remove:

docker rm ID_or_Name ID_or_Name

Run and Remove:

docker run --rm image_name

Remove all exited containers

List:

docker ps -a -f status=exited

Remove:

docker rm $(docker ps -a -f status=exited -q)

Remove containers using more than one filter

List:

docker ps -a -f status=exited -f status=created

Remove:

docker rm $(docker ps -a -f status=exited -f status=created -q)

Remove containers according to a pattern

List:

docker ps -a |  grep "pattern”

Remove:

docker ps -a | grep "pattern" | awk '{print $1}' | xargs docker rm

Stop and remove all containers

List:

docker ps -a

Remove:

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

Removing Volumes

List:

docker volume ls

Remove:

docker volume rm volume_name volume_name

Remove dangling volumes - Docker 1.9 and later

List:

docker volume ls -f dangling=true

Remove:

docker volume prune

免责声明

如果您下载、安装、使用、修改本系统及相关代码,即表明您信任本系统。在使用本系统时造成对您自己或他人任何形式的损失和伤害,我们不承担任何责任。 如您在使用本系统的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。 请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受。 除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本系统。您的下载、安装等行为即视为您已阅读并同意上述协议的约束。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment