22.8.8更新
相关前言
简单来说因为开发者没有秉持“外部参数皆不可信的原则”进行开发,导致产品满足以下两个条件:
- 攻击者可以控制要构造的参数
- 参数带入数据库查询(直接拼接到SQL语句,没有作过滤处理)
SQL注入的常见类型
- UNION query SQL injection(union查询注入)
- Boolean-based blind SQL injection(布尔盲注)
- Error-based SQL injection(基于报错的注入)
- Time-based blind SQL injection(时间盲注)
- Stacked queries SQL injection
MySQL一些重要数据库
在MySQL5.0版本后,默认在数据库中会存放一个”infomation_schema”的数据库。此库中有三个表:
- SCHEMATA:存储该用户创建的所有数据库的库名。记录库名的字段名为SCHEMA_NAME
- TABLES:存储该用户创建的所有数据库的库名和表名。字段名分别为TABLE_SCHEMA和TABLE_NAME
- COLUMNS:存储该用户创建的所有数据库的库名、表名和字段名,字段名分别为TABLE_SCHEMA、TABLE_NAME和COLUMN_NAME
基础SQL语句
查询语句
1 | # 不知道任何条件时: |
limit用法
格式:limit m, n
m为开始位置,从0开始。n为记录条数。
常见函数
- database():当前网站数据库
- version():当前MySQL版本
- user():当前MySQL用户
- concat相关函数:拼接字符串
- substr(str, n, m):分割字符串,返回str从第n个开始的m个字符(从1开始)
- length(str):返回字符串的长度
- char(n):返回ascii码
- ascii(c):返回编码
- count():计数
- mid():与substr()一致,后者被拦截时尝试
- ord():与ascii()一致。二者在接收字符串参数时只编码第一位字符
- left(str, n):从第一位向右截取n位
多行执行
sql通过分号来执行相应语句,但是一般不会允许通过一行执行多行。在Stacked queries
注入中可以使用此方式
注释符
#
或--空格
或/**/
内联注释
1 | /*!UNIOM*/ |
大小写
诸如DaTaBaSe()
之类
Union注入
测试
访问id=1’返回结果与id=1不同
访问id=1 and 1=1 因为and 1=1为真,返回与id=1相同结果。
访问id=1 and 1=2 因为后者为假 返回与id=1不同结果。
结论:可能存在SQL注入。
ORDER BY 关键字
语法:
1 | SELECT column_name,column_name |
有以下数据:
1 | +----+--------------+---------------------------+-------+---------+ |
下面的 SQL 语句从 “Websites” 表中选取所有网站,并按照 “alexa” 列排序:
1 | SELECT * FROM Websites |
下面的 SQL 语句从 “Websites” 表中选取所有网站,并按照 “country” 和 “alexa” 列排序:
1 | SELECT * FROM Websites |
此时会先对country字段排序,然后在每个country里对alexa进行排序。
查询字段数量
先使用'
符号检查有无漏洞存在,然后查询版本信息、数据库名、用户名等,再从information_schema
数据库中查询出数据库名、表名、字段名,就可以知道字段数量。
接下来使用order by 1-99语句查询表的字段数量
访问id=1 order by 3返回与id=1相同结果。访问id=1 order by 4返回不同结果,则字段数为3。
https://www.runoob.com/sql/sql-union.html)
查询相关语句
查询一般会使用like
关键字:
1 | select ... form ... where ... like '%x%'; |
like
前为字段名,%
表示任意匹配。
判断前后端分离
现在网站一般都是前后端分离,前端进行请求时会请求后端api接口。我们可以通过网络数据包请求的url判断是否为前后端分离。再判断是哪种请求方式
基于时间的盲注
是否存在注入
当没有明显回显时无从判断是否存在sql注入,可以使用sleep(1)
这样的语句结合响应的时间来判断是否存在注入。
注意:sleep(1)
并不意味着语句真的只会执行1秒。例如如果延时函数存在于where中被执行,那么每条匹配的结果都会执行判断的延迟函数,因此实际上应该被执行n秒(n为sleep被实际执行的次数),且sql在逻辑判断中与其他编程语言类似,只有and
逻辑运算前者为真时后者才有机会被执行,此时如果判断的第一条语句没有真的情况,and
后的sleep
将不会被执行,宏观上表现为没有延迟。
枚举数据库
结合字符串分割函数与条件判断,可以盲注出一些数据库的数据。
例如:
1 | # 判断数据库名长度 |
Bypass
在很多情况比如CTF中,可能会有一些敏感语句的拦截。
注释
--+
,#
,/**/
空格绕过
符号 | url |
---|---|
空格 | %20 |
‘ | %27 |
# | %23 |
/ | %2f |
水平tab | %09 |
\n | %0a |
垂直tab | %0b |
新的一页 | %0c |
return | %0d |
空格 | %a0 |
常见用法
1 | /**/代替空格 |
内联注释
把一些特有的仅在MySQL上的语句放在/*!...*/
中
这样这些语句如果在其他数据库中是不会被执行,但在MySQL中会执行
1 | select id from users where id = 1 union /*!select*/ 1,2,3,4,5,6,7,8; |
函数替换
将敏感函数替换为等价其他函数。例如:
substr()、mid()、left();
ascii()、ord();