返回首页
EN
H7 / SECURITY RESEARCH NOTES

Espcms注入挖掘案例

本页导航5 个章节

前言

准备将《代码审计-企业级Web代码安全架构》这本书提及的所有漏洞案例完整详细复现,并提供源代码包,方便后续新人从这本书入手的时候自己复现案例才能学的更深刻。


漏洞标题

Espcms注入挖掘案例 书P47

准备工作

  • Seay源代码审计系统
  • Phpstorm(其他IDE也行,因为平常用Phpstorm写代码,所以用习惯了)
  • Espcms源代码包

开始

  • 安装espcms,这里遇到个坑,安装好登录后台时报了无法连接数据库的错误,解决办法如图:

image.png

  • 根据书上说用Seay源代码审计系统自动审计该cms,可发现书上所说的sql注入的位置,如图:

image.png

  • 用Phpstorm打开该cms的源代码,找到oncitylist()方法所在的位置,这里提供一个小技巧,ctrl+shift+f即可打开Phpstorm的全局搜索,直接搜oncitylist()即可找到所在位置

  • 接下来分析oncitylist()这个方法,代码如图:

image.png

可以看到这个方法前4行涉及两个变量,一个是$parentid,一个是$verid,它们都经过accept()这个方法接收然后再进行赋值。第5行定义了所要查询的数据库表名称,ctrl+b快捷键在Phpstorm中可以查看某个元素的源代码,这里可以查出db_prefix常量为'espcms',拼接之后可以得知要查询的数据库表为espcms_city。第6行可以看到定义sql语句时传入了$parentid这个变量,也就是前面通过accept()方法接收的变量。然后第7行执行sql语句并返回结果集赋值给$rs变量,第8行往后简单说就是将从数据库中取出的结果打印出来。

  • 这时注意到parentid是外部传入的参数,拼接到了sql语句中,那么是否做好过滤就是防止sql注入的关键。这里用了accept方法接收parentid参数,那现在看accept方法的源码

image.png

分析accept这个方法,发现当传入的第二个参数为R时,意味着$_GET数组或者$_POST数组其中之一会引用 赋值给变量$var,目的是从$_GET数组或者$_POST数组中获取accept方法传入的第一个参数的值,如果 获取到了该值,则将该值传入daddslashes函数,返回的值赋给变量$putvalue,否则NULL赋给$putvalue 那下面看函数$daddslashes源码

image.png

分析该函数,可以得知,这里的get_magic_quotes_gpc()函数判断magic_quotes_gpc选项是否开启, 如果开启则返回true,否则返回false。magic_quotes_gpc开启的话$_GET,$_POST,$_COOKIE里的 单引号,双引号,反斜杠和null会被反斜杠转义。这里传入的参数和这里的函数结合起来的业务逻辑就是, 如果你没有开启magic_quotes_gpc选项,那么我采用addslashes()函数来帮你转义掉单引号,双引号 反斜杠和null。 该函数分析完了,我们继续回到accept函数,因为accept方法默认参数$htmlcode为true,$rehtml为 false,所以将上一行转义后的$putvalue传入方法htmldecode,然后我们看一下htmldecode的源码:

image.png

分析该函数,trim()函数去除字符串首尾的空白字符,htmlspecialchars()函数将特殊字符转换为HTML 实体字符,比如大于小于号,双引号。 preg_replace()函数在这里对script这样的函数进行了替换,所以这个htmldecode函数相当于是一个 xss过滤器。 接下来我们回到accept()方法,所以总结一下这个accept()方法,在这里的作用就是将接收到的参数进行 了一个sql注入和xss的过滤。然后我们返回到oncitylist()函数,这里快捷键ctrl + e可以切换最近涉及 到的文件,咱们返回到citylist.php文件,咱们仔细看执行的sql语句

image.png

咱们发现传入sql语句的变量$parentid并没有单双引号包裹,那么这就意味着可能存在着数字型sql注入, 那前面的过滤单双引号什么的就没什么用了。接着我们来分析怎么才能构造相应的exp(全称exploit),中 文是利用的意思,这里是简称就叫exp,哈哈。 首先我们知道出问题的方法是一个叫oncitylist()的方法,它是类important的方法,然后我们看该文件citylist.php的父目录名为control,然后再看该control 目录下的其他文件,都是定义了一个important类,所以懂点开发就知道这是MVC设计模式中的控制器, 那么就好搞了,咱们先找到程序入口文件index.php,该文件和control目录同级,都属于adminsoft 目录。index.php源码如下,这里分段截:

image.png

可以看到该文件开始定义了许多常量,咱们可以看到常量adminfile被定义为了adminsoft,再看一下 admin_ROOT常量的定义,这里涉及到__FILE__,在PHP中它叫魔术常量,是指的是当前文件的绝对路径和 文件名。strrpos()函数计算指定字符串在目标字符串中最后一次出现的位置,返回值是int型数字。这里的 意思是返回adminfile常量(即adminsoft)在该文件index.php的绝对路径的位置,然后看substr()函数 ,它是返回一个字符串的子串,相当于截取一个字符串从指定位置一定长度的字符串,所以该行代码结合起来 就是返回绝对路径到adminsoft这样一个目录路径,相当于绝对路径/upload/adminsoft。 然后再看第31行和第34行代码,涉及到indexget()函数,这个函数在57行,如下:

image.png

可以看出跟accept()函数基本一模一样,包括indexdaddslashes()函数也跟accept()函数的 daddslashes()函数一样。这里就不多说了。 接下来继续往下看,源码如下:

image.png

咱们先分析代码,第37行到44行代码意思就是如果变量$archive和数组中任何一个匹配,即包含对应 变量$archive的文件,这个文件在adminsoft目录下control目录下,MVC中的C控制器。所以 这里可以知道$archive就是传递的控制器。如果没有该文件则报access error然后退出程序。 然后实例化important类,即刚才我们看到的citylist.php文件中的important类。 第47行到第49行代码就是调用相应的$action方法,所以我们知道$archive和$action都是可以 用户自己传入的。然后我们就可以构造相应的exp了,如下: localhost/espcms/upload/adminsoft/index.php?archive=citylist&action=citylist&parentid=-1 union select 1,2,databases(),4,5 截图如下:

image.png