TARS web后端审计小结
TARS web后端审计小结
0x00 什么是TARS?
Tars是基于名字服务使用Tars协议的高性能RPC开发框架,同时配套一体化的服务治理平台,帮助个人或者企业快速的以微服务的方式构建自己稳定可靠的分布式应用.
Tars是将腾讯内部使用的微服务架构TAF(Total Application Framework)多年的实践成果总结而成的开源项目。
即高性能rpc开发框架,RPC(Remote Procedure Call)—远程过程调用,通过网络从远程计算机程序调用服务,可以理解为数据的处理以及功能的实现都在远程计算机上实现,前后端分离的模式。
0x01 使用TARS的web程序前后端结构
使用TARS作为后端的web程序的前后端结构与传统的前后端分离结构类似。

0x02 TARS目录文件介绍
以http协议的HelloServer为例。
- HelloImp Servant的接口实现类,实现服务定义的Tars接口
HelloImp.h
#ifndef _HelloImp_H_
#define _HelloImp_H_
#include "servant/Application.h"
#include "Hello.h"
/**
* HelloImp继承hello.h中定义的Hello对象
*
*/
class HelloImp : public TestApp::Hello
{
public:
virtual ~HelloImp() {}
/**
* 初始化,Hello的虚拟函数,HelloImp初始化时调用
*/
virtual void initialize();
/**
* 析构,Hello的虚拟函数,服务析构HelloImp退出时调用
*/
virtual void destroy();
/**
* 实现tars文件中定义的test接口
*/
virtual int test(tars::TarsCurrentPtr current) { return 0;};
};
/////////////////////////////////////////////////////
#endif
HelloImp.cpp:
#include "HelloImp.h"
#include "servant/Application.h"
using namespace std;
//////////////////////////////////////////////////////
void HelloImp::initialize()
{
//initialize servant here:
//...
}
//////////////////////////////////////////////////////
void HelloImp::destroy()
{
//destroy servant here:
//...
}
- HelloServer是服务的实现类
HelloServer.h:
#ifndef _HelloServer_H_
#define _HelloServer_H_
#include <iostream>
#include "servant/Application.h"
using namespace tars;
/**
* HelloServer继承框架的Application类
**/
class HelloServer : public Application
{
public:
/**
*
**/
virtual ~HelloServer() {};
/**
* 服务的初始化接口
**/
virtual void initialize();
/**
* 服务退出时的清理接口
**/
virtual void destroyApp();
};
extern HelloServer g_app;
////////////////////////////////////////////
#endif
HelloServer.cpp:
#include "HelloServer.h"
#include "HelloImp.h"
using namespace std;
HelloServer g_app;
/////////////////////////////////////////////////////////////////
void
HelloServer::initialize()
{
//initialize application here:
//添加Servant接口实现类HelloImp与路由Obj绑定关系
addServant<HelloImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HelloObj");
}
/////////////////////////////////////////////////////////////////
void
HelloServer::destroyApp()
{
//destroy application here:
//...
}
int
main(int argc, char* argv[])
{
try
{
g_app.main(argc, argv);
g_app.waitForShutdown();
}
catch (std::exception& e)
{
cerr << "std::exception:" << e.what() << std::endl;
}
catch (...)
{
cerr << "unknown exception." << std::endl;
}
return -1;
}
在实际开发中,根据服务功能实现的难度而定,目录下的cpp和.h文件会更加复杂。
0x03 TARS后端服务web漏洞审计
tars作为后端对数据进行处理,因为没有前端web的呈现,出现web漏洞的种类会少很多,比较多的漏洞会有sql注入,ssrf,越权以及命令执行。
这里以一个登录服务为例。(IDE为CLion, 项目名称等数据均已做脱敏处理)
这个loginserver目录结构大致如下。

先从jce文件看起,这个文件相当于总结呈现了各个接口,定义了请求的结构体。


可以看到,这里定义了请求和响应的结构体,以及统计了各个接口函数,相当于一个api文件,从这里入手。
比如这里我们要审计loginServerWeb函数时,使用IDE 进行跟进。
跳转到TestLoginImp.cpp文件。一般Imp文件定义了大部分功能实现的函数。

调用了jce中定义的请求的结构体以及响应的结构体。
接下来便是取参和调用。

可以看到,参数又传到GetNewLoginStat函数中去,继续跟进。

与我们熟悉的其他语言一样,这里也有类似的对参数进行过滤,可以看到这里对sUser参数进行了一个escapeString. 继续往下看。

这个函数中,还存在sql语句拼接,这也是TARS出现sql注入最频发的地方,显然这里sPwd参数是从函数的参数中直接取的,没有像username一样进行过滤,明显的注入点。
可以发现,对tars的注入审计与其他语言类似,都是跟进变量,检查变量是否可控,是否能导致危险操作。审计的难点在于对整个tars结构的了解,如果拿到手一个不熟悉C++项目确实有点茫然。
至于TARS其他web漏洞的审计,也是如此,入参,取参,跟进参数,检测参数是否可控。即从jce文件入手,逐个跟进审计函数,需要注意的是结构体定义的数据类型很重要,有些地方的参数没做过滤可能是因为数据类型为Int,到头来无用功。