这个前台注入漏洞存在已久,从MetInfo发布的6.0版本就存在,且后来官方的修复代码,也可以直接绕过。笔者于7月份提交了当时最新 MetInfo 6.1.0版本SQL注入漏洞,该漏洞直到6.1.3版本才被修复。如下漏洞分析,权当思路分享。

2018-1-29, MetInfo官方重写后台及前台代码,并发布了MetInfo6.0。然而这一新版代码,却存在一个严重的前台SQL注入漏洞,我们来看一下具体详情。

首先漏洞存在于app\system\message\web\message.class.php文件中,变量{$_M[form][id]} 直接拼接在SQL语句中,且验证码检测函数是在SQL语句查询之后,这也就造成了我们可以无视验证码检测函数,进行SQL注入。具体问题函数代码如下:

那么实际上,开发者是有考虑到SQL注入问题,并写了sqlinsert 来检测SQL注入攻击的,甚至还对{$_M[form][id]}进行了is_numeric判断处理,但是为什么最终还是存在SQL注入呢?下面我们具体来看看 {$_M[form][id]} 变量的获取过程。

想要触发这个SQL注入漏洞,我们可以通过前台的在线留言和在线反馈两个功能来触发。我们这里先分析在线留言处的程序逻辑。我们填写留言处的表单,并在最下方添加上id字段,其值对应我们的攻击payload,具体如下:(为了避免图片太长,我把一些参数的值给略去)

然后我们在message\index.php文件中打下断点,会发现在app\system\include\class\common.class.php的构造方法中,加载了表单,具体的调用链即代码如下:

此时this对象指的是web类,我们继续跟进web类的load_form方法。

我们会发现common基类的load_form方法将GET、POST、COOKIE获取的所有数据存放在$_M['form']中,数据仅用daddslashes函数处理。而web类的load_form方法重写了common类的load_form方法,对$_M['form']中的所有数据进行了sqlinsert处理,并且在后面判断$_M['form']['id']是否为数字,如果不是数字就直接设置为空字符串。这些过滤函数具体代码如下:

可以看到sqlinsert函数对sleep关键字进行了处理,但是我们还是可以使用MYSQL中的benchmark函数轻松绕过(这两个函数都能利用在时间盲注中,具体可以参考:)。但是我们的payload却绕不过is_numeric函数,所以此时的$_M['form']['id']会被设置成空字符串。那为什么还存在SQL攻击呢?我们接着看程序逻辑。

在跟进程序的过程中,我们会发现在执行完load::sys_class(‘upfile’, ‘new’)代码后,$_M['form']['id']的值又变成了我们传入的payload,这说明这里面一定是又重新进行了表单赋值。

果不其然,程序中加载的upfile类又重新载入了$_M['form']的值,而且并没有进行除了基类中daddslashes方法以外的消毒处理,这也是造成SQL注入的原因。

我们可以根据上面的漏洞原理,轻松的写出攻击脚本:

接着,我们再来对比一下5月份的修复代码,此时MetInfo官方并没有更新版本号,而是偷偷修复了代码,修复代码如下右图:

可以清晰的看见daddslashes方法开始对每个参数进行sqlinsert处理。而上面我们说过,这个消毒函数是可以绕过的,所以我们依然可以进行SQL注入。

虽然可以进行盲注,但是还是太耗费时间了,我们是否有办法将其转换成布尔盲注呢?答案是可以的,接下来我们就来看看,如何将这一处时间盲注变成布尔盲注。

在app\system\message\web\message.class.php文件中,我们会发现如果SQL语句查询结果中的value字段非空,则会进行验证码的检测,否则会直接返回反馈已经被关闭。

这样子,我们就可以根据不同的返回结果,进行布尔盲注。现在我们来看一下如何找到满足查询结果中的value字段非空的columnid,直接在MYSQL中做如下查询:

这样子我们就找到了两个可用的columnid最终我们同样可以写出攻击脚本,如下:

我们再来看另一处注入点,前面我们分析的是在线留言处的SQL注入问题,这次我们要分析在线反馈处的SQL注入,漏洞的成因都是类似的。不过在利用这个漏洞时,我们需要经过feedback类check_field方法的检测。

这里实际上可用的id有两个,如下:

例如这里我想利用id=71,那么需要构造如下数据包,才会进入漏洞触发处。

现在绕过了check_field方法的检测,我们就顺利来到了触发SQL注入漏洞的feedback累的add方法,其位置在app\system\feedback\web\feedback.class.php,具体代码如下:

我们会发现这次的验证码校验,位置在注入点前面,所以利用起来比较麻烦。这里我们可以使用爆破验证码结合时间盲注的方式进行攻击,用以下程序生成全排列验证码字典:

from itertools import product rand_chrs="A2B3C4D5E6F7G8H9iJKLMNPQRSTUVWXYZ"with open("codes.txt",'w') as f:    for code in product(rand_chrs,rand_chrs,rand_chrs,rand_chrs):        code = ''.join(list(code))        print(code)        f.write(code+'\n')

但是这样的攻击成本还是太高了,如果大家会机器学习,可以加入相关算法来自动识别验证码。

最后我们来看一下MetInfo 6.1.3最新版的修复情况如何,具体

情况如下DIFF图:

文章中提到的这个漏洞点,实际上也可以从其他入口点进行触发,之前也已经有师傅放出分析文章,漏洞的成因都是一样的,具体可以参阅文末的相关文章,这里不再赘述。本文分析到此结束,如有不当还望各位斧正。