Insecure CAPTCHA,意思为不安全的验证码
全称为Completely Automated Public Turing Test to Tell Computers and Humans Apart
,意思是全自动公共图灵测试,区分计算机和人类
顾名思义,想通过验证码拦截我们的操作,绕过即可
在进行实验前,可能又出现报错信息,只需要修改dvwa
目录下得配置文件dvwa/config/config.inc.php
将这两个的值改为统一内容即可
审计源码
<?php
// 判断 POST 传参 Change ,和 step 为 1
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
// 隐藏验证码表单
$hide_form = true;
// 获取输入的新密码和二次密码
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// 检查第三方验证码
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key'],
$_POST['g-recaptcha-response']
);
// 查看验证码正确
if( !$resp ) {
// 判断 $reps 进行了 ! 取反,代表 $resp 返回的错误是一个 True 值
// 验证码错误
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {
// 验证码正确
// 判断两次输入密码是否想通过
if( $pass_new == $pass_conf ) {
// 进入下一阶段
// 你通过了验证码!单击按钮确认更改。
echo "
<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>
<form action=\"#\" method=\"POST\">
<input type=\"hidden\" name=\"step\" value=\"2\" />
<input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" />
<input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" />
<input type=\"submit\" name=\"Change\" value=\"Change\" />
</form>";
}
else {
// 两次输入密码不匹配
$html .= "<pre>Both passwords must match.</pre>";
$hide_form = false;
}
}
}
// 判断传参 Change,并判断 step 是否为 2
// 这里很明显有一个漏洞,这个if语句不在上一个 step 2的嵌套中,直接传参 step == 2 就可以绕过验证码
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
// 隐藏验证码表单
$hide_form = true;
// 获取两次输入密码
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// 检查两次输入密码是否相同
if( $pass_new == $pass_conf ) {
// 相同
// 这里也是用 mysqli_real_escape_string 进行了一个转移,所以sql注入不太理想
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// 使用md5加密输入的新密码
$pass_new = md5( $pass_new );
// 更新数据库
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// 密码更改成功
echo "<pre>Password Changed.</pre>";
}
else {
// 两次输入密码不一致
echo "<pre>Passwords did not match.</pre>";
$hide_form = false;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
这里的验证码是调用的Google
的,所以需要访问外网就可以调用成功。不能访问可无妨。
一个很明显的错误,step = 2
的判断应该在step = 1
的嵌套中,所以直接传参step=2
,输入两次一样的密码就可以绕过验证码
HackBar测试
,当然也可以使用burpsuite
可以看到密码更改成功,更改成功后,我使用更改的密码发现登录失败,使用空密码更改成功
后开看了源码发现,这里传参的两次密码应该是password_new
和password_conf
,眼花了,不过没什么问题
所以这里使用burpsuite
更好,可以直接获取数据包头
审计源码
<?php
// 判断传入的 Change 和 step
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
// 隐藏验证码
$hide_form = true;
// 获取两次输入密码
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// 检查引入的 Goolge 验证码
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
// 检测验证码是否正确
if( !$resp ) {
// 验证码错误
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {
// 验证码正确
if( $pass_new == $pass_conf ) {
// 进入下一阶段
// 你通过了验证码!单击按钮确认更改。
// 这里于上次不同,多加了一个 passed_captcha 传参,值为 true
echo "
<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>
<form action=\"#\" method=\"POST\">
<input type=\"hidden\" name=\"step\" value=\"2\" />
<input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" />
<input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" />
<input type=\"hidden\" name=\"passed_captcha\" value=\"true\" />
<input type=\"submit\" name=\"Change\" value=\"Change\" />
</form>";
}
else {
// 两次输入密码不一致
$html .= "<pre>Both passwords must match.</pre>";
$hide_form = false;
}
}
}
// 判断传入 Change 和 step == 2
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
// 隐藏验证码
$hide_form = true;
// 获取两次输入密码
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// 检查是否完成了一阶段,判断的方式是检查passed_captcha值是否为空
// !取反,如果为空,打印 你没有通过验证码
if( !$_POST[ 'passed_captcha' ] ) {
$html .= "<pre><br />You have not passed the CAPTCHA.</pre>";
$hide_form = false;
return;
}
// 检查两次输入密码是否一致
if( $pass_new == $pass_conf ) {
// 一致
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// 更改数据库密码
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// 打印密码更改成功
echo "<pre>Password Changed.</pre>";
}
else {
// 两次输入密码不一致
echo "<pre>Passwords did not match.</pre>";
$hide_form = false;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
这里加入了一个passed_captcha
来检测是否通过了step==1
阶段,判断的方式是值是否为空,问题很突出,只需要传参任意值
就可以绕过验证码
HackBar测试
,这一次我没有输错
由于截图没有完整,这里我输入的是Change=Change&password_new=Admin123&password_conf=Admin123&step=2&passed_captcha=Junglezt
密码更改成功
其实前面这两题可以进行CSRF
攻击,直接复制源代码中的HTLM
代码就可以
实际步骤这里就不演示了
审计源码
<?php
// 获取传入的 Change
if( isset( $_POST[ 'Change' ] ) ) {
// 隐藏验证码
$hide_form = true;
// 后去两次输入的密码
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// 进入验证码
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
// 判断两种成立条件 resp 验证码返回正常 或者
// POST g-recaptcha-response的值为hidd3n_valu3 和 $_SERVER获取 HTTP_USER_AGENT 值为 reCAPTCHA
// $_SERVER HTTP_USER_AGENT 获取 请求头中的 User-Agent: 值
if (
$resp ||
(
$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
)
){
// 验证码正确,判断两次输入密码是否一直
if ($pass_new == $pass_conf) {
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// 使用 md5 加密密码
$pass_new = md5( $pass_new );
// 更新数据库密码
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// 打印密码更改成功
echo "<pre>Password Changed.</pre>";
} else {
// 两次输入密码不一致
$html .= "<pre>Both passwords must match.</pre>";
$hide_form = false;
}
} else {
// 验证码错误
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
// 生成反CSRF令牌,并没有看到验证user_token的地方
generateSessionToken();
?>
通过审计代码,通过验证码验证只有两种方式,验证码正常或者获取POST传参g-recaptcha-response值为hidd3n_valu3
和User-Agent值为reCAPTCHA
就可以绕过,所以这次我们使用burpsuite
进行抓包测试
如果出现上述错误服务器返回 500 错误的话,是我们刚开始配置dvwa/config/config.inc.php
文件中的两个值没有配置一样
配置一样后,或者是user_token
值得问题,你需要再次抓包
再次测试
密码更改成功
审计源码
<?php
// 判断传入的 Change
if( isset( $_POST[ 'Change' ] ) ) {
// 检查user_token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 隐藏二维码
$hide_form = true;
// 获取输入的新密码
$pass_new = $_POST[ 'password_new' ];
// 去除左右两边的空
$pass_new = stripslashes( $pass_new );
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// 获取第二次输入的密码
$pass_conf = $_POST[ 'password_conf' ];
// 去除左右两边的空
$pass_conf = stripslashes( $pass_conf );
$pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_conf = md5( $pass_conf );
// 获取输入的当前密码
$pass_curr = $_POST[ 'password_current' ];
// 去除左右两边的空
$pass_curr = stripslashes( $pass_curr );
$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_curr = md5( $pass_curr );
// 引入 Goolge 验证码进行验证
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
// 判断验证码是否正确
if( !$resp ) {
// 验证码错误发生什么
echo "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
}
else {
// 使用PDO方法查看当前密码
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
$data->execute();
// 判断两次输入的密码是否一直,并且当前密码是否相同
if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {
// 更新数据库密码
$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->execute();
// 打印密码更改成功
echo "<pre>Password Changed.</pre>";
}
else {
// 密码更改失败
echo "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";
$hide_form = false;
}
}
}
// 生成 CSRF user_token
generateSessionToken();
?>
验证码检测已经写死了,不能进行绕过,而且还必须输入当前的密码才可以修改密码,引入了user_token防止CSRF攻击
手机扫一扫
移动阅读更方便
你可能感兴趣的文章