渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

admin 2025年6月27日13:43:01渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips已关闭评论3 views字数 2463阅读8分12秒阅读模式

一次SQL注入不成但解锁爆出额外信息的 Tips

  • 前言
  • 基本介绍
  • 获取到数据库用户名步骤
  • 本地 MySQL 分析
    • 查看当前用户权限
    • 爆出库名【任意用户都可以】
  • Ending...

前言

一次渗透测试项目中朋友甩过来的疑似SQL注入点, 当时并没有注入成功, 并已经感觉几乎是没有概率造成 SQL 注入的. 随后第二天朋友通过一些手段拿到了数据库用户名称. 下面来看一下原因~

基本介绍

先来一个脱敏的报告吧, 来描述一下大致场景:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

这边通过单引号爆出语法错误, 那么按理来说是存在注入的, 并且通过字段名与直觉可以感觉到这是一个基于 ORDER BY 的注入, ORDER BY 注入我会啊, 只要 ORDER BY 一个不存在的列名就好了, 就能看出来是不是注入:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

WTF?不应该啊, 为什么不会报错呢?正常情况应该这样:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

后来简单尝试了几下基于 ORDER BY 的 Payload 就没再看这个点了, 一方面不知道代码和SQL是怎么写的, 另一方面爆出来的错误有点模糊, 感觉很奇怪.

获取到数据库用户名步骤

再后来就听朋友说获取到了数据库名称?我有点不信, 步骤如下:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

payload 中, 输入了数字 + 字母, 得到了Unknown column的错误, 这就有戏, 随后下面的 payload 如:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

就能够获得到用户名?到现在我还是有点晕, 为什么会这样...

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

本地 MySQL 分析

对于思考为什么ORDER BY + 任意列名都不会报错, 这里想到的是可能后端将其转为了字符串, 所以导致每次 ORDER BY 了一个常量, 并不会对排序进行发生实质性的改变:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

不过针对于这种情况, 后续可以通过往列名后面依次增加单引号来进行判断是否存在注入, 如下:

package com.heihu577;

import java.sql.*;

publicclassMySQLConnectorTest{
publicstaticvoidmain(String[] args)throws Exception {
        Connection connection =
                DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/docker_database?useSSL=false&useUnicode=true&characterEncoding=UTF-8""root""root");
        String sql = "SELECT * FROM user ORDER BY 'hacker''";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);
    }
}

一个单引号, 打乱了SQL顺序, 包报错:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

两个单引号可正常发送数据:

package com.heihu577;

import java.sql.*;

publicclassMySQLConnectorTest{
publicstaticvoidmain(String[] args)throws Exception {
        Connection connection =
                DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/docker_database?useSSL=false&useUnicode=true&characterEncoding=UTF-8""root""root");
        String sql = "SELECT * FROM user ORDER BY 'hacker'''";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
            System.out.println(resultSet.getString("user"));
/**
             * admin
             * guest
             */

        }
    }
}

为什么数字 + 字母前面会增加r.r.通常是 SQL 语句中的别名, 如下:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

可能是开发者调试某些数据的原因, 做了这么一个判断与转换. 那么接下来看一下之前抛出的异常:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

去搜了一下, 发现这篇文章: https://wenku.csdn.net/answer/4xfnmxod5k

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

所以这边是触发了函数调用导致的, 当一个用户不存在某些函数的具体权限的话, 则会抛出异常信息, 将用户名带出来, 为了验证这个说法, 先在本地创建一个普通用户:

mysql> create user 'heihu577'@'%' identified by 'heihu577';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on docker_database.* to 'heihu577'@'%' identified by 'heihu577' with grant option;
Query OK, 0 rows affected, 1 warning (0.00 sec)

并且给予这个用户docker_database这个数据库下的操作权限, 首先是正常的函数调用:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

看起来其实没什么大问题, 不过怎么样将用户名暴露出来呢?

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

由于当前heihu577这个用户只存在docker_database下的权限, 当调用abcdefg.1()时会发生歧义, 误以为会去abcdefg中调用函数:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

查看当前用户权限

除了可以爆出用户名以外, 也可以用来判断当前用户的权限, 如果是 root 这种权限比较大的用户, 如图:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

会爆出函数不存在, 如果是普通用户 (或权限较小的用户), 会爆出具体的用户名:

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

爆出库名【任意用户都可以】

渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

Ending...

原文始发于微信公众号(Heihu Share):渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tips

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月27日13:43:01
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   渗透测试 | 一次SQL注入不成但解锁爆出额外信息的 Tipshttps://cn-sec.com/archives/4204003.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.