利用Python进行Web渗透测试(八):改进暴力探测器的显示结果和新功能(转载)
本篇将会涉及:
- 改善探测器的结果显示
- 为探测器添加新的特征
- 测试探测器的新特征
文章目录 [隐藏]
改善探测器的结果显示
在上一篇我们使用Python编写了一个暴力探测器,用来探测web站点上可能存在利用漏洞的目录和路径。
![](http://upload-images.jianshu.io/upload_images/38544-b38c11828ea5ae5e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在这个0.1的版本中,我们只是将网址和其响应状态码打印到终端中,命令行中黑底白字的显示,似乎很不美观也不容易找出重点信息。
有什么办法可以改善一下呢?
我们可以借助于一个模块——termcolor,一个用于将输出进行颜色格式化的工具。
我们来看看termcolor的一个官方示例:
import sys
from termcolor import colored, cprint
text = colored('Hello, World!', 'red', attrs=['reverse', 'blink'])
print(text)
cprint('Hello, World!', 'green', 'on_red')
print_red_on_cyan = lambda x: cprint(x, 'red', 'on_cyan')
print_red_on_cyan('Hello, World!')
print_red_on_cyan('Hello, Universe!')
for i in range(10):
cprint(i, 'magenta', end=' ')
cprint("Attention!", 'red', attrs=['bold'], file=sys.stderr)
运行代码,会在终端输出带有颜色的字符:
![](http://upload-images.jianshu.io/upload_images/38544-e526369fc0ac0cac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
从上面的示例我们可以知道,使用termcolor的colored()方法,可以将普通字符格式化为带有颜色的字符,cprint()方法则可以直接打印出特定颜色的字符。
termcolor自带了八种颜色供我们使用,分别是:
- grey:灰色
- red:红色
- green:绿色
- yellow:黄色
- blue:蓝色
- magenta:品红色
- cyan:青色
- white:白色
在探测器中,我们使用colored()方法对状态码进行颜色格式化。
除了添加颜色的显示外,在结果中仅仅显示URL的状态码似乎有点单调,我们再添加几个结果显示:
- 网页文本的行数;
- 网页文本的字符数;
- 网页中的词数;
- 网页内容的哈希值;
# 统计网页行数
lines = r.text.count("\n")
# 统计网页字符数
charts = len(r._content)
# 统计网页词数
words = len(re.findall(r"\S+",r.text))
# 哈希值
hashs = str(hashlib.md5(r.content).hexdigest())
接下来,我们将颜色格式化和新的结果显示添加到request_performer()类中:
class request_performer(Thread):
def __init__(self,word,url):
Thread.__init__(self)
try:
self.word = word.split("\n")[0]
self.urly = url.replace('FUZZ',self.word)
self.url = self.urly
except Exception as e:
print(e)
def run(self):
try:
r = requests.get(self.url)
# 统计网页行数
lines = str(r.text.count("\n"))
# 统计网页字符数
charts = str(len(r._content))
# 统计网页词数
words = str(len(re.findall(r"\S+", r.text)))
# 哈希值
hashs = str(hashlib.md5(r.content).hexdigest())
# 状态码
scode = r.status_code
if '200' <= scode < '300':
print(colored(scode,'green') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
elif '400' <= scode < '500':
print(colored(scode,'red') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
elif '300' <= scode < '400':
print(colored(scode,'blue') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
else:
print(colored(scode,'yellow') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
i[0] = i[0] -1
except Exception as e:
print(e)
我们设置状态码在大于等于200小于300为绿色,大于等于400小于500为红色,大于等于300小于400为蓝色。
在终端中运行命令:
python3 brutediscovery.py -w http://www.scruffybank.com/FUZZ -t 5 -f common.txt
可以看到显示出来的结果清晰明了很多了:
![](http://upload-images.jianshu.io/upload_images/38544-dd6a3221e943fa15.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
添加新的功能选项
在上面的示例中,我们将探测器的显示结果优化了一下,使其更加美观。但是,还有一个问题——404页面的处理。
在字典文件小、字典条目少的情况下,即使我们的探测器探测出很多的404页面,在结果中也容易排除开来。但是如果字典的条目很多,探测出来的404页面也会很多,在命令行界面就会掩盖了成功的响应。我们需要将404页面从结果中剔除掉。
由404页面问题延伸开来,我们的功能的需求就是:通过命令行关键字参数指定,去除某个响应状态码的显示结果。
在request_performer()类中,新添加一个属性hidecode:
class request_performer(Thread):
def __init__(self,word,url,hidecode):
Thread.__init__(self)
try:
self.word = word.split("\n")[0]
self.urly = url.replace('FUZZ',self.word)
self.url = self.urly
self.hidecode = hidecode
except Exception as e:
print(e)
然后在request_performer()类中排除响应状态码为hidecode的请求结果:
def run(self):
try:
r = requests.get(self.url)
# 统计网页行数
lines = str(r.text.count("\n"))
# 统计网页字符数
charts = str(len(r.text))
# 统计网页词数
words = str(len(re.findall(r"\S+", r.text)))
# 哈希值
hashs = str(hashlib.md5(r.content).hexdigest())
# 状态码
scode = str(r.status_code)
if scode != str(self.hidecode):
if '200' <= scode < '300':
print(colored(scode,'green') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
elif '400' <= scode < '500':
print(colored(scode,'red') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
elif '300' <= scode < '400':
print(colored(scode,'blue') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
else:
print(colored(scode,'yellow') + "\t" + charts + " \t" + lines + " \t" + words+" \t"+hashs+"\t"+self.url)
i[0] = i[0] -1
except Exception as e:
print(e)
如果响应状态码不等于指定剔除的状态码,就打印结果。
再在启动函数start()中设置新功能的命令行参数:
def start(argv):
banner()
if len(sys.argv) < 5:
usage()
sys.exit()
try:
opts,args = getopt.getopt(argv,"w:t:f:c:")
except getopt.GetoptError:
print("错误的参数")
sys.exit()
hidecode = 000
for opt,arg in opts:
if opt == '-w':
url = arg
elif opt == '-f':
dicts = arg
elif opt == '-t':
threads = arg
elif opt == '-c':
hidecode = arg
try:
f = open(dicts,'r')
words = f.readlines()
except:
print("打开文件错误:",dicts,"\n")
sys.exit()
launcher_thread(words,threads,url,hidecode)
接着,完善 launcher_thread()函数:
def launcher_thread(names,th,url,hidecode):
global i
i = []
resultlist = []
print("==============================================")
print("状态码"+"\t"+"字符数"+"\t"+"行数"+"\t"+"词数"+"\t"+"MD5"+"\t"+"网址")
print("==============================================")
i.append(0)
while len(names):
try:
if i[0] < int(th):
n = names.pop(0)
i[0] = i[0]+1
thread = request_performer(n,url,hidecode)
thread.start()
except KeyboardInterrupt:
print("用户停止了程序运行。完成探测")
sys.exit()
return True
所有的函数就修改完毕。
测试新功能
改好了代码,我们来测试一下新的功能。目标站点同样选用虚拟机环境中的靶机http://www.scruffybank.com/,common.txt作为字典文件。
因为我们在start()函数里面设置了hidecode的默认值为000,所以我们新增的-c选项不加也可以运行。
先看看不加-c选项的结果:
python3 bruteforce3.py -w http://www.scruffybank.com/FUZZ -t 5 -f common.txt
和第二版的程序效果一致:
![](http://upload-images.jianshu.io/upload_images/38544-2807013ee6716961.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
我们再加上-c选项排除404页面:
python bruteforce3.py -w http://www.scruffybank.com/FUZZ -t 5 -f common.txt -c 404
所有状态码为404的页面都没有显示出来:
![](http://upload-images.jianshu.io/upload_images/38544-69043f2a85b548d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
我们打开其中一个网址看看:
![](http://upload-images.jianshu.io/upload_images/38544-7c0775cfdc58a786.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
三个字母加一个换行符一共4个字符、1行文本、1个词数,与探测器返回的结果相同。
这样我们的探测器更新到第三版,功能也越来越丰富了。
下一篇,我们会继续为我们的渗透测试探测器增加功能。
文章版权所有:州的先生博客,转载必须保留出处及原文链接
原文地址:https://zmister.com/archives/181.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# coding:utf-8 import requests from threading import Thread import sys import getopt from termcolor import colored, cprint import re import hashlib # 程序标识 def banner(): print("\n********************") name = ''' ______ _ _ |___ / (_) | | / / _ __ ___ _ ___| |_ ___ _ __ / / | '_ ` _ \| / __| __/ _ \ '__| / /__| | | | | | \__ \ || __/ | /_____|_| |_| |_|_|___/\__\___|_| ''' print(name) print("州的先生-暴力发掘器 v0.1") print("***********************") # 程序用法 def usage(): print("用法:") print(" -w:网址 (http://wensite.com/FUZZ)") print(" -t:线程数") print(" -f:字典文件") print("例子:bruteforcer.py -w http://bxu2713810459.my3w.com/FUZZ -t 5 -f commom.txt") class request_performer(Thread): def __init__(self, word, url): Thread.__init__(self) try: self.word = word.split("\n")[0] self.urly = url.replace('FUZZ', self.word) self.url = self.urly except Exception as e: print(e) def run(self): try: r = requests.get(self.url) # 统计网页行数 lines = r.text.count("\n") # 统计网页字符数 charts = len(r._content) # 统计网页词数 words = len(re.findall(r"\S+", r.text)) # 哈希值 hashs = str(hashlib.md5(r.content).hexdigest()) scode = r.status_code if 200 <= scode and scode < 300: print( colored(scode, 'green') + "\t" + " \t" + str(lines) + " \t" + str(words) + " \t" + hashs + "\t" + self.url) elif 400 <= scode and scode < 500: print(colored(scode,'red') + "\t" + charts + " \t" + str(lines) + " \t" + str(words) + " \t" + hashs + "\t" + self.url) elif 300 <= scode and scode < 400: print(colored(scode,'blue') + "\t" + charts + " \t" + str(lines) + " \t" + str(words) + " \t" + hashs + "\t" + self.url) else: print(colored(scode, 'yellow') + "\t" + charts + " \t" + str(lines) + " \t" + str(words) + " \t" + hashs + "\t" + self.url) i[0] = i[0] - 1 except Exception as e: print(e) def launcher_thread(names, th, url): global i i = [] resultlist = [] i.append(0) while len(names): try: # if i[0] > th: n = names.pop(0) i[0] = i[0] + 1 thread = request_performer(n, url) thread.start() except KeyboardInterrupt: print("用户停止了程序运行。完成探测") sys.exit() return True def start(argv): banner() if len(sys.argv)>5: usage() #sys.exit() try: opts, args = getopt.getopt(sys.argv[1:], "w:t:f:") except getopt.GetoptError: print("错误的参数") sys.exit() for opt, arg in opts: if opt == '-w': url = arg elif opt == '-f': dicts = arg elif opt == '-t': threads = int(arg) try: f = open(dicts, 'r') words = f.readlines() print(words) except Exception as e: print("打开文件错误:", dicts, "\n") print(e) sys.exit() launcher_thread(words, threads, url) if __name__ == '__main__': try: start(sys.argv[1:]) except KeyboardInterrupt: print("用户停止了程序运行。完成探测")