TARS web后端審計小結(jié)
0x00 什么是TARS?
Tars是基于名字服務(wù)使用Tars協(xié)議的高性能RPC開發(fā)框架,同時配套一體化的服務(wù)治理平臺,幫助個人或者企業(yè)快速的以微服務(wù)的方式構(gòu)建自己穩(wěn)定可靠的分布式應(yīng)用.
Tars是將騰訊內(nèi)部使用的微服務(wù)架構(gòu)TAF(Total Application Framework)多年的實(shí)踐成果總結(jié)而成的開源項(xiàng)目。
即高性能rpc開發(fā)框架,RPC(Remote Procedure Call)—遠(yuǎn)程過程調(diào)用,通過網(wǎng)絡(luò)從遠(yuǎn)程計算機(jī)程序調(diào)用服務(wù),可以理解為數(shù)據(jù)的處理以及功能的實(shí)現(xiàn)都在遠(yuǎn)程計算機(jī)上實(shí)現(xiàn),前后端分離的模式。
0x01 使用TARS的web程序前后端結(jié)構(gòu)
使用TARS作為后端的web程序的前后端結(jié)構(gòu)與傳統(tǒng)的前后端分離結(jié)構(gòu)類似。
0x02 TARS目錄文件介紹
以http協(xié)議的HelloServer為例。
- HelloImp Servant的接口實(shí)現(xiàn)類,實(shí)現(xiàn)服務(wù)定義的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的虛擬函數(shù),HelloImp初始化時調(diào)用
*/
virtual void initialize();
/**
* 析構(gòu),Hello的虛擬函數(shù),服務(wù)析構(gòu)HelloImp退出時調(diào)用
*/
virtual void destroy();
/**
* 實(shí)現(xiàn)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是服務(wù)的實(shí)現(xiàn)類
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() {};
/**
* 服務(wù)的初始化接口
**/
virtual void initialize();
/**
* 服務(wù)退出時的清理接口
**/
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接口實(shí)現(xiàn)類HelloImp與路由Obj綁定關(guān)系
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;
}
在實(shí)際開發(fā)中,根據(jù)服務(wù)功能實(shí)現(xiàn)的難度而定,目錄下的cpp和.h文件會更加復(fù)雜。
0x03 TARS后端服務(wù)web漏洞審計
tars作為后端對數(shù)據(jù)進(jìn)行處理,因?yàn)闆]有前端web的呈現(xiàn),出現(xiàn)web漏洞的種類會少很多,比較多的漏洞會有sql注入,ssrf,越權(quán)以及命令執(zhí)行。
這里以一個登錄服務(wù)為例。(IDE為CLion, 項(xiàng)目名稱等數(shù)據(jù)均已做脫敏處理)
這個loginserver目錄結(jié)構(gòu)大致如下。
先從jce文件看起,這個文件相當(dāng)于總結(jié)呈現(xiàn)了各個接口,定義了請求的結(jié)構(gòu)體。
可以看到,這里定義了請求和響應(yīng)的結(jié)構(gòu)體,以及統(tǒng)計了各個接口函數(shù),相當(dāng)于一個api文件,從這里入手。
比如這里我們要審計loginServerWeb函數(shù)時,使用IDE 進(jìn)行跟進(jìn)。
跳轉(zhuǎn)到TestLoginImp.cpp文件。一般Imp文件定義了大部分功能實(shí)現(xiàn)的函數(shù)。
調(diào)用了jce中定義的請求的結(jié)構(gòu)體以及響應(yīng)的結(jié)構(gòu)體。
接下來便是取參和調(diào)用。
可以看到,參數(shù)又傳到GetNewLoginStat函數(shù)中去,繼續(xù)跟進(jìn)。
與我們熟悉的其他語言一樣,這里也有類似的對參數(shù)進(jìn)行過濾,可以看到這里對sUser參數(shù)進(jìn)行了一個escapeString. 繼續(xù)往下看。
這個函數(shù)中,還存在sql語句拼接,這也是TARS出現(xiàn)sql注入最頻發(fā)的地方,顯然這里sPwd參數(shù)是從函數(shù)的參數(shù)中直接取的,沒有像username一樣進(jìn)行過濾,明顯的注入點(diǎn)。
可以發(fā)現(xiàn),對tars的注入審計與其他語言類似,都是跟進(jìn)變量,檢查變量是否可控,是否能導(dǎo)致危險操作。審計的難點(diǎn)在于對整個tars結(jié)構(gòu)的了解,如果拿到手一個不熟悉C++項(xiàng)目確實(shí)有點(diǎn)茫然。
至于TARS其他web漏洞的審計,也是如此,入?yún)ⅲⅲM(jìn)參數(shù),檢測參數(shù)是否可控。即從jce文件入手,逐個跟進(jìn)審計函數(shù),需要注意的是結(jié)構(gòu)體定義的數(shù)據(jù)類型很重要,有些地方的參數(shù)沒做過濾可能是因?yàn)閿?shù)據(jù)類型為Int,到頭來無用功。