一次SQL注入导致的"越权"
原文来自SecIN社区—作者:tkswifty
相关背景
在实际的业务开发中,SQL交互往往是业务系统中不可或缺的一项。在Java中提供了类似Mybatis、Hibernate、SpringData JPA等来满足相关的数据库交互需要。但是由于种种原因,开发人员在处理应用程序和数据库交互时,使用字符串拼接的方式构造SQL语句,导致了SQL注入问题。那么有时候面对大量的接口存在SQL注入,迭代困难的时候,过滤器/拦截器便是很多开发人员的首选,通过过滤相关的SQL关键字,避免SQL注入得到进一步利用。
针对上述场景,很多时候需要加检查过滤器设计是否严谨,检查是否有漏网之鱼,导致SQL注入漏洞被攻击者进行利用。前段时间审计某项目时发现一处SQL注入导致的"越权",以下是相关的过程。
挖掘过程
系统基于SpringMVC进行开发,业务主要是与简历编辑相关。相关的问题接口主要在修改个人简历处。一般来说,这种修改个人信息的业务,除了修改内容以外,主要传递两个关键信息:
- 当前用户的身份凭证userId
- 当前用户的业务编号(这里是简历),resumeId
在进行接口业务请求时,将业务相关的关键参数userid聪当前用户的身份凭证(一般是session)获取,绑定个人用户身份,然后从前端获取需要修改的resumeId,最后在保存信息进行SQL交互时,从会话在获取的userId再与resumeId进行二次绑定,保证userId对应的用户仅能修改自己的简历。类似的SQL语句如下:
UPDATE user_resume SET content='test',user_name='test'{省略相关内容} where userId = $userId and resumeId=$resumeId;
如下是相关的代码:
首先是Controller,在Controller层对用户的输入进行相关的封装(这里是简历的相关信息),通过自动绑定的处理方式,直接将用户的输入绑定到resume对象里,然后通过当前登录会话获取当前用户的userId,通过调用service的update方法进行简历内容的更新:
@ResponseBody
@RequestMapping(value = "/updateResume", method = RequestMethod.POST)
public PagedResult<ResponseRes> updateResume(Resume resume) {
String userId = (String)session.getAttribute("userid");
PagedResult<ResponseRes> pageResult = this.resumeService
.update(resume,userid);
return pageResult;
}
查看service层实现,调用的是resumeService的update方法:
public PagedResult<ResponseRes> updateResume(Resume resume,String userid) {
String rusumeId = resume.getId();
if(resumeId!=null){
boolean updateStatus = resumeDao.update(resume, userid,resumeId);
if(updateStatus){
//更新成功,封装返回结果
......
}else{
//更新失败
......
}
}else{
}
return updateResule;
}
讲封装好的简历内容以及userId跟ResumeId传入resumeDao的update方法进行处理,这里使用的是mybatis框架进行处理,查看mapper的具体实现:
UPDATE user_resume SET
......
<if test='resume.address!=null'>
,address=${resume.address},
</if>
......
where userId=${userId} and resumeId=${resumeId};
</select>
所以整个简历更新的流程如上描述,因为在进行SQL交互时,通过update对简历表进行维护,通过userId和resumeId限定要更新的行。因为userId跟用户会话进行绑定,所以用户仅能更新自己对应的简历,防止了越权问题。
但是这里由于在Mybatis中使用了$进行注解,存在SQL注入风险。那么进一步检查是否存在相关的防护措施。这里发现相关的过滤器措施,应该是系统注入太多了,所以开发统一通过过滤器对用户输入进行处理,检查过滤器的具体实现。
同样的过滤器还是检查如下几点:
- 过滤器的顺序
- 获取数据的方式是否覆盖全面
- 过滤的规则内容
这里由两个过滤器组成,分别负责xss以及SQL注入的输入检测。因为都是直接检测到恶意输入就直接返回通用报错页面,所以这里不存在顺序问题导致的filter绕过。
其次是获取数据的方式,这里通过MultipartHttpServletRequest multiReq = multipartResolver.resolveMultipart(request);对当前文件上传进行转换,转换成普通的request对象后再进行相关的输入检查,防止multipart提交导致的bypass:
private CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException {
public static String[] MULTI_FILE_WHITE_LIST = new String[]{"/manager/uplode"};
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String pathInfo = request.getPathInfo() == null ? "" : request.getPathInfo();
String url = request.getServletPath() + pathInfo;
String contentType = request.getContentType();// 获取请求的content-type
//如果是文件上传接口不需要进行转换,需要在接口处直接进行输入检查
...
// 文件上传请求 *特殊请求
if (multipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multiReq = multipartResolver.resolveMultipart(request);
request = multiReq;
}
//SQL注入检查
......
此外针对更新简历接口,其提交的数据类型为正常的key-value形式,所以这里filter获取数据的方式是覆盖全面的。
最后是相关的过滤规则,这里要结合数据库类型进行判断。系统使用的是mysql的数据库,过滤规则如下:
String badSqlStr ="'|and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|table|from|grant|use|group_concat|column_name|information_schema.columns|table_schema|union|where|select|delete|update|sleep|order|by|count|*|chr|mid|master|truncate|char|declare|;|--|+|,|like|//|/|%|#";
过滤了大部分的SQL关键字,包括select这种SQL注入拖取内容必须的关键字,还有xp_cmdshell这类敏感的SQL函数。针对更新简历接口,其中的SQL注入乍一看应该是无法进行获取数据库敏感信息等恶意操作了。
通过上述分析,更新简历接口的越权跟SQL注入问题貌似暂时得到了缓解。实际上这里可以通过SQL注入,来“越权”修改他人的简历。
可以查到相关update语句的条件为where userId=${userId} and resumeId=${resumeId},其中userId从当前会话获取,用户不可控,resumeId为前端传递,用户可控。那么也就是说,当前端传递的resumeId为1 or userId=2时,即可在更新当前用户简历同时,更新userId=2的用户的简历内容,达到越权的效果。
提交的参数内容如下(因为过滤器中并未过滤or关键字,所以该逻辑可以绕过过滤器安全检查):
address=xxxxx&{相关简历内容}&resumeId=10001 or userId=2
最终执行的SQL语句大致如下:
UPDATE user_resume SET content='test',user_name='test'{省略相关内容} where userId = $userId and resumeId=$resumeId or userId=2;
这里结合数据库表进一步说明具体效果,为了方便说明,将数据库内容简化成如下结构,userId代表用户身份,resumeId代表对应的简历,最后content代表简历的内容:

正常情况下,假设登录了userId为1的账户,尝试更新其resumeId为10000的简历,对应执行的SQL语句为(这里把内容test修改为test111):
UPDATE user_resume SET content='test111' where userId = 1 and resumeId=10000;
执行后对应的user_resume表内容变化如下:

根据前面的分析,因为resumeId存在SQL注入且用户可控,此时尝试提交resumeId=1 or userId=2,尝试越权将userId=2的用户简历内容修改为Access-Control-Bypass,对应执行的SQL语句如下:
UPDATE user_resume SET content='Access-Control-Bypass' where userId = 1 AND resumeId=1 OR userId = 2;
成功利用SQL注入"越权"修改他人用户的简历信息:

针对SQL注入的修复,通过过滤器/拦截器对用户的输入进行检查并不是最佳的选择。在满足特定的场景情况下,可能会导致例如上述的“越权”问题。
与此同时,很多开发人员存在误区,认为使用JPA、HQL进行SQL交互后便不会存在SQL问题了,SQL注入的本质是在处理应用程序和数据库交互时,使用字符串拼接的方式构造SQL语句,同时相关的敏感参数可控,只要满足即存在SQL注入风险,只是使用了HQL后,由于其特点无法直接执行原生SQL,及写文件,执行命令等操作,也不支持跨库查表等敏感操作。但是依旧可以结合实际的场景,尝试达到上述的“越权”危害。
一次SQL注入导致的"越权"的更多相关文章
- 然之协同系统6.4.1 SQL注入导致getshell
前言 先知上一个大佬挖的洞,也有了简单的分析 https://xianzhi.aliyun.com/forum/topic/2135 我自己复现分析过程,漏洞的原理比较简单,但是漏洞的利用方式对我而 ...
- sql参数化防止sql注入导致的暴露数据库问题
#转载请联系 假如你在京东工作,你要做的任务就是做一个商品搜索的东西供用户使用. 然后你写出了这么一个程序的雏形. import pymysql def main(): conn = pymysql. ...
- 网络安全学习阶段性总结:SQL注入|SSRF攻击|OS命令注入|身份验证漏洞|事物逻辑漏洞|目录遍历漏洞
目录 SQL注入 什么是SQL注入? 掌握SQL注入之前需要了解的知识点 SQL注入情况流程分析 有完整的回显报错(最简单的情况)--检索数据: 在HTTP报文中利用注释---危险操作 检索隐藏数据: ...
- Java开发工程师(Web方向) - 03.数据库开发 - 第3章.SQL注入与防范
第3章--SQL注入与防范 SQL注入与防范 经常遇到的问题:数据安全问题,尤其是sql注入导致的数据库的安全漏洞 国内著名漏洞曝光平台:WooYun.org 数据库泄露的风险:用户信息.交易信息的泄 ...
- WEB安全:SQL注入
SQL注入是站点和web应用程序中最常见的安全漏洞. 这样的恶意技术有非常多应用场景, 但(SQL注入)一般是指在数据输入的地方注入代码以利用数据库应用程序中的安全漏洞. SQL注入在接收用户输入的接 ...
- 卧槽,sql注入竟然把我们的系统搞挂了
前言 最近我在整理安全漏洞相关问题,准备在公司做一次分享.恰好,这段时间团队发现了一个sql注入漏洞:在一个公共的分页功能中,排序字段作为入参,前端页面可以自定义.在分页sql的mybatis map ...
- 自动化SQL注入工具 sqlmap 使用手册
0x00 sqlmap介绍 什么是sqlmap? sqlmap是一个开源的渗透测试工具,它自动化了检测和利用SQL注入缺陷 以及接管数据库服务器的过程.它配备了一个强大的检测引擎 ,以及终极渗透测试仪 ...
- dedecms SESSION变量覆盖导致SQL注入漏洞修补方案
dedecms的/plus/advancedsearch.php中,直接从$_SESSION[$sqlhash]获取值作为$query带入SQL查询,这个漏洞的利用前提是session.auto_st ...
- ecshop SQL注入漏洞导致代码执行
漏洞名称:ecshop SQL注入漏洞导致代码执行补丁编号:11208761补丁文件:/includes/libinsert.php补丁来源:云盾自研漏洞描述:ecshop的/includes/lib ...
随机推荐
- Luogu P4546 [THUWC2017]在美妙的数学王国中畅游
题意 题意奇奇怪怪,这里就不写了. \(\texttt{Data Range:}1\leq n\leq 10^5,1\leq m\leq 2\times 10^5\) 题解 为什么你们都是卡在数学方面 ...
- [Luogu P1268] 树的重量 (巧妙的构造题)
题面 传送门:https://www.luogu.org/problemnew/show/P1268 Solution 这是一道极其巧妙的构造题 先做一个约定[i,j]表示从i到j的距离 我们可以先从 ...
- Java程序员成长之路
北哥在前文总结了程序员的核心能力,但在专业能力维度,只是做了大概的阐述,并没有详细展开.从今天开始,我会把我作为程序员成长过程中,学习的知识总结成系列文章陆续发出来,供大家学习参考. 本文是第一篇,关 ...
- 18 socket
18 socket 推荐: http://www.360doc.com/content/11/0609/15/5482098_122692444.shtml Socket=Ip address+ TC ...
- char和signed char不同编译器下的使用反思
遇到一个问题,在使用一个算法的时候出现了仿真正常,但是在使用时出现函数的返回数据只有正值的异常. 在定位算法问题的时候,由算法函数最后的返回值由后向前推,最后发现问题在与char类型的值在不同编译器下 ...
- linux 内核 同步原理
中断分为同步中断和异步中断. 同步中断是由CPU控制单元产生的,"同步"是指只有在一条指令执行完毕后,CPU才会发出中断,比如系统调用 异步中断是由其他硬件设备依照CPU时钟信号产 ...
- python之 栈与队列
忍不住想报一句粗口"卧槽"这尼玛python的数据结构也太特么方便了吧 想到当初学c语言的数据结构的时候,真的是一笔一划都要自己写出来,这python尼玛直接一个模块就ok 真的是 ...
- 2020-11-02(三年之约D92)-优秀不是一种行为,而是一种习惯
1.阅读:<软技能-代码之外的生存指南>- 第45章 培养习惯:刷新你的代码 成就我们的恰恰就是那些不断重复做的事情.因此,优秀不是一种行为,而是一种习惯--亚里士多德 习惯主要由三个要素 ...
- BRT快速公交系统的可视化实践
前言 随着城市进程的加快,中国城市机动车的数量飞速增长,造成城市交通拥堵问题越来越严重,城市居民对于改善出行条件的需求尤其是公共交通的便捷性问题也越来越迫切.而BRT(快速公交系统)作为一种新型的客运 ...
- 鸿蒙系统freeModbusTcp移植简介
freeModebus是工业中常用的一种通信, 在鸿蒙系统来移植 细节查看代码中,博文只是一些参考以及注意点, 参考了 wifi连接: https://harmonyos.51cto.com/post ...