返回首页
EN
H7 / SECURITY RESEARCH NOTES

Espcms搜索注入分析

本页导航5 个章节

前言

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


漏洞标题

Espcms搜索注入分析 书P73

准备工作

  • 源代码包下载及安装什么的就不说了,以及安装时遇到的坑也不说了,因为都在上一篇复现该cms的文章 提到了,这里不提第二遍

  • 由于该漏洞出现在更老版本的espcms,当前自己 手上的espcms漏洞已修复,所以首先改一下该cms的漏洞相关文件,才能复现老版本的漏洞,改动如下:

  • 第一:将interface/search.php中的in_taglist()方法的原本代码(图中我注释的代码)改掉, 图中已标明

image.png

  • 第二:将public/class_function.php中的inputcodetrim()函数替换为如下代码:
function inputcodetrim($str) {
		if (empty($str)) return $str;
		$str = str_replace("&", "&", $str);
		$str = str_replace(">", ">", $str);
		$str = str_replace("&lt;", "<", $str);
		$str = str_replace("&lt;", "<", $str);
		$str = str_ireplace("select", "", $str);
		$str = str_ireplace("join", "", $str);
		$str = str_ireplace("union", "", $str);
		$str = str_ireplace("where", "", $str);
		$str = str_ireplace("insert", "", $str);
		$str = str_ireplace("delete", "", $str);
		$str = str_ireplace("update", "", $str);
		$str = str_ireplace("like", "", $str);
		$str = str_ireplace("drop", "", $str);
		$str = str_ireplace("create", "", $str);
		$str = str_ireplace("modify", "", $str);
		$str = str_ireplace("rename", "", $str);
		$str = str_ireplace("count", "", $str);
		$str = str_ireplace("from", "", $str);
		$str = str_ireplace("group by", "", $str);
		$str = str_ireplace("concat", "", $str);
		$str = str_ireplace("alter", "", $str);
		$str = str_ireplace("cas", "cast", $str);
		$str = preg_replace("/<span[^>]+>/i", "<span>", $str);
		$str = preg_replace("/<p[^>]+>/i", "<p>", $str);
		$str = preg_replace("/<font[^>]+>/i", "<font>", $str);
		$str = preg_replace("/width=(\'|\")?[\d%]+(\'|\")?/i", "", $str);
		$str = preg_replace("/height=(\'|\")?[\d%]+(\'|\")?/i", "", $str);
		$str = preg_replace("'<style[^\f]*?(\/style>)'si", "", $str);
		return $str;
	}

开始

  • 该漏洞位置出现在interface/search.php文件中的in_taglist()方法中,老办法,先分析方法源码 搞清楚怎么才能调用该方法,哪个参数存在问题,如图:

image.png

  • 首先能看到方法开始就调用了一个父类的方法start_pagetemplate(),然后包含了class_pagebotton.php 文件,根据名字并且看源码可以知道估计是关于视图模板渲染和分页什么的,所以不必太关心这两行代码。 继续往下看

image.png

  • 如图可以看到213行-217行代码用accept()方法(accept()方法不再提,前面漏洞文章已经说过了)接收 了3个参数$page,$lng,$tagkey,$page和$lng不用管,重点看$tagkey变量,第217行代码采用了函数 urldecode()进行url解码,问题就在这,意味着我们可以用url两次编码来绕过前面accept()方法对单双 引号的过滤。第218行代码用inputcodetrim()方法处理了该变量,我们看一下该函数源码:

image.png

  • 可以看到,该函数主要用替换的方式来防止sql注入,可以看到如图可以采用双写绕过,比如用ununionion ,经过inputcodetrim()函数之后就变成了union。接下来返回search.php文件继续阅读。

image.png

  • 可以看到第219-226行代码,主要就是对$db_where变量的一个拼接,可以发现,当$tagkey变量为空 时,会执行一个callmessage方法,查看该源码发现就是一个页面回跳,即$tagkey变量没有被传入时,会 返回原本的页面,所以这里不用管。然后可以看到,$tagkey变量被拼接到了$db_where变量中,然后 往后看第231行代码是关于视图模板的,不用管。第235行代码可以发现,后续将会查espcms_document这个 表。第236行代码执行了一个db_numrows()方法,查看该方法源码:

image.png

  • 该方法执行了sql语句,那我们尝试调用一下该方法试一下,该方法是interface下的php文件中的,前面 漏洞复现文章已经提到过了怎么调用,所以这里直接调用一下,我们将该处执行的sql语句打印一下。

image.png

  • 这里我们加上代码print_r(),然后访问该链接,http://localhost/espcms/upload/index.php? page=1&ac=search&at=taglist&tagkey=1,tagkey传入1,可以看到$dbwhere为

image.png

  • 所以db_numrows()方法执行的完整sql语句就是 select count(*) as num from espcms_document where lng='cn' and isclass=1 and isclass=1 and find_in_set('1',tags) 该函数就是查询符合where条件的数据的数目并返回,这里可以知道,tagkey是用户输入的。我们不用管 find_in_set()函数什么意思。咱们返回search.php继续阅读:

image.png

  • 可以看到第238行到242行代码,$countnum返回数目后,方便进行页数的计算。然后243行又有一条sql语句, 又将$dbwhere变量拼接了进去。然后245-246行代码调用了一个PageSQL方法,查看该方法,主要也是对 sql语句的完善,第247行代码执行了sql语句,所以截至246行,我们将完整sql语句打印出来看一看,如图:

image.png

  • 访问该urlhttp://localhost/espcms/upload/index.php? page=1&ac=search&at=taglist&tagkey=1

image.png

  • 然后再往下就是将数据渲染到模板返回给用户了。所以,我们的利用点就很清楚了,利用tagkey这个用户 可控的参数进行双url编码绕过accept()方法的单双引号过滤,再利用双写的方式绕过inputcodetrim()这个 函数即可,因为报错不回显,所以采用盲注,联合查询不能用,因为前后执行了两个sql语句,字段数不一样, 构造如下exp: localhost/espcms/upload/index.php?page=1&ac=search&at=taglist&tagkey=1%2527,tags) or 1=1 and (seselectlect length(username) ffromrom espcms_admin_member limit 0,1)=5 -- hhaha 可以猜出用户表第一个用户名长度,接着可以继续做,这里就不讲了