在学习SQL注入之前我们必须先知道什么是SQL注入。----这里的内容只供学习使用,如有其他危害行为,概不负责
SQL注入(SQL Injection)是一种常见的网络安全漏洞,攻击者通过将恶意的SQL代码插入到应用程序的查询中,从而对数据库执行未授权的操作。具体来说,攻击者可以利用这个漏洞来:
- 获取敏感数据:比如用户名、密码、信用卡信息等。
- 修改数据:例如更新、删除数据库中的数据。
- 执行管理操作:如创建新的管理员账户或改变数据库的结构。
- 绕过认证:如通过伪造的查询绕过登录验证
当然SQL注入还可以通过其他方式进行防护:
- 使用预处理语句和参数化查询:这可以确保用户输入不会被直接嵌入到SQL查询中。
- 输入验证和过滤:对用户输入进行严格的验证和清洗。
- 最小化数据库权限:确保数据库账户只有最低限度的权限。
- 使用ORM框架:使用对象关系映射(ORM)工具可以减少直接编写SQL代码的需要,从而降低风险。
知道了如何去攻击,自然就可以知道怎么去防护。分类方式有很多,自然不同分类之间就会不同,所以这里通过pikachu靶场来进行演示练习
1、数字型注入
这里我输入了2,点击查询,给我返回了一个用户名,和邮箱地址,我们可以在地址栏中看出,这是一个post请求
我们就应该很清楚的知道后端对数据库做了一个什么操作,这里我们正常情况下不知道数据库的任何信息,但我们现在是知道的
SELECT username,email FROM pikachu.member WHERE id=2;
从数据库查到的结果返回前端
但是攻击者有时不按套路出牌,在后面加上or 1=1 ,后面的结果一直是对的,所以下面的指令,会将所有的数据输出
SELECT username,email FROM pikachu.member WHERE id=2 or 1=1;
这时危害就出现了,正常我们只需查出自己的数据即可,但是现在数据库里的所有信息全都出来了
2、字符型注入
首先我输入lihua,回显用户名不存在,接下来我输入一个数据库里存在的用户vince,而这个是一个get请求
这里回显了id和email字段的内容
我们可以猜到数据库一定是做了以下查询语句
SELECT id,email FROM pikachu.member WHERE username = 'vince';
这时我们考虑用同样的方法看行不行
点击后发现,返回用户不存在,为什么呢,我们必须要知道他执行了一个什么样的查询语句,其实是这样的
SELECT id,email FROM pikachu.member WHERE username = 'vince or 1 = 1';
数据库中不存在vince or 1 = 1这样的用户自然就查无此人了,那我们需要怎么做呢,字符型注入,就是不管我们输入什么,到了后端都会变成字符串,我们需要做的一个操作就是让vince这个与前面的单引号进行闭合,把后面的单引号注释掉,即可
那么就可以这样写 vince ' or 1 = 1 # 这里#号启注释作用,也可以用 俩个 - 加空格 即 --空格 , 此时语句就变成了
SELECT id,email FROM pikachu.member WHERE username = 'vince ' or 1 = 1 #';
其实这个是有点问题的,就像下面这样,这样直接查当然查不出来,因为#号后面的东西会全都注释掉这条指令就无法执行,我们知道即可
最关键的就是要闭合前面存在的字符串
3、搜索型注入
来到这一关,让我们去输入点东西,我输入l,返回了如下
那我们就可以知道,该查询语句为 SELECT username,id,email FROM pikachu.member WHERE username LIKE '%l%';
同样做闭合,即输入 l%' or 1=1 #
SELECT username,id,email FROM pikachu.member WHERE username LIKE '%l%' or 1=1 #;
重点还是闭合,下面的xx型注入,会有更深刻的体会
4、xx型注入
首先我输入vince,返回,这个我们就不做过多解释
这个闭合就有点困难,我们先看看源码,文件在phpstudy_pro\WWW\pikachu\vul\sqli\sqli_x.php
所以我们输入的应该是 vince ') or 1=1 # ,就可以查询到所有数据,不过前面的vince可以换成其他的,意思就是随便输入一点字符,为什么呢,留给你们
当然在实际的情况中,我们并不能知道源码写的是什么,这个时候我们就要尝试,根据经验,然后去想象。
那么我们怎么知道我们输入的东西是正确的闭合还是错误的,在有些情况下,后台过滤较为简单输入后会有报错,即称为报错注入,我通过字符型注入演示一下
我输入 aaa ' or 1=1 #,后数据全部显示
我再输入aaa " or 1=1 # ,就有了报错
我们知道这里是用了,单引号进行闭合,不是双引号,所以出错
我们再说说怎么判断注入点,我们输入vince ' AND 1=1 # 和vince 'AND 1=2 #
我们发现前面的正常显示,后面的报错如果
当我只输入了一个单引号,就有了如下报错,告诉我语法上有问题,不过这样的报错是可以隐藏不显示的,这就涉及到了,盲注,这个涉及了很多东西,我们以后再说
这里我们借着靶场,再详细讲一下联合查询
我们想要一次执行俩条查询语句,那么就需要union来连接,但是,俩条查询语句必须查询的字段数是一样的例如
SELECT username,email FROM pikachu.member WHERE id =1 UNION SELECT username,pw FROM pikachu.member WHERE id = 2;
前面是主查询语句,后面是副查询语句,前面的查询出来结果后,之后只有俩字段,为了正常显示,所以后面的查询语句必须只能查询俩个字段
如果副语句是:SELECT 1,2 ,就会直接输入数据库
那么他有什么无害呢,我们知道数据库内置的函数可以查询数据库版本,那么我们就可以输入
aa' UNION SELECT VERSION(),USER() #
这里我们是知道主查询语句查询几个字段,那如果不知道呢,我们就需要用到order by这个用法,我们再来回顾一下,他的作用是排序,在后面输入数字,将会在数据库中对应的字段进行排序如果输入n,没有第n个字段就会报错,那么我们依据这个特性来确定主语句的字段数
先输入 aa ' order by 5 # ,出现报错,当然你们可以输入10,11等等,如果不是我们就用二分法来接着输入
接下来输入3,报错,
再输入2,这就说明后面的order by被数据库执行了,即是俩个字段
对于元数据库的利用,这里也详细的讲一下:
其中的字符串上一篇中有解释,这里同样用pikachu数据库做演示
查库:select schema_name from information_schema.schemata;
查表:select table_name from information_schema.tables where table_schema='pikachu';
查列:select column_name from information_schema.columns where table_name'member';
查字段:select username,password from pikachu.member;
mysql数据库是不区分大小写的,以后我们在进行注入的时候利用元数据库较多
欲知后事如何,且听下回分解