from 90sec
漏洞文件:
/system/module/file/model.php
public function pasteImage($data, $uid) { $data = str_replace('"', '"', $data); if(!$this->checkSavePath()) return false; ini_set('pcre.backtrack_limit', strlen($data)); preg_match_all('/<img src="(data:image/(S+);base64,(S+))" .+ />/U', $data, $out); foreach($out[3] as $key => $base64Image) { $imageData = base64_decode($base64Image); $imageSize = array('width' => 0, 'height' => 0); $file['id'] = $key; $file['extension'] = $out[2][$key]; $file['size'] = strlen($imageData); $file['addedBy'] = $this->app->user->account; $file['addedDate'] = helper::today(); $file['title'] = basename($file['pathname']); $file['pathname'] = $this->setPathName($file); $file['editor'] = 1; file_put_contents($this->savePath . $file['pathname'], $imageData); $this->compressImage($this->savePath . $file['pathname']); $imageSize = $this->getImageSize($this->savePath . $file['pathname']); $file['width'] = $imageSize['width']; $file['height'] = $imageSize['height']; $file['lang'] = 'all'; $this->dao->insert(TABLE_FILE)->data($file)->exec(); $_SESSION['album'][$uid][] = $this->dao->lastInsertID(); $data = str_replace($out[1][$key], $this->webPath . $file['pathname'], $data); } return $data; }
主要观察的地方是file_put这里,我们看看哪里可控。$imageData是由穿入的内容经过正则匹配然后遍历经过base64解码出来的内容。
$this->savePath . $file['pathname']
$this->savePath 不可控,$file['pathname']目前不知道
先看看这个函数从哪里调用过来的
关联文件:/system/module/file/control.php
public function ajaxPasteImage($uid) { if($_POST) { echo $this->file->pasteImage($this->post->editor, $uid); } }
Uid就不多说了,首先肯定是当post请求的时候才能够进入我们发现隐患的函数,这个不困难
data是由editor参数传入的,uid不确定是否能够控制但目前的条件来说无关紧要,继续回到原来的地方
foreach($out[3] as $key => $base64Image) { $imageData = base64_decode($base64Image); $imageSize = array('width' => 0, 'height' => 0); $file['id'] = $key; $file['extension'] = $out[2][$key]; $file['size'] = strlen($imageData); $file['addedBy'] = $this->app->user->account; $file['addedDate'] = helper::today(); $file['title'] = basename($file['pathname']); $file['pathname'] = $this->setPathName($file); $file['editor'] = 1;
Data既然是可控的,那么自然out[3]也是可控内容,这里的 $file['extension'] = $out2 = $this->setPathName($file);我们唯一不能控值的pathname是从这里赋出来的,先跟入函数看看
public function setPathName($file, $objectType = 'upload') { if(strpos('slide,source,themePackage', $objectType) === false) { $sessionID = session_id(); $randString = substr($sessionID, mt_rand(0, strlen($sessionID) - 5), 3); $pathName = date('Ym/dHis', $this->now) . $file['id'] . mt_rand(0, 10000) . $randString; } elseif($objectType == 'source') { /* Process file path if objectType is source. */ $template = $this->config->template->{$this->app->clientDevice}->name; $theme = $this->config->template->{$this->app->clientDevice}->theme; return "source/{$template}/{$theme}/{$file['title']}.{$file['extension']}"; } elseif($objectType == 'themePackage') { return "{$file['title']}.{$file['extension']}"; } /* rand file name more */ list($path, $fileName) = explode('/', $pathName); $fileName = md5(mt_rand(0, 10000) . str_shuffle(md5($fileName)) . mt_rand(0, 10000)); return $path . '/f_' . $fileName . '.' . $file['extension']; }
前面的if都是不具备条件的自然是执行最后的操作,但这里看见没$file['extension']是后缀,是我们可以控制的,那么就是可以getshell了。。。。
本地复现下试试:
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论