前言
對于龐大的網(wǎng)絡(luò)空間來說搭综,存在著各式各樣的應(yīng)用、設(shè)備等等資產(chǎn)皱炉,而對這些資產(chǎn)進(jìn)行識別,無論拿來做掃描器還是批量分析狮鸭,都是非常有價(jià)值的合搅,高效的應(yīng)用指紋識別是一個(gè)長久可研究的課題多搀,本文主要探討如何建立高效可靠的指紋識別方法。
傳統(tǒng)的指紋識別
一些掃描器里面使用的比較多的都是通過特殊路徑 靜態(tài)文件的md5 值或者大小 關(guān)鍵詞等灾部,例如使用比較廣泛的一個(gè)指紋數(shù)據(jù)庫 酗昼。
存在幾個(gè)問題
- 效率太低,每一個(gè)路徑都需要訪問一次梳猪。容易被waf攔截
- 目前很多網(wǎng)站的靜態(tài)資源 cdn于gzip 壓縮麻削,md5 其實(shí)是不一樣的 ,識別率很低
現(xiàn)代化指紋識別
怎么來快速的精確的指紋識別春弥,觀察了大部分的web系統(tǒng)發(fā)現(xiàn)呛哟,訪問首頁并且獲取response header 能識別出80% 的app
例如WordPress,discuz 會把獨(dú)特的cookie放到header 里面匿沛。
discuz 的關(guān)鍵詞 _saltkey=
默認(rèn)首頁也會有很多固定的關(guān)鍵詞扫责, WordPress wp-conetnt
剩下的指紋再去特殊url提取,這樣效率和準(zhǔn)確率會提高很多很多逃呼。
現(xiàn)代化指紋識別方案
指紋庫設(shè)計(jì)
數(shù)據(jù)庫結(jié)構(gòu)
[圖片上傳失敗...(image-7b51e8-1532176739869)]
指紋庫類型目前有3種 鳖孤,當(dāng)然后續(xù)還需要加上正則。
finger 規(guī)則是一個(gè) string 之后的python 字典,里面有例如狀態(tài)嗎,規(guī)則等字段,例如 weblogic 的指紋規(guī)則
{'port':7001,'url': '/console/login/LoginForm.jsp', 'code': 200, 'grep': 'WebLogic Server'}
下面介紹每一種指紋庫實(shí)例
指紋規(guī)則
web_header_contain
首頁 response 里面的 header 查找特征符
速度最快,優(yōu)先極最高抡笼。很多web cms 都會寫特殊的cookie 鍵值苏揣。
例如 discuz,jboss,wordpress 等。
規(guī)則編寫,以discuz 為例
? tools curl -I www.cctry.com
HTTP/1.1 200 OK
Server: Microsoft-IIS/6.0
Connection: keep-alive
Date: Thu, 07 Jan 2016 18:22:34 GMT
Content-Type: text/html; charset=gbk
Content-Length: 0
X-Powered-By: PHP/5.2.17
Set-Cookie: Vguy_2132_saltkey=O6srsEYk; expires=Sat, 06-Feb-2016 18:22:22 GMT; path=/; httponly
Set-Cookie: Vguy_2132_lastvisit=1452187342; expires=Sat, 06-Feb-2016 18:22:22 GMT; path=/
Set-Cookie: Vguy_2132_sid=MwE6e0; expires=Fri, 08-Jan-2016 18:22:22 GMT; path=/
Set-Cookie: Vguy_2132_lastact=1452190942%09index.php%09; expires=Fri, 08-Jan-2016 18:22:22 GMT; path=/
X-Daa-Tunnel: hop_count=1
經(jīng)過分析,字符串 _saltkey= 為discuz header 中的規(guī)則
具體規(guī)則如下
[圖片上傳失敗...(image-9dae8f-1532176739869)]
web_index_contain
在緩存的首頁里面查找關(guān)鍵詞或者正則匹配
優(yōu)先級次之,只需要 get請求一次即可推姻。
例如Office Anywhere 指紋 編寫流程
數(shù)據(jù)包分析
? tools curl http://125.91.218.186:8000/ | grep '/images/tongda.ico'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2001 100 2001 0 0 11795 0 --:--:-- --:--:-- --:--:-- 11840
<link rel="shortcut icon" href="/images/tongda.ico">
規(guī)則編寫
[圖片上傳失敗...(image-a6e555-1532176739869)]
web_url_contain
特殊url 查找指定的關(guān)鍵詞(返回狀態(tài)碼也指定)平匈。
優(yōu)先級最低。
例如 weblogic 的指紋 finger 過程
數(shù)據(jù)包分析
? tools curl -I http://202.97.194.9:7001/console/login/LoginForm.jsp
HTTP/1.1 200 OK
Cache-Control: no-cache
Date: Thu, 07 Jan 2016 18:53:28 GMT
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: ADMINCONSOLESESSION=XQXrWT0LQTvpf8Jv75nMnQB9vN0cGppy7bTfJxfH9S673VTGP1Wl!1715621632; path=/
Content-Language: zh-CN
X-Powered-By: Servlet/2.5 JSP/2.1
規(guī)則
{'url': '/console/login/LoginForm.jsp', 'code': 200, 'grep': 'WebLogic Server'}
表
[圖片上傳失敗...(image-524889-1532176739869)]
程序編寫
指紋識別模塊代碼
# coding:utf-8
"""
*@Projet Yafinger
*@Author yaseng@uauc.net
*@Desc playweb finger modules
"""
import ast,time
import config
from lib import util
def get_web_app(url):
rsp_index = util.http_get(url)
str_index = ""
if rsp_index == None :
return None
list_app=[]
fingers=config.get('fingers');
for finger in fingers :
rule = ast.literal_eval(finger['finger'])
if finger['type'] == 'web_index_contain':
# limit header and body and code exp : {'header':'jsessionid=','code': 200, 'grep': '.action'}
if rule.has_key('header') and rule['header'] not in str(rsp_index['headers']).lower() :
continue
if rsp_index['code'] == rule['code'] and rule['grep'] in rsp_index['data'] :
list_app.append({'app_id':finger['id'], 'url':url})
util.log("url:%s app:%s" % (url, finger['app_name']))
elif finger['type'] == 'web_url_contain' :
rsp_tmp = util.http_get(url + rule['url'])
if rsp_tmp == None :
continue
if rsp_tmp['code'] == rule['code'] and rule['grep'] in rsp_tmp['data'] :
list_app.append({'app_id':finger['id'], 'url':url})
util.log("url:%s app:%s" % (url + rule['url'], finger['app_name']))
elif finger['type'] == 'web_header_contain' :
if rule['grep'] in str(rsp_index['headers']).lower() :
list_app.append({'app_id':finger['id'], 'url':url})
util.log("url:%s app:%s" % (url , finger['app_name']))
time.sleep(0.01)
return list_app
單獨(dú)識別
簡單調(diào)用指紋識別模塊代碼
# coding:utf-8
"""
*@Projet Yafinger
*@Author yaseng@uauc.net
*@Desc yafinger test
__ __ ___
/\ \ /\ \ /'___\ __
\ `\`\\/'/ __ /\ \__/ /\_\ ___ __ __ _ __
`\ `\ /' /'__`\ \ \ ,__\\/\ \ /' _ `\ /'_ `\ /'__`\/\`'__\
`\ \ \ /\ \L\.\_\ \ \_/ \ \ \ /\ \/\ \ /\ \L\ \ /\ __/\ \ \/
\ \_\\ \__/.\_\\ \_\ \ \_\\ \_\ \_\\ \____ \\ \____\\ \_\
\/_/ \/__/\/_/ \/_/ \/_/ \/_/\/_/ \/___L\ \\/____/ \/_/
/\____/
\_/__/
"""
import os, time, sys, Queue, threading, ast
import config
from lib import util
from lib.db import *
from optparse import OptionParser
from modules import finger
if __name__ == "__main__":
usage= '''%prog --host host --port port --finger <all|app_name> \r\nExample:%prog --url http://127.0.0.1 --finger phpmyadmin '''
parser = OptionParser(usage=usage)
parser.add_option("-u", "--url", dest="url", help="target url")
parser.add_option("-f", "--finger", dest="finger", help="finger_db app_name,default all ", default="all")
options, arguments = parser.parse_args()
if options.url == None :
parser.print_help()
exit(0)
db = MySQL(config.db_config)
sql_finger_where=' ' if options.finger == 'all' else " and app_name='%s' " % options.finger
db.query("SELECT * from pw_finger_db where `enable`=1 %s " % sql_finger_where)
fingers = db.fetch_all()
if len(fingers) == 0 :
util.log('finger app_name %s not found' % options.finger ,3,'finger')
config.set("fingers",fingers)
util.log("load fingers count %d" % len(fingers),1,'finger')
finger.get_web_app(options.url)
批量識別
可以使用線程池來實(shí)現(xiàn)批量指紋識別藏古。
指紋結(jié)果
融合到系統(tǒng)中指紋保存在數(shù)據(jù)庫中增炭,本模塊可以快速整合到掃描器或者其他項(xiàng)目中。
yafinger
yet another web fingerprinter
https://github.com/yaseng/yafinger
issue
- 指紋庫需要補(bǔ)充
- 可以不局限于web指紋
- 某些情況可能目前的指紋規(guī)則不符合拧晕,還需要添加新的指紋規(guī)則隙姿,例如正則