### 0x00 MetInfo是一个比较的企业建站软件,用户众多。在去年的时候,曾爆出过几个漏洞,有XXE,SQL注入,任意文件读取等,详情见以下链接。印象比较深刻的是两个SQL注入漏洞,一个位于message.calss.php,一个位于feedback.class.php。漏洞都位于前台。只不过第二个洞比较苛刻,每注入一次需要输入一次验证码,利用起来貌似很鸡肋。最近看了一次metinfo,找到一个利用SQL注入写入shell的简便方法,不需要脱裤。 * https://nosec.org/home/detail/1889.html * https://nosec.org/home/detail/1740.html ### 0x01 首先看app/system/include/class/web.class.php文件,在web类的析构函数中,先读取了缓冲区的数据(在加载基础配置文件的时候进行的ob_start(),打开的缓冲区),经过一系列替换操作(几乎无影响)之后赋值给了$output变量,这里缓冲区数据可以理解为打开缓冲区以后调用echo方法输出的数据。  接着调用replace_attr方法进行了标签处理,这里也没太大影响。  最后进入重点,如果提交的参数metinfonow和$_M['config']['met_member_force']的值相同,则调用file_put_contents函数把上述过程中缓冲区读取的内容写入到$_M['form']['html_filename']文件。这里$_M['form']数组中的内容是$_GET,$_POST,$_COOKIE参数的集合。具体代码就不贴了。也就是说,这里文件名可控,不管改成php,phtm,php5都可以。 ...
### 0x00 MetInfo是一个比较的企业建站软件,用户众多。在去年的时候,曾爆出过几个漏洞,有XXE,SQL注入,任意文件读取等,详情见以下链接。印象比较深刻的是两个SQL注入漏洞,一个位于message.calss.php,一个位于feedback.class.php。漏洞都位于前台。只不过第二个洞比较苛刻,每注入一次需要输入一次验证码,利用起来貌似很鸡肋。最近看了一次metinfo,找到一个利用SQL注入写入shell的简便方法,不需要脱裤。 * https://nosec.org/home/detail/1889.html * https://nosec.org/home/detail/1740.html ### 0x01 首先看app/system/include/class/web.class.php文件,在web类的析构函数中,先读取了缓冲区的数据(在加载基础配置文件的时候进行的ob_start(),打开的缓冲区),经过一系列替换操作(几乎无影响)之后赋值给了$output变量,这里缓冲区数据可以理解为打开缓冲区以后调用echo方法输出的数据。  接着调用replace_attr方法进行了标签处理,这里也没太大影响。  最后进入重点,如果提交的参数metinfonow和$_M['config']['met_member_force']的值相同,则调用file_put_contents函数把上述过程中缓冲区读取的内容写入到$_M['form']['html_filename']文件。这里$_M['form']数组中的内容是$_GET,$_POST,$_COOKIE参数的集合。具体代码就不贴了。也就是说,这里文件名可控,不管改成php,phtm,php5都可以。  但是前提是必须知道$_M['config']['met_member_force'],通过分析,这个变量位于met_config表中id=45的位置。在install/index.php中,met_member_force是取得a-z的7位随机数。这里看了下,没有存在伪随机数漏洞,很可惜。  所以这里可以利用SQL注入,直接注入met_config表中id=45对应的值,来获取met_member_force。如果只注入一条数据,效率就会快很多。 ### 0x02 既然文件名可控,接下来看看文件内容是否可控,分析下web类的子类。在这里我找到一个doupfile方法,位于app/system/include/module/uploadify.class.php文件中。  看最后一行代码,echo jsonencode($back),这里$back变量通过json格式化进入了缓冲区,往上走,看下$back是否可控。在这一行:$back = $this->upload($_M['form']['formname']);这里调用upload方法,将上传文件的参数名传了进去,跟进upload方法。  在upload方法中,把上传文件的属性都赋值给了$filear数组。接着往下看。  可以看到,检测文件后缀的时候,调用了getext方法,这里以“.”对文件名进行分割,取了数组的最后一位。如果上传文件名里没有“.”,那么分割后数组中只有一个元素。也就是说,上传不含“.”的文件名,getext取得的扩展名就是上传的文件名。  接着看文件后缀名检测,如果文件名的后缀不在白名单中(这里白名单固定),会把文件扩展名拼接{$_M['word']['upfileTip3']}传入error方法中。  跟进error方法,把传入的参数赋值给了$back['errorcode'],说明echo jsonencode($back)的内容是可控的。  到这里基本就结束了,文件名和文件内容都可控,接下来构造payload。 ### 0x03 构造payload如下:  查看根目录  查看1.php文件内容,并访问  成功写入代码 