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

本篇继续对于安全性测试话题,结合DVWA进行研习。InsecureCaptcha不安全验证码1.验证码到底是怎么一回事这个Captcha狭义而言就是谷歌提供的一种用户验证服务,全称为:CompletelyAutomatedPublicTuringTesttoTellComputersandHumansApart(全自动区分计算机和人类的图灵测试)。*很巧妙的是,Captcha单独成词的意思就是,抓...

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

本篇继续对于安全性测试话题,结合DVWA进行研习。

Insecure Captcha不安全验证码

1. 验证码到底是怎么一回事

这个Captcha狭义而言就是谷歌提供的一种用户验证服务,全称为:Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)。

*很巧妙的是,Captcha单独成词的意思就是,抓到你了哟^_^*

Captcha在各种海外网站被广泛用于用户验证。而在国内,由于众所周知的原因,我们不用谷歌的服务,很多接口平台都可以提供类似服务。

比如apishop的这个四位验证码服务接口:

那么验证码到底在用户验证的过程中起到什么样的作用呢?

验证码最大的作用就是防止攻击者使用工具或者软件自动调用系统功能

就如Captcha的全称所示,他就是用来区分人类和计算机的一种图灵测试,这种做法可以很有效的防止恶意软件、机器人大量调用系统功能:比如注册、登录功能。

我们前面讲到的Brute Force字典式暴力破解,就必须要使用工具大量尝试登录。如果这个时候系统有个严密的验证码机制,此类攻击就无计可施了。

其工作流程如下所示:

2. 验证码绕过

为什么前文要在验证码机制前面黑体强调他要是严密的,那当然是如果验证码机制设计不得当,绕过它也只是分分钟的事情。。。

DVWA提供的试验模块长这个样子:

我们将其安全级别调到最低,使用ZAP做为代理进行抓包,填入任意密码触发请求,看到请求内容如下:

这是个啥子意思呢,我们参考一下DVWA的后台逻辑:

<?phpif( 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'],  $_POST['g-recaptcha-response'] ); // Did the CAPTCHA fail? if( !$resp ) {  // 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$html .= “ <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 = ((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 );  // Update database  $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>' );  // Feedback for the end user  $html .= “<pre>Password Changed.</pre>“; } else {  // Issue with the passwords matching  $html .= “<pre>Passwords did not match.</pre>“;  $hide_form = false; } ((is_null($___mysqli_res = mysqli_close($GLOBALS[“___mysqli_ston“]))) ? false : $___mysqli_res);}?>

代码有点长,但是可以明显看出来,这个机制是很简单的。整个验证逻辑将验证分为两步:Step1,Step2,而对于captcha验证的逻辑只存在于Step1中的小小一段:

既然所有验证逻辑都只存在于Step1,那么如果我直接绕过它,有可能吗?

其实非常简单,这里我们要用到抓包-改包-重发的方法,ZAP已经给我们提供了“请求断点”功能。

点击上图中绿色断点按钮,ZAP就进入请求断点状态,在此状态下ZAP不再简单的将客户端和服务器之间的请求交互转发,而是像其他编程工具的断点功能一样,让请求反馈变为单步执行。那么我们就可以在请求发出,尚未传递至服务器之前,对请求内容进行篡改:

改包重发的结果:

密码修改成功,而这整个过程中我们完全没有去处理captcha的验证码,也就是说这个验证码被完全绕过了!

3. DVWA的验证码机制完善防御

既然验证码逻辑是有可能被绕过,接下来我们来研究一下,如何建立更完善的机制呢。

Medium级别

<?phpif( 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' ],  $_POST['g-recaptcha-response'] ); // Did the CAPTCHA fail? if( !$resp ) {  // 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$html .= “ <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_ne
源文地址:https://www.guoxiongfei.cn/cntech/18364.html