| 
 | 
 
web应用指纹识别,是web渗透信息收集最关键的一步,这方面开源的工具也非常多,像BlindElephant,whatweb 以及在非安全圈都很火的wappalyzer。本文主要描述如何使用wappalyzer的perl与php接口进行指纹识别。wappalyzer的功能是识别单个uri的指纹,其原理就是给指定URI发送HTTP请求,获取响应头与响应体并按指纹规则进行匹配。这也是web应用指纹识别最基础的部分,除此之外,还有指纹置信度计算(如何去处伪造指纹,多种指纹特征如何综合判断,隐藏指纹信息如何提取),整个站点的指纹识别还涉及到有效爬虫抓取,分布式计算等问题,这些都不在本文内容中。 
一、perl版本 
原理: 
给指定uri发送HTTP请求,通过分析HTTP相应的以下部分来判断指纹 
(1)  headers特征  
响应头key:value对,多个key:value用逗号隔开,例如 
 
 
"headers": { "X-AMP-Version": "([\\d.]+)\\;version:\\1", "Set-Cookie": "^AMP=" }, 
 
(2)   html特征  
响应体内容,多个规则用逗号隔开,例如 
 
 
"html": [ "<div class=\"[^\"]*parbase", "_jcr_content", "/etc/designs/", "/etc/clientlibs/" ] 
 
特别注意:html全文匹配的规则一定要谨慎编写 (3)  url特征 
url内容,例如 
 
 
"url": "/cgi-bin/UCEditor\\?(?:.*&)?merchantid=." 
 
(4)  meta特征 
响应html 页面中诸如<meta name="version"content="neblog-1.0"/>中的名字name:内容content对,多个规则用逗号隔开,例如 
 
 
"meta": { "generator": "webEdition", "DC.title": "webEdition" } 
 
(5)  script特征 
 
 
"script": [ "angular(?:\\-|\\.)([\\d.]*\\d)[^/]*\\.js\\;version:\\1", "/([\\d.]+(\\-?rc[.\\d]*)*)/angular(\\.min)?\\.js\\;version:\\1", "angular.*\\.js" ] 
 
局限性: 
不支持规则文件中APP版本号与置信度的获取 
对非utf8的中文编码可能会存在问题 
优点: 
较之PHP版本,使用qr正则预编译处理,可以提前发现正则的问题,这是我选择该语言版本的主要原因。 
(接下来的php版本就能让你知道正则不预编译处理有多坑了!) 
 
脚本的功能: 
(1)指纹识别结果按JSON格式返回,以便后续指纹信息入库等处理 
(2)支持批量uri查询 
(3)支持指定自定义JSON格式的指纹规则文件  
(默认的指纹文件放置在/usr/lib/perl5/WWW/apps.json,具体的路径会因cpan模块的安装路径有区别 
可以使用perl -V 察看@INC变量来确定路径,或者更暴力的find吧) 
安装: 
 
 
cpan -i  WWW::Wappalyzer   
 
 
 
clone https://github.com/tanjiti/FingerPrint.git 
 
 
运行: 
(1)获取单个uri的指纹 
 
 
perl FingerPrint.pl www.xxx.com<uri 必选> tanjiti.json[指纹规则文件,可选] 
 
返回结果  
 
{ 
"www.xxx.com": { 
"blogs": [ 
"WordPress" 
], 
"web-servers": [ 
"Nginx" 
], 
"cdn": [ 
"CloudFlare" 
], 
"cms": [ 
"WordPress" 
], 
"font-scripts": [ 
"Google Font API" 
], 
"javascript-frameworks": [ 
"jQuery" 
], 
"javascript-graphics": [ 
"Javascript Infovis Toolkit" 
] 
} 
} 
 
(2) 从文件读取url列表进行批量指纹识别,并将结果输出到文件中 
 
perl FingerPrint.pl url.txt<uri 文件路径 必选> tanjiti.json[指纹规则文件,可选] 
 
结果输出到 url.txt__fingerprint 文件里 
指纹规则文件编写示例: 
 
 
more tanjiti.json 
 
 
 
"apps": { 
"Discuz!":{ 
      "website": "www.discuz.net/forum.php", 
       "cats": [ 1 ], 
"meta": { "generator": "Discuz"}, 
"headers": {"Set-Cookie": "_lastact.*_sid|_sid.*_lastact|_sid.*smile|smile.*_sid"}, 
"url": "/uc_server[/$]|uc_client[/$]", 
"html": "Powered by (?:Discuz!|<a href=\"http://www\\.discuz\\.net/\"|UCenter)", 
"implies": "php" 
}, 
   "PHP": { 
"website": "php.net", 
"cats": [ 27 ], 
"headers": { "Server": "php/?([\\d.]+)?\\;confidence:40\\;version:\\1", "X-Powered-By": "php/?([\\d.]+)?\\;confidence:40\\;version:\\1", "Set-Cookie": "PHPSESSID" }, 
"url": "\\.php(?:$|\\?)" 
} 
} 
 
 
二、php版本 
原理 同perl版本,区别有两点:1. HTTP请求部分:较之perl使用LWP发送HTTP请求,php使用curl发送HTTP请求 
2.规则匹配部分:指纹规则的匹配部分使用javascript语法,然后通过php的v8js模块来解析。(为什么要这样做呢?当返回响应体内容很多,指纹正则写的很烂的时候,会卡死在规则匹配这一过程中,现在的规则下sina,163等大站基本卡死!) 
运行 
PHP版的接口已经能直接使用了,只是需要替换规则文件,囧 
第一步:安装php、curl及v8js 
 
 
apt-get install php5-dev php-pear build-essential libv8-dev php5-curl 
 
 
 
pecl install channel://pecl.php.net/v8js-0.1.3 
 
 
 
echo extension=v8js.so >> /etc/php5/cli/php.ini 
 
验证是否安装成功 
php -m | grep v8js 
v8js -----------OK 
 
第二步:下载Wappalyzer脚本 
 
 
git clone https://github.com/ElbertF/Wappalyzer.git 
 
 
 
cp -R Wappalyzer/drivers/php/* . 
 
 
 
cp Wappalyzer/share/js/wappalyzer.js js/ 
 
 
 
cp Wappalyzer/share/apps.json .  (指纹规则文件) 该规则文件的正则编写的有问题,所以我使用的以前版本的规则文件 
cp /usr/lib/perl5/WWW/apps.json . 
 
php版指纹识别程序结构如下:index.php 主程序 
Wappalyzer.php 
WappalyzerException.php 
js/driver.js js/wappalyzer.js 
apps.json 指纹规则文件 
第三步:验证是否成功 
 
 
php index.php www.tanjiti.com 
 
输出格式为 
应用名,版本号,置信度,app类型 (比perl版本多了对版本号,置信度的获取) 
 
 
CloudFlare, , 100%, cdn 
Javascript Infovis Toolkit, , 100%, javascript-graphics 
jQuery, , 100%, javascript-frameworks 
Nginx, , 100%, web-servers 
PHP, 5.5.9, 100%, programming-languages 
Ubuntu, , 100%, operating-systems 
WordPress,  4.0, 100%, cms, blogs 
 
 
三、PHP版本补充知识 
阅读源码的确能学到不少东西 
(1)v8js基本使用 
v8js的基本使用示例:使用php运行js 
编写简单的js文件 
 
 
vim test.js 
 
 
 
var name = "tanjiti" 
print(name," ",name.length, " characters") 
 
 
使用php运行js 
 
 
<?php 
$start = microtime(true); 
$v8 = new V8Js(); 
try{ 
$file = "test.js"; 
$result = $v8->executeString(file_get_contents($file),$file); 
} catch (Exception $e){ 
print $e->getMessage()."\n"; 
exit; 
} 
$end = microtime(true); 
$duration = $end - $start; 
echo "\n$duration us\n"; 
?> 
 
运行 
 
php testV8.php  
tanjiti 7 characters 
0.018015146255493 us         
 
(2) curl基本使用 
使用curl向指定url发送请求,并将响应结果按StdClass结构存储响应体的url,host,html,headers四个部分 
 
 
<?php 
if ( php_sapi_name() !== 'cli' ) { 
exit('Run me from the command line'); 
} 
$url = !empty($argv[1]) ? $argv[1] : ''; 
if ( !$url ) { 
echo "Usage: php {$argv[0]} <url>\n"; 
exit(0); 
} 
$result = curl($url);  
var_dump($result); 
function curl($url) 
{ 
echo 'cURL request: ' . $url . "\n"; 
$ch = curl_init($url); //初始化 
curl_setopt_array($ch, array(//设置选项 
CURLOPT_SSL_VERIFYPEER => false, 
CURLOPT_HEADER         => true, 
CURLOPT_RETURNTRANSFER => true, 
CURLOPT_FOLLOWLOCATION => true, 
CURLOPT_MAXREDIRS      => 3, //重定向 
CURLOPT_TIMEOUT        => 5, //超时时间,单位s 
CURLOPT_USERAGENT      => 'Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1' //User-Agent 
)); 
$response = curl_exec($ch); 
if ( curl_errno($ch) !== 0 ) { 
throw new Exception('cURL error: ' . curl_error($ch)); 
} 
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 
if ( $httpCode != 200 ) { 
throw new Exception('cURL request returned HTTP code ' . $httpCode); 
} 
$result = new stdClass(); 
$result->url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); 
$result->host = parse_url($result->url, PHP_URL_HOST); 
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 
$result->html = substr($response, $headerSize); 
$result->html = mb_check_encoding($result->html, 'UTF-8') ? $result->html : utf8_encode($result->html); 
$headers = trim(substr($response, 0, $headerSize)); 
$headers = preg_split('/^\s*$/m', $headers); 
$headers = end($headers); 
$lines = array_slice(explode("\r\n", $headers), 1); 
foreach ( $lines as $line ) { 
if ( strpos(trim($line), ': ') !== false ) { 
list($key, $value) = explode(': ', $line); 
$result->headers[strtolower($key)] = $value; 
} 
} 
return $result; 
} 
?> 
 
 
运行 
 
php testCurl.php www.tanjiti.com/xss.php?a=lala    
cURL request: www.tanjiti.com/xss.php?a=lala 
object(stdClass)#1 (4) { 
["url"]=> 
string(37) "HTTP://www.tanjiti.com/xss.php?a=lala" 
["host"]=> 
string(15) "www.tanjiti.com" 
["html"]=> 
string(4) "lala" 
["headers"]=> 
array(11) { 
["date"]=> 
string(29) "Fri, 31 Oct 2014 10:08:50 GMT" 
["content-type"]=> 
string(9) "text/html" 
["transfer-encoding"]=> 
string(7) "chunked" 
["connection"]=> 
string(10) "keep-alive" 
["set-cookie"]=> 
string(133) "__cfduid=db05b3ccf4d2b4db66bb46b1058c616831414750130574; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.tanjiti.com; HttpOnly" 
["x-powered-by"]=> 
string(20) "PHP/5.5.9-1ubuntu4.4" 
["x-content-type-options"]=> 
string(7) "nosniff" 
["x-frame-options"]=> 
string(10) "sameorigin" 
["x-xss-protection"]=> 
string(12) "1;mode=block" 
["server"]=> 
string(16) "cloudflare-nginx" 
["cf-ray"]=> 
string(20) "181f0dbc131a036e-LAX" 
} 
} |   
 
 
 
 |