某协同系统漏洞挖掘过程记录

记录一次某协同系统SQL注入漏洞挖掘过程

记录一次某协同系统SQL注入漏洞挖掘过程

0x01 寻找注入点

分析项目结构和依赖,发现没有如mybatis等第三方数据持久化框架,存在Dao目录

在Java Web开发中,DAO(Data Access Object)是一个设计模式,用于将数据访问逻辑从业务逻辑中分离出来,提高代码的可维护性和可重用性。DAO层是一个抽象接口,封装了数据的CRUD操作(增加、删除、修改、查询),并且提供了面向对象的方式访问数据库。

所以一般来讲其与数据库交互的代码都是在该目录中实现的。

我们首先找到dao接口(主要是定义了对数据库进行CRUD操作的方法)

其中SysDao接口定义了查询数据库等操作的方法

image-20230712165455340

他有5个实现,其中BasicDaoImplModeDaoImplSysTableDao为Dao实现类

image-20230712165641669

我们看到在SysDao定义方法中getStringData这个方法看命名就像是通过传入string来获取数据,于是我们根据到getStringData(String var1)的实现

image-20230712170132646

其在SysTableDao类中,调用重载方法String getStringData(String sql, Object[] params)

image-20230712170258952

最终调用getStringData(final String sql, final Object[] params, boolean debug),该方法也是getStringData的具体实现

image-20230712170732949

其主要逻辑是

  • 从回调方法允许获取Connection实例;
  • 通过Connection实例创建PreparedStatement实例;
  • 通过executeQuery执行SQL语句,如果是查询,则通过ResultSet读取结果集
  • 最后处理结果集类型,返回

当调用getStringData(String sql)是传入的参数params为null,不会进入if逻辑中处理,其实就相当于直接执行了sql参数。

于是我们寻找哪里调用了getStringData(String)方法。

image-20230712171952396

发现有6个jsp中调用了getStringData(String)方法

一个个跟进发现除了index.jsp外其他jsp均可控

image-20230712174111768

例如share_select.jsp中获取请求中typefid参数,当type的值为2时会直接拼接fid到sql语句中,调用getStringData方法。这里很明显存在SQL注入。

但是尝试直接访问该JSP会跳转至登录页,该系统存在jsp的鉴权操作。我们顺势找找有关的filter,看有没有可以绕过的方法。

0x02 绕过鉴权

我们找到web.xml,寻找有没有相关filter

image-20230712175219511

果然有一个拦截.jsp的filter,跟进到其中找到doFilter方法实现

image-20230718174024535

首先调用ServletRequest.getRequestURI()获取请求接口地址,随后判断请求接口地址是否包括或者以某特定字符串结尾做响应处理。从中看到当我们请求jsp时会调用validata()方法

image-20230712181119389

其主要是获取请求参数,检测sql注入黑名单字符:

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

当是未授权请求时(即UserSession为null)会进行设置返回包跳转,在doFilter方法中有三处调用

image-20230718172503692

当我们访问xx.jsp时会进入到这个if判断中

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

于是我们可以构造访问地址为/xxxx/share_select.jsp;jpg可成功测试SQL注入

image-20230713150944399

0x03 寻找绕过sqlValidate的利用

我们回到SysDao接口,其还有一个继承接口Dao

image-20230713152752062

看到其定义了getFieldSetBySql()的方法,这个方法也像是通过sql语法获取数据。

我们跟进来点其实现类BasicDaoImpl中查看其具体实现

image-20230713153015612

他有两个getFieldSetBySql的重载方法,主要是实现是在getFieldSetBySql(String sql, Object[] params, String tableName)方法中

其首先是调用SQLTranslatorManager.translator()解析处理sql语句

image-20230713154235131

这里translator默认是false,所以直接返回原始sql语句

image-20230713154325245

回到getFieldSetBySql方法,处理完sql语句,调用this.getDataTable方法执行sql语句获取结果

image-20230713154607690

因为传入tableName为null,所以不在if逻辑中,当我们调用getFieldSetBySql(String sql, String tableName)方法时,传入params参数为null,也会跳过ToolFormatSql.format(sql, params);,最后调用execute方法执行sql语句。

分析完getFieldSetBySql方法处理逻辑,我们寻找调用该方法且参数可控地方,利用IDEA找到了多处调用

image-20230713155855413

但是基本都是拼接user.getUserID作为SQL语句,没有找到可控点,一时陷入不知所措

不过根据javaweb项目 有Dao层就会有Service

Service层叫服务层,被称为服务,粗略的理解就是对一个或多个Dao进行再次封装,封装成一个服务,所以这一层不会是一个原子操作了,需要事务控制。

我们在其Service层寻找有没有调用getFieldSetBySql的方法,经过筛查最终找到一处在FormService类中调用getFieldSetBySql的方法,其拼接参数到sql语句且处理逻辑比较简单

image-20230713163528841

右键方法名找到调用该方法的地方,最后定位在validate.jsp

image-20230713164047268

可以看到这里解析请求中的json数据,根据type选择处理方式,当type等于0是进入formService.getFormTableInfo方法,所以relId这个参数存在SQL注入风险,同时根据json特性可通过unicode编码绕过前面filter中对sql注入的检测,具体利用就不赘述了

  • 发表于 2023-07-24 09:00:00
  • 阅读 ( 6080 )
  • 分类:漏洞分析

1 条评论

小何同学
也太强了
请先 登录 后评论
请先 登录 后评论
中铁13层打工人
中铁13层打工人

79 篇文章

站长统计