一、什么是SQL注入
- 服务器没有严格的校验客户端发送的数据,导致将用户精心构造的数据作为 SQL 语句执行,从而导致数据库的内容被修改或泄露。
二、如何探测sql注入点
- 用户的输入能是否改变显示的内容,如果能够改变说明后台对输入有处理
- 例如,传回的数据有没有改变、是否存在显示的内容、以及其它一些不可见的信息
- 构建一条绝对出错的输入('")(),查看当前页面的返回内容
- 如果报错了,就说明用户输入的内容会被作为sql指令的一部分
- 尝试对SQL指令进行闭合,并且构建出相关的语法,查询自己需要的内容
- 闭合实际就是猜测后台使用的SQL指令
三、如何获取信息
- 通过联合查询注入的方式,获取到想要得到的信息(返回了查询到的信息)
- 在进行联合查询的时候,两条查询语句的列数必须是相同的
- SELECT * FROM xxx UNION SELECT 1,2,3,...; 直到不报错
- SELECT * FROM xxx ORDER BY N; 直到报错为止
- 有时,网页上只会显示查询到的第一条内容,此时在使用联合查询的时候,我们是看不到自己构建的查询语句查询到的内容的,可以通过将默认的查询条件设置为查不到来显示自己的内容。
- SELECT * FROM USER WHERE id=-1 UNION SELECT 1,2,3;
- 并不是所有查询到的内容都会被显示出来,我们需要结合页面利用联合查询中的字段
- SELECT * FROM USER WHERE id=-1 union SELECT 1,version(),database()
- 在进行联合查询的时候,两条查询语句的列数必须是相同的
- 报错注入方式(必须有报错信息)
- updatexml(str, xpath, str): 函数的作用是解析 xpath 语法进行内容的替换
- xpath 中 ~是绝对报错的,后续可以拼接自己想要查询的语句,注意需要加()
SELECT UPDATEXML(0, concat('~',(SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='security' AND TABLE_NAME='users')), 0)
- 缺点,只能获取到最多32字符的数据
SELECT UPDATEXML(0, concat('~',(SELECT SUBSTR((SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.TABLES), 32, 32))), 0)
- extractvalue:使用方式和 UPDATEXML 完全一致,但是少了第三个参数
- 双注入(8.0不支持):
SELECT COUNT(*) FROM TABLE GROUP BY FLOOR(RAND(0)*2);
- rand()函数的参数一定要写成0,否则概率性失效
- floor(rand(0) * 2) 得到的结果必然是 0 或者 1
- count(*) 配合 group by 会产生虚拟表,就是虚拟表部分出现了问题导致了错误
- 0 是否存在 FLOOR(RAND(0) * 2),不存在
- 1 创建 FLOOR(RAND(0)*2),1
- 1 是否存在 FLOOR(RAND(0)*2),存在
- 0 是否存在 FLOOR(RAND(0)*2),不存在
- 1 创建 FLOOR(RAND(0)*2),键是唯一的,所以报错(报错的是键名)
- updatexml(str, xpath, str): 函数的作用是解析 xpath 语法进行内容的替换
四、我们能够获取到什么信息
- 最基本的信息,例如 version() database() user() 等
- 通过 information_schema 获取数据库中的所有 数据库名、表名、字段名
- SCHEMATA: 保存了所有数据库的信息
SELECT * FROM information_schema.SCHEMATA
- TABLES:保存了数据库和表的对应关系
SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE()
- COLUMNS: 保存了指定数据库的表和字段的对应关系
SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='USER';
五、一些问题
- 为什么不使用 # 进行注入?
- 并不是通用的注释,它只能被用于 mysql 数据库
- 直接写在 URL 中时,表示的是锚点跳转,使用需要转义 %23
六、涉及的函数
- version(): 当前的数据库版本
- database(): 当前所使用的数据库
- user(): 当前的用户名和主机名
- group_concat(): 拼接查询到的所有结果为一个字符串
- concat: 拼接任意个数的字符串
- substr: 截取指定字符串中的一部分
- count:用于分组查询,计算每一组查询到了多少条内容
- floor:向下取整函数
- rand:随机数函数,返回的是一个0~1的随机小数