6.3.1 挖掘经验
认证漏洞在代码审计的时候能遇到比较多的是出现在 cookie 验证上面,通常是没有使用 session 来认证,而是直接将用户信息保存在 cookie 中,程序使用的时候直接调用。一般这个过程都有一个统一的函数去取数据调用,容易导致 SQL 注入和越权等漏洞。在挖掘登录认证漏洞的时候,可以先看一下程序的登录功能代码,看看整个登录过程的业务逻辑有没有可以控制 session 值或者直接绕过密码验证的漏洞;另外需要关注程序验证是否为登录的代码,通俗的说是验证 cookie 的代码,是不是直接去取 cookie 里面的值,然后怎么去判断这个值来验证是否登录。以前见过相当粗糙的验证是直接判断 cookie 里面的 username 参数是否为空,还有就是以 cookie 里面的用户名来作为当前用户,这种情况直接把用户名改成 admin 等管理员用户名就直接是管理员权限了。
6.3.1.1 cookie 认证安全
cookie 可以保存任何字符串,各个浏览器保存 cookie 字节数大小不一样,一般都不超过 4096 个字节,通常 cookie 用来保存登录账号的标识信息,比如用户名或者 sessionid 等,浏览器每次请求的时候都会再次带上对应这个域名的 cookie 信息,服务器应用程序可以对 cookie 进行读取修改或者删除等任意操作。
cookie 出现问题比较多的是 cookie 的 SQL 注入等常见漏洞,以及 Web 应用程序在服务端直接读取 cookie 的用户名或者 ID 值来操作当前这个用户的数据,这里存在很大的一个问题是 cookie 可以伪造,从而就导致了伪造用户身份登录的漏洞。
通常一个 cookie 验证的代码大概如下:
<?php session_start (); function login () { if (账号密码正确) { setcookie ( 'username' , 'admin' ); $_SESSION['username'] = 'admin' ; } } // 判断 cookie 里面的用户名是否和 session 里的用户名一致 if ( $_COOKIE['username']===$_SESSION['username'] ) { // 操作 $_SESSION['username'] 用户的数据 } else { login (); }
这样的写法一般情况不会出现验证上面的安全问题,下面我们通过案例来看看有问题的写法。
6.3.1.2 Espcms 任意用户登录分析
我们这里以乌云漏洞编号为 WooYun-2015-90324 的“ESPCMS 所有版本任意用户登录”漏洞来做一个简单的分析。
在文件/interface/memebermain.php 的 in_center() 函数可以看到如下代码:
function in_center () { if ( $this->CON['mem_isucenter'] ) { include_once admin_ROOT . 'public/uc_client/client.php' ; } parent :: start_pagetemplate (); parent :: member_purview (); $lng = ( admin_LNG == 'big5' ) ? $this->CON['is_lancode'] : admin_LNG ; $db_where = "userid=$this->ec_member_username_id AND username='$this-> ec_member_username' " ; $db_table1 = db_prefix . 'member AS a' ; $db_table2 = db_prefix . 'member_value AS b' ; $db_sql = "SELECT * FROM $db_table1 LEFT JOIN $db_table2 ON a.userid = b.userid WHERE a.userid = $this->ec_member_username_id " ; $rsMember = $this->db->fetch_first ( $db_sql ); $rsMember['rankname'] = $this->get_member_purview ( $rsMember['mcid'] , 'rankname' ); $userid = $this->ec_member_username_id ; // 获取 userid if ( empty ( $userid )) { exit ( 'user err ! ' ); } $db_table = db_prefix . "order" ; $db_where = " WHERE userid=$userid" ;
在代码中$userid=$this->ec_member_username_id;这行代码设置当前用户 ID,随后根据这个$userid 变量去直接操作这个 id 的用户数据,而这个$this->ec_member_username_id 变量的值又是从哪来的呢?注意代码最开始的地方有调用 parent::member_purview() 函数,我们跟过去看看,在/public/class_connector.php 文件的 member_purview() 函数,代码如下:
function member_purview ( $userrank = false , $url = null , $upurl = false ) { $this->ec_member_username = $this->fun->eccode ( $this->fun-> accept ( 'ecisp_member_username' , 'C' ), 'DECODE' , db_pscode ); $user_info = explode ( '|' , $this->fun->eccode ( $this->fun-> accept ( 'ecisp_member_info' , 'C' ), 'DECODE' , db_pscode )); list ( $this->ec_member_username_id , $this->ec_member_alias , $this-> ec_member_integral , $this->ec_member_mcid , $this->ec_member_email , $this->ec_member_lastip , $this->ec_member_ipadd , $this->ec_member_useragent , $this->ec_member_adminclassurl ) = $user_info ;
可以看到 list() 函数中使用$user_info 数组为$this->ec_member_username_id 变量进行赋值,而$user_info 数组是从 cookie 中解密出来的,关于这个算法的加密代码在/public/class_function.php 文件的 eccode() 函数,代码如下:
function eccode ( $string , $operation = 'DECODE' , $key = '@LFK24s224%@safS3s%1f%' , $mcrype = true ) { $result = null ; if ( $operation == 'ENCODE' ) { for ( $i = 0 ; $i < strlen ( $string ); $i++ ) { $char = substr ( $string , $i , 1 ); $keychar = substr ( $key , ( $i % strlen ( $key )) - 1 , 1 ); $char = chr ( ord ( $char ) + ord ( $keychar )); $result.=$char ; } $result = base64_encode ( $result ); $result = str_replace ( array ( '+' , '/' , '=' ), array ( '-' , '_' , '' ), $result ); } elseif ( $operation == 'DECODE' ) { $data = str_replace ( array ( '-' , '_' ), array ( '+' , '/' ), $string ); $mod4 = strlen ( $data ) % 4 ; if ( $mod4 ) { $data .= substr ( '====' , $mod4 ); } $string = base64_decode ( $data ); for ( $i = 0 ; $i < strlen ( $string ); $i++ ) { $char = substr ( $string , $i , 1 ); $keychar = substr ( $key , ( $i % strlen ( $key )) - 1 , 1 ); $char = chr ( ord ( $char ) - ord ( $keychar )); $result.=$char ; } } return $result ; }
这是一个很明显的可逆算法,这里就不再重点分析这个算法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论