1. 程式人生 > >metasploit msgrpc c++實現遠端過程呼叫

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 哪位大俠知道還請指導下 謝!