遇到一道CTF题目:http://web.jarvisoj.com:32772/
找到了这个题目最早出现的地方和原理解释:http://cvk.posthaven.com/sql-injection-with-raw-md5-hashes
哎,都是8年前的题目了,感觉自己进展好慢。
看解释原理也不复杂,就是MD5()函数中参数为true时,输出形式为原始二进制格式,如果,找到一个字符串MD5后得到的原始二进制格式在SQL中拼接成 类似 ‘or ‘1xxx的形式就可以绕过了.文章中作者写脚本找到了一个字符串ffifdyop满足了我们的要求。php手册对MD5()的介绍.
但是我还是有些疑惑,什么叫原始二进制格式?
先说说MD5的加密结果,百度百科上解释的:算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
也就是说MD5的输出结果应该是一个类似128位的01组成的值,不过我们平时将这个值以16进制的字符串格式输出。注意是字符串格式,也就是说在储存时不是那个128位的散列值,而是将它转换成字面值输出。就比如数字1储存在计算机里储存为00110001,但是这个00110001换算成十进制并不是1。这就是字面值和储存在计算里的值的不同。
那么PHP中的MD5(xxx,true)和MD5(xxx,false)到底有什么不同。
第一个输出的就是我们平时所看到的MD5计算后的值,32位,那第二个是什么呢?
官方解释是原始的二进制格式的结果,是128位的01代码,其实再转换成16进制,就是32位,就是前面那个32位的字符串,我们来验证一下:
将那串32位16进制数复制,打开HXD,新建文件,粘贴写入,看看效果:
可以看到当这串16进制数以文件的原始格式储存时,就是后面那串’or’….
所以这道题目利用的是MD5(参数为true)的结果是原始二进制格式,会再进行编码,就会得到可以注入的字符串,带入到sql语句中完成绕过。而参数为false时得到的是二进制格式的字面值值,本身就是字符串,不会再进行编码,带入sql语句的就是那串16进制字符串,不会再编码成其他形式。
不过我也是有些疑问,就是具体采用的哪种编码转换的,大部分编码都兼容ASCII码,所以用不同的编码基本上都可看到’or’这些部分,毕竟是对照ASCII码转换的,不过其他部分就是用不同的编码不同格式:
另外这个16进制转字符用的是怎样的格式,难道是ASCII码码:
编码这里确实不是很懂,谁了解的话帮我一下。
文章同步到我的博客:http://www.zjzhhb.com/archives/429
转载指明出处