游客发表
ShopXO的任意下载模块存在一个任意文件读取漏洞,攻击者可以通过构造特定的文件URL参数,直接读取服务器上的漏洞敏感文件。这个漏洞的任意成因并不复杂,但影响范围却相当广——只要目标站点使用了受影响版本的文件ShopXO,且下载功能未做严格过滤,漏洞攻击者就能在未授权的任意情况下拿到系统任意文件的内容。
具体来说,文件问题出在application/index/controller/DownloadController.php这个文件里。漏洞正常逻辑下,任意用户请求下载某个商品附件时,文件系统会根据传入的漏洞id或file参数去数据库查记录,然后返回对应的任意文件路径。但代码没有对参数做白名单校验,文件也没有用realpath()限制路径范围。漏洞攻击者可以直接把参数改成../../../../etc/passwd这种形式,让系统以为要下载的就是这个文件,接着file_get_contents()一读,内容就回显到响应里了。
我本地搭了一个ShopXO 2.3.0的环境做验证。访问/index.php?s=/index/download/index&id=../../../../../../etc/passwd,页面直接返回了root用户的行。换用file参数同样有效,比如&file=../../../../../../proc/self/environ,能读到环境变量。这说明漏洞不是某个参数特有的,而是整个下载入口都缺少路径约束。
有人可能会问,PHP的open_basedir能不能拦?能,但很多站点没开。而且即使开了,如果配置不当,比如只限制了部分目录,攻击者依然可以跳出去。更麻烦的是,这个漏洞不需要登录。ShopXO的下载功能默认对游客开放,因为很多商家希望用户不注册也能下载试用版或说明书。这就让攻击面从后台用户扩大到了整个互联网。
实际扫描中,我用FOFA找了一批ShopXO站点,随机抽了二十个测试,有六个直接读出了/etc/passwd。其中一个还读到了config/database.php,里面明文写着数据库账号密码。如果攻击者进一步利用,完全可以通过数据库写入webshell,或者直接连接内网其他服务。危害等级至少是高危。
修复思路其实不复杂。官方在后续版本里加了str_replace('../', '', $param),但这种方法不彻底,因为....//或URL编码可以绕过。更稳妥的做法是:先对参数做basename()处理,只保留文件名;再用realpath()拼接基础目录,判断最终路径是否在允许的目录内。如果不在,直接返回403。同时,下载文件最好通过数据库ID映射,而不是让用户传路径。
对于还没升级的用户,临时缓解可以在Nginx层加规则,拦截URL里带../或%2e%2e的请求。但这不是长久之计。我见过一些站长直接删掉了下载控制器,改用静态文件直链——虽然牺牲了权限控制,但至少堵住了这个洞。
这个漏洞让我想起早期ThinkPHP的很多类似问题。框架本身不背锅,但开发者习惯性地信任用户输入,把文件路径直接拼进函数里,这种模式在CMS和商城系统里太常见了。ShopXO不是第一个,也不会是最后一个。如果你手里有这类系统,别光看版本号,手动测一下下载参数,比什么都实在。
友情链接