邪恶八进制信息安全团队技术讨论组's Archiver

axpwx 2007-5-18 05:19

[原创]你的验证码安全吗?

文章作者:Axpwx
信息来源:邪恶八进制信息安全团队([url]www.eviloctal.com[/url])

[b]注意:本文章首发[url]www.axpwx.cn[/url] ,后由原创作者友情提交到邪恶八进制信息安全团队,转载请注明首发站点 [/b]

验证码的作用主要有防止暴力破解,防止恶意灌水,防止自动提交等,在这里我就不多说了。验证码的类型也有数字、字母等,甚至厉害点的还有中文的。但是不管你的验证码多么厉害,只要你在表单验证中存在如下的失误,你的验证码就形同虚设!

验证码的一般思路,就是每次登陆的地方访问一个脚本文件,该文件生成含验证码的图片并将值写入到Session里,提交的时候验证登陆的脚本就会判断提交的验证码是否与Session里的一致。

问题出现了,在登陆密码错误之后,我们不去访问生成验证图片的文件,那么如果Session中的验证码没有被清空,此时验证码就是跟上次的一样,辛辛苦苦构建的验证码机制就形同虚设了。

下面我们先来看一段有问题的代码:
登陆部分:[color=#007700][/color] [color=#007700][color=#000000][color=#007700]<[/color][color=#0000bb]tr[/color][color=#007700]>
     <[/color][color=#0000bb]td[/color][color=#007700]>[/color][color=#0000bb]管理员姓名:[/color][color=#007700]</[/color][color=#0000bb]td[/color][color=#007700]>
     <[/color][color=#0000bb]td[/color][color=#007700]><[/color][color=#0000bb]input type[/color][color=#007700]=[/color][color=#dd0000]"text" [/color][color=#0000bb]name[/color][color=#007700]=[/color][color=#dd0000]"username" [/color][color=#007700]/></[/color][color=#0000bb]td[/color][color=#007700]>
   </[/color][color=#0000bb]tr[/color][color=#007700]>
   <[/color][color=#0000bb]tr[/color][color=#007700]>
     <[/color][color=#0000bb]td[/color][color=#007700]>[/color][color=#0000bb]管理员密码:[/color][color=#007700]</[/color][color=#0000bb]td[/color][color=#007700]>
     <[/color][color=#0000bb]td[/color][color=#007700]><[/color][color=#0000bb]input type[/color][color=#007700]=[/color][color=#dd0000]"password" [/color][color=#0000bb]name[/color][color=#007700]=[/color][color=#dd0000]"password" [/color][color=#007700]/></[/color][color=#0000bb]td[/color][color=#007700]>
   </[/color][color=#0000bb]tr[/color][color=#007700]>
      <[/color][color=#0000bb]tr[/color][color=#007700]>
     <[/color][color=#0000bb]td[/color][color=#007700]>[/color][color=#0000bb]验证码:[/color][color=#007700]</[/color][color=#0000bb]td[/color][color=#007700]>
     <[/color][color=#0000bb]td[/color][color=#007700]><[/color][color=#0000bb]input type[/color][color=#007700]=[/color][color=#dd0000]"text" [/color][color=#0000bb]name[/color][color=#007700]=[/color][color=#dd0000]"captcha" [/color][color=#0000bb]onkeyup[/color][color=#007700]=[/color][color=#dd0000]"pressCaptcha(this)" [/color][color=#007700]/></[/color][color=#0000bb]td[/color][color=#007700]>
   </[/color][color=#0000bb]tr[/color][color=#007700]>
   <[/color][color=#0000bb]tr[/color][color=#007700]>
   <[/color][color=#0000bb]td colspan[/color][color=#007700]=[/color][color=#dd0000]"2" [/color][color=#0000bb]align[/color][color=#007700]=[/color][color=#dd0000]"right"[/color][color=#007700]>
   <[/color][color=#0000bb]img src[/color][color=#007700]=[/color][color=#dd0000]"index.php?act=captcha&1628020115" [/color][color=#0000bb]width[/color][color=#007700]=[/color][color=#dd0000]"145" [/color][color=#0000bb]height[/color][color=#007700]=[/color][color=#dd0000]"20" [/color][color=#0000bb]alt[/color][color=#007700]=[/color][color=#dd0000]"CAPTCHA" [/color][color=#0000bb]border[/color][color=#007700]=[/color][color=#dd0000]"1" [/color][color=#0000bb]onclick[/color][color=#007700]= [/color][color=#0000bb]this[/color][color=#007700].[/color][color=#0000bb]src[/color][color=#007700]=[/color][color=#dd0000]"index.php?act=captcha&"[/color][color=#007700]+[/color][color=#0000bb]Math[/color][color=#007700].[/color][color=#0000bb]random[/color][color=#007700]() [/color][color=#0000bb]style[/color][color=#007700]=[/color][color=#dd0000]"cursor: pointer;" [/color][color=#0000bb]title[/color][color=#007700]=[/color][color=#dd0000]"看不清?点击更换另一个验证码。" [/color][color=#007700]/>
   </[/color][color=#0000bb]td[/color][color=#007700]>
   </[/color][color=#0000bb]tr[/color][color=#007700]>[/color][/color][/color][color=#007700]
[/color]这里没什么问题,来看登陆验证的代码(我想这样的验证思路,也是大多数人都在用的吧):
[color=#000000][color=#0000bb]<?php
[/color][color=#ff8000]/*------------------------------------------------------ */
//-- 验证登陆信息
/*------------------------------------------------------ */
[/color][color=#007700]if ([/color][color=#0000bb]$_REQUEST[/color][color=#007700][[/color][color=#dd0000]&#39;act&#39;[/color][color=#007700]] == [/color][color=#dd0000]&#39;signin&#39;[/color][color=#007700])
{
  include([/color][color=#dd0000]&#39;../includes/cls_captcha.php&#39;[/color][color=#007700]);

  [/color][color=#ff8000]/* 检查验证码是否正确 */
  [/color][color=#0000bb]$validator [/color][color=#007700]= new [/color][color=#0000bb]captcha[/color][color=#007700]();
  if (![/color][color=#0000bb]$validator[/color][color=#007700]->[/color][color=#0000bb]check_word[/color][color=#007700]([/color][color=#0000bb]$_POST[/color][color=#007700][[/color][color=#dd0000]&#39;captcha&#39;[/color][color=#007700]]))
  {
    [/color][color=#0000bb]sys_msg[/color][color=#007700]([/color][color=#0000bb]$_LANG[/color][color=#007700][[/color][color=#dd0000]&#39;captcha_error&#39;[/color][color=#007700]], [/color][color=#0000bb]1[/color][color=#007700]);
  }

  [/color][color=#ff8000]/* 检查密码是否正确 */
  [/color][color=#0000bb]$sql [/color][color=#007700]= [/color][color=#dd0000]"SELECT user_id, user_name, password, action_list FROM " [/color][color=#007700].[/color][color=#0000bb]$ecs[/color][color=#007700]->[/color][color=#0000bb]table[/color][color=#007700]([/color][color=#dd0000]&#39;admin_user&#39;[/color][color=#007700]).
      [/color][color=#dd0000]" WHERE user_name=&#39;$_POST[username]&#39; AND password=&#39;" [/color][color=#007700].[/color][color=#0000bb]md5[/color][color=#007700]([/color][color=#0000bb]$_POST[/color][color=#007700][[/color][color=#dd0000]&#39;password&#39;[/color][color=#007700]]). [/color][color=#dd0000]"&#39;"[/color][color=#007700];
  [/color][color=#0000bb]$row [/color][color=#007700]= [/color][color=#0000bb]$db[/color][color=#007700]->[/color][color=#0000bb]GetRow[/color][color=#007700]([/color][color=#0000bb]$sql[/color][color=#007700]);

  if ([/color][color=#0000bb]$row[/color][color=#007700])
  {
    [/color][color=#ff8000]// 登录成功
    [/color][color=#0000bb]set_admin_session[/color][color=#007700]([/color][color=#0000bb]$row[/color][color=#007700][[/color][color=#dd0000]&#39;user_id&#39;[/color][color=#007700]], [/color][color=#0000bb]$row[/color][color=#007700][[/color][color=#dd0000]&#39;user_name&#39;[/color][color=#007700]], [/color][color=#0000bb]$row[/color][color=#007700][[/color][color=#dd0000]&#39;action_list&#39;[/color][color=#007700]]);

    [/color][color=#ff8000]// 更新最后登录时间和IP
    [/color][color=#0000bb]$db[/color][color=#007700]->[/color][color=#0000bb]Execute[/color][color=#007700]([/color][color=#dd0000]"UPDATE " [/color][color=#007700].[/color][color=#0000bb]$ecs[/color][color=#007700]->[/color][color=#0000bb]table[/color][color=#007700]([/color][color=#dd0000]&#39;admin_user&#39;[/color][color=#007700]).
          [/color][color=#dd0000]" SET last_time=&#39;" [/color][color=#007700].[/color][color=#0000bb]date[/color][color=#007700]([/color][color=#dd0000]&#39;Y-m-d H:i:s&#39;[/color][color=#007700], [/color][color=#0000bb]time[/color][color=#007700]()). [/color][color=#dd0000]"&#39;, last_ip=&#39;" [/color][color=#007700].[/color][color=#0000bb]real_ip[/color][color=#007700](). [/color][color=#dd0000]"&#39;"[/color][color=#007700].
          [/color][color=#dd0000]" WHERE user_id=$_SESSION[admin_id]"[/color][color=#007700]) OR die([/color][color=#0000bb]$db[/color][color=#007700]->[/color][color=#0000bb]ErrorMsg[/color][color=#007700]());

    if (isset([/color][color=#0000bb]$_POST[/color][color=#007700][[/color][color=#dd0000]&#39;remember&#39;[/color][color=#007700]]))
    {
      [/color][color=#0000bb]setcookie[/color][color=#007700]([/color][color=#dd0000]&#39;ECSCP[admin_id]&#39;[/color][color=#007700],  [/color][color=#0000bb]$row[/color][color=#007700][[/color][color=#0000bb]0[/color][color=#007700]], [/color][color=#0000bb]time[/color][color=#007700]() + [/color][color=#0000bb]3600 [/color][color=#007700]* [/color][color=#0000bb]24 [/color][color=#007700]* [/color][color=#0000bb]360[/color][color=#007700]);
      [/color][color=#0000bb]setcookie[/color][color=#007700]([/color][color=#dd0000]&#39;ECSCP[admin_pass]&#39;[/color][color=#007700], [/color][color=#0000bb]md5[/color][color=#007700]([/color][color=#0000bb]$row[/color][color=#007700][[/color][color=#dd0000]&#39;password&#39;[/color][color=#007700]] . [/color][color=#0000bb]$_CFG[/color][color=#007700][[/color][color=#dd0000]&#39;hash_code&#39;[/color][color=#007700]]), [/color][color=#0000bb]time[/color][color=#007700]() + [/color][color=#0000bb]3600 [/color][color=#007700]* [/color][color=#0000bb]24 [/color][color=#007700]* [/color][color=#0000bb]360[/color][color=#007700]);
    }

    [/color][color=#0000bb]header[/color][color=#007700]([/color][color=#dd0000]&#39;location:./&#39;[/color][color=#007700]);
  }
  else
  {
    [/color][color=#0000bb]sys_msg[/color][color=#007700]([/color][color=#0000bb]$_LANG[/color][color=#007700][[/color][color=#dd0000]&#39;login_faild&#39;[/color][color=#007700]], [/color][color=#0000bb]1[/color][color=#007700]);
  }
}
[/color][color=#0000bb]?>[/color][/color]问题就出在上面这段代码里,在检查密码错误之后,并没有更新验证码,这样我们就可以把登陆页面的验证码图片部分去掉,而只要用URL访问一下验证码的页面,就可以只提交用户名、密码、刚才得到的验证码实现暴力破解了,利用此方法,同样可以实现灌水,刷票等。
大家可以看下面的图片,增强点直观的认识。
[url=http://www.axpwx.cn/attachment.php?id=122][img]http://www.axpwx.cn/attachments/date_200701/thumb_18c3b0e30964fd80c438db2fbb3eb599.jpg[/img][/url]
解决方法:我们需要在检查密码错误后更新验证码,对于留言等类型的,还要在提交成功后更新验证码。
[attach]5887[/attach]
安全就是这样,我们总是想让自己的程序更安全,但是一般情况下,我们又总是走在常规思维里跳不出来,于是导致我们的程序出现了很多"非常规漏洞",或者叫做"缺陷",总之就是不完美。我写这篇文章除了指出上面这个问题之外,还希望大家都能行动起来,用"非常规"眼光,重新检查下自己的程序,把更多以前自己没有发现的小问题写出来,让大家共同提高!

混世魔王 2007-5-22 01:44

验证码安全这个问题,
以前看过lake2的分析过。不过是asp的。
LZ是php的...

bink 2007-5-22 11:34

是个逻辑性问题。就是说在发生验证错误的情况下不刷新验证码,因此可以用来尝试无限猜解并且Session 中的验证码不边。刚去看了看我们的系统。呵呵。正常。无论是否验证成功。每次提交即刷新验证码。

ddiovedd 2007-5-22 16:20

发生验证错误的情况下刷新验证码,这个并不是最好方法,最好的是同时清空验证码中的Session

我非我 2007-5-22 16:37

nice idea.
Perhaps we can send a special PHP_SESSIONID to get an empty session and bypass the check code

虫虫 2007-5-24 08:53

[quote]引用第4楼我非我于2007-05-22 16:37发表的 :
nice idea.
Perhaps we can send a special PHP_SESSIONID to get an empty session and bypass the check code[/quote]

能想象。 也就是说,如果根本就不去读取那个生成验证码及图片的程序,session中的checkCode就不会被设置,为空。 貌似是一个好方法……
可是…… 程序一般会判断提交的CheckCode是否为空~~,为空就不让进~ 哈哈` ~~ 泼凉水~~

唐不狐 2007-5-24 10:24

lake2的《轻轻绕过你的验证码》,连表述都很相似,甚至是那张截图。这种漏洞目前还是普遍存在的

bink 2007-5-24 11:26

[quote]引用第6楼唐不狐于2007-05-24 10:24发表的 :
lake2的《轻轻绕过你的验证码》,连表述都很相似,甚至是那张截图。这种漏洞目前还是普遍存在的[/quote]


目前很少有站点关注安全问题。何况验证码出现问题对站点的影响也不是很大。如果人人都关注安全。那么我们都可以关站了。也没有什么漏洞可寻了。

sugarjh 2007-5-26 13:29

应该怎么解决才好呢?

tanaer 2007-5-27 02:21

PjBlog 貌似有这个问题,,

   ,,![s:263]

bink 2007-5-29 00:19

[quote]引用第11楼tanaer于2007-05-27 02:21发表的 :
PjBlog 貌似有这个问题,,

   ,,![s:263][/quote]

我玩过PJ。验证码那里确实有使用上的问题。但安全问题还没看呢。呵呵。下次看看。

axpwx 2007-6-2 06:17

[quote]引用第13楼bink于2007-05-29 00:19发表的 :


我玩过PJ。验证码那里确实有使用上的问题。但安全问题还没看呢。呵呵。下次看看。[/quote]


别的Blog代码我没看过,但是我知道SABlog有这个问题。

wsclon 2007-10-3 05:02

PjBLOG使用起来最大的问题就是验证码了,安全性还不错。

页: [1]
© 1999-2008 EvilOctal Security Team