shell bypass 403

GrazzMean Shell

Uname: Linux yisu-647059427c03a 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64
Software: nginx/1.22.1
PHP version: 7.3.31 [ PHP INFO ] PHP os: Linux
Server Ip: 103.146.158.90
Your Ip: 216.73.216.141
User: www (1000) | Group: www (1000)
Safe Mode: OFF
Disable Function:
passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv

name : c_system_api.php
<?php

/**
 * API相关函数.
 */

if (!defined('ZBP_PATH')) {
    exit('Access denied');
}

//###############################################################################################################

/**
 * API Check Enable
 */
function ApiCheckEnable()
{
    if (!$GLOBALS['option']['ZC_API_ENABLE']) {
        $GLOBALS['zbp']->ShowError($GLOBALS['lang']['error']['95'], null, null, null, 503);
    }
}

/**
 * API TokenVerify
 */
function ApiTokenVerify()
{
    global $zbp;

    if ($zbp->CheckIsLoggedin() == false) {
        // 在 API 中
        if (($auth = GetVars('HTTP_AUTHORIZATION', 'SERVER')) && (substr($auth, 0, 7) === 'Bearer ')) {
            // 获取 Authorization 头
            $api_token = substr($auth, 7);
        } else {
            // 获取(POST 或 GET 中的)请求参数
            $api_token = GetVars('token');
        }

        $user = $zbp->VerifyAPIToken($api_token);

        if ($user != null) {
            define('ZBP_IN_API_VERIFYBYTOKEN', true);
            $zbp->user = $user;
            $zbp->islogin = true;
            return true;
        }
    }
}

/**
 * API 显示报错函数
 */
function ApiDebugDisplay($error)
{
    $GLOBALS['hooks']['Filter_Plugin_Debug_Display']['ApiDebugDisplay'] = PLUGIN_EXITSIGNAL_RETURN;
    ApiResponse(null, $error);
    //die;
}

/**
 * API ShowError函数
 */
function ApiShowError($errorCode, $errorText, $file = null, $line = null, $moreinfo = array(), $httpcode = 200)
{
    $GLOBALS['hooks']['Filter_Plugin_Zbp_ShowError']['ApiShowError'] = PLUGIN_EXITSIGNAL_RETURN;
    //如果是$errorCode == 2就是http 404
    if ($errorCode == 2 && $httpcode == 200) {
        $httpcode = 404;
    }
    $zbe = ZBlogException::GetInstance();
    $zbe->ParseError($errorCode, $errorText, $file, $line);
    ApiResponse(null, $zbe, $httpcode, $errorText);
    die;
}

/**
 * 载入 API Mods.
 */
function ApiLoadMods(&$mods)
{
    global $zbp;

    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Extend_Mods'] as $fpname => &$fpsignal) {
        $add_mods = $fpname();

        if (!is_array($add_mods)) {
            continue;
        }

        foreach ($add_mods as $mod => $file) {
            $mod = strtolower($mod);
            if (array_key_exists($mod, $mods)) {
                continue;
            }

            $mods[$mod] = $file;
        }
    }

    // 从 zb_system/api/ 目录中载入 mods
    foreach (GetFilesInDir(ZBP_PATH . 'zb_system/api/', 'php') as $mod => $file) {
        $mods[$mod] = $file;
    }
    return true;
}

/**
 * 移除指定的 API Mods.
 */
function ApiRemoveMods($name)
{
    global $mods;
    unset($mods[$name]);
    return $mods;
}

/**
 * 检查API Mods的白名单和黑名单.
 * $mods_allow白名单请慎用,启用白名单后,不在白名单的mod都将被拒绝
 * 如果只想关闭某些模块只需要对$mods_disallow黑名单进行添加
 */
function ApiCheckMods(&$mods_allow, &$mods_disallow)
{
    global $zbp, $mod, $act;

    //接口及对$mods_allow, $mods_disallow的添加
    foreach ($GLOBALS['hooks']['Filter_Plugin_API_CheckMods'] as $fpname => &$fpsignal) {
        $new_allow = $new_disallow = array();
        $fpname($new_allow, $new_disallow);

        $mods_allow = array_merge($mods_allow, $new_allow);
        $mods_disallow = array_merge($mods_disallow, $new_disallow);
    }

    $b = false;

    foreach ($mods_allow as $array) {
        if (!empty($array) && is_array($array)) {
            foreach ($array as $k => $v) {
                $list_mod = $k;
                $list_act = $v;
                if (is_integer($k)) {
                    $list_mod = $v;
                    $list_act = '';
                }
                if ($mod == $list_mod && ($list_act == '' || $act == $list_act)) {
                    $b = true;
                    break;
                }
            }
        }
    }

    if (!empty($mods_allow) && $b == false) {
        $zbp->ShowError(96, __FILE__, __LINE__);
    }

    $b = true;

    foreach ($mods_disallow as $array) {
        if (!empty($array) && is_array($array)) {
            foreach ($array as $k => $v) {
                $list_mod = $k;
                $list_act = $v;
                if (is_integer($k)) {
                    $list_mod = $v;
                    $list_act = '';
                }
                if ($mod == $list_mod && ($list_act == '' || $act == $list_act)) {
                    $b = false;
                    break;
                }
            }
        }
    }

    if (!empty($mods_disallow) && $b == false) {
        $zbp->ShowError(96, __FILE__, __LINE__);
    }
    return true;
}

/**
 * API 响应.
 *
 * @param array|null $data
 * @param ZBlogException|null $error
 * @param int $code
 * @param string|null $message
 */
function ApiResponse($data = null, $error = null, $code = 200, $message = null)
{
    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Pre_Response'] as $fpname => &$fpsignal) {
        $fpname($data, $error, $code, $message);
    }

    if ($error !== null) {
        if (is_object($error)) {
            $error_info = array(
                'code' => method_exists($error, 'getCode') ? $error->getCode() : $error->code,
                'type' => property_exists($error, 'type') ? $error->type : $error->getCode(),
                'message' => method_exists($error, 'getMessage') ? $error->getMessage() : $error->message,
            );

            if ($GLOBALS['zbp']->isdebug) {
                $error_info['message_full'] = property_exists($error, 'messagefull') ? $error->messagefull : '';
                $error_info['file'] = method_exists($error, 'getFile') ? $error->getFile() : $error->file;
                $error_info['line'] = method_exists($error, 'getLine') ? $error->getLine() : $error->line;
            }

            if ($code === 200) {
                $code = 500;
            }
            if (empty($message)) {
                $message = 'System error: ' . $error_info['message'];
            }
        } else {
            $error_info = $error;
        }
    } else {
        $error_info = null;
    }

    $response = array(
        'code' => $code,
        'message' => !empty($message) ? $message : 'OK',
        'data' => $data,
        'error' => $error_info,
    );

    // 显示 Runtime 调试信息
    if (!defined('ZBP_API_IN_TEST') && $GLOBALS['option']['ZC_RUNINFO_DISPLAY']) {
        $runtime = RunTime(false);
        unset($runtime['error_detail']);
        $response['runtime'] = $runtime;
    }

    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Response'] as $fpname => &$fpsignal) {
        $fpname($response);
    }

    if (!defined('ZBP_API_IN_TEST')) {
        @ob_clean();
        if (!headers_sent()) {
            header('Content-Type: application/json; charset=utf-8');
        }
    }

    if (is_object($error) && $code >= 500) {
        SetHttpStatusCode($code);
    }

    $r = JsonEncode($response);

    echo $r;

    if (empty($error) && $code !== 200) {
        // 如果 code 不为 200,又不是系统抛出的错误,再来抛出一个 Exception,适配 phpunit
        ZBlogException::SuspendErrorHook();
        throw new Exception($message, $code);
    }

    return $r;
}

/**
 * API 原始数据输出.
 *
 * @param string|null $raw
 * @param string $raw_type
 * @return string|null
 */
function ApiResponseRaw($raw, $raw_type = 'application/json')
{
    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Pre_Response_Raw'] as $fpname => &$fpsignal) {
        $fpname($raw, $raw_type);
    }

    if (!defined('ZBP_API_IN_TEST')) {
        ob_end_clean();
        if (!headers_sent()) {
            header('Content-Type: ' . $raw_type . '; charset=utf-8');
        }
    }

    echo $raw;
    return $raw;
}

/**
 * API 检测权限.
 *
 * @param bool $loginRequire
 * @param string $action
 * @param bool $throwException
 */
function ApiCheckAuth($loginRequire = false, $action = 'view', $throwException = true)
{
    // 登录认证
    if ($loginRequire && !$GLOBALS['zbp']->user->ID) {
        if ($throwException == true) {
            $GLOBALS['zbp']->ShowError($GLOBALS['lang']['error']['6'], __FILE__, __LINE__, null, 401);
        } else {
            return false;
        }
    }

    // 权限认证
    if (!$GLOBALS['zbp']->CheckRights($action)) {
        if ($throwException == true) {
            $GLOBALS['zbp']->ShowError($GLOBALS['lang']['error']['6'], __FILE__, __LINE__, null, 403);
        } else {
            return false;
        }
    }

    return true;
}

/**
 * API 获取指定属性的Array
 *
 * @param object $object
 * @param array $other_props 追加的属性
 * @param array $remove_props 要删除的属性
 * @param array $with_relations 要追加的关联对象
 */
function ApiGetObjectArray($object, $other_props = array(), $remove_props = array(), $with_relations = array())
{
    $array = $object->GetData();
    unset($array['Meta']);

    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Get_Object_Array'] as $fpname => &$fpsignal) {
        $fpname($object, $array, $other_props, $remove_props, $with_relations);
    }

    foreach ($other_props as $key => $value) {
        $array[$value] = $object->$value;
    }
    switch (get_class($object)) {
        case 'Member':
            $remove_props[] = 'Guid';
            $remove_props[] = 'Password';
            $remove_props[] = 'IP';
            break;
        default:
            # code...
            break;
    }

    foreach ($remove_props as $key => $value) {
        unset($array[$value]);
    }
    foreach ($with_relations as $relation => $info) {
        $relation_obj = $object->$relation;
        if (is_array($relation_obj)) {
            $array[$relation] = ApiGetObjectArrayList(
                $relation_obj,
                isset($info['other_props']) ? $info['other_props'] : array(),
                isset($info['remove_props']) ? $info['remove_props'] : array(),
                isset($info['with_relations']) ? $info['with_relations'] : array()
            );
        } else {
            $array[$relation] = ApiGetObjectArray(
                $relation_obj,
                isset($info['other_props']) ? $info['other_props'] : array(),
                isset($info['remove_props']) ? $info['remove_props'] : array(),
                isset($info['with_relations']) ? $info['with_relations'] : array()
            );
        }
    }
    return $array;
}

/**
 * API 获取指定属性的Array 列表.
 *
 * @param array $list
 * @param array $other_props 追加的属性
 * @param array $remove_props 要删除的属性
 * @param array $with_relations 要追加的关联对象
 */
function ApiGetObjectArrayList($list, $other_props = array(), $remove_props = array(), $with_relations = array())
{
    global $zbp;

    if (array_key_exists('Author', $with_relations)) {
        $zbp->LoadMembersInList($list);
    }

    foreach ($list as &$object) {
        $object = ApiGetObjectArray($object, $other_props, $remove_props, $with_relations);
    }

    return $list;
}

/**
 * API 获取约束过滤条件
 * 将请求中的参数转换为 SQL LIMIT/ORDER 查询条件.
 *
 * @param int $limitDefault 默认记录数
 * @param array $sortableColumns sortby 对应的模块数据表中支持排序的属性
 * @param int $max_count_perpage 每页最多条数
 * @return array
 */
function ApiGetRequestFilter($limitDefault = null, $sortableColumns = array(), $max_count_perpage = null)
{
    global $zbp;

    $condition = array(
        'limit' => array(0, $limitDefault),
        'order' => null,
        'option' => null,
    );
    $sortBy = (string) GetVars('sortby');
    $order = strtoupper((string) GetVars('order'));
    $pageNow = (int) GetVars('page');
    $perPage = (int) GetVars('perpage');

    $max_count_perpage = ($max_count_perpage !== null) ? $max_count_perpage : $zbp->apiMaxCountPerPage;

    if (($perPage > (int) $max_count_perpage) || ((int) $perPage <= 0)) {
        if ($limitDefault !== null) {
            $perPage = $limitDefault;
        } else {
            $perPage = 10;
        }
    }

    // 排序顺序
    if (!empty($sortBy) && isset($sortableColumns[$sortBy])) {
        $condition['order'] = array($sortableColumns[$sortBy] => 'ASC');
    }
    if (!is_null($condition['order']) && $order == 'DESC') {
        $condition['order'][$sortableColumns[$sortBy]] = $order;
    }

    if ($perPage) {
        $p = new Pagebar(null, false); // 第一个参数为 null,不需要分页 Url 处理
        $p->PageNow = (int) $pageNow == 0 ? 1 : (int) $pageNow;
        $p->PageCount = $perPage;
        $limit = array(($p->PageNow - 1) * $p->PageCount, $p->PageCount);
        $op = array('pagebar' => &$p);

        $condition['limit'] = $limit;
        $condition['option'] = $op;
    }

    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Get_Request_Filter'] as $fpname => &$fpsignal) {
        $fpname($condition);
    }
    return $condition;
}

/**
 * 获取分页信息.
 *
 * @param array|null $option
 * @return array
 */
function ApiGetPagebarInfo($option = null)
{
    if ($option === null) {
        // 用 stdClass 而不用 array() ,为了为空时 json 显示 {} 而不是 []
        return new stdClass;
    }

    $info = array();
    $pagebar = &$option['pagebar'];

    //$info['Count'] = $pagebar->Count;
    $info['AllCount'] = $pagebar->AllCount;
    $info['CurrentCount'] = $pagebar->CurrentCount;
    //$info['PageBarCount'] = $pagebar->PageBarCount;
    //$info['PageCount'] = $pagebar->PageCount;
    $info['PerPageCount'] = $pagebar->PerPageCount;
    $info['PageAll'] = $pagebar->PageAll;
    $info['PageNow'] = $pagebar->PageNow;
    $info['PageCurrent'] = $pagebar->PageCurrent;
    $info['PageFirst'] = $pagebar->PageFirst;
    $info['PageLast'] = $pagebar->PageLast;
    $info['PagePrevious'] = $pagebar->PagePrevious;
    $info['PageNext'] = $pagebar->PageNext;

    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Get_Pagination_Info'] as $fpname => &$fpsignal) {
        $fpname($info, $pagebar);
    }
    return $info;
}

/**
 * API 获取及过滤关联对象请求.
 *
 * @param array $info 传入到 ApiGetObjectArray 的关联信息
 * @return array
 */
function ApiGetAndFilterRelationQuery($info)
{
    $relations_req = trim(GetVars('with_relations'));

    if (empty($relations_req)) {
        return array();
    }

    $relations = explode(',', $relations_req);
    $ret_relations = array();

    foreach ($relations as $relation) {
        $relation = trim($relation);
        if (array_key_exists($relation, $info)) {
            $ret_relations[$relation] = $info[$relation];
        }
    }

    return $ret_relations;
}

/**
 * API 传统登录时的POST方式下的 CSRF 验证.
 *
 * @param boolean $force_check 是否强制检查
 */
function ApiVerifyCSRF($force_check = false)
{
    global $zbp, $mod, $act;

    if (!defined('ZBP_IN_API_VERIFYBYTOKEN')) {
        $csrf_token = GetVars('csrf_token');

        if (!$force_check) {
            if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
                return;
            }

            if (php_sapi_name() == 'cli') {
                return;
            }

            // 不需要校验 CSRF 的 API
            $skip_acts = array(
                array('mod' => 'member', 'act' => 'login'),
                array('mod' => 'comment', 'act' => 'post')
            );

            foreach ($GLOBALS['hooks']['Filter_Plugin_API_VerifyCSRF_Skip'] as $fpname => &$fpsignal) {
                $fpname($skip_acts);
            }

            foreach ($skip_acts as $api_act) {
                if (!isset($api_act['mod'])) {
                    continue;
                }
                if (!isset($api_act['act']) && $api_act['mod'] == $mod) {
                    // 如果只定义了 mod 并匹配,放行(比如说定义了 mod=member ,那 member mod 下所有 POST 都放行)
                    return;
                }
                if ($api_act['mod'] == $mod && $api_act['act'] == $act) {
                    // 匹配了 mod 和 act,放行
                    return;
                }
            }
        }

        if (!$zbp->VerifyCSRFToken($csrf_token, 'api')) {
            $GLOBALS['zbp']->ShowError($GLOBALS['lang']['error']['5'], __FILE__, __LINE__, null, 419);
        }

        return true;
    }
}

/**
 * API 载入 POST 数据(前端 JSON).
 */
function ApiLoadPostData()
{
    $input = file_get_contents('php://input');
    if ($input && ($data = json_decode($input, true)) && is_array($data)) {
        $_POST = array_merge($data, $_POST);
    }
}

/**
 * API 派发.
 *
 * @param array       $mods
 * @param string      $mod
 * @param string|null $act
 */
function ApiDispatch($mods, $mod, $act)
{
    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Dispatch'] as $fpname => &$fpsignal) {
        $fpname($mods, $mod, $act);
    }

    if (empty($act)) {
        $act = 'get';
    }

    if (isset($mods[$mod]) && file_exists($mod_file = $mods[$mod])) {
        include_once $mod_file;
        $func = 'api_' . $mod . '_' . $act;
        if (function_exists($func)) {
            $result = call_user_func($func);

            ApiResultData($result);

            if (isset($result['raw'])) {
                return ApiResponseRaw($result['raw'], isset($result['raw-type']) ? $result['raw-type'] : 'application/json');
            }
            if (isset($result['json'])) {
                return ApiResponseRaw(JsonEncode($result['json']));
            }

            return ApiResponse(
                isset($result['data']) ? $result['data'] : null,
                isset($result['error']) ? $result['error'] : null,
                isset($result['code']) ? $result['code'] : 200,
                isset($result['message']) ? $result['message'] : 'OK'
            );
        }
    }

    $GLOBALS['zbp']->ShowError($GLOBALS['lang']['error']['96'], __FILE__, __LINE__, null, 404);
}

/**
 * API 地址生成.
 *
 * @param string $mod
 * @param string $act
 * @param array  $query
 *
 * @return string
 */
function ApiUrlGenerate($mod, $act = 'get', $query = array())
{
    global $zbp;

    $mod = strtolower($mod);
    $act = strtolower($act);

    if (count($query) > 0) {
        $query_string = '&' . http_build_query($query);
    } else {
        $query_string = '';
    }

    return $zbp->host . 'zb_system/api.php?mod=' . $mod . '&act=' . $act . $query_string;
}

/**
 * API 开启检测限流.
 */
function ApiCheckLimit()
{
    if ($GLOBALS['option']['ZC_API_THROTTLE_ENABLE']) {
        ApiThrottle('default', $GLOBALS['option']['ZC_API_THROTTLE_MAX_REQS_PER_MIN'] ? $GLOBALS['option']['ZC_API_THROTTLE_MAX_REQS_PER_MIN'] : 60);
    }
}

/**
 * API 限流.
 *
 * @param string  $name
 * @param integer $max_reqs
 * @param integer $period
 */
function ApiThrottle($name = 'default', $max_reqs = 60, $period = 60)
{
    global $zbpcache;

    if (!isset($zbpcache)) {
        return false;
    } else {
        $zbpcache->Connect();
    }

    $user_id = md5(GetGuestIP());

    $cache_key = "api-throttle:$name:$user_id";
    $cached_value = $zbpcache->Get($cache_key);
    $cached_req = json_decode($cached_value, true);
    if (!$cached_value || !$cached_req || (time() >= $cached_req['expire_time'])) {
        $cached_req = array('hits' => 0, 'expire_time' => (time() + $period));
    }

    if ($cached_req['hits'] >= $max_reqs) {
        $GLOBALS['zbp']->ShowError('Too many requests.', __FILE__, __LINE__, null, 429);
    }

    $cached_req['hits']++;
    $zbpcache->Set($cache_key, json_encode($cached_req), ($cached_req['expire_time'] - time()));

    return true;
}

/**
 * API 返回数据处理函数
 */
function ApiResultData(&$result)
{
    global $mod, $act;

    foreach ($GLOBALS['hooks']['Filter_Plugin_API_Result_Data'] as $fpname => &$fpsignal) {
        $fpname($result, $mod, $act);
    }
}

/**
 * API 检查Http Method
 */
function ApiCheckHttpMethod($allow_method = 'GET|POST|PUT|DELETE')
{
    if (isset($_SERVER['REQUEST_METHOD']) && stripos($allow_method, $_SERVER['REQUEST_METHOD']) === false) {
        $GLOBALS['zbp']->ShowError($GLOBALS['lang']['error']['5'], __FILE__, __LINE__, null, 405);
    }
}
© 2026 GrazzMean