用户
搜索
  • TA的每日心情
    开心
    半小时前
  • 签到天数: 137 天

    连续签到: 137 天

    [LV.7]常住居民III

    i春秋-核心白帽

    Rank: 4

    48

    主题

    103

    帖子

    1714

    魔法币
    收听
    0
    粉丝
    5
    注册时间
    2020-10-2

    积极活跃奖

    发表于 2021-7-14 20:18:09 0741
    本帖最后由 Johnson666 于 2021-7-17 23:25 编辑

    MySQL超长字符截断SQL-Column-Truncation

    本篇文章作者Johnson666,本篇文章参与i春秋作家连载计划所属明天不熬夜了团队,未经许可禁止转载。连载方向:web安全,内网安全
    目录:
    1.XXE注入
    2.记内网渗透的流程
    3.MySQL超长字符截断SQL-Column-Truncation

    (1).SQL-Column-Truncation介绍

    mysql超长字符截断又名为“SQL-Column-Truncation”。

    在mysql中的一个设置里有一个sql_mode选项,当sql_mode设置为default 时,即没有开启STRICT_ALL_TABLES选项或者TRADITIONAL 选项或者加上的是ANSI选项时(MySQL sql_mode默认即default),MySQL对插入超长的值只会提示 warning,而不是error,这样就可能会导致一些截断问题。

    比如:
    第一种:没有开启STRICT_ALL_TABLES选项或者TRADITIONAL 选项

    第二种:加上的是ANSI选项

    在这里,username为varchar(5),即最大规定长度为5,而输入的值为admsddsff,长度为9,超过规定长度,可是并没有报错。通过查询可知被截断了。那么我们可以利用这个漏洞。
    第一种和第二种都是如图这样的结果:

    (2).sql-mode的各项设置

    MySQL5.0以上版本支持三种sql_mode模式:ANSITRADITIONALSTRICT_TRANS_TABLES

    1、ANSI模式:
    宽松模式,更改语法和行为,使其更符合标准SQL。对插入数据进行校验,如果不符合定义类型或长度,对数据类型调整或截断保存,报warning警告。对于本文开头中提到的错误,可以先把sql_mode设置为ANSI模式,这样便可以插入数据,而对于除数为0的结果的字段值,数据库将会用NULL值代替。

    2、TRADITIONAL模式:
    严格模式,当向mysql数据库插入数据时,进行数据的严格校验,保证错误数据不能插入,报error错误,而不仅仅是警告。用于事物时,会进行事物的回滚。 注释:一旦发现错误立即放弃INSERT/UPDATE。如果你使用非事务存储引擎,这种方式不是你想要的,因为出现错误前进行的数据更改不会“滚动”,结果是更新“只进行了一部分”。

    3、STRICT_TRANS_TABLES模式:
    严格模式,进行数据的严格校验,错误数据不能插入,报error错误。如果不能将给定的值插入到事务表中,则放弃该语句。对于非事务表,如果值出现在单行语句或多行语句的第1行,则放弃该语句。

    STRICT_TRANS_TABLES
    在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制。必须设置,以后各项可能依赖于该项的设置

    NO_ENGINE_SUBSTITUTION
    如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常

    ONLY_FULL_GROUP_BY
    对于GROUP BY操作,如果在SELECT中出现的单独的列,没有在GROUP BY子句中出现,那么这个SQL是不合法的

    NO_AUTO_VALUE_ON_ZERO
    该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户希望插入的值为0,而该列又是自增长的,那么这个选项就有用了

    NO_ZERO_IN_DATE
    在严格模式下,不允许日期和月份为零

    NO_ZERO_DATE
    设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告

    ERROR_FOR_DIVISION_BY_ZERO
    在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如果未给出该模式,那么数据被零除时MySQL返回NULL

    NO_AUTO_CREATE_USER
    禁止GRANT语句创建密码为空的用户

    PIPES_AS_CONCAT
    将“||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似

    ANSI_QUOTES
    启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符
    也可以在命令行查看和设置sql_mode变量

    (3).测试

    新建一张表测试,表结构如下(mysql 5.1):

    CREATE TABLE USERS(
                        id int(11) NOT NULL,
                        username varchar(7) NOT NULL,  //长度为7
                        password varchar(12) NOT NULL
    )

    分别插入以下SQL语句(注入提示消息)。

    1.插入正常的SQL语句。

    mysql> insert into users(id,username,password) values(1,'admin','admin');
    Query OK,1 row affected (0.00 sec)    //成功插入,无警告,无错误

    2.插入错误的SQL语句,此时的“admin ”右面有三个空格,长度为8,已经超过了原有的规定长度。

    mysql> insert into users(id,username,password) values(2,'admin   ' ,'admin');
    Query oK,1 row affected,1 warning (0.00 sec)    //成功插入,一个警告

    3.插入错误的SQL语句,长度已经超过原有的规定长度。

    mysql> insert into users(id,username,password) values(3 ,'admin   x','admin');
    Query OK,1 row affected,1 warning (0.00 sec)    //成功插入,一个警告

    MySQL提示三条语句都已经插入到数据库,只不过后面两条语句产生了警告。那么最终有没有插入到数据库呢?执行SQL语句查看一下就知道了。

    mysql> select username from users;
    +----------+
    | username |
    +----------+
    |admin    |
    |admin    |
    |admin    |
    +----------+
    3 rows in set (0.00 sec)

    可以看到,三条数据都被插入到数据库,但值发生了变化,此时再通过length来取得长度,判断值的长度。

    mysql> select length(username) from users where id =1;
    +------------------+
    | length(username) |
    +------------------+
    |              5|
    +------------------+
    1 row in set (0.00 sec)
    mysql> select length(username) from users where id =2;
    +------------------+
    | length(username) |
    +------------------+
    |              7|
    +------------------+
    1 row in set (0.00 sec)
    mysql> select length(username) from users where id =3;
    +------------------+
    | length(username) |
    +------------------+
    |              7|
    +------------------+

    可以发现,第二条与第三条数据的长度为7,也就是列的规定长度,由此可知,在默认情况下,如果数据超出列默认长度,mysql会将其截断。

    但这样何来攻击一说呢?下面查询用户名为'admin'的用户就知道了。

    mysql> select username from users where username= 'admin';
    +----------+
    | username |
    +----------+
    |admin    |
    |admin    |
    |admin    |
    +----------+

    只查询用户名为admin 的用户,但是另外两个长度不一致的admin用户也被查询出,这样就会造成一些安全问题,比如,有一处管理员登录是这样判断的,语句如下:

    $sql = "select count(*) from users where username='admin' and password='*****'";
    假设这条SQL语句没有任何注入漏洞,攻击者也可能登录到管理页面。

    假设管理员登录的用户名为admin,那么攻击者仅需要注册一个“admin “用户即可轻易进入后台管理页面,像某些著名的建站系统就被这样的方式攻击过。

    4、预防方法
    在sql-mode里加上STRICT_TRANS_TABLES或者TRADITIONAL
    加上STRICT_TRANS_TABLES或者TRADITIONAL后,输入的数据超过规定长度就会报错,不能输入。

    第一种:加上TRADITIONAL

    第二种:加上STRICT_TRANS_TABLES

    两种都是如下的结果:


    发新帖
    您需要登录后才可以回帖 登录 | 立即注册