欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ LibCurl實(shí)現(xiàn)Web指紋識(shí)別功能

 更新時(shí)間:2023年11月22日 08:29:26   作者:微軟技術(shù)分享  
Web指紋識(shí)別是一種通過分析Web應(yīng)用程序的特征和元數(shù)據(jù),以確定應(yīng)用程序所使用的技術(shù)棧和配置的技術(shù),本文將通過C++中LibCurl庫實(shí)現(xiàn)簡(jiǎn)單是指紋識(shí)別功能,感興趣的可以了解下

Web指紋識(shí)別是一種通過分析Web應(yīng)用程序的特征和元數(shù)據(jù),以確定應(yīng)用程序所使用的技術(shù)棧和配置的技術(shù)。這項(xiàng)技術(shù)旨在識(shí)別Web服務(wù)器、Web應(yīng)用框架、后端數(shù)據(jù)庫、JavaScript庫等組件的版本和配置信息。通過分析HTTP響應(yīng)頭、HTML源代碼、JavaScript代碼、CSS文件等,可以獲取關(guān)于Web應(yīng)用程序的信息。指紋識(shí)別在信息搜集、滲透測(cè)試、安全審計(jì)等方面具有重要作用。有許多開源和商業(yè)工具可以用于執(zhí)行Web指紋識(shí)別,例如Wappalyzer、WebScarab、Nmap等。

Web指紋識(shí)別的主要目的包括:

  • 技術(shù)識(shí)別: 了解Web應(yīng)用程序所使用的服務(wù)器軟件、框架、數(shù)據(jù)庫等技術(shù)。
  • 版本檢測(cè): 確定這些技術(shù)的具體版本,有助于判斷應(yīng)用程序是否存在已知的漏洞。
  • 配置檢測(cè): 獲取Web應(yīng)用程序的配置信息,包括安裝路徑、默認(rèn)文件、目錄結(jié)構(gòu)等。
  • 漏洞分析: 通過已知漏洞與特定版本相關(guān)聯(lián),評(píng)估Web應(yīng)用程序的安全性。

指紋識(shí)別是滲透測(cè)試中常用的一項(xiàng)技術(shù),用于識(shí)別目標(biāo)Web應(yīng)用程序所使用的框架、技術(shù)和配置。其中,通過計(jì)算特定頁面的哈希值進(jìn)行指紋識(shí)別是一種常見的方法,主要通過以下步驟實(shí)現(xiàn):

  • 1.利用CURL庫獲取頁面內(nèi)容: 使用LibCURL庫可以方便地獲取目標(biāo)網(wǎng)站的頁面內(nèi)容,將其讀入到std::string字符串中,以便后續(xù)處理。
  • 2.MD5算法計(jì)算哈希值: 對(duì)獲取的頁面內(nèi)容進(jìn)行MD5哈希計(jì)算,得到一個(gè)唯一的哈希值。MD5是一種常用的哈希算法,將任意長(zhǎng)度的數(shù)據(jù)映射成128位的哈希值,通常以16進(jìn)制表示。
  • 3.比對(duì)預(yù)先計(jì)算的框架頁面哈希值: 預(yù)先計(jì)算一些特定頁面的哈希值,這些頁面通常是目標(biāo)框架中相對(duì)獨(dú)立且不經(jīng)常變動(dòng)的頁面。將獲取到的頁面的哈希值與預(yù)先計(jì)算的哈希值進(jìn)行比對(duì)。
  • 4.框架識(shí)別: 如果哈希值匹配,則說明目標(biāo)頁面的框架很可能是預(yù)先定義的框架,從而實(shí)現(xiàn)對(duì)框架的識(shí)別。比對(duì)的過程可以使用簡(jiǎn)單的相等比對(duì),也可以設(shè)置一定的相似度閾值。

通過計(jì)算頁面哈希值進(jìn)行指紋識(shí)別是一種有效的方式,特別是針對(duì)那些相對(duì)穩(wěn)定的頁面。首先我們利用LibCURL庫將目標(biāo)頁面讀入到std::string字符串中,然后調(diào)用MD5算法計(jì)算出該頁面的HASH值并比對(duì),由于特定框架中總是有些頁面不會(huì)變動(dòng),我們則去校驗(yàn)這些頁面的HASH值,即可實(shí)現(xiàn)對(duì)框架的識(shí)別。

LibCURL讀入頁面

當(dāng)我們需要獲取遠(yuǎn)程服務(wù)器上的網(wǎng)頁內(nèi)容時(shí),使用C++編寫一個(gè)簡(jiǎn)單的程序來實(shí)現(xiàn)這個(gè)目標(biāo)是非常有用的。在這個(gè)例子中,我們使用了libcurl庫,在程序中引入libcurl庫的頭文件,并使用#pragma comment指令引入相關(guān)的庫文件。接下來,我們定義了一個(gè)回調(diào)函數(shù)WriteCallback,該函數(shù)將獲取的數(shù)據(jù)追加到一個(gè)std::string對(duì)象中。

主要的功能實(shí)現(xiàn)在GetUrlPageOfString函數(shù)中。該函數(shù)接受一個(gè)URL作為參數(shù),并使用libcurl庫來執(zhí)行HTTP GET請(qǐng)求。我們通過設(shè)置CURLOPT_URL選項(xiàng)來指定URL路徑,同時(shí)關(guān)閉了SSL證書驗(yàn)證以及啟用了重定向。我們還設(shè)置了一些超時(shí)選項(xiàng),以確保在連接或接收數(shù)據(jù)時(shí)不會(huì)花費(fèi)太長(zhǎng)時(shí)間。通過調(diào)用curl_easy_perform執(zhí)行請(qǐng)求,并通過回調(diào)函數(shù)將獲取到的數(shù)據(jù)存儲(chǔ)在read_buffer中。最后,我們輸出接收到的數(shù)據(jù)的長(zhǎng)度。

#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>
#include "curl/curl.h"

#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")

using namespace std;

// 存儲(chǔ)回調(diào)函數(shù)
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
  ((std::string*)userp)->append((char*)contents, size * nmemb);
  return size * nmemb;
}

// 獲取數(shù)據(jù)并放入string中.
std::string GetUrlPageOfString(std::string url)
{
  std::string read_buffer;
  CURL *curl;

  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  if (curl)
  {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 忽略證書檢查
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  // 重定向

    curl_easy_setopt(curl, CURLOPT_URL, url);           // URL路徑
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);      // 查找次數(shù),防止查找太深
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // 連接超時(shí)
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);        // 接收數(shù)據(jù)時(shí)超時(shí)設(shè)置

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer);

    curl_easy_perform(curl);
    curl_easy_cleanup(curl);

    return read_buffer;
  }
  return "None";
}

int main(int argc, char *argv[])
{
  std::string urls = GetUrlPageOfString("https://www.baidu.com");
  std::cout << "接收長(zhǎng)度: " << urls.length() << " bytes" << std::endl;

  system("pause");
  return 0;
}

運(yùn)行上述代碼將會(huì)輸出訪問特定主機(jī)所接收到的流量字節(jié)數(shù),如下圖所示;

LibCURL獲取狀態(tài)碼

在這個(gè)C++程序中,我們使用了libcurl庫來獲取指定URL的HTTP狀態(tài)碼。首先,我們引入libcurl庫的頭文件,并通過#pragma comment指令引入相關(guān)的庫文件。然后,我們定義了一個(gè)靜態(tài)的回調(diào)函數(shù)not_output,該函數(shù)用于屏蔽libcurl的輸出。

接著,我們定義了GetStatus函數(shù),該函數(shù)接受一個(gè)URL作為參數(shù),并返回該URL對(duì)應(yīng)的HTTP狀態(tài)碼。在函數(shù)中,我們使用curl_easy_setopt設(shè)置了一些選項(xiàng),包括URL、寫數(shù)據(jù)的回調(diào)函數(shù)(這里我們使用not_output屏蔽輸出),以及通過curl_easy_getinfo獲取狀態(tài)碼。

在main函數(shù)中,我們調(diào)用GetStatus函數(shù)并輸出獲取到的狀態(tài)碼。這個(gè)例子非常簡(jiǎn)單,但展示了使用libcurl庫獲取HTTP狀態(tài)碼的基本方法。

#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>
#include "curl/curl.h"

#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")

using namespace std;

// 屏蔽輸出
static size_t not_output(char *d, size_t n, size_t l, void *p){ return 0; }

// 獲取狀態(tài)碼
long GetStatus(std::string url)
{
  CURLcode return_code;
  long retcode = 0;
  return_code = curl_global_init(CURL_GLOBAL_WIN32);
  if (CURLE_OK != return_code)
    return 0;

  CURL *easy_handle = curl_easy_init();
  if (NULL != easy_handle)
  {
    curl_easy_setopt(easy_handle, CURLOPT_URL, url);                   // 請(qǐng)求的網(wǎng)站
    curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, not_output);   // 設(shè)置回調(diào)函數(shù),屏蔽輸出
    return_code = curl_easy_perform(easy_handle);                       // 執(zhí)行CURL

    return_code = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &retcode);
    if ((CURLE_OK == return_code) && retcode)
    {
      return retcode;
    }
  }
  curl_easy_cleanup(easy_handle);
  curl_global_cleanup();
  return retcode;
}

int main(int argc, char *argv[])
{
  long ref = GetStatus("https://www.baidu.com/");
  std::cout << "返回狀態(tài)碼: " << ref << std::endl;

  system("pause");
  return 0;
}

運(yùn)行上述代碼可得到特定網(wǎng)址的狀態(tài)碼信息,圖中200表示訪問正常;

計(jì)算字符串Hash值

我們使用Boost庫中的boost/crc.hppboost/uuid/detail/md5.hpp來計(jì)算CRC32和MD5值。首先,定義GetCrc32函數(shù),該函數(shù)接受一個(gè)字符串作為輸入,使用Boost庫中的crc_32_type計(jì)算字符串的CRC32值。

接著,我們定義了GetMd5函數(shù),該函數(shù)接受一個(gè)字符數(shù)組和其大小作為輸入,使用Boost庫中的boost::uuids::detail::md5計(jì)算字符串的MD5值。在這個(gè)例子中,我們使用了Boost的md5實(shí)現(xiàn)。

在main函數(shù)中,我們創(chuàng)建了一個(gè)測(cè)試字符串"hello lyshark",并分別調(diào)用GetMd5和GetCrc32函數(shù)來計(jì)算其MD5和CRC32值。最后,我們輸出計(jì)算得到的MD5和CRC32值。

#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>

#include <boost/crc.hpp>
#include <boost/uuid/detail/md5.hpp>
#include <boost/algorithm/hex.hpp>

using namespace std;
using namespace boost;

// 應(yīng)用于crc32
long GetCrc32(std::string sz_string)
{
  long ref;
  crc_32_type crc32;
  cout << hex;
  crc32.process_bytes(sz_string.c_str(), sz_string.length());
  return crc32.checksum();
}

// 應(yīng)用于md5
std::string GetMd5(const char  * const buffer, size_t buffer_size)
{
  if (buffer == nullptr)
    return false;

  std::string str_md5;
  boost::uuids::detail::md5 boost_md5;
  boost_md5.process_bytes(buffer, buffer_size);
  boost::uuids::detail::md5::digest_type digest;
  boost_md5.get_digest(digest);
  const auto char_digest = reinterpret_cast<const char*>(&digest);
  str_md5.clear();
  boost::algorithm::hex(char_digest, char_digest + sizeof(boost::uuids::detail::md5::digest_type), std::back_inserter(str_md5));
  return str_md5;
}

int main(int argc, char *argv[])
{
  std::string urls = "hello lyshark";
  std::cout << "計(jì)算Hash: " << urls << std::endl;

  // 計(jì)算MD5
  std::string str = GetMd5(urls.c_str(), urls.length());
  std::cout << "計(jì)算 MD5: " << str << std::endl;

  // 計(jì)算CRC32
  long crc = GetCrc32(urls.c_str());
  std::cout << "計(jì)算 CRC32: " << crc << std::endl;

  system("pause");
  return 0;
}

通過計(jì)算可得到hello lyshark字符串的CRC32與MD5特征碼,如下圖;

當(dāng)具備了hash值的計(jì)算后,我們只需要將上述兩個(gè)功能組合起來就可以實(shí)現(xiàn)提取特定頁面的特征碼,首先通過libcurl庫完成對(duì)頁面的訪問,接著就是計(jì)算特征碼即可。

#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>
#include "curl/curl.h"

#include <boost/crc.hpp>
#include <boost/uuid/detail/md5.hpp>
#include <boost/algorithm/hex.hpp>

#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")

using namespace std;

// 存儲(chǔ)回調(diào)函數(shù)
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
  ((std::string*)userp)->append((char*)contents, size * nmemb);
  return size * nmemb;
}

// 獲取數(shù)據(jù)并放入string中.
std::string GetUrlPageOfString(std::string url)
{
  std::string read_buffer;
  CURL *curl;

  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  if (curl)
  {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 忽略證書檢查
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  // 重定向

    curl_easy_setopt(curl, CURLOPT_URL, url);           // URL路徑
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);      // 查找次數(shù),防止查找太深
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // 連接超時(shí)
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);        // 接收數(shù)據(jù)時(shí)超時(shí)設(shè)置

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer);

    curl_easy_perform(curl);
    curl_easy_cleanup(curl);

    return read_buffer;
  }
  return "None";
}

// 應(yīng)用于md5
std::string GetMd5(const char  * const buffer, size_t buffer_size)
{
  if (buffer == nullptr)
    return false;

  std::string str_md5;
  boost::uuids::detail::md5 boost_md5;
  boost_md5.process_bytes(buffer, buffer_size);
  boost::uuids::detail::md5::digest_type digest;
  boost_md5.get_digest(digest);
  const auto char_digest = reinterpret_cast<const char*>(&digest);
  str_md5.clear();
  boost::algorithm::hex(char_digest, char_digest + sizeof(boost::uuids::detail::md5::digest_type), std::back_inserter(str_md5));
  return str_md5;
}

// 計(jì)算特定頁面MD5
std::string CalculationMD5(std::string url)
{
  std::string page_string = GetUrlPageOfString(url);

  if (page_string != "None")
  {
    std::string page_md5 = GetMd5(page_string.c_str(), page_string.length());
    std::cout << "[+] 計(jì)算頁面: " << url << std::endl;
    std::cout << "[+] 壓縮數(shù)據(jù): " << page_md5 << std::endl;
    return page_md5;
  }
  return "None";
}

int main(int argc, char *argv[])
{
  std::string md5 = CalculationMD5("https://www.baidu.com");

  system("pause");
  return 0;
}

上述代碼運(yùn)行后,則可以計(jì)算出特定網(wǎng)站的MD5值,如下圖;

解析對(duì)比Hash值

指紋識(shí)別依賴于特征庫,如果需要實(shí)現(xiàn)自己的指紋識(shí)別工具則需要我么能自行去收集各類框架的特征庫,有了這些特征庫就可以定義一個(gè)如下所示的JSON文本,該文本中container用于存儲(chǔ)框架類型,其次hash則用于存放特征碼,最后的sub_url則是識(shí)別路徑。

{
    "data_base":
     [
        { "container": "typecho", "hash": "04A40072CDB70B1BF54C96C6438678CB" ,"sub_url":"/index.php/about.html" },
        { "container": "wordpress", "hash": "04A40072CBB70B1BF54C96C6438678CB" ,"sub_url":"/admin.php" },
        { "container": "baidu", "hash": "EF3F1F8FBB7D1F545A75A83640FF0E9F" ,"sub_url":"/index.php" }
    ]
}

接著就是解析這段JSON文本,我們利用BOOST提供的JSON解析庫,首先解析出所有的鍵值對(duì),將其全部讀入到定義的結(jié)構(gòu)體映射中,然后嘗試輸出看看,注意壓縮和解包格式必須對(duì)應(yīng)。

#include <iostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

using namespace std;
using namespace boost;
using namespace boost::property_tree;

// 定義映射字段
typedef struct
{
  std::vector<std::string> container;
  std::vector<std::string> hash;
  std::vector<std::string> sub_url;
}database_map;

// 獲取文本中的JSON,放入自定義database_map
std::vector<database_map> GetDataBase()
{
  std::vector<database_map> ref;

  boost::property_tree::ptree ptr;
  boost::property_tree::read_json("database.json", ptr);

  if (ptr.count("data_base") == 1)
  {
    boost::property_tree::ptree p1, p2;

    p1 = ptr.get_child("data_base");

    // 定義映射類型
    std::vector<std::string> x, y, z;
    database_map maps;

    for (ptree::iterator it = p1.begin(); it != p1.end(); ++it)
    {
      // 讀取出json中的數(shù)據(jù)
      p2 = it->second;
      std::string container = p2.get<std::string>("container");
      std::string hash = p2.get<std::string>("hash");
      std::string sub_url = p2.get<std::string>("sub_url");

      // 臨時(shí)存儲(chǔ)數(shù)據(jù)
      x.push_back(container);
      y.push_back(hash);
      z.push_back(sub_url);
    }
    // 打包結(jié)構(gòu)壓入ref中
    maps.container = x;
    maps.hash = y;
    maps.sub_url = z;
    ref.push_back(maps);
  }
  return ref;
}
int main(int argc, char *argv[])
{
  std::vector<database_map> db_map = GetDataBase();

  for (int x = 0; x < db_map.size(); x++)
  {
    // 依次將字典讀入內(nèi)存容器.
    database_map maps = db_map[x];
    std::vector<std::string> container = maps.container;
    std::vector<std::string> hash = maps.hash;
    std::vector<std::string> sub_url = maps.sub_url;

    // 必須保證記錄數(shù)完全一致
    if (container.size() != 0 && hash.size() != 0 && sub_url.size() != 0)
    {
      for (int x = 0; x < container.size(); x++)
      {
        std::cout << "容器類型: " << container[x] << std::endl;
        std::cout << "指紋: " << hash[x] << std::endl;
        std::cout << "根路徑: " << sub_url[x] << std::endl;
        std::cout << std::endl;
      }
    }
  }
  std::system("pause");
  return 0;
}

運(yùn)行后則可以實(shí)現(xiàn)正常的json文檔解析,如下圖;

最后增加循環(huán)對(duì)比流程,這里我們以百度為例測(cè)試一下提取字段是否可以被解析。

#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>
#include "curl/curl.h"

#include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <boost/crc.hpp>
#include <boost/uuid/detail/md5.hpp>
#include <boost/algorithm/hex.hpp>

#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")

using namespace std;
using namespace boost;
using namespace boost::property_tree;

// 定義映射字段
typedef struct
{
  std::vector<std::string> container;
  std::vector<std::string> hash;
  std::vector<std::string> sub_url;
}database_map;

// 存儲(chǔ)回調(diào)函數(shù)
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
  ((std::string*)userp)->append((char*)contents, size * nmemb);
  return size * nmemb;
}
// 屏蔽輸出
static size_t not_output(char *d, size_t n, size_t l, void *p){ return 0; }

// 獲取數(shù)據(jù)并放入string中.
std::string GetUrlPageOfString(std::string url)
{
  std::string read_buffer;
  CURL *curl;

  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  if (curl)
  {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 忽略證書檢查
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  // 重定向

    curl_easy_setopt(curl, CURLOPT_URL, url);           // URL路徑
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);      // 查找次數(shù),防止查找太深
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // 連接超時(shí)
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);        // 接收數(shù)據(jù)時(shí)超時(shí)設(shè)置

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer);

    curl_easy_perform(curl);
    curl_easy_cleanup(curl);

    return read_buffer;
  }
  return "None";
}

// 獲取狀態(tài)碼
long GetStatus(std::string url)
{
  CURLcode return_code;
  long retcode = 0;
  return_code = curl_global_init(CURL_GLOBAL_WIN32);
  if (CURLE_OK != return_code)
    return 0;

  CURL *easy_handle = curl_easy_init();
  if (NULL != easy_handle)
  {
    curl_easy_setopt(easy_handle, CURLOPT_URL, url);                   // 請(qǐng)求的網(wǎng)站
    curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, not_output);   // 設(shè)置回調(diào)函數(shù),屏蔽輸出
    return_code = curl_easy_perform(easy_handle);                       // 執(zhí)行CURL

    return_code = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &retcode);
    if ((CURLE_OK == return_code) && retcode)
    {
      return retcode;
    }
  }
  curl_easy_cleanup(easy_handle);
  curl_global_cleanup();
  return retcode;
}

// 應(yīng)用于md5
std::string GetMd5(const char  * const buffer, size_t buffer_size)
{
  if (buffer == nullptr)
    return false;

  std::string str_md5;
  boost::uuids::detail::md5 boost_md5;
  boost_md5.process_bytes(buffer, buffer_size);
  boost::uuids::detail::md5::digest_type digest;
  boost_md5.get_digest(digest);
  const auto char_digest = reinterpret_cast<const char*>(&digest);
  str_md5.clear();
  boost::algorithm::hex(char_digest, char_digest + sizeof(boost::uuids::detail::md5::digest_type), std::back_inserter(str_md5));
  return str_md5;
}

// 獲取文本中的JSON,放入自定義database_map
std::vector<database_map> GetDataBase()
{
  std::vector<database_map> ref;

  boost::property_tree::ptree ptr;
  boost::property_tree::read_json("database.json", ptr);

  if (ptr.count("data_base") == 1)
  {
    boost::property_tree::ptree p1, p2;

    p1 = ptr.get_child("data_base");

    // 定義映射類型
    std::vector<std::string> x, y, z;
    database_map maps;

    for (ptree::iterator it = p1.begin(); it != p1.end(); ++it)
    {
      // 讀取出json中的數(shù)據(jù)
      p2 = it->second;
      std::string container = p2.get<std::string>("container");
      std::string hash = p2.get<std::string>("hash");
      std::string sub_url = p2.get<std::string>("sub_url");

      // 臨時(shí)存儲(chǔ)數(shù)據(jù)
      x.push_back(container);
      y.push_back(hash);
      z.push_back(sub_url);
    }
    // 打包結(jié)構(gòu)壓入ref中
    maps.container = x;
    maps.hash = y;
    maps.sub_url = z;
    ref.push_back(maps);
  }
  return ref;
}

int main(int argc, char *argv[])
{
  std::vector<database_map> db_map = GetDataBase();

  for (int x = 0; x < db_map.size(); x++)
  {
    // 依次將字典讀入內(nèi)存容器.
    database_map maps = db_map[x];
    std::vector<std::string> container = maps.container;
    std::vector<std::string> hash = maps.hash;
    std::vector<std::string> sub_url = maps.sub_url;

    // 必須保證記錄數(shù)完全一致
    if (container.size() != 0 && hash.size() != 0 && sub_url.size() != 0)
    {
      for (int x = 0; x < container.size(); x++)
      {
        // 開始編寫掃描函數(shù)
        // 1.拼接字符串
        std::string ur = "https://www.baidu.com";
        
        std::string this_url = boost::str(boost::format("%s%s") %ur %sub_url[x]);

        // 2.判斷頁面是否存在
        long ref_status = GetStatus(this_url);
        if (ref_status != 0 && ref_status == 200)
        {
          // 3.讀入頁面字符串,判斷是否成功
          std::string read_page = GetUrlPageOfString(this_url);
          if (read_page != "None")
          {
            std::string check_md5 = GetMd5(read_page.c_str(),read_page.length());
            std::cout << "[+] 頁面MD5: " << check_md5 << std::endl;
            std::cout << "[+] 數(shù)據(jù)庫: " << hash[x] << std::endl;
            
            // 4.比對(duì)MD5值是否相同
            if (check_md5 == std::string(hash[x]))
            {
              std::cout << "[*] 診斷框架為: " << container[x] << std::endl;
              break;
            }
          }
        }
      }
    }
  }
  std::system("pause");
  return 0;
}

如下圖所示,說明對(duì)比通過,接著就可以增加命令行參數(shù)并使用了。

完整代碼總結(jié)

C++指紋識(shí)別助手程序,它使用了libcurl庫進(jìn)行HTTP請(qǐng)求,通過比對(duì)頁面的MD5值與預(yù)先存儲(chǔ)在數(shù)據(jù)庫中的MD5值,從而識(shí)別目標(biāo)網(wǎng)站所使用的容器框架。

通過參數(shù)-u用于識(shí)別一個(gè)網(wǎng)站是什么框架,使用-g則是獲取當(dāng)前頁面指紋特征,如下圖;

#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>
#include "curl/curl.h"

#include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <boost/crc.hpp>
#include <boost/uuid/detail/md5.hpp>
#include <boost/algorithm/hex.hpp>

#include <boost/program_options.hpp>

#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")

using namespace std;
using namespace boost;
using namespace boost::property_tree;
namespace opt = boost::program_options;

// 定義映射字段
typedef struct
{
  std::vector<std::string> container;
  std::vector<std::string> hash;
  std::vector<std::string> sub_url;
}database_map;

void ShowOpt()
{
  fprintf(stderr,
    "#                       #                          #       \n"
    "#                       #                          #       \n"
    "#     #    #    #####   ######    ######   # ###   #   ##  \n"
    "#     #    #   #        #     #  #     #   ##      #  #    \n"
    "#     #    #    ####    #     #  #     #   #       ###     \n"
    "#      #####        #   #     #  #    ##   #       #  #    \n"
    "######     #   #####    #     #   #### #   #       #   ##  \n\n"
    );
}

// 存儲(chǔ)回調(diào)函數(shù)
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
  ((std::string*)userp)->append((char*)contents, size * nmemb);
  return size * nmemb;
}
// 屏蔽輸出
static size_t not_output(char *d, size_t n, size_t l, void *p){ return 0; }

// 獲取數(shù)據(jù)并放入string中.
std::string GetUrlPageOfString(std::string url)
{
  std::string read_buffer;
  CURL *curl;

  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  if (curl)
  {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 忽略證書檢查
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  // 重定向

    curl_easy_setopt(curl, CURLOPT_URL, url);           // URL路徑
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);      // 查找次數(shù),防止查找太深
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // 連接超時(shí)
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);        // 接收數(shù)據(jù)時(shí)超時(shí)設(shè)置

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer);

    curl_easy_perform(curl);
    curl_easy_cleanup(curl);

    return read_buffer;
  }
  return "None";
}

// 獲取狀態(tài)碼
long GetStatus(std::string url)
{
  CURLcode return_code;
  long retcode = 0;
  return_code = curl_global_init(CURL_GLOBAL_WIN32);
  if (CURLE_OK != return_code)
    return 0;

  CURL *easy_handle = curl_easy_init();
  if (NULL != easy_handle)
  {
    curl_easy_setopt(easy_handle, CURLOPT_URL, url);                   // 請(qǐng)求的網(wǎng)站
    curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, not_output);   // 設(shè)置回調(diào)函數(shù),屏蔽輸出
    return_code = curl_easy_perform(easy_handle);                       // 執(zhí)行CURL

    return_code = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &retcode);
    if ((CURLE_OK == return_code) && retcode)
    {
      return retcode;
    }
  }
  curl_easy_cleanup(easy_handle);
  curl_global_cleanup();
  return retcode;
}

// 應(yīng)用于md5
std::string GetMd5(const char  * const buffer, size_t buffer_size)
{
  if (buffer == nullptr)
    return false;

  std::string str_md5;
  boost::uuids::detail::md5 boost_md5;
  boost_md5.process_bytes(buffer, buffer_size);
  boost::uuids::detail::md5::digest_type digest;
  boost_md5.get_digest(digest);
  const auto char_digest = reinterpret_cast<const char*>(&digest);
  str_md5.clear();
  boost::algorithm::hex(char_digest, char_digest + sizeof(boost::uuids::detail::md5::digest_type), std::back_inserter(str_md5));
  return str_md5;
}

// 獲取文本中的JSON,放入自定義database_map
std::vector<database_map> GetDataBase()
{
  std::vector<database_map> ref;

  boost::property_tree::ptree ptr;
  boost::property_tree::read_json("database.json", ptr);

  if (ptr.count("data_base") == 1)
  {
    boost::property_tree::ptree p1, p2;

    p1 = ptr.get_child("data_base");

    // 定義映射類型
    std::vector<std::string> x, y, z;
    database_map maps;

    for (ptree::iterator it = p1.begin(); it != p1.end(); ++it)
    {
      // 讀取出json中的數(shù)據(jù)
      p2 = it->second;
      std::string container = p2.get<std::string>("container");
      std::string hash = p2.get<std::string>("hash");
      std::string sub_url = p2.get<std::string>("sub_url");

      // 臨時(shí)存儲(chǔ)數(shù)據(jù)
      x.push_back(container);
      y.push_back(hash);
      z.push_back(sub_url);
    }
    // 打包結(jié)構(gòu)壓入ref中
    maps.container = x;
    maps.hash = y;
    maps.sub_url = z;
    ref.push_back(maps);
  }
  return ref;
}

// 掃描判斷容器類型
void ScanPage(std::string urls)
{
  std::vector<database_map> db_map = GetDataBase();

  for (int x = 0; x < db_map.size(); x++)
  {
    // 依次將字典讀入內(nèi)存容器.
    database_map maps = db_map[x];
    std::vector<std::string> container = maps.container;
    std::vector<std::string> hash = maps.hash;
    std::vector<std::string> sub_url = maps.sub_url;

    // 必須保證記錄數(shù)完全一致
    if (container.size() != 0 && hash.size() != 0 && sub_url.size() != 0)
    {
      for (int x = 0; x < container.size(); x++)
      {
        // 1.拼接字符串
        std::string this_url = boost::str(boost::format("%s%s") % urls %sub_url[x]);

        // 2.判斷頁面是否存在
        long ref_status = GetStatus(this_url);
        if (ref_status != 0 && ref_status == 200)
        {
          // 3.讀入頁面字符串,判斷是否成功
          std::string read_page = GetUrlPageOfString(this_url);
          if (read_page != "None")
          {
            std::string check_md5 = GetMd5(read_page.c_str(), read_page.length());
            std::cout << "[+] 頁面MD5: " << check_md5 << std::endl;
            std::cout << "[+] 數(shù)據(jù)庫: " << hash[x] << std::endl;

            // 4.比對(duì)MD5值是否相同
            if (check_md5 == std::string(hash[x]))
            {
              std::cout << "[*] 診斷框架為: " << container[x] << std::endl;
              break;
            }
          }
        }
      }
    }
  }
}

int main(int argc, char *argv[])
{
  opt::options_description des_cmd("\n Usage: 容器識(shí)別助手 \n\n Options");
  des_cmd.add_options()
    ("url,u", opt::value<std::string>(), "指定目標(biāo)URL地址")
    ("get,g", opt::value<std::string>(), "提取頁面指紋")
    ("help,h", "幫助菜單");

  opt::variables_map virtual_map;
  try
  {
    opt::store(opt::parse_command_line(argc, argv, des_cmd), virtual_map);
  }
  catch (...){ return 0; }

  // 定義消息
  opt::notify(virtual_map);

  // 無參數(shù)直接返回
  if (virtual_map.empty())
  {
    ShowOpt();
    return 0;
  }
  // 幫助菜單
  else if (virtual_map.count("help") || virtual_map.count("h"))
  {
    ShowOpt();
    std::cout << des_cmd << std::endl;
    return 0;
  }
  else if (virtual_map.count("url"))
  {
    std::string address = virtual_map["url"].as<std::string>();
    ScanPage(address);
  }
  else if (virtual_map.count("get"))
  {
    std::string address = virtual_map["get"].as<std::string>();
    std::string read_page = GetUrlPageOfString(address);
    std::cout << "[+] 提取指紋: " << GetMd5(read_page.c_str(), read_page.length()) << std::endl;
  }
  else
  {
    std::cout << "參數(shù)錯(cuò)誤" << std::endl;
  }
  return 0;

  std::system("pause");
  return 0;
}

以上就是C++ LibCurl實(shí)現(xiàn)Web指紋識(shí)別功能的詳細(xì)內(nèi)容,更多關(guān)于C++ LibCurl指紋識(shí)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++核心編程之占位參數(shù)和默認(rèn)參數(shù)

    C++核心編程之占位參數(shù)和默認(rèn)參數(shù)

    這篇文章主要介紹了C++核心編程之占位參數(shù)和默認(rèn)參數(shù),c++中函數(shù)的形參列表中的形參是可以有默認(rèn)值的,函數(shù)的形參列表里可以有占位參數(shù),用來占位,調(diào)用函數(shù)時(shí)必須填補(bǔ)位置。下面更多相關(guān)內(nèi)容的詳細(xì)介紹,需要的小伙伴可以參考一下
    2022-03-03
  • C++語言const 關(guān)鍵字使用方法圖文詳解

    C++語言const 關(guān)鍵字使用方法圖文詳解

    在類中,如果你不希望某些數(shù)據(jù)被修改,可以使用const關(guān)鍵字加以限定。const 可以用來修飾成員變量、成員函數(shù)以及對(duì)象
    2020-01-01
  • C++ 壓縮文件及文件夾方法 使用zlib開源庫

    C++ 壓縮文件及文件夾方法 使用zlib開源庫

    下面小編就為大家分享一篇C++ 壓縮文件及文件夾方法 使用zlib開源庫,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • C語言中的內(nèi)存管理之掌握動(dòng)態(tài)分配的技巧(最新推薦)

    C語言中的內(nèi)存管理之掌握動(dòng)態(tài)分配的技巧(最新推薦)

    在C語言編程中,內(nèi)存管理是一項(xiàng)至關(guān)重要的技能,它直接關(guān)系到程序的性能和穩(wěn)定性,特別是在處理大型數(shù)據(jù)集或需要靈活內(nèi)存布局的場(chǎng)景下,本文將深入探討C語言中的動(dòng)態(tài)內(nèi)存分配技巧,幫助開發(fā)者更好地掌握這一核心技能
    2025-03-03
  • C++實(shí)現(xiàn)對(duì)RGB圖片進(jìn)行編碼的示例代碼

    C++實(shí)現(xiàn)對(duì)RGB圖片進(jìn)行編碼的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用得到的RGB信息重新對(duì)RGB圖片進(jìn)行編碼,以及對(duì)其他圖片如BMP所得到的RGB信息進(jìn)行編碼從而得到*.jpg文件,感興趣的可以了解一下
    2023-05-05
  • C語言 字符串指針詳解及示例代碼

    C語言 字符串指針詳解及示例代碼

    本文主要介紹C語言 字符串指針,這里整理了詳細(xì)資料,并附示例代碼及實(shí)現(xiàn)結(jié)果,有興趣的小伙伴可以參考下
    2016-08-08
  • C語言浮點(diǎn)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式詳解

    C語言浮點(diǎn)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式詳解

    任何數(shù)據(jù)在內(nèi)存中都是以二進(jìn)制的形式存儲(chǔ)的,例如一個(gè)short型數(shù)據(jù)1156,其二進(jìn)制表示形式為00000100 10000100,下面這篇文章主要給大家介紹了關(guān)于C語言浮點(diǎn)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式,需要的朋友可以參考下
    2023-03-03
  • C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法

    C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法

    這篇文章主要介紹了C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 如何在C++類的外部調(diào)用類的私有方法

    如何在C++類的外部調(diào)用類的私有方法

    這篇文章主要介紹了如何在C++類的外部調(diào)用類的私有方法,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-09-09
  • 解決C++中重定義的方法總結(jié)

    解決C++中重定義的方法總結(jié)

    本篇文章是對(duì)C++中重定義的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05

最新評(píng)論