背景
在安全测试中,经常会遇到需要进行暴力破解账号密码的场景,用于测试系统是否存在弱密码,或者进行用户名枚举等。对于此种需求,我们主要需要的是操作简单、功能强大、测试速度快、测试结果准确,目前已经有许多工具可以支持这种功能,最常用的如BurpSuite、Hydra等。但在实际的测试过程中经常也会遇到各种特殊的场景,现有的工具不能很好提供很好的支持,此时多数使用自己编写的脚本。目前主流的编程语言均支持发送HTTP的功能,但发包速度各不相同,而对于暴力破解而言,发包速度无疑是重中之重,另外各种语言常见的WEB框架响应时间也不相同。为了详细了解不同语言、框架、工具的发包速度和响应速度,故进行如下场景测试。
概述
本次测试分为两大部分,一个是发送端,主要工具如下,其中部分语言或工具可能并不适合,仅用于对比:
工具 | 版本 |
---|---|
Python3-requests | Python-3.7.3+requests-2.21.0 |
Python3-aiohttp | Python-3.7.3+aiohttp-3.5.4 |
C# | .NET Core-3.0+C#-8.0 |
Java | java-1.8.0_211 |
Golang | go-1.13.1 |
Nodejs-request | node-v10.16.0+request-2.88.0 |
Php | php-7.3.4 |
Ruby | ruby-2.3.3p222 |
Shell-curl | curl-7.64.0 |
BurpSuite | BurpSuite-2.0.11beta |
Hydra | Hydra-v8.8 |
另一部分是常见的WEB后端框架:
工具 | 版本 |
---|---|
Python3-flask | Python-3.7.3+flask-1.1.1 |
Python3-sanic | Python-3.7.3+sanic-19.6.3 |
Ruby-ruby on rails | ruby-2.3.3p222+Rails-5.1.3 |
Java-SpringBoot | java-1.8.0_211+SpringBoot-2.1.9.RELEASE |
Golang | go-1.13.1 |
Php | php-7.3.4 |
Nodejs-express | node-v10.16.0+express-4.17.1 |
C#-ASP.NET | .NET Core-3.0+C#-8.0 |
在一次完整的HTTP请求中,主要可分为以下几个部分:
- 准备HTTP请求
- 发送HTTP请求
- 解析HTTP请求,处理并准备HTTP响应
- 返回HTTP响应
- 解析并处理HTTP响应
在以上5个步骤中,第1和5步主要由发送端的速度决定,第2和4步主要由网络情况决定,第3步主要由WEB服务器及后端服务决定。
准备
测试方法:服务端模拟账号密码验证,密码为字典的最后一项,密码字典大约为10k。发送端模拟爆破并计时,多次测试后统计爆破平均用时。
以下是各工具发送端的代码:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BurpSuite
: 在BurpSuite中抓包,然后在Intruder模块中设置payload即可.
|
|
以下是服务端的代码:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
结果
发送速度对比:
发送端 | 服务端 | 线程数 | 密码数 | 网络延时 | 耗时(秒) | 备注 |
---|---|---|---|---|---|---|
Python3-requests | Python3-flask | 1 | 10k | 无 | 38 | 稳定 |
Python3-aiohttp | Python3-flask | 1 | 10k | 无 | 15 | 无序,全部跑完约15秒 |
C# | Python3-flask | 1 | 10k | 无 | 27 | 误差2秒 |
Java | Python3-flask | 1 | 10k | 无 | 18 | 稳定 |
Golang | Python3-flask | 1 | 10k | 无 | 18 | 稳定 |
Nodejs-request | Python3-flask | 1 | 10k | 无 | 15 | 无序,全部跑完约15秒 |
Php | Python3-flask | 1 | 10k | 无 | 53 | 不稳定,误差5秒 |
Ruby | Python3-flask | 1 | 10k | 无 | 120 | 稳定 |
Shell-curl | Python3-flask | 1 | 10k | 无 | 412 | 太慢 |
BurpSuite | Python3-flask | 1 | 10k | 无 | 420 | 太慢 |
Hydra | Python3-flask | 1 | 10k | 无 | 1h56m | 单线程慢到不能用 |
静态语言(C#/Java/Golang)普遍快于动态语言(Python/Ruby/Php),但动态语言如果采用异步框架(Python3-aiohttp/Nodejs-request)的话,则可以达到与静态语言的相当水品。而反观现成的工具(curl/BurpSuite/Hydra)等,虽然它们功能强大使用简单方便,但在单线程的情况下速度慢到几乎不能用,完全不能与手动编码的工具相比。
不过以上只是测试在本地的情况,一般情况下网络延时都会远远大于其他部分的耗时,故下面模拟延迟200ms(服务端等待200ms后返回)的网络情况再次测试,不过由于加上延时后速度慢很多,所以将密码数量下降至1K。
发送端 | 服务端 | 线程/并发数 | 密码数 | 网络延时 | 耗时(秒) |
---|---|---|---|---|---|
Python3-requests | Python3-flask | 1 | 1k | 200ms | 206 |
C# | Python3-flask | 1 | 1k | 200ms | 204 |
Java | Python3-flask | 1 | 1k | 200ms | 204 |
Golang | Python3-flask | 1 | 1k | 200ms | 203 |
Php | Python3-flask | 1 | 1k | 200ms | 207 |
Ruby | Python3-flask | 1 | 1k | 200ms | 208 |
Shell-curl | Python3-flask | 1 | 1k | 200ms | 245 |
BurpSuite | Python3-flask | 1 | 1k | 200ms | 205 |
Hydra | Python3-flask | 1 | 1k | 200ms | 961 |
可以看到使用编程语言编写的工具,无论是静态还是动态差距都不大,相比于没有网络延迟时,速度大约下降了50-100倍;而现有的工具,下降则并不多,curl和BurpSuite大约只下降了5倍,而Hydra大约只慢了1/3。故可以看出,手动编写的工具瓶颈在于网络及服务端,自身速度很快;而现有工具则是自身速度不够快,网络及服务端的影响则较小。
要想真正达到高速爆破,还是得使用多线程和异步框架:
发送端 | 服务端 | 线程/并发数 | 密码数 | 网络延时 | 耗时(秒) |
---|---|---|---|---|---|
Python3-requests | Python3-flask | 16 | 1k | 200ms | 13 |
Python3-aiohttp | Python3-flask | 16 | 1k | 200ms | 13 |
Nodejs-request | Python3-flask | 16 | 1k | 200ms | 14 |
BurpSuite | Python3-flask | 16 | 1k | 200ms | 59 |
Hydra | Python3-flask | 16 | 1k | 200ms | 57 |
可以看到在16线程时,相比于单线程,手动编写的工具速度大约提升了15倍,BurpSuite大约提升了3倍多,Hydra提升了17倍,异步框架与多线程相当。
多线程的速度明显加强,那么到底多少线程合适又成了另外一个问题,继续测试:
发送端 | 服务端 | 线程/并发数 | 密码数 | 网络延时 | 耗时(秒) |
---|---|---|---|---|---|
Python3-requests | Python3-flask | 1 | 1k | 200ms | 206 |
Python3-requests | Python3-flask | 2 | 1k | 200ms | 103 |
Python3-requests | Python3-flask | 4 | 1k | 200ms | 52 |
Python3-requests | Python3-flask | 8 | 1k | 200ms | 26 |
Python3-requests | Python3-flask | 16 | 1k | 200ms | 13 |
Python3-requests | Python3-flask | 32 | 1k | 200ms | 7 |
Python3-requests | Python3-flask | 64 | 1k | 200ms | 3.5 |
Python3-requests | Python3-flask | 128 | 1k | 200ms | 2.6 |
Python3-requests | Python3-flask | 256 | 1k | 200ms | 2.6 |
Python3-requests | Python3-flask | 512 | 1k | 200ms | 2.7 |
Python3-requests | Python3-flask | 1024 | 1k | 200ms | 2.7 |
在线程数较少时,线程数量越多,速度越快,几乎与线程数成正比,但是在到达一定数量后速度就不再变化了,这里有两种可能,一种是发送速度达到极限,另一种可能是服务端响应速度达到极限,于是开始考虑更换更快的服务端框架。
目前主流的后端框架响应时间对比如下:
发送端 | 服务端 | 线程/并发数 | 密码数 | 网络延时 | 耗时(秒) |
---|---|---|---|---|---|
Python3-aiohttp | Python3-flask | 64 | 100k | 无 | 164 |
Python3-aiohttp | Python3-sanic | 64 | 100k | 无 | 108 |
Python3-aiohttp | Ruby-ruby on rails | 64 | 100k | 无 | 340 |
Python3-aiohttp | Java-SpringBoot | 64 | 100k | 无 | 125 |
Python3-aiohttp | Golang | 64 | 100k | 无 | 95 |
Python3-aiohttp | Php | 64 | 100k | 无 | 193 |
Python3-aiohttp | Nodejs-express | 64 | 100k | 无 | 115 |
Python3-aiohttp | C#-ASP.NET | 64 | 100k | 无 | 147 |
由于没有采用专门的部署方式,只是使用各工具自带的调试模式,所以部分框架测试结果存在较大差距。不过从上面的结果也可以看出静态语言和异步框架是明显强于动态语言的。
继续测试多线程的情况,现在服务端改为Golang,网络延迟继续调成200ms,结果如下:
发送端 | 后端 | 线程/并发数 | 密码数 | 网络延时 | 耗时(秒) |
---|---|---|---|---|---|
Python3-requests | Golang | 64 | 10k | 200ms | 40 |
Python3-requests | Golang | 128 | 10k | 200ms | 29 |
Python3-requests | Golang | 256 | 10k | 200ms | 23 |
Python3-requests | Golang | 512 | 10k | 200ms | 19 |
Python3-requests | Golang | 1024 | 10k | 200ms | 17 |
Python3-requests | Golang | 2048 | 10k | 200ms | 17 |
可以看到线程数继续上升后,耗时依然在减少,说明线程数提升还是可以提升发送速度的。但是在实际的环境中,存在瓶颈的多半还是在网络速度和服务端响应速度上,发送速度到达一定程度后对总体而言不会再有提升。另外,若果想要提升总体速度,使用现有的工具任然是不够的,还是使用编程语言编写的工具速度会快很多。
总结
对于发送端而言,静态语言一般快于动态语言、多线程快于单线程、异步快于同步、简单工具快于复杂工具。
在网络情况较差或服务端响应速度较慢的情况下,使用现有的工具(BurpSuite、Hydra等)并开启多线程是足够的;但在网络情况良好且服务端响应较快时,现有工具的速度则不够用了,应该使用支持多线程或协程、编码简单并且自己较为熟悉的语言,python/java/go/nodejs/c#等都是不错的选择。
对于后端框架而言,静态语言同样快于动态语言、异步快于同步,不过这种响应速度在实际场景中意义不大,因为大多数场景下其他操作的时间会远远大于这里的响应时间,且实际部署方式也会有所不同,这里的测试结果只能用于参考。