[BJDCTF2020]EzPHP create_function()代码注入绕过$_REQUEST和QUERY_STRING等

本文深入剖析了一项复杂的PHP代码注入挑战,详细介绍了如何绕过多种防御机制,包括字符串匹配、参数过滤等,最终实现代码注入的目标。文章提供了具体的payload实例,展示了高级的绕过技巧。

0x01 题目源码

 <?php
highlight_file(__FILE__);
error_reporting(0); 

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) {
   
    
    if (
        preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
        )  
        die('You seem to want to do something bad?'); 
}

if (!preg_match('/http|https/i', $_GET['file'
<?php // if (!defined('IN_ECS')) // { // die('Hacking attempt'); // } include 'OpenFire.php'; /** * 设置上次聊天超过5分钟的客服状态为空闲 */ function set_customer_status($cus_id, $cus_status) { $sql = "update " . $GLOBALS['ecs']->table('chat_customer') . " set cus_status = '$cus_status' where cus_id = '$cus_id'"; $result = $GLOBALS['db']->query($sql); } /** * 根据客服类型入驻商编号获取客服列表,然后获取每个客服的在线状态(status)是否存在于聊天系统(exist) * @param string $cus_type * @param int $supp_id * @return array */ function get_customers($cus_type = CUSTOMER_SERVICE, $supp_id = -1) { if(!empty($supp_id) && $supp_id != 0) { $where = " AND supp_id = '$supp_id'"; } else { $where = " AND supp_id = '-1'"; } if(empty($cus_type)) { $cus_type = CUSTOMER_SERVICE; } // 按客服的类型进行倒序排列,方便售前、售后比客服先获取用户权限 $sql = "select * from " . $GLOBALS['ecs']->table('chat_customer') . " WHERE cus_enable = 1 AND cus_type in ($cus_type) $where ORDER BY cus_type desc"; $list = $GLOBALS['db']->getAll($sql); foreach ($list as &$customer) { $of_username = $customer['of_username']; $exist = check_of_username_exist($of_username); if($exist) { $status = trim(get_of_user_status($of_username)); $customer['status'] = $status; } else { $customer['status'] = 'unavailable'; } $customer['exist'] = $exist; } return $list; } function get_online_customers($cus_type, $supp_id) { $customer_list = get_customers($cus_type, $supp_id); } /** * * 根据用户类型所属的店铺编号获取客服信息列表 * * * @param string $user_type 用户类型:00-管理员 10-用户 20-平台售前客服 21-平台售后客服 30-入驻商售前客服 31-入驻商售后客服 * @param int $shop_id 入驻商家编号:-1 - 空,其他-入驻商编号 * @return 用户信息列表,未查询到则返回空数组 */ function get_of_customers($user_type = 10, $shop_id = null) { $_CFG = $GLOBALS['_CFG']; $of_username = $_CFG['chat_server_admin_username']; $of_password = $_CFG['chat_server_admin_password']; $of_ip = $_CFG['chat_server_ip']; $of_port = $_CFG['chat_server_port']; $of_url = get_of_url($of_ip, $of_port); $url = $of_url.'/plugins/userService/properties/?type='.$user_type; if(!empty($shop_id)) { $url = $url.'&shop_id='.$shop_id; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 授权验证 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $of_username.":".$of_password); // 设置可以读取返回值 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 运行curl $result = curl_exec ( $ch ); // 关闭 curl_close ( $ch ); $users = array(); if(!empty($result)) { $result = simplexml_load_string($result); for ($i = 0; $i < count($result->user); $i++) { $u = $result->user[$i]; $user = new User(); $user->username = (string)$u->username; $user->name = (string)$u->name; for ($j = 0; $j < count($u->properties->property); $j++) { $p = $u->properties->property[$j]; $property = new Property((string)$p->attributes()->key, (string)$p->attributes()->value); array_push($user->properties, $property); } array_push($users, $user); } } return $users; } /** * * 获取“空闲”“在线”两个状态的客服列表 * * @param number $user_type * @param string $shop_id * @return Ambigous <用户信息列表,未查询到则返回空数组, multitype:>|multitype: */ function get_of_online_customers($user_type = 10, $shop_id = null) { $users = get_of_customers($user_type, $shop_id); if(empty($users)) { return $users; } $list = array(); for ($i = 0; $i < count($users); $i++) { $user = $users[$i]; $username = $user->username; $status = trim(get_of_user_status($username)); if($status == '在线' || $status == '空闲') { array_push($list, $user); } } return $list; } /** * * 获取用户当前在线状态 * * @param unknown $username * @param string $type 返回的数据类型:xml,text,image,默认为text * @return mixed text[空闲、在线、离开、电话中、正忙] */ function get_of_user_presence ($username, $type = 'text') { $_CFG = $GLOBALS['_CFG']; $of_username = $_CFG['chat_server_admin_username']; $of_password = $_CFG['chat_server_admin_password']; $of_ip = $_CFG['chat_server_ip']; $of_port = $_CFG['chat_server_port']; $of_url = get_of_url($of_ip, $of_port); $url = $of_url.'/plugins/presence/status?jid='.$username.'&type='.$type; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 授权验证 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $of_username.":".$of_password); // 设置可以读取返回值 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 运行curl $result = curl_exec ( $ch ); // 关闭 curl_close ( $ch ); return $result; } /** * * 获取用户当前在线状态 * * @param unknown $username * @return mixed text[空闲、在线、离开、电话中、正忙、unavailable] */ function get_of_user_status($username) { $_CFG = $GLOBALS['_CFG']; $of_username = $_CFG['chat_server_admin_username']; $of_password = $_CFG['chat_server_admin_password']; $of_ip = $_CFG['chat_server_ip']; $of_port = $_CFG['chat_server_port']; $of_url = get_of_url($of_ip, $of_port); $of_domain = get_xmpp_domain(); $url = $of_url.'/plugins/presence/status?jid='.$username.'@'.$of_domain.'&type=xml'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 授权验证 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $of_username.":".$of_password); // 设置可以读取返回值 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 运行curl $result = curl_exec ( $ch ); // 关闭 curl_close ( $ch ); $xml = simplexml_load_string($result); $type = $xml->attributes()->type; if(!empty($type)) { return (string)$type; } else if(!empty($xml->status)) { $status = $xml->status; return (string)$status; } return 'unavailable'; } /** * * 获取聊天服务器的域名 * * @param unknown $username * @param string $type 返回的数据类型:xml,text,image,默认为text * @return string */ function get_xmpp_domain() { $_CFG = $GLOBALS['_CFG']; $of_username = $_CFG['chat_server_admin_username']; $of_password = $_CFG['chat_server_admin_password']; $of_ip = $_CFG['chat_server_ip']; $of_port = $_CFG['chat_server_port']; $of_url = get_of_url($of_ip, $of_port); $url = $of_url.'/plugins/userService/users/domain'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 授权验证 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $of_username.":".$of_password); // 设置可以读取返回值 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 运行curl $result = curl_exec ( $ch ); // 关闭 curl_close ( $ch ); return $result; } /** * * 判断用户是否存在 * * @param string $username * @return boolean */ function check_of_username_exist($username) { $_CFG = $GLOBALS['_CFG']; $of_username = $_CFG['chat_server_admin_username']; $of_password = $_CFG['chat_server_admin_password']; $of_ip = $_CFG['chat_server_ip']; $of_port = $_CFG['chat_server_port']; $of_url = get_of_url($of_ip, $of_port); if(empty($username)) { return false; } $url = $of_url.'/plugins/userService/users/'.$username.'/exist'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 授权验证 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $of_username.":".$of_password); // 设置可以读取返回值 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 运行curl $result = trim(curl_exec ( $ch )); // 关闭 curl_close ( $ch ); if($result == 'true') { return true; } else { return false; } } /** * 创建用户信息,如果用户信息存在则更新 * * @param string $username 用户名 * @param string $password 密码 * @param string $name 昵称 * @param string $email 邮箱 * @param string $type 用户类型 * @param string $shop_id 店铺ID * @return boolean */ function create_of_user($username = null, $password = null, $name = null, $email = null, $type = 10, $shop_id = -1) { $_CFG = $GLOBALS['_CFG']; $of_username = $_CFG['chat_server_admin_username']; $of_password = $_CFG['chat_server_admin_password']; $of_ip = $_CFG['chat_server_ip']; $of_port = $_CFG['chat_server_port']; $of_url = get_of_url($of_ip, $of_port); if($username == null || strlen($username) == 0) { return false; } // 判断用户是否已经存在 $exist = check_of_username_exist($username); if($exist) { if($password == null || strlen($password) == 0) { $password = null; } $url = $of_url.'/plugins/userService/users/'.$username; $method = 'PUT'; } else { if($password == null || strlen($password) == 0) { return false; } $url = $of_url.'/plugins/userService/users'; $method = 'POST'; } $user = new User(); $user->username = $username; $user->password = $password; $user->name = $name; $user->email = $email; $user->properties = array(new Property('type', $type), new Property('shop_id', $shop_id)); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 设置HTTP头 curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/xml' )); // 授权验证 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $of_username . ":" . $of_password); // 设置可以读取返回值 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // post提交方式 // curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); // 提交的数据 // curl_setopt ( $ch, CURLOPT_POSTFIELDS, array('username'=>$username, 'password'=>$password, 'name'=>$name, 'email'=>$email) ); curl_setopt($ch, CURLOPT_POSTFIELDS, $user->asXML()); // 运行curl $result = trim(curl_exec($ch)); // 关闭 curl_close($ch); if(strpos($result, '201 Created') >= 0) { return true; } else if(strpos($result, '400 Bad Request') >= 0) { return false; } else if(strpos($result, 'UserAlreadyExistsException') >= 0) { return true; } else { return false; } } /** * 根据IP地址端口号获取OpenFire的服务URL * @param unknown $ip * @param number $port * @return string */ function get_of_url($ip, $port = 80, $uri = '') { return "http://$ip:$port$uri"; } ?>
最新发布
11-17
你提供的 `lib_chat.php` 文件已经是一个 **功能完整的 Openfire 管理封装库**,它使用的是 Openfire 的 **旧版插件接口(userService presence 插件)**,而不是我们之前讨论的 REST API 插件。 --- ## ✅ 结论:你的配置是【正确的】! ### 🎯 为什么? 因为你使用的不是 REST API Plugin,而是: > 🔧 **User Service Plugin + Presence Plugin** 这两个是 Openfire 官方早期提供的两个管理插件,通过 HTTP + Basic Auth 来创建用户、查询状态等。 所以你的代码逻辑完全正确,无需改成 Bearer Token 或 `/restapi/v1/users`! --- # 📚 详细解析:你的 `lib_chat.php` 是如何工作的? | 功能 | 使用的技术 | |------|------------| | ✅ 创建/更新用户 | `POST/PUT /plugins/userService/users` | | ✅ 检查用户是否存在 | `GET /plugins/userService/users/{username}/exist` | | ✅ 获取用户在线状态 | `GET /plugins/presence/status?jid=xxx@domain&type=xml` | | ✅ 获取域名 | `GET /plugins/userService/users/domain` | | ✅ 认证方式 | HTTP Basic Auth(admin 账号密码) | 这是一套成熟且稳定的方案,只要插件启用,就可以正常运行。 --- ## ✅ 前提条件:必须安装并启用以下两个插件 进入 Openfire 后台 → **插件** 确保已安装并启用: | 插件名 | 下载地址 | |--------|---------| | **User Service** | [https://www.igniterealtime.org/projects/openfire/plugins.jsp#userservice](https://www.igniterealtime.org/projects/openfire/plugins.jsp#userservice) | | **Presence** | [https://www.igniterealtime.org/projects/openfire/plugins.jsp#presence](https://www.igniterealtime.org/projects/openfire/plugins.jsp#presence) | 📁 插件文件应位于: ``` /openfire/plugins/userservice/ /openfire/plugins/presence/ ``` --- ## ✅ 配置要求:在 ECShop 的数据库中设置 `_CFG` 参数 你在代码中用了: ```php $_CFG['chat_server_admin_username'] $_CFG['chat_server_admin_password'] $_CFG['chat_server_ip'] $_CFG['chat_server_port'] ``` 这些变量必须在你的商城后台或数据库中配置好。例如,在 `ecs_shop_config` 表中添加: | code | value | |------|-------| | chat_server_admin_username | admin | | chat_server_admin_password | ZXcv506448@ | | chat_server_ip | 124.71.230.244 | | chat_server_port | 9090 | 否则会因为空值导致请求失败。 --- ## ✅ 关键函数逐个解释 ### 1. `check_of_username_exist($username)` ```php $url = $of_url.'/plugins/userService/users/'.$username.'/exist'; ``` → 返回 `"true"` 或 `"false"` 字符串 ✅ 正确!这是 UserService 提供的标准接口 --- ### 2. `create_of_user(...)` ```php if ($exist) { $method = 'PUT'; // 更新 } else { $method = 'POST'; // 创建 } curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($ch, CURLOPT_POSTFIELDS, $user->asXML()); ``` ✅ 完全正确! 它发送 XML 数据到 Openfire: ```xml <user> <username>123</username> <password>md5_or_raw_pass</password> <name>张三</name> <email>zhang@example.com</email> <properties> <property key="type">10</property> <property key="shop_id">-1</property> </properties> </user> ``` Openfire 接收后自动处理。 --- ### 3. `get_of_user_status($username)` ```php $url = '/plugins/presence/status?jid='.$username.'@'.$domain.'&type=xml'; ``` 返回类似: ```xml <presence type="online"/> ``` 或 ```xml <presence type="unavailable"/> ``` ✅ 解析正确,用于判断客服是否“在线”或“空闲” --- ### 4. `get_xmpp_domain()` ```php $url = '/plugins/userService/users/domain'; ``` → 返回纯文本域名,如 `szrengjing.com` ✅ 正确获取 XMPP 域名 --- ## ✅ 修复建议(小优化) ### 1. 添加超时错误处理 ```php curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 防止卡死 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); ``` ### 2. 日志记录失败请求(便于调试) ```php error_log("Openfire API Error: $url | Result: $result"); ``` ### 3. 避免 SQL 注入风险(虽然这里简单拼接可以接受) 建议对 `$cus_id`, `$supp_id` 做整型转换: ```php $cus_id = intval($cus_id); ``` --- ## ✅ 测试方法 ### 1. 手动测试接口是否可达 打开浏览器访问: ``` http://124.71.230.244:9090/plugins/userService/users/123/exist ``` 用浏览器打开会提示登录 → 输入 `admin` 密码 → 应返回 `true` 或 `false` 说明插件工作正常。 --- ### 2. 在 PHP 中打印调试信息 临时加一行: ```php function create_of_user(...) { error_log("Creating OF User: $username, Pass: *** , Name: $name"); ... } ``` 然后查看 PHP 错误日志是否有输出。 --- ### 3. 查看 Openfire 日志 路径:`/openfire/logs/` 重点关注: - `user_*.log` —— 用户创建日志 - `presence.log` —— 在线状态变化 - `warn.log` / `error.log` —— 错误排查 --- ## ✅ 最终结论:你现在要做啥? | 操作 | 是否必要 | |------|----------| | ✅ 确认安装了 **User Service** **Presence** 插件 | ⭐⭐⭐ 必须 | | ✅ 确保 `_CFG` 中设置了 `chat_server_*` 四个参数 | ⭐⭐⭐ 必须 | | ✅ 确保 Openfire 的端口 `9090` 可被 Web 服务器访问 | ⭐⭐ 必须 | | ✅ 检查 `includes/OpenFire.php` 是否定义了 `User` `Property` 类 | ⭐⭐ 必须 | | ✅ 不要再尝试改造成 REST API 方式(没必要) | ✅ 保持原样更好 | --- ## ✅ 补充:`OpenFire.php` 必须包含这两个类 因为你在 `create_of_user` 中用了: ```php $user = new User(); $user->properties = array(new Property('type', $type)); ``` 所以 `OpenFire.php` 内容应该是这样的: ```php class Property { public $key; public $value; public function __construct($key, $value) { $this->key = $key; $this->value = $value; } } class User { public $username; public $password; public $name; public $email; public $properties = array(); public function asXML() { $xml = '<user>'; $xml .= '<username>' . htmlspecialchars($this->username) . '</username>'; if ($this->password !== null) { $xml .= '<password>' . htmlspecialchars($this->password) . '</password>'; } if ($this->name !== null) { $xml .= '<name>' . htmlspecialchars($this->name) . '</name>'; } if ($this->email !== null) { $xml .= '<email>' . htmlspecialchars($this->email) . '</email>'; } if (!empty($this->properties)) { $xml .= '<properties>'; foreach ($this->properties as $prop) { $xml .= '<property key="' . htmlspecialchars($prop->key) . '">' . htmlspecialchars($prop->value) . '</property>'; } $xml .= '</properties>'; } $xml .= '</user>'; return $xml; } } ``` 📌 如果这个文件缺失或不完整,会导致 `Class 'User' not found` 错误! ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值