漏洞概况
这个漏洞的成因是没有考虑到php是弱类型语言,不合理使用intval()函数而造成的任意用户登录。
环境搭建
- espcms 6.4.15.08.25
- php 5.6.40
- Ubuntu 18.04 + Mysql 5.7 + Apache2
漏洞利用
搭建好环境后,我们先注册几个会员账号。
登录后台管理员账号后可以在会员管理这里看到注册的会员账号。
可以看到我们注册了5个用户,为了登录ID为3的用户,我们可以先注册一个以”数字3+字符串”的用户3test
刷新当前页面,用burpsuite抓包,将ecisp_member_info
的值修改得和ecisp_member_info
一样。
1 | ecisp_member_username=57liGUuVT2EkJ0mZuAZgYCl%2B%2Fi3PJuRjagZ21ZMaR7I%3D; ecisp_member_info=57liGUuVT2EkJ0mZuAZgYCl%2B%2Fi3PJuRjagZ21ZMaR7I%3D; |
发送修改后的数据包,发现成功登录了ID为3的用户lxx。
漏洞分析
interface/membermain.php
:
1 | function in_center() { |
我们跟踪一下espcms验证用户信息的流程,in_center()
函数会调用member_purview()
,这是处理uid的函数。
public/class_connector.php
:
先通过$this->fun->accept('ecisp_member_info', 'C')
获取cookie中的ecisp_member_info
值。
这里没有传入$htmlcode
,所以$htmlcode
默认为true,会执行
1 | ($rehtml ? $this->preg_htmldecode($putvalue) : $this->htmldecode($putvalue)) |
又因为没有传入$rehtml
,所以$rehtml
默认为false,会执行
1 | $this->preg_htmldecode($putvalue) |
返回的结果就是57liGUuVT2EkJ0mZuAZgYCl+/i3PJuRjagZ21ZMaR7I=
接着返回的字符串就会传入$this->fun->eccode($this->fun->accept('ecisp_member_info', 'C'), 'DECODE', db_pscode)
。跟进eccode()
函数,发现会对传入的字符串进行解密操作。
经过decryptCookie()
函数后就可以获得解密后的ecisp_member_info
值。
比如我们新注册的用户是3test
,那么返回的$user_info
值就是3test
,然后将这个值赋给$ec_member_username_id
。
漏洞的主要成因就是对$ec_member_username_id
进行了intval操作。因为php是弱类型语言,所以3test
就会被intval理解为3。
1 | $this->ec_member_username_id = intval($ec_member_username_id); |
执行完member_purview()
函数,$this->ec_member_username_id
就是3,此时$db_where
就是
1 | userid=3 AND username='3test' |
1 | function in_center(){ |
此时sql查询语句为:
1 | SELECT * FROM espcms_member AS a LEFT JOIN espcms_member_value AS b ON a.userid = b.userid WHERE a.userid = 3 |
可以看到这时返回的结果就是ID为3的用户lxx。
官方补丁
这个补丁完全可以绕过啊,官方没有没有成功修复这个漏洞orz…