问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
某协同系统漏洞挖掘过程记录
记录一次某协同系统SQL注入漏洞挖掘过程
记录一次某协同系统SQL注入漏洞挖掘过程 0x01 寻找注入点 ---------- 分析项目结构和依赖,发现没有如mybatis等第三方数据持久化框架,存在Dao目录 > 在Java Web开发中,DAO(Data Access Object)是一个设计模式,用于将数据访问逻辑从业务逻辑中分离出来,提高代码的可维护性和可重用性。DAO层是一个抽象接口,封装了数据的CRUD操作(增加、删除、修改、查询),并且提供了面向对象的方式访问数据库。 所以一般来讲其与数据库交互的代码都是在该目录中实现的。 我们首先找到dao接口(主要是定义了对数据库进行CRUD操作的方法) 其中`SysDao`接口定义了查询数据库等操作的方法 ![image-20230712165455340](https://shs3.b.qianxin.com/butian_public/f368371ffa10c786fc120e7a99e6b67f1c8e0eb2a19eb.jpg) 他有5个实现,其中`BasicDaoImpl`,`ModeDaoImpl`和`SysTableDao`为Dao实现类 ![image-20230712165641669](https://shs3.b.qianxin.com/butian_public/f885297cd3959259fe0d86065953807e7f12f0cfd5285.jpg) 我们看到在`SysDao`定义方法中`getStringData`这个方法看命名就像是通过传入string来获取数据,于是我们根据到`getStringData(String var1)`的实现 ![image-20230712170132646](https://shs3.b.qianxin.com/butian_public/f318125ee66e72c9e145b69e66ddd272b6051276be82e.jpg) 其在`SysTableDao`类中,调用重载方法`String getStringData(String sql, Object[] params)` ![image-20230712170258952](https://shs3.b.qianxin.com/butian_public/f4036932bca2c14b1da70b835556a20b3f69c018f22d9.jpg) 最终调用`getStringData(final String sql, final Object[] params, boolean debug)`,该方法也是`getStringData`的具体实现 ![image-20230712170732949](https://shs3.b.qianxin.com/butian_public/f878794672b19e953840aa591e4b12fdd05c644fe81d6.jpg) 其主要逻辑是 - 从回调方法允许获取`Connection`实例; - 通过`Connection`实例创建`PreparedStatement`实例; - 通过`executeQuery`执行SQL语句,如果是查询,则通过`ResultSet`读取结果集 - 最后处理结果集类型,返回 当调用`getStringData(String sql)`是传入的参数`params`为null,不会进入if逻辑中处理,其实就相当于直接执行了`sql`参数。 于是我们寻找哪里调用了`getStringData(String)`方法。 ![image-20230712171952396](https://shs3.b.qianxin.com/butian_public/f32640689b89aa35178cc2fb5697aa5ec6b6e884e9c0d.jpg) 发现有6个jsp中调用了`getStringData(String)`方法 一个个跟进发现除了index.jsp外其他jsp均可控 ![image-20230712174111768](https://shs3.b.qianxin.com/butian_public/f590076728320218a85f7fb90751dc87d6d8eb1a2b52a.jpg) 例如`share_select.jsp`中获取请求中`type`和`fid`参数,当`type`的值为`2`时会直接拼接`fid`到sql语句中,调用`getStringData`方法。这里很明显存在SQL注入。 但是尝试直接访问该JSP会跳转至登录页,该系统存在jsp的鉴权操作。我们顺势找找有关的filter,看有没有可以绕过的方法。 0x02 绕过鉴权 --------- 我们找到`web.xml`,寻找有没有相关filter ![image-20230712175219511](https://shs3.b.qianxin.com/butian_public/f272552d397a1ccc2b08305c6a8db661afde28c4c09a7.jpg) 果然有一个拦截`.jsp`的filter,跟进到其中找到`doFilter`方法实现 ![image-20230718174024535](https://shs3.b.qianxin.com/butian_public/f2479817bf5f5a98fd318f6d7e935e4de45b655604276.jpg) 首先调用`ServletRequest.getRequestURI()`获取请求接口地址,随后判断请求接口地址是否包括或者以某特定字符串结尾做响应处理。从中看到当我们请求jsp时会调用`validata()`方法 ![image-20230712181119389](https://shs3.b.qianxin.com/butian_public/f87124910c497541a3c0770388c0b9ec1e8b9656c03ad.jpg) 其主要是获取请求参数,检测sql注入黑名单字符: ```java private static boolean sqlValidate(String str) { str = str.toLowerCase(); String[] badStrs = new String[]{"exec%20", "execute%20", "drop%20", "truncate%20", "net%20user%20", "xp_cmdshell%20", "select%20", "insert%20", "update%20"}; String[] arr$ = badStrs; int len$ = badStrs.length; for(int i$ = 0; i$ < len$; ++i$) { String badStr = arr$[i$]; if (str.contains(badStr)) { return true; } } return false; } ``` 当存在以上黑名单字符串时返回true,最后进入if逻辑跳转至登录页。 扎眼一看好像该filter只会对参数存在sql注入黑名单字符串的请求进行跳转,直接访问应该是直接放行,但是我们实际访问还是跳到了登录页,有点迷惑。 根据关键字找到该filter中有一个方法`verificationURL()`: ![image-20230718172103904](https://shs3.b.qianxin.com/butian_public/f6739646616fb1e20e6eea1c9455a04b9066da09f2e13.jpg) 当是未授权请求时(即UserSession为null)会进行设置返回包跳转,在doFilter方法中有三处调用 ![image-20230718172503692](https://shs3.b.qianxin.com/butian_public/f194235946e57aebdf527fc2533f34fb02e6a2b236b6b.jpg) 当我们访问`xx.jsp`时会进入到这个if判断中 ```java if ((!uri.endsWith(".jsp") || !this.isNotValidatePage(uri)) && !uri.endsWith(".xml") && !uri.endsWith(".xf") || this.verificationURL(request, uri, response)) ``` 其逻辑是请求`xxx.jsp`,`!uri.endsWith(".jsp")`默认为false,会依次调用`isNotValidatePage()`(`isNotValidatePage`主要是判断请求的jsp是不是登录等可以未授权方法的白名单jsp文件,默认也是返回false)和`verificationURL()`。 此时因为我们是未授权访问所以该if语句最终结果为`if(false || false || false)`不会进入到下面逻辑中,所以被进行了拦截返回到了登录页。 不过此处因为调用`request.getRequestURI()`方法,可以利用`;`进行绕过(即构造xxx.jsp;.jpg),同时在`doFilter`逻辑中当访问路径以图片后缀结尾时直接放行 ![image-20230712181918594](https://shs3.b.qianxin.com/butian_public/f250209f2f2e85dfa3aa2c36c4271d111f5816b9176c7.jpg) 于是我们可以构造访问地址为`/xxxx/share_select.jsp;jpg`可成功测试SQL注入 ![image-20230713150944399](https://shs3.b.qianxin.com/butian_public/f350193132c169f362e8a2217a1f81daaa32a3d1fbaad.jpg) 0x03 寻找绕过sqlValidate的利用 ----------------------- 我们回到`SysDao`接口,其还有一个继承接口`Dao` ![image-20230713152752062](https://shs3.b.qianxin.com/butian_public/f550440cfa957238f9b7ba0f1b59ce324252ee28dc008.jpg) 看到其定义了`getFieldSetBySql()`的方法,这个方法也像是通过sql语法获取数据。 我们跟进来点其实现类`BasicDaoImpl`中查看其具体实现 ![image-20230713153015612](https://shs3.b.qianxin.com/butian_public/f71191139e9ef88f966ad960109bf95a4beed3c9dcadd.jpg) 他有两个`getFieldSetBySql`的重载方法,主要是实现是在`getFieldSetBySql(String sql, Object[] params, String tableName)`方法中 其首先是调用SQLTranslatorManager.translator()解析处理sql语句 ![image-20230713154235131](https://shs3.b.qianxin.com/butian_public/f646778e9d9e9924ff19d20576ed6e4e9f92357883b1a.jpg) 这里`translator`默认是`false`,所以直接返回原始sql语句 ![image-20230713154325245](https://shs3.b.qianxin.com/butian_public/f4891761da628e6a6c6cfa78b5fcfb67400e030de43b7.jpg) 回到`getFieldSetBySql`方法,处理完sql语句,调用`this.getDataTable`方法执行sql语句获取结果 ![image-20230713154607690](https://shs3.b.qianxin.com/butian_public/f23066254020369957437f856de62549ae3a4efe20669.jpg) 因为传入`tableName`为null,所以不在if逻辑中,当我们调用`getFieldSetBySql(String sql, String tableName)`方法时,传入`params`参数为null,也会跳过`ToolFormatSql.format(sql, params);`,最后调用`execute`方法执行sql语句。 分析完`getFieldSetBySql`方法处理逻辑,我们寻找调用该方法且参数可控地方,利用IDEA找到了多处调用 ![image-20230713155855413](https://shs3.b.qianxin.com/butian_public/f733538d96530f2356bee8ec9605aa42c2b04744731ec.jpg) 但是基本都是拼接`user.getUserID`作为SQL语句,没有找到可控点,一时陷入不知所措 不过根据javaweb项目 有`Dao`层就会有`Service`层 > Service层叫服务层,被称为服务,粗略的理解就是对一个或多个Dao进行再次封装,封装成一个服务,所以这一层不会是一个原子操作了,需要事务控制。 我们在其`Service`层寻找有没有调用`getFieldSetBySql`的方法,经过筛查最终找到一处在`FormService`类中调用`getFieldSetBySql`的方法,其拼接参数到sql语句且处理逻辑比较简单 ![image-20230713163528841](https://shs3.b.qianxin.com/butian_public/f54874443eb3e988eacd5fe5c5bbc9c535c3331ac2931.jpg) 右键方法名找到调用该方法的地方,最后定位在`validate.jsp`中 ![image-20230713164047268](https://shs3.b.qianxin.com/butian_public/f6425386a13081aeef08fe0421bc6aa030f5fc2004b1f.jpg) 可以看到这里解析请求中的json数据,根据type选择处理方式,当type等于0是进入`formService.getFormTableInfo`方法,所以`relId`这个参数存在SQL注入风险,同时根据json特性可通过unicode编码绕过前面filter中对sql注入的检测,具体利用就不赘述了
发表于 2023-07-24 09:00:00
阅读 ( 5046 )
分类:
漏洞分析
0 推荐
收藏
1 条评论
小何同学
2023-07-24 09:31
也太强了
请先
登录
后评论
请先
登录
后评论
中铁13层打工人
72 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!