sql注入:md5($password,true)

CTF 专栏收录该内容
1 篇文章 0 订阅

       前几天做了一道CTF的题目,是在”实验吧“的一道简单的web题目,当然这道题目很多人都解出来了,因为它的.php文件名就是答案。

       他的网页链接里面的php文件名就是’ffifdyop.php‘。

 

       上面的’ffifdyop‘就是我们要输入的密码。哦,忘了介绍,这道题目只需要表单提交密码。

      当然如果直接输入ffifdyop,提交后就能出现flag。我也不知道出题的本意是如何,但是也许大家不知道这道题的原理是什么,为什么ffifdyop是答案。比如我,我之前一直不知道这个sql注入的原理是什么。

       下面就说明这道题的sql注入的原理,我们可以直接看到后台里面的php判断代码:

<!-- $password=$_POST['password'];
	$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
	$result=mysqli_query($link,$sql);
		if(mysqli_num_rows($result)>0){
			echo 'flag is :'.$flag;
		}
		else{
			echo '密码错误!';
		} -->

       从代码很容易知道,用mysqli_num_rows()函数来判断是否sql语句查询结果有返回值,那么重点就是那条sql语句。那么唯一可以sql注入的地方就是md5($password,true)这个地方。

       那么首先介绍一下md5这个函数。

     语法

                  md5(string,raw)

        

参数描述
string必需。要计算的字符串。
raw

可选。

  • 默认不写为FALSE。32位16进制的字符串
  • TRUE。16位原始二进制格式的字符串

      

          

content: ffifdyop
hex: 276f722736c95d99e921722cf9ed621c
raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
string: 'or'6]!r,b

    这里需要注意的是,当raw项为true时,返回的这个原始二进制不是普通的二进制(0,1),而是  'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c  这种。

       上面的’ffifdyop‘字符串对应的16位原始二进制的字符串就是”    'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c    “  。  '  \  '后面的3个字符连同'  \  '算一个字符,比如’    \xc9    ‘,所以上述一共16个。当然,像’    \xc9    ‘这种字符会显示乱码。

       然后我们可以用’ffifdyop‘带入,看一下实际的效果。

      

      

       这里32位的16进制的字符串,两个一组就是上面的16位二进制的字符串。比如27,这是16进制的,先要转化为10进制的,就是39,39在ASC码表里面就是’    '    ‘字符。6f就是对应‘    o    ’。

       然后我们得到的sql语句就是 SELECT * FROM admin WHERE username = 'admin' and password = ''or'6�]��!r,��b'

       为什么password = ''or'6�]��!r,��b'的返回值会是true呢,因为or后面的单引号里面的字符串(6�]��!r,��b),是数字开头的。当然不能以0开头。(我不知道在数据库里面查询的时候,�这种会不会显示)

       这里引用一篇文章,连接在下面,里面的原话“a string starting with a 1 is cast as an integer when used as a boolean.“

      在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于password=‘xxx’ or 1  ,也就相当于password=‘xxx’ or true,所以返回值就是true。当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的。

       当然如果只有数字的话,就不需要单引号,比如password=‘xxx’ or 1,那么返回值也是true。(xxx指代任意字符)

       表里就只有一条数据,用于测试。

       

       

       

       

       所以到这里为止,就完成了sql注入。同时要注意的是,这种sql语句,在mysql里面是可以行得通的,但是在oracle数据库里面这样的语句是有语法错误的。

       所以回过头来为什么ffifdyop就是答案,因为ffifdyop的md5的原始二进制字符串里面有‘or’6这一部分的字符。那么进一步思考这个单引号是否是必要的,这两个单引号是为了与原有的语句的单引号配对。所以我们理解了这个sql注入的原理,那么就明白了我们需要怎样的字符串。

       当然答案也不止这一个。

content: 129581926211651571912466741651878684928
hex: 06da5430449f8f6f23dfc1276f722738
raw: \x06\xdaT0D\x9f\x8fo#\xdf\xc1'or'8
string: T0Do#'or'8

        这个字符串也是符合要求的。因为它含有‘or’8

       也许还有其他符合要求的字符串,也可以自己写个代码去计算,但是计算次数会很大,下面那篇文章里的作者就是自己写的代码计算的。

       那我们从正向推算一下,要怎么得到我们要的答案。首先我们要找到一个字符串,这个字符串经过md5得到的16位原始二进制的字符串能帮我们实现sql注入。首先or这个字符串是必要的,同时为了配对原先sql语句里面有的单引号

  在or的两边要有单引号,使它变成  password=‘xxx’or‘xxx’  的形式,所以我们需要的字符串的原始二进制格式的字符串里要包含    ‘or’    ,如果根据原始二进制来找到我们要的字符串可能会比较麻烦,那么可以根据32位16进制的字符串来查找,根据上面介绍的,  ‘or’   对应的16进制是   276f7227    ,所以我们的目标就是要找一个字符串取32位16进制的md5值里带有276f7227这个字段的,接着就是要看关键的数字部分了,在276f7227这个字段后面紧跟一个数字,除了0,1-9,对应的asc码值是49-57,转化为16进制就是31-39,也就是我们需要有276f7227+(31-39)这个字段,就可以满足要求。比如xxxxxxxxxxxxxxxx276f7227(31-39)xxxxxx

 

参考文章:http://cvk.posthaven.com/sql-injection-with-raw-md5-hashes

 

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值