滲透測試是保衛網絡安全的一種有效且必要的技術手段,而滲透測試的本質就是信息收集,信息搜集整理可為后續的情報跟進提供強大的保證,目標資產信息搜集的廣度,決定滲透過程的復雜程度,目標主機信息搜集的深度,決定后滲透權限的持續把控。
系統主要基于Python實現了Web指紋探測、端口掃描和服務探測、真實IP信息探測、WAF防火墻探測、子域名掃描、目錄掃描和敏感信息探測的功能。
CMS識別功能主要通過調用本地識別接口識別,或者調用網絡識別接口識別兩種方式,其中本地接口識別主要是通過比對常見CMS的特征來完成識別。系統收集了1400+的國內常見指紋,并且以josn文件類型的方式保存,便于以后的補充和擴展。
而網絡接口識別則是通過在線指紋識別網站whatweb的api來實現,whatweb在線識別演示如圖所示。
CDN判斷功能主要是通過兩種本地判斷方式和三種網絡接口在線判斷方式共同運行,最后結合五種判斷方式得到的結果得出最終結論的方法實現。本地判斷主要是借助Socket模塊中的getaddrinfo方法來解析域名,以及nslookup查詢域名信息的方法來判斷是否存在CDN防護。
三種網絡接口在線判斷CDN服務的演示如圖所示。
子域名掃描功能一方面是通過本地字典爆破,另外一方面主要是通過Bing搜索引擎,對要查詢的域名進行谷歌語法搜索子域名。
敏感目錄文件掃描功能主要是通過讀取本地字典文件,然后拼接URL,并且把拼接后的URL通過Python中的HackRequests模塊進行request請求,如果拼接后的URL返回狀態碼200,那么我們可以判斷拼接后的URL可以正常訪問,也就說明我們從本地字典中讀取到的目錄或者文件是存在的。如果拼接后的URL返回狀態碼不是200,那么我們從本地字典中讀取到的目錄或文件可能是不存在的。
端口掃描功能主要是通過Python中的Socket模塊創建TCP三次握手連接,并通過返回值是否為0來判斷端口是否存活。以及使用Python中的Nmap模塊,來調用端口掃描神器Nmap進行端口掃描功能。
服務探測主要是通過Socket模塊中的sendall方法來發送請求,然后接收響應包并對響應包中的內容與本地保存的服務特征信息進行關鍵字匹配,以此來判斷開放端口對應的服務類型,同時輸出返回信息,可以在本地無法匹配到相關特征時進行人工判斷服務類型。
系統以webinfo.py為主程序文件,通過與用戶交互,獲取用戶指令,然后根據用戶輸入的指令來調用不同的模塊代碼文件,進而實現對應的功能。
系統主函數的主要功能是通過與用戶交互,提示用戶輸入正確的選項,并根據用戶的輸入來調用其他對應的功能函數,完成用戶想要完成的不同功能。同時應做好程序的異常處理機制,防止因用戶的不正確輸入,而導致程序崩潰的情況發生,提高程序的健壯性。
if __name__=="__main__":
try:
demo=input("請選擇功能模塊a.cms識別,b.cdn判斷,c.子域名掃描,d.敏感目錄文件掃描,e.端口掃描服務探測(輸入序號即可):")
if(demo=="a"):
try:
test=int(input("輸入數字1進行單個url解析cms,輸入數字2進行文件批量解析cms:"))
if(test==1):
try:
domain=input("輸入要檢測web指紋的url(注意不帶路徑如https://www.baidu.com):")
try:
urllib.request.urlopen(domain)
print("開始調用本地接口檢測"+domain+"的cms!")
webcms=webcms(domain)
webcms.run()
print("開始調用網絡接口檢測"+domain+"的cms!")
info=str(cmso2(domain))
print(domain+"解析到的其他信息為:"+info)
except urllib.error.HTTPError:
print("域名有誤,請檢查并按格式輸入!")
time.sleep(2)
except urllib.error.URLError:
print("域名有誤,請檢查并按格式輸入!")
time.sleep(2)
except Exception as e:
print("程序運行出錯!請檢查并再次嘗試!")
time.sleep(2)
if(test==2):
threads=[20]
filename=input("請輸入要解析的url文件路徑:")
try:
t=threading.Thread(target=cmsfile(filename),args=filename)
for ti in threads:
t.setDaemon(True)
t.start()
for ti in threads:
t.join()
except Exception as e:
print("輸入有誤,或文件路徑找不到,請檢查并按格式輸入!")
time.sleep(2)
except Exception as e:
print("輸入有誤,請檢查并按格式輸入!")
time.sleep(2)
elif(demo=="b"):
cdn.run()
elif(demo=="c"):
subdomain.jkxz()
elif(demo=="d"):
dirfilesm.bprun()
elif(demo=="e"):
portscan.port()
else:
print("輸入出錯,請重試!")
time.sleep(2)
except Exception as e:
print("程序運行出錯!請檢查并再次嘗試!")
time.sleep(2)
CMS識別時先通過與用戶交互,判斷用戶是進行單個URL識別還是進行批量文件識別,這一過程實現方式和主函數模塊類似,主要是通過if判斷變量test的值。如果test的值為1,則代表用戶選擇單個URL識別功能,如果test的值為2,則代表用戶選擇批量文件識別的功能。批量文件識別時,主要涉及到Python中文件的操作。
具體識別時主要分為本地接口識別和網絡接口api識別兩種方式。本地識別先通過爬蟲獲取目標網站的特征信息,這一過程通過類Downloader來完成。Downloader類主要定義了三個函數方法:get,post和download,通過這三個函數可以對目標網站進行爬蟲,獲取到目標網站的基本特征信息。
獲取到的網站特征信息再和本地的josn文件進行比對,從而識別出目標網站的CMS信息。這個過程主要是通過類webcms來實現,類webcms一方面將本地josn文件中的內容讀取到隊列中,另外一方面將爬取到的信息與隊列中的信息進行正則匹配,根據匹配結果得出識別結論。為了提高程序運行效率,需要同時對提取本地josn文件內容的過程和比對信息的過程進行多線程的操作。
網絡api識別接口的實現,主要是對通過api請求得到的數據進行二次處理,得到相應的CMS信息,同時也可借助該接口得到目標網站的其他相關信息。
class webcms(object):
workQueue=queue.Queue()
URL=""
threadNum=0
NotFound=True
Downloader=Downloader()
result=""
def __init__(self,url,threadNum=20):
self.URL=url
self.threadNum=threadNum
filename=os.path.join(sys.path[0], "data", "data.json")
fp=open(filename,encoding="utf-8")
webdata=json.load(fp,encoding="utf-8")
for i in webdata:
self.workQueue.put(i)
fp.close()
def getmd5(self, body):
m2=hashlib.md5()
m2.update(body.encode())
return m2.hexdigest()
def th_whatweb(self):
if(self.workQueue.empty()):
self.NotFound=False
return False
if(self.NotFound is False):
return False
cms=self.workQueue.get()
_url=self.URL + cms["url"]
html=self.Downloader.get(_url)
print ("[whatweb log]:checking %s"%_url)
if(html is None):
return False
if cms["re"]:
if(html.find(cms["re"])!=-1):
self.result=cms["name"]
self.NotFound=False
return True
else:
md5=self.getmd5(html)
if(md5==cms["md5"]):
self.result=cms["name"]
self.NotFound=False
return True
def run(self):
while(self.NotFound):
th=[]
for i in range(self.threadNum):
t=threading.Thread(target=self.th_whatweb)
t.start()
th.append(t)
for t in th:
t.join()
if(self.result):
print ("[cmsscan]:%s cms is %s"%(self.URL,self.result))
else:
print ("[cmsscan]:%s cms NOTFound!"%self.URL)
def cmso2(domain):
requests.packages.urllib3.disable_warnings()
response=requests.get(domain,verify=False)
whatweb_dict={"url":response.url,"text":response.text,"headers":dict(response.headers)}
whatweb_dict=json.dumps(whatweb_dict)
whatweb_dict=whatweb_dict.encode()
whatweb_dict=zlib.compress(whatweb_dict)
data={"info":whatweb_dict}
res=requests.post("http://whatweb.bugscaner.com/api.go",files=data)
dic=json.loads(res.text)
if('CMS' in dic.keys()):
info=str(dic['CMS'])
info=info.replace("[","")
info=info.replace("]","")
info=info.replace("'","")
print(domain+"的cms為:"+info)
else:
print(domain+"的cms未能識別!")
return dic
CDN判斷功能的實現主要是通過系統中的五個功能函數,分別對目標域名進行CDN檢測,最后再統計各個功能函數的檢測結果。當五個功能函數的檢測結果中有三個或者三個以上是存在CDN防護的情況下,可以認為目標域名存在CDN防護,反之則可以認為目標域名不存在CDN防護。這一過程的實現主要是通過設定flag,并根據函數返回結果對flag進行加權賦值,最后再根據flag的值得出最終的結果。
五個功能函數中的前兩個函數主要是通過Socket模塊中的getaddrinfo方法解析域名,以及nslookup查詢域名信息的方法來得到域名對應的IP列表。如果以此得到的目標域名的IP數量在兩個或者兩個以上,則說明目標域名可能存在CDN防護,這兩個函數返回結果為True,反之則說明目標域名可能不存在CDN防護,函數返回結果為False。
另外三個函數主要借助第三方查詢網站查詢目標域名的cname域名信息,并以此判斷目標域名是否存在CDN防護。具體實現則主要借助爬蟲來完成,同時對返回的數據信息進行篩選處理,得到我們想要的結果。
def getipo1(domain):
ip_list=[]
flag1=0
ipaddr=socket.getaddrinfo(domain,None)
for item in ipaddr:
if item[4][0] not in ip_list:
ip_list.append(item[4][0])
flag1=flag1+1
return flag1,ip_list
def getipo2(domain):
flag2=0
pi=subprocess.Popen('nslookup {}'.format(domain), shell=True, stdout=subprocess.PIPE)
out=pi.stdout.read().decode('gbk') # 編碼根據實際結果調整
# 判斷返回值中是否有 Addresses 字段,且該字段下 ip 地址要大于等于 2 個,即說明使用了 CDN
strs=re.findall(r'Addresses:(\s*(((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\s*)*)', out, re.S)
if strs==[]:
return flag2
else:
l=strs[0][0].split('\r\n\t')
for address in l:
flag2=flag2+1
return flag2
def getipo3(domain):
flag3=0
url='http://cdn.chinaz.com/search/?host='+domain
strhtml=requests.get(url)
soup=BeautifulSoup(strhtml.text,'lxml')
#a=soup.find_all(text=(re.compile("可能使用CDN云加速")))
b=soup.find_all(text=(re.compile("不屬于CDN云加速")))
if(b==[]):
flag3=flag3+1
return flag3
if(b!=[]):
return flag3
def getipo4(domain):
flag4=0
info="未知"
url='http://tools.bugscaner.com/api/whichcdn/'
payload={'url':domain}
res=requests.post(url,data=payload)
content=json.loads(res.text)
if(str(content['secess'])=="True"):
flag4=flag4+1
info=content['info']
return flag4,info
if(str(content['secess'])=="False"):
return flag4,info
def getipo5(domain):
flag5=0
info="未知"
#browser=webdriver.PhantomJS(executable_path=r'D:\GeckoDriver\phantomjs-2.1.1-windows\bin\phantomjs.exe')
url='https://tools.ipip.net/cdn.php'
#browser.get(url)
#Cookie=browser.get_cookies()
#browser.close()
#strr=''
#for c in Cookie:
#strr +=c['name']
#strr +='='
#strr +=c['value']
#strr +=';'
cookie="LOVEAPP_SESSID=19676de35da2f3d730a92ceac59888c2d9f44f1b; __jsluid_s=7312e36ccdfd6c67bd2d54a59f5ef9f2; _ga=GA1.2.671769493.1617350155; _gid=GA1.2.268809088.1617350155; Hm_lvt_6b4a9140aed51e46402f36e099e37baf=1617350155; login_r=https%253A%252F%252Ftools.ipip.net%252F;"
payload={'node':663,'host':domain}
user_agent=UserAgent().random
headers={"User-Agent":user_agent,"Cookie":cookie}
res=requests.post(url,data=payload,headers=headers)
#print(res.text)
soup=BeautifulSoup(res.text,'lxml')
data=soup.find_all('td')
#print(data)
a=soup.find_all(text=(re.compile("未知")))
if(a!=[]):
return flag5,info
else:
for item in data:
info1=item.find('a')
info=info1.text
#print(info)
flag5=flag5+1
return flag5,info
域名掃描功能主要是通過本地字典爆破和搜索引擎搜索兩種方法來實現。其中字典爆破是通過加載本地字典來拼接URL,并對拼接后的URL進行request請求,然后根據返回的狀態碼來判斷子域名是否存在。
搜索引擎搜索則主要借助特殊搜索語法site的使用,同時借助爬蟲技術,對搜索到的數據進行篩選處理,進而得到目標域名的子域名信息。
def bp(url):
user_agent=UserAgent().random
header={"User-Agent":user_agent}
try:
h=HackRequests.hackRequests()
res=h.http(url,headers=header)
if (res.status_code==200):
print("成功爆破出子域名:"+url)
except:
pass
def zymbp(filename,domain):
try:
f=open(filename,encoding='utf8')
lines=f.readlines()
i=-1
for key in lines:
i=i+1
key=lines[i].strip('\n')
url="http://"+key+"."+domain
threads=[20]
t=threading.Thread(target=bp(url),args=url)
for ti in threads:
t.setDaemon(True)
t.start()
for ti in threads:
t.join()
except Exception as e:
print("輸入有誤,或文件路徑找不到,請檢查并按格式輸入!")
time.sleep(2)
def bprun():
filename=input("請輸入要爆破的子域名字典路徑:")
try:
domain=input("請輸入要爆破的域名(格式為:baidu.com):")
try:
threads=[20]
t=threading.Thread(target=zymbp(filename,domain),args=(filename,domain))
for ti in threads:
t.setDaemon(True)
t.start()
for ti in threads:
t.join()
except Exception as e:
print("程序運行出錯!請檢查并再次嘗試!")
time.sleep(2)
except Exception as e:
print("輸入有誤,或文件路徑找不到,請檢查并按格式輸入!")
time.sleep(2)
def bing_search(site,pages):
subdomain=[]
user_agent=UserAgent().random
headers={'User-Agent':user_agent,'Accept':'*/*','Accept_Language':'en-US,en;q=0.5','Accept-Encoding':'gzip,deflate','referer':"http://cn.bing.com/search?q=email+site%3abaidu.com&qs=n&sp=-1&pq=emailsite%3abaidu.com&first=2&FORM=PERE1"}
for i in range(1,int(pages)+1):
url="https://cn.bing.com/search?q=site%3a"+site+"&go=Search&qs=Search&qs=ds&first="+str((int(i)-1)*10)+"&FORM=PERE"
conn=requests.session()
conn.get('http://cn.bing.com',headers=headers)
html=conn.get(url,stream=True,headers=headers,timeout=8)
soup=BeautifulSoup(html.content,'html.parser')
job_bt=soup.findAll('h2')
for i in job_bt:
link=i.a.get('href')
domain=str(urlparse(link).scheme+"://"+urlparse(link).netloc)
if(domain in subdomain):
pass
else:
subdomain.append(domain)
print("成功搜索出子域名:"+domain)
def runbing():
try:
site=input("請輸入要查詢的域名(格式為:baidu.com):")
page=int(input("請輸入查詢的頁數:"))
try:
bing_search(site,page)
except Exception as e:
print("程序運行出錯!請檢查并再次嘗試!")
time.sleep(2)
except Exception as e:
print("輸入有誤,請檢查并按格式輸入!")
time.sleep(2)
敏感目錄文件的掃描功能主要是通過加載本地字典文件,對當前URL進行拼接,然后再借助HackRequests庫對拼接后的URL進行request請求驗證。當返回狀態碼為200時,則認為當前請求的目錄或者文件存在。
def dirfilebp(filename,domain):
try:
f=open(filename,encoding='utf8')
lines=f.readlines()
i=-1
for key in lines:
i=i+1
key=str(lines[i].strip('\n'))
url=domain+key
threads=[20]
t=threading.Thread(target=bp(url),args=url)
for ti in threads:
t.setDaemon(True)
t.start()
for ti in threads:
t.join()
except Exception as e:
print("輸入有誤,或文件路徑找不到,請檢查并按格式輸入!")
time.sleep(2)
def bp(url):
user_agent=UserAgent().random
header={"User-Agent":user_agent}
try:
h=HackRequests.hackRequests()
res=h.http(url,headers=header)
if (res.status_code==200):
print("成功爆破出目錄或文件:"+url)
except:
pass
端口掃描功能一方面是借助Python中的Socket模塊創建TCP三次握手連接,并通過返回值是否為0來判斷端口是否存活。另外一方面則是借助Python中的Nmap模塊,來調用端口掃描神器Nmap進行端口掃描功能。
服務探測主要是通過Socket模塊中的sendall方法來發送請求,然后接收響應包并對響應包中的內容與本地保存的服務特征信息進行關鍵字匹配,以此來判斷開放端口對應的服務類型,同時輸出返回信息,可以在本地無法匹配到相關特征時進行人工判斷服務類型。
def sorun(queue_s,ip):
while not queue_s.empty():
try:
port=queue_s.get()
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(1)
c=s.connect_ex((ip,port))
if (c==0):
print ("%s:%s is open" % (ip,port))
else:
# print "%s:%s is not open" % (ip,port)
pass
except:
pass
def somain(ip,spo,epo):
threads=[]
threads_count=100 # 線程數,默認 100
queue_s=queue.Queue()
#ip=ip
try:
for i in range(spo,epo+1): # 默認掃描1-1000的端口,可以手動修改這里的端口范圍
queue_s.put(i) # 使用 queue.Queue().put() 方法將端口添加到隊列中
for i in range(threads_count):
threads.append(sorun(queue_s,ip)) # 掃描的端口依次添加到線程組
for i in threads:
i.start()
for i in threads:
i.join()
except:
pass
def nmscan(hosts,port):
nm=nmap.PortScanner()
nm.scan(hosts=hosts, arguments=' -v -sS -p '+port)
try:
for host in nm.all_hosts():
print('----------------------------------------------------') #輸出主機及主機名
print('Host : %s (%s)' % (host, nm[host].hostname())) #輸出主機狀態,如up、down
print('State : %s' % nm[host].state())
for proto in nm[host].all_protocols(): #遍歷掃描協議,如tcp、udp
print('----------') #輸入協議名
print('Protocol : %s' % proto) #獲取協議的所有掃描端口
lport=nm[host][proto].keys() #端口列表排序
list(lport).sort() #遍歷端口及輸出端口與狀態
for port in lport:
print('port : %s\tstate : %s' % (port, nm[host][proto][port]['state']))
except:
pass
def regex(response, port):
text=""
if re.search(b'<title>502 Bad Gateway', response):
proto={"Service failed to access!!"}
for pattern in SIGNS:
pattern=pattern.split(b'|')
if re.search(pattern[-1], response, re.IGNORECASE):
proto="["+port+"]" + " open " + pattern[1].decode()
break
else:
proto="["+port+"]" + " open " + "Unrecognized"
print(proto)
def request(ip,port):
response=''
PROBE='GET / HTTP/1.0\r\n\r\n'
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
result=sock.connect_ex((ip, int(port)))
if result==0:
try:
sock.sendall(PROBE.encode())
response=sock.recv(256)
print(response)
if response:
regex(response, port)
except ConnectionResetError:
pass
else:
pass
sock.close()
def fwmain(ip,port):
print("Scan report for "+ip+"\n")
for line in port.split(','):
request(ip,line)
time.sleep(0.2)
print("\nScan finished!....\n")
運行演示如下圖
代碼地址:https://github.com/twsec-pro/twsecBS
文章來自https://www.cnblogs.com/TWX521/p/16308471.html
果圖
各位朋友大家好!
今天給大家帶來的是 純CSS3超酷書架樣式404頁面動畫特效!
有喜歡的可以按照自己的意愿進行修改!
有想要文件版源碼的可以私聊我!
廢話不多說 上源碼!
@font-face {
font-family: 'icomoon';
src:url('../fonts/icomoon.eot?rretjt');
src:url('../fonts/icomoon.eot?#iefixrretjt') format('embedded-opentype'),
url('../fonts/icomoon.woff?rretjt') format('woff'),
url('../fonts/icomoon.ttf?rretjt') format('truetype'),
url('../fonts/icomoon.svg?rretjt#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
avascript
有下面一組數據
const data=[
{ name:'小明', score:'90',age:10 },
{ name:'小王', score:'100',age:9 },
{ name:'小趙', score:'80',age:9 },
{ name:'小強', score:'97',age:8 }
]
我們現在的需求是對score和age兩列進行求和計算。下面我們先對求和方法進行封裝,這里我分享兩種常用的方法。
方法一:采用遞歸的方式
export const getTotal=(data,key)=> {
var len=data.length;
if(len==0){
return 0;
} else if (len==1){
// 特殊情況;當其中某個值為空時默認為數字0
return Number(data[0][key]?data[0][key]:0);
} else {
// 特殊情況;當其中某個值為空時默認為數字0
// 遞歸的方式調用getTotal方法
return Number(data[0][key]?data[0][key]:0) + getTotal(data.slice(1),key);
}
}
// 調用 getTotal(data,'score')或 getTotal(data,'age')
方法二:函數式編程reduce
export const getTotal=(data,key)=> {
// 一維數組求和方法reduce
return data.reduce(function(prev, curr, idx, arr){
if(typeof prev=='object') {
return Number(prev[key]) + Number(curr[key]);
}else{
return prev + Number(curr[key]);
}
});
}
// 調用 getTotal(data,'score')或 getTotal(data,'age')
然后我們如果要在項目中使用可以遍歷age和score兩個字段進行調用公共方法實現多個列求和。
如果求和之后數據需要保留小數點后兩位或三位有效數字,可以根據具體情況進行相應封裝,我們這里就不做一一分享了。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。