黑名单过滤下为何还能无限制SQL注入

admin 2024年5月13日00:39:44评论25 views字数 5613阅读18分42秒阅读模式

文章首发于奇安信攻防社区

链接:https://forum.butian.net/share/2905

0x01 前言

这周看到了某公众号发的springboot+vue实现的一个后台管理系统。阅读量还挺高的,就下了一下源码翻一翻,发现里边漏洞还挺多的。尤其是SQL方面,作者虽然做了过滤但还是因为配置不当的导致SQL注入。

黑名单过滤下为何还能无限制SQL注入
image-20240405151739486

后边经过作者的同意,然后把本次代码审计的思路放出来和大家分享一下

黑名单过滤下为何还能无限制SQL注入
image-20240405155534442

0x02 SQL注入

mybatis-plus对绝大部分场景进行了预编译处理。但是类似动态表名、orderby这种需要拼接的场景配置不当还是会存在漏洞。本次就是记录一下在代码审计中遇到的一个奇怪的SQL注入,在对请求参数进行黑名单过滤十分严格的情况,代码逻辑不当导致SQL注入!

分页SQL注入分析

翻了一下pom.xml文件,发现该项目持久层使用的是Mybatis-puls框架!

黑名单过滤下为何还能无限制SQL注入
image-20240403021320315

我对mybatis-plus的理解就是封装了一些sql以减少代码量,其对绝大部分场景进行了预编译处理。但是类似动态表名、orderby这种需要拼接的场景配置不当还是会存在漏洞。

在翻工具类时发现该项目有对sql注入进行过滤

黑名单过滤下为何还能无限制SQL注入
image-20240403025212716

那就跟进去看看在哪里做了过滤,只在com.utils.Query#Query中有4处调用

黑名单过滤下为何还能无限制SQL注入
image-20240411115923581

跟进com.utils.Query#Query看看,发现该类具有两个重载的构造方法,接收的参数类型不同

  • JQPageInfo:封装了分页参数的实体类

  • Mapparams:集合类型的params参数

黑名单过滤下为何还能无限制SQL注入
image-20240411120600013

但其对sql注入的防御逻辑都相同,都是对sidx和order参数进行处理后,然后封装成Page对象

黑名单过滤下为何还能无限制SQL注入
image-20240411121107373
黑名单过滤下为何还能无限制SQL注入
image-20240411121146368

源码:

package com.utils;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.baomidou.mybatisplus.plugins.Page;

/**
 * 查询参数
 */

public class Query<Textends LinkedHashMap<StringObject{
    private static final long serialVersionUID = 1L;
    /**
     * mybatis-plus分页参数
     */

    private Page<T> page;
    /**
     * 当前页码
     */

    private int currPage = 1;
    /**
     * 每页条数
     */

    private int limit = 10;

    public Query(JQPageInfo pageInfo) {
        //分页参数
        if(pageInfo.getPage()!= null){
            currPage = pageInfo.getPage();
        }
        if(pageInfo.getLimit()!= null){
            limit = pageInfo.getLimit();
        }


        //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
        String sidx = SQLFilter.sqlInject(pageInfo.getSidx());
        String order = SQLFilter.sqlInject(pageInfo.getOrder());


        //mybatis-plus分页
        this.page = new Page<>(currPage, limit);

        //排序
        if(StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(order)){
            this.page.setOrderByField(sidx);
            this.page.setAsc("ASC".equalsIgnoreCase(order));
        }
    }


    public Query(Map<String, Object> params){
        this.putAll(params);

        //分页参数
        if(params.get("page") != null){
            currPage = Integer.parseInt((String)params.get("page"));
        }
        if(params.get("limit") != null){
            limit = Integer.parseInt((String)params.get("limit"));
        }

        this.put("offset", (currPage - 1) * limit);
        this.put("page", currPage);
        this.put("limit", limit);

        //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
        String sidx = SQLFilter.sqlInject((String)params.get("sidx"));
        String order = SQLFilter.sqlInject((String)params.get("order"));
        this.put("sidx", sidx);
        this.put("order", order);

        //mybatis-plus分页
        this.page = new Page<>(currPage, limit);

        //排序
        if(StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(order)){
            this.page.setOrderByField(sidx);
            this.page.setAsc("ASC".equalsIgnoreCase(order));
        }

    }

    public Page<T> getPage() {
        return page;
    }

    public int getCurrPage() {
        return currPage;
    }

    public int getLimit() {
        return limit;
    }
}

很完美的防御、不过这里就有点奇怪了,翻了几个sql的xml文件,发现都没有使用到这个page对象

黑名单过滤下为何还能无限制SQL注入
image-20240411121930477

那我们从页面中随便找一个带分页的查询请求分析一下,例如:

/jixiaokaohe/page?page=1&limit=10&sort=id

跟进到他的controller->com.controller.JixiaokaoheController#page

调用的是jixiaokaoheService.queryPage来进行的查询,使用MPUtil.sort来自定义了一个wrapper

黑名单过滤下为何还能无限制SQL注入
image-20240403032355989

继续跟进到com.service.impl.JixiaokaoheServiceImpl#queryPage

可以看到这块使用了sql过滤的com.utils.Query#Query(java.util.Map<java.lang.String,java.lang.Object>)

黑名单过滤下为何还能无限制SQL注入
image-20240403032630418

继续向下跟

黑名单过滤下为何还能无限制SQL注入
image-20240403033241569
黑名单过滤下为何还能无限制SQL注入
image-20240403033302136

可以看到最终sql的实现使用的是开头说的自定义的wrapper来构建查询条件。

黑名单过滤下为何还能无限制SQL注入
image-20240403033810081

跟进去看看->com.utils.MPUtil#sort

发现在这块对sort参数直接使用了拼接而且没有进行过滤

黑名单过滤下为何还能无限制SQL注入
image-20240403033917326

打个poc试一下吧!

page=1&limit=10&sort=id+and+updatexml(1,concat(0x7e,database()),0)#
黑名单过滤下为何还能无限制SQL注入
image-20240403034431648

其他SQL注入分析

从Mybatis-puls的简介中可以看到:Mybatis-Plus是一个Mybatis(opens new window)的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发。因此mybatis中实现sql的方式在Mybatis-puls同样适用。

#{}预处理、${}拼接就不用多说了。直接实现sql的xml搜索${

黑名单过滤下为何还能无限制SQL注入
image-20240403040500351

可以发现多出使用拼接,那直接选择一个分析一下

黑名单过滤下为何还能无限制SQL注入
image-20240404211942229

一路向上跟进

com.service.impl.CommonServiceImpl#remindCount

黑名单过滤下为何还能无限制SQL注入
image-20240404212053916

最终跟到com.controller.CommonController#remindCount,发现全程也无过滤

黑名单过滤下为何还能无限制SQL注入
image-20240404212127974

根据接口,构造,打个poc

users union select group_concat(SCHEMA_NAME) from information_schema.SCHEM
黑名单过滤下为何还能无限制SQL注入
image-20240404211110262

SQL注入总结

在对动态表名、orderby这种需要拼接的场景下,在代码实现时一定要仔细!总体来说mybatispuls框架中SQL注入漏洞挖掘相较于mybatis中更为困难,需要我们更加有耐心!

0x03 任意用户密码重置

这是在无意间发现的一个功能,感觉是作者设计的一个功能。但我没太看懂作者的意图,重置密码的接口可以不进行权限认证就使用!

@IgnoreAuth这个注解的作用是不进行权限认证,之后就是通过用户名来查询用户,然后修改用户的密码为123456

黑名单过滤下为何还能无限制SQL注入
image-20240404232632119
GET /springboot57n6g/users/resetPass?username=admin HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Accept: application/json, text/plain, */*
sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"
sec-ch-ua-platform: "Windows"
sec-ch-ua-mobile: ?0
Accept-Encoding: gzip, deflate, br
Sec-Fetch-Site: same-origin
Sec-Fetch-Dest: empty
Referer: http://localhost:8081/
Sec-Fetch-Mode: cors
Accept-Language: zh-CN,zh;q=0.9
黑名单过滤下为何还能无限制SQL注入
image-20240404233310202

0x04 任意文件上传

黑名单过滤下为何还能无限制SQL注入
image-20240405012738083

分析

com.controller.FileController#upload中实现的文件上传功能,通过最后一个点来获取上传文件后缀,在结合时间生成心的文件名,但未对文件进行过滤。导致任意文件上传

黑名单过滤下为何还能无限制SQL注入
image-20240405012907744

0x05 任意文件下载

黑名单过滤下为何还能无限制SQL注入
image-20240405012147812

分析

com.controller.FileController#download中实现的文件下载功能,但是在94行文件路径是由拼接而得:静态目录/upload/filename

由于filename我们可控。并且也无过滤,导致目录穿越下载任意文件

黑名单过滤下为何还能无限制SQL注入
image-20240405012326337

0x06 总结

开发注重功能的同时也应该考虑到一些安全问题。就像重置密码那个问题,作者就没有思考到安全问题。

原文始发于微信公众号(迪哥讲事):黑名单过滤下为何还能无限制SQL注入

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月13日00:39:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   黑名单过滤下为何还能无限制SQL注入https://cn-sec.com/archives/2733692.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息