在 Windows环境、PHP版本<=5.3 的环境中, Metinfo 存在一个前台任意文件上传漏洞。攻击者可以通过该漏洞直接获取网站权限,漏洞影响至 Metinfo 最新版(目前最新版本为 6.2.0 )漏洞思路参考自 Metinfo6 Arbitrary File Upload Via Iconv Truncate ,原文中对 POC 打了码,我们可以自己来挖掘一下。
漏洞分析
Metinfo 提供了一个强大的上传类,其中有一个实现了上传功能的方法 doupfile 。在下图 第5行 的代码中,设置了上传文件的一些模式信息,同时在 第11行 处,用 $info 变量来设置文件的属性信息。然而 $info 变量来自用户可控数据 $_M['form'] ,我们细看 set_upfile、set_upload 这两个方法中都设置了什么。

在 set_upfile、set_upload 这两个方法中,我们看到其都设置了 savepath 属性,该属性用于表示上传文件的保存路径。其中,在先调用的 set_upfile 函数中, savepath 属性默认值为 /website_root/upload/file/ 。而后调用的 set_upload 函数中,用可控数据重新赋值给 savepath 属性。之所以要关注这个属性,是因为该属性会影响我们上传文件的存储位置,且这个属性也是引发本次漏洞的关键之一。

我们继续看 doupfile 方法,在 $this->set_upload($info) 之后,紧接着执行 $this->upload($_M['form']['formname']) ,该方法则调用 upfile 类的 upload 方法。在 upfile 类的 upload 方法中,程序将 $_FILES 变量存在 $filear 变量中,然后对一些上传条件进行逐一判断。可以看到程序使用黑、白名单对文件后缀合法性进行检测。规则相对严格,暂时无法绕过,我们继续往下看。

当判断完文件后缀名,程序又对文件名中的非法字符进行替换。这里有一个 $this->is_rename 变量,该变量用于决定是否对上传文件进行重命名,其值可由用户控制(即前面提到的 $_M['form']['is_rename'] 变量)。

接着,只要 $this->savepath 以 /webroot/upload/ 开头且不包含 ./ ,就会将它和 $this->savename 拼接起来,作为文件的绝对路径(如果想绕过 ./ 的过滤,在 windows 下可以使用 ..\ 来进行路径穿越)。如果系统为 windows ,将会调用 iconv 函数对文件绝对路径进行编码转换,而问题就出在这里。

低版本的 PHP 中, iconv 函数存在字符转换截断问题。而我在尝试的过程中,发现了一些和漏洞发现者不一样的地方。原作者的 payload 中使用的是 %81 ,而这个字符在 windows 下作为文件夹名的一部分是不行的,所以在上图 第13行 创建目录会失败,导致程序提前终止,所以有了作者后续的一系列绕过操作。而我在测试的时候使用的是 %80 ,这个字符在 windows 下作为文件夹名的一部分是可以的,所以我们直接就完成了整个漏洞的分析。
下面,我们也来看看漏洞作者使用 %81 字符时会遇到的问题。首先,程序会根据路径逐级判断目录是否存在。如果不存在,则创建目录。而我们想用 %81 字符使 iconv 发生截断,但是 windows 下不允许这个字符存在文件名中,所以作者又利用了 windows 的特性,构造出 payload: a.php%80\..\1.jpg 。

如果 payload: a.php%80\..\1.jpg 能顺利拼接成文件名,那也就完成了整个漏洞复现。然而在 Metinfo 中,在未定义 define('IN_ADMIN', true); ,变量 $_M['form']['is_rename'] 中的数据就会经过 sqlinsert 函数处理,而这个函数恰恰把 \ 符号给替换成 / 了,那么就变成了 payload: a.php%80/../1.jpg ,这样就会触发上边的 ./ 匹配规则,所以我们得想办法绕过。

如果之前审计过 Metinfo 的 SQL 注入漏洞,就知道可以通过 admin/index.php 来绕过 sqlinsert 函数。我们可以利用该文件中的 define('IN_ADMIN', true) ,然后通过构造 Web 路由完成漏洞触发。

EXP构造
关于 EXP 这里不会具体给出,只给思路。我们可以登录后台,寻找上传文件的地方。抓包,然后再根据上文提到的一些必要参数,构造相应数据包即可。 EXP 运行结果如下:

转载
分享
已经复现成功,是我的php版本问题,谢谢
不对,是这个,执行后会报错c=uploadify&m=include&a=doupimg&lang=cn&data_key=undefined&lang=cn&savepath=a.php%80..\1.jpg',希望大佬指点指点,谢谢
上传临时文件夹(upload_tmp_dir)没有写权限,请联系空间商修改。。。大佬可以看一下吗?c=uploadify.class&m=include&a=doupfile&lang=cn&savepath=a.php%80/..\1.jpg
@mochazz 嗯呐,回完之后发现误解了,没找到删除评论的地方,不好意思了
@luckyeast 你可能误解我意思了,这个洞本来就不用后台登录。我上面说的后台登录,只是对于不熟悉这个CMS路由的人,想构造payload,可以通过后台的上传功能,抓包观察其路由参数格式。
这个我也复现了一下,不需要登陆后台就能触发,访问那个admin/index.php,然后构造参数就可以了