前言
昨天看了極致CMS1.7,今天再來看看極致CMS1.9版本修復了什么漏洞,哪些漏洞還能用,是不是還有新的東西,
下載鏈接:
極致CMS
這次我下的是1.9.2的穩定版,
下載到本地搭建一下環境,然后就是安裝,安裝的時候注意到了這里:

我記得1.7版本安裝的時候管理員和密碼默認都是空的讓自己填,這里的話默認的管理員和密碼格式大概是jizhicms加上四個數字,這玩意怎么說呢,說是弱口令叭,但是9999*9999也挺難爆的,去爆破還不如找洞舒服,
看看后臺
安裝好之后還是先進一下后臺,登錄那里發現驗證碼那里比1.7的驗證碼難識別的多,感覺靠百度的那個基本不行了,而且試了一下,一個驗證碼可以利用無數次仍然沒改,所以這個驗證碼的用處其實不大,
進入后臺還是老樣子傳馬試試,這次改了配置增加php的檔案型別,仍然無法上傳成功,
看一下原始碼;
$fileType = $this->webconf['fileType'];
if(strpos($fileType,strtolower($pix))===false || stripos($pix,'php')!==false){
$data['error'] = "Error: 檔案型別不允許上傳!";
$data['code'] = 1002;
JsonReturn($data);
}
額外增加了對php的過濾,因此沒法直接上傳php了,考慮上傳phtml這樣的,但是默認肯定是不決議的,考慮傳.htaccess,但是因為檔案名不可控也不行,又全域查找了一下,能上傳檔案的有5個地方,全都進行了php后綴的過濾,因此檔案上傳這塊感覺就已經徹底GG了,
又拿1.7版本的SQL注入的EXP打了一下也沒成功,看一下代碼上發生了什么改變:
$openid = format_param($openid,1);
$islive = M('member')->find(array('openid'=>$openid));
發現對$openid進行了一層format_parm函式的過濾,感覺有點眼熟啊,跟進一下:
/**
引數過濾,格式化
**/
function format_param($value=null,$int=0,$default=false){
if($value==null){ return '';}
if($value===false && $default!==false){ return $default;}
switch ($int){
case 0://整數
return (int)$value;
case 1://字串
$value = SafeFilter($value);
$value=htmlspecialchars(trim($value), ENT_QUOTES);
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if(!get_magic_quotes_gpc())$value = addslashes($value);
}
return $value;
case 2://陣列
if($value=='')return '';
array_walk_recursive($value, "array_format");
return $value;
case 3://浮點
return (float)$value;
case 4:
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if(!get_magic_quotes_gpc())$value = addslashes($value);
}
return trim($value);
}
}
原來是這個過濾函式,SafeFilter是進行XSS過濾的不用管,$value=htmlspecialchars(trim($value), ENT_QUOTES);把單雙引號都給html轉義了,
此外還有一層對單雙引號這樣的加反斜杠的過濾,
再接著看一下find函式有什么變化:

跟進findAll方法,主要的變化就是加了一層這個:
$conditions = $this->__prepera_format($conditions);
具體不分析了,跟進一下看看代碼邏輯,發現對于我們要進行SQL注入的話并無影響,接下來的就是進入query函式,也是有了變化:
//執行 SQL 陳述句,回傳PDOStatement物件,可以理解為結果集
public function query($sql){
$this->arrSql[] = $sql;
$this->Statement = $this->pdo->query($sql);
if ($this->Statement) {
return $this;
}else{
$msg = $this->pdo->errorInfo();
if($msg[2]){
//Error_msg('資料庫錯誤:' . $msg[2] . end($this->arrSql));
$log_name = date('Y-m-d-H-i-s-').time();
register_log('資料庫錯誤:' . $msg[2] . end($this->arrSql),$log_name);
exit;
}
}
}
1.7版本是會直接把錯誤資訊echo出來,這里的話是寫入日志,不過沒啥用,只要能注入的話就直接堆疊了,也不需要用到報錯注入,
經過這波分析,基本可以確定的就是,CMS本身的find方法是存在漏洞的(說是漏洞也不太好),也就是說,find方法的第一個引數并沒有在find方法內進行過濾,還是在進入find方法前進行了一波format_param函式的過濾,因此現在的思路就是找一個開發的遺漏,類似find方法這樣的注入引數可控而且因為開發的疏忽,并沒有進行format_param的過濾,就可以實作SQL注入了,
之前版本除去wechat這里的SQL注入外,url上的注入也是非常容易利用的,但是試了一下發現也不太行,REQUEST_URI都會被html進行轉義,跟進了一下,發現是Fr.php的route方法的第207行呼叫了format_param,相當于對$_SERVER['REQUEST_URI']這整個部分都進行了一次過濾,因此關于路徑上的SQL注入就徹底GG了,

嘗試挖掘SQL注入(失敗)
全域搜索了find方法一點一點的看,首先是這個HomeController下面的差點就成功的:

$id可以通過路由或者get之類的傳參,路由的話之前分析過了,都會被html編碼一次,因此這里get傳的話是一點都沒有被過濾的,直接拼接進SQL陳述句:
$details = M($this->type['molds'])->find(array('id'=>$id,'isshow'=>1));
我本來想著已經成功了,結果發現不行,跟進一下會發現M($this->type['molds'])出了問題:

跟進入就會發現本來的::table就是jz_menu了,結果這里又拼接了一次jz_:
self::$table = DB_PREFIX.strtolower(self::$table);
導致查的表變成了jz_jz_menu,然后就是前面我說的那個不影響SQL注入的預處理,把我自己打敗了:

//預處理SQL
private function __prepera_format($rows)
{
$table = self::$table;
$stmt = $this->db->getTable($table);
$stmt->execute();
$columns = $stmt->fetchAll(PDO::FETCH_CLASS);
$newcol = array();
foreach ($columns as $key => $value) {
$field = strtolower($value->Field);
if(stripos($value->Type,'int')!==false || stripos($value->Type,'decimal')!==false){
if(isset($rows[$field])){
if($rows[$field]!=='' && $rows[$field]!==false){
$newcol[$field] = $rows[$field];
}else{
$newcol[$field] = 0;
}
}
}else{
if(isset($rows[$field])){
if($rows[$field]!=='' && $rows[$field]!==false ){
$newcol[$field] = $rows[$field];
}else{
$newcol[$field] = null;
}
}
}
}
return $newcol;
//return array_intersect_key($rows,$newcol);
}
他會先預查一次表,把然后傳入的$rows的鍵名在預查的表中才行,說白了就是如果正常查jz_menu表,表中有id這一列,因此就不影響,但是這里查的是jz_jz_menu表了,查不到任何東西,因此$rows這里就被扔掉了,加上查的是不存在的表,直接報錯,也就失敗了,草了氣死我了,
看了一下1.7版本同樣存在這個問題,這個主要的原因主要還是在于正常的話會傳$table的名字,因此不會出現前面有前綴的情況,但是遇到默認的情況的話,開發處理的就有些問題了,
后來把find方法看完了,感覺沒一個能SQL注入的,其他的update啥的以后再看了,太難了,
插件
這個插件仍然可以自由編輯代碼安裝后配置一下密碼,再點配置輸入密碼仍然可以寫檔案,拿到shell,不過確實這是插件本身功能的問題,要不直接把這個插件刪掉,要么就是更改功能,只能編輯html這樣的靜態檔案,要么就是后臺添加一個驗證,安裝插件需要驗證一個單獨的密碼,這樣可能才會好一點,不過現在SQL注入給修了,除了弱密碼, 后臺基本都進不來,所以其實挺安全的了,
此外1.7版本中任意下載指定url的zip檔案然后解壓的漏洞1.9.2版本也沒有修,
任意檔案夾下載那里倒是加上了一層過濾:

因此沒法任意下載檔案夾了,
總結
總的來說1.9版本基本上已經算是牢不可破了,前臺想要SQL注入真是tm的難,我現在就期待開發趕緊修了那個雙層表前綴的問題(笑),不知道別的師傅挖到了SQL注入沒,
這個下午基本上還是沒審出什么東西來,還是太菜了,明天有空再看一天,還找不到洞就算了,嗚嗚嗚太菜了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/272834.html
標籤:其他
上一篇:sqli-labs通關筆記
