[XCTF]江苏工匠杯easyphp

拿到题目后首先大致分析一下,找flag,在最后发现一个if语句当同时满足key1=1和key2=1时才给flag,看起来比较复杂,先进行代码审计吧

<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;

$a = $_GET['a'];
$b = $_GET['b'];

if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
    if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
        $key1 = 1;
        }else{
            die("Emmm...再想想");
        }
    }else{
    die("Emmm...");
}

$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
    if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
        $d = array_search("DGGJ", $c["n"]);
        $d === false?die("no..."):NULL;
        foreach($c["n"] as $key=>$val){
            $val==="DGGJ"?die("no......"):NULL;
        }
        $key2 = 1;
    }else{
        die("no hack");
    }
}else{
    die("no");
}

if($key1 && $key2){
    include "Hgfks.php";
    echo "You're right"."\n";
    echo $flag;
}

代码审计

1.首先来看第一个if语句

if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
    if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
        $key1 = 1;
        }else{
            die("Emmm...再想想");
        }
    }else{
    die("Emmm...");
}

get传入a,b两个参数,第一行if先判断a是否大于6000000并且长度不能大于3,所以这里我们可以用科学计数法来表示a,即a=9e9。第二行if进行了一个哈希碰撞,截取md5加密后的b的后六位和8b184b比较,如果相等则满足条件,这里引用了一个脚本

import random
import hashlib
 
res = "8b184b"
while 1:
    temp = random.randint(10**11, 10**12 - 1)
    temp = str(temp)
    MD5 = hashlib.md5()
    MD5.update(temp.encode(encoding='utf-8'))
    flag = MD5.hexdigest()
    if flag[-6:]==res :
        print("碰撞成功:"+flag)
        print("明文为:"+temp)
        break
    else:
        print("碰撞中.....")

2.来看第二部分代码

$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
    if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
        $d = array_search("DGGJ", $c["n"]);
        $d === false?die("no..."):NULL;
        foreach($c["n"] as $key=>$val){
            $val==="DGGJ"?die("no......"):NULL;
        }
        $key2 = 1;
    }else{
        die("no hack");
    }
}else{
    die("no");
}

传入一个json格式的数组参数c,并且数组中m的值要大于2022(is_numeric() 函数用于检测变量是否为数字或数字字符串。是数字返回true,否则返回false),当字符串与数字进行比较时会把字符串强制转化为整型即"123abc"会转成123,"abc"会转成0,类似于弱比较所以这里的m等于2023abc即可。接着第三行key为n的value必须为一个数组并且要有两个,并且第一个要是数组,所以n大致为{"m":"9999abc","n":[["xxx"],xxx]}。接着执行array_search() 函数(array_search() 函数在数组中搜索某个键值,并返回对应的键名)搜索n中是否有DGGJ,有的话才能使$key2=1,第二次使用foreach循环搜索n中的值是否含有"DGGJ",没有的话才能使$key2=1,我们传入一个数字时,字符串会强制转换成数字,DGGJ会转换成0,所以我们只要传入0就行了,所以c为{"m":"9999abc","n":[["666"],0]},完整的payload为:?a=9e9&b=261815215889&c={"m":"9999abc","n":[["666"],0]}


总结

这道题主要就是弱类型绕过,即字符串在和数字比较时会强制转换成数字,利用这一点可以进行绕过。另外一个就是哈希碰撞的脚本,在平时做题的时候可以多多积累这些脚本,扩大自己的知识库,如果有时间的话应该了解脚本代码是如何实现的。

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值