返回介绍

6.3.1 挖掘经验

发布于 2024-10-11 22:07:45 字数 4684 浏览 0 评论 0 收藏 0

认证漏洞在代码审计的时候能遇到比较多的是出现在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文