metasploit msgrpc c++實現遠端過程呼叫
想入手metasploit原始碼,又不知道從何而入,看了下UI部分,發現已經存在了armitage、msfgui、以及現在的收費web。瀏覽了下《Metasploit Remote API4.1 Guide》
運用msgrpc時需要填寫正確的post型別:
POST /api/1.0HTTP/1.1
Host: RPC Server
Content-Length:128
Content-Type:binary/message
<128 bytes ofencoded data>
rpc採用msgpack,貌似是最快的吧,支援c++的說,翻看msgpack官網的文件覺得太屎了。總的還是自己參考了msfguijava程式寫的。
之前沒用過WinHttp,看了msdn結合wireshark捕獲自己的報文,形成了如下的例項,有啥不對的還請提醒。
//1, 首先我們開啟一個Session獲得一個HINTERNET session控制代碼;
//2, 然後我們使用這個session控制代碼與伺服器連線得到一個HINTERNET connect控制代碼;
//3, 然後我們使用這個connect控制代碼來開啟Http 請求得到一個HINTERNET request控制代碼;
//4, 這時我們就可以使用這個request控制代碼來發送資料與讀取從伺服器返回的資料;
//5, 最後依次關閉request,connect,session控制代碼。
voidRPCconnetion::begin(string ip,int port,string cmd,std::vector<string>param,std::map<string,result_object> *unmsg)//cmd為方法名,param為方法引數列表
{
DWORD dwSize =0;
DWORD dwDownloaded =0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
hSession =NULL,hConnect =NULL,hRequest = NULL;//全域性變數,初始化
hSession =WinHttpOpen(NULL,//useragent
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if(hSession)
hConnect =WinHttpConnect(hSession,
MutiiByteToWide(ip).data(),//轉化為寬字元型,自己實現
port,0);//port 55553
if(hConnect)
hRequest =WinHttpOpenRequest(hConnect,
L"POST",
L"/api/1.0",
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer>pk(&buffer);
pk.pack_array(param.size()+1);//函式名和引數的長度
pk.pack(cmd);//RPC函式名
f(param.size()!=0)
for(inti=0;i<param.size();i++)//打包時需進行互斥操作??
pk.pack(param.at(i));//RPC引數
if(hRequest)//傳送請求
bResults =WinHttpSendRequest(hRequest,
L"Content-Type:binary/message-pack",//Content-Type
0,
(LPVOID)(buffer.data()),
buffer.size(),//strlen(strPostData),
buffer.size(),//strlen(strPostData),
0);//將資料放在PostData中傳送
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
// Keep checking for data until there isnothing left.
if (bResults)
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
char * error;
sprintf(error,"Error%u in WinHttpQueryDataAvailable.\n",GetLastError());
MessageBoxA(NULL,error,NULL,MB_OK);
}
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize+1];
if (!pszOutBuffer)
{
char* error;
sprintf(error,"Out ofmemory\n");
MessageBoxA(NULL,error,NULL,MB_OK);
dwSize=0;
}
else
{
// Read the Data.
ZeroMemory(pszOutBuffer,dwSize+1);
if (!WinHttpReadData( hRequest,(LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
{
char * error;
sprintf(error,"Error%u in WinHttpReadData.\n",GetLastError());
MessageBoxA(NULL,error,NULL,MB_OK);
}
elseif(dwSize>0)//&&!strcmp(cmd.data(),"console.read")
{
msgpack::unpackedmsg;
msgpack::unpack(&msg,pszOutBuffer,dwSize);
msgpack::objectobj = msg.get();//
unMsg(obj,unmsg);//結構體進行接受轉換的型別,可參考msfgui java msgrpc.java程式碼
// Free the memoryallocated to the buffer.
delete [] pszOutBuffer;
}
}
} while (dwSize>0);
// Report any errors.
if (!bResults)
{
char *error;
sprintf(error,"Error%d has occurred.\n",GetLastError());
MessageBoxA(NULL,error,NULL,MB_OK);
}
}
呼叫rpc的簡單程式介面如下:
完成後進行簡單的呼叫:
1、 開啟服務端
Msfrpcd –S –P 123 (注意此時必須將設定為-S不使用ssl)。其中linux環境下實施簡單
Winsdows msf4.4版本環境下在metasploit主目錄下新建如下bat檔案即可,設定rpc服務端
@echo off
set BASE=%~dp0
cd "%BASE%"
setPATH=%BASE%ruby\bin;%BASE%java\bin;%BASE%tools;%BASE%svn\bin;%BASE%nmap;%BASE%postgresql\bin;%PATH%
IF NOT EXIST "%BASE%java" GOTONO_JAVA
set JAVA_HOME="%BASE%java"
cd "%BASE%msf3"
start ruby msfrpcd -S -P 123//設定自己的引數即可
2、 運用上面Cpp 的程式碼,注意配置好msgpack的環境變數(可baidu得到)
程式碼例項如下:
RPCconnetion rpc ; //前面程式碼封裝到此類
string str;
string rpcToken;
std::vector<string> param;
string rpcId;
string ip = "192.168.11.4";
int port =55553;
param.push_back("msf");
param.push_back("123");
std::map<string,result_object>results;
rpc.begin(ip,port,"auth.login",param,&results);
if((results.find("result")->second).type==STRING_OBJECT)
if(!(results.find("result")->second).str.compare("success"))
rpcToken=results.find("token")->second.str;//獲取臨時型的token
// rpcToken = "perxx";//永久的token
param.clear();
param.push_back(rpcToken);
results.clear();
rpc.begin(ip,port,"console.create",param,&results);
if((results.find("id")->second).type==STRING_OBJECT)
rpcId = results.find("id")->second.str;//少判斷
param.clear();
param.push_back(rpcToken);
param.push_back(rpcId);
results.clear();
rpc.begin(ip,port,"console.read",param,&results);//每次新建的console會產生新的banner
str.append(results.find("data")->second.str);
param.clear();
param.push_back(rpcToken);
param.push_back(rpcId);
param.push_back("nmap -O192.168.11.19 -oX www\n");
results.clear();
rpc.begin(ip,port,"console.write",param,&results);
param.clear();
param.push_back(rpcToken);
param.push_back(rpcId);
results.clear();
rpc.begin(ip,port,"console.read",param,&results);
bool busy =results.find("busy")->second.b;
while(busy)
{
Sleep(5000);
results.clear();
rpc.begin(ip,port,"console.read",param,&results);
str.append(results.find("data")->second.str);
busy = results.find("busy")->second.b;
}
rpc.disconnect();
//string str ="xiaohu\nweiwu\n";
//linuxstr2str(&str);
result_view.SetWindowText((LPCTSTR)str.c_str());
3、 Ruby msgpack rpc輔助除錯
Linux環境下直接msfrpc –a server_ip –S –P 123
Windows下與上面類似在最後一行換成start ruby msfrpc –a server_ip –S –P 123 //startruby msfrpcd -S -P 123
相關命令列有:rpc.call(“auth.login”,”msf”,”123”)等,可參考metasploit remote api
不過最近的簡版程式中,一直報unpack_error異常insufficient bytes 哪位大俠知道還請指導下 謝!