[BJDCTF2020]Easy MD5(超级详细)

文章讲述了如何利用PHP的MD5函数第二个参数为true时返回原始二进制格式进行SQL注入。通过构造特定字符串,使得MD5值在SQL查询中形成永恒为真的条件。此外,文章还讨论了弱比较与强比较在PHP中的应用,以及如何通过数组传参和0e开头的哈希值进行绕过比较的策略。

这里说一下做题的时候看了些wp都是直接告诉输入ffifdyop就行 完全不明白为啥 看了些wp后。整体综合了一下

打开靶场后只有一个查询框

一顿输入后无果 只能通过url看到是get传参 用burp抓包看看

关于md5($pass,true)的注入

这里的篇幅会有点长 因为这块比较重要 这块明白后后面的非常简单

发现了提示 select * from `admin` where password=md5($pass,true)

也就是通过注入来进行绕过    这里先看下php MD5函数的用法

 32位16进制字符串的意思是:将MD5加密得到的128 位长度的"指纹信息",以每4位为一组,分为32组,每组以转换为16进制,进行转换得到一个32位的字符串。

总的来说就是我们平时看到的MD5加密的结果
16位原始二进制格式的字符串的意思是:将128 位长度的"指纹信息"分组转化为16位的一个字符串,然后两个字符为一组,依照ACILL码转化为字符串。

也就是说,就是当md5函数的第二个参数为true时,该函数的输出是原始二进制格式,会被作为字符串处理。

这里进行绕过就是需要构造一个语句使sql语句永恒为真 

例如这样:select * from `admin` where password=’’or’xxx    当or后面的值为true时即可完成注入

思路来了

要达到注入。首先要有一个字符串,这个字符串经过md5得到的16位原始二进制的字符串能帮我们实现sql注入。首先or这个字符串是必要的,因为需要构造永恒为真的语句。同时为了配对原先sql语句里面有的单引号进行闭合

所以我们需要的字符串的原始二进制格式的字符串里要包含    ‘or’    ,  ‘or’   对应的16进制是   276f7227 ,所以我们的目标就是要找一个字符串取32位16进制的md5值里带有276f7227这个字段的,接着就是要看关键的数字部分了,在276f7227这个字段后面紧跟一个数字,除了0,1-9,对应的asc码值是49-57,转化为16进制就是31-39,也就是我们需要有276f7227+(31-39)这个字段,就可以满足要求

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

这里引用一下原文章 链接在下面

这里需要注意的是,当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    ‘这种字符会显示乱码。 实际效果在下面的图中

 这里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开头,只要是数字开头都是可以的。

这里贴上一个链接 对sql注入:md5($password,true) 讲解非常详细

sql注入:md5($password,true)_md5($pass,true)_March97的博客-CSDN博客

看完这个文章后就可以明白为啥ffifdyop就是答案,因为ffifdyop的md5的原始二进制字符串里面有‘or’6这一部分的字符 得到这个字符后插入sql语句就使其为真就可以对其进行注入了

这里看下ffifdyop的效果

代码如下

<?php
$str = "ffifdyop";
echo "The string: ".$str."<br>";
echo "TRUE - Raw 16 character binary format:如下所示: ".md5($str, TRUE)."<br>";
echo "FALSE - 32 character hex number: ".md5($str)."<br>";
?>

 运行后的结果如下所示

这里可以使用ASCII码在线转换器看效果

 

 将ffifdyop传入 即可到达第二个页面  这里开始就很简单了

MD5弱比较

 查看页面源代码发现需要传入两个参数 

 

满足a与b的参数不同且两者的MD5相同就会返回正确的值

注意这里是弱比较==

这里有两种方法 第一种采用数组传参 数组传参方式格式为num[]=w  num为参数(例如本题的a) w为传入的值 最终传入的值如下

?a[]=1&b[]=2  因为md5不能处理数组,md5 函数哈希数组会返回 NULL。从而达到两者相等进行绕过。

 

第二种方法,php 0e开头的数字会当做科学计数法解析,因此只要构造两组md5值开头为0e的值即可绕过。

原理是PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。

例如

QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

这些网上有很多 这里就例举一个 伙伴们可以自行百度

题外话

有的题目是传参参数为字母和数字的MD5比较 用的也是弱类型比较 也可以采用这种方法

这里贴一个链接 讲解php弱类型的比较

https://www.cnblogs.com/Mrsm1th/p/6745532.html

输入数组后就跳转到了下一个页面

MD5强比较

还是一样的,只不过是post传参 且这里是强类型比较===

=是赋值  ==是弱比较  ===强比较(数值与类型都要相同)

这里只能使用数组传参了 之前的那个页面由于是弱比较 所以有两种方法可以进行MD5绕过

这里是强比较所以只能使用数组 不过这道题  数组可以通杀绕过这两层的MD5

Payload如下  post传参

param1[]=2&param2[]=3

 

 

 

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

layz_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值