HEX
Server: nginx/1.18.0
System: Linux iZj6c1ieg2jrpk1z5tzi19Z 6.3.9-1.el7.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jun 21 22:18:40 EDT 2023 x86_64
User: www (1001)
PHP: 8.2.4
Disabled: 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
Upload Files
File: /www/wwwroot/www.cytocare.cn/wp-content/plugins/vaptcha-sms/lib/VaptchaSms.class.php
<?php
if ( !defined('ABSPATH') ) {
   exit('No direct script access allowed');
}
//session_start();
class Vaptcha
{
    private $vid;
    private $key;
    // private $publicKey;
    private $lastCheckdownTime = 0;
    private $isDown = false;
    private $config;

    //宕机模式通过签证
    private static $passedSignatures = array();

    public function __construct($vid, $key)
    {
        $this->vid = $vid;
        $this->key = $key;
        $this->config = include(dirname(__FILE__).'/config.php');
    }

    /**
     * 获取流水号
     *
     * @param string $sceneId 场景id
     * @return void
     */
    public function getChallenge($sceneId = 0) 
    {
        $url = $this->config['API_URL'].$this->config['GET_knock_URL'];
        $now = $this->getCurrentTime();
        $query = "id=$this->vid&scene=$sceneId&time=$now&version=".$this->config['VERSION'].'&sdklang='.$this->config['SDK_LANG'];
        $signature = $this->HMACSHA1($this->key, $query);
        if (!$this->isDown)
        {
            $knock = self::readContentFormGet("$url?$query&signature=$signature");
            if ($knock === $this->config['REQUEST_UESD_UP']) {
                self::$passedSignatures = array();
                return $this->getDownTimeCaptcha();
            }
            if (empty($knock)) {
                if ($this->getIsDwon()) {
                    $this->lastCheckdownTime = $now;
                    $this->isDown = true;
                    self::$passedSignatures = array();
                }
                return $this->getDownTimeCaptcha();
            } 
            return json_encode(array(
                "vid" =>  $this->vid,
                "knock" => $knock
            ));
        } else {
        if ($now - $this->lastCheckdownTime > $this->config['DOWNTIME_CHECK_TIME']) {
                $this->lastCheckdownTime = $now;
                $knock = self::readContentFormGet("$url?$query&signature=$signature");
                if ($knock && $knock != $this->config['REQUEST_UESD_UP']){
                    $this->isDown = false;
                    self::$passedSignatures = array();
                    return json_encode(array(
                        "vid" =>  $this->vid,
                        "knock" => $knock
                    ));
                }
            }
            return $this->getDowniTimeCaptcha();
        }
    }

    /**
     * 二次验证
     *
     * @param [string] $knock 流水号
     * @param [sring] $token 验证信息
     * @param string $sceneId 场景ID 不填则为默认场景
     * @return void
     */
    public function validate($server,$knock, $token, $sceneId = 0)
    {
        $str = 'ffline-';
        if (strpos($token, $str, 0))
            return $this->downTimeValidate($token);
        else
            return $this->normalValidate($server,$knock, $token, $sceneId);
    }

    /**
     * @param $smsid
     * @param $smskey
     * @param $phone
     * @param $vcode
     * @return string
     * 验证短信验证码
     */
    public function validateSmsCode($smsid, $smskey, $phone, $vcode ){
        if( !self::isPhoneNumber($phone) || empty($vcode) ){
            return '请填写正确的手机号和验证码。';
        }
        $post_data = array(
            'smsid' => $smsid,
            'smskey' => $smskey,
            'phone' => $phone,
            'vcode' => $vcode,
        );

        $url = 'https://sms.vaptcha.com/verify';
        $args = array(
            'body'        => $post_data,
            'timeout'     => '5',
            'redirection' => '5',
            'httpversion' => '1.0',
            'blocking'    => true,
            'headers'     => array("Content-type:application/json;charset='utf-8'",
                "Accept:application/json"),
        );

        $response = wp_remote_post($url,$args);
        $data =  json_decode($response['body']);
        return $data;
    }


    public function getChannelData()
    {
        $url = $this->config['Channel_DownTime'] . $this->vid;
        $response = wp_remote_get($url);
        $res = $response['body'];
        $data = str_replace('static(', '',  $res);
        $data = str_replace(')', '', $data);
        $data = json_decode($data, true);
        return $data;
    }

    private function getPublicKey()
    {
        return self::readContentFormGet($this->config['Channel_DownTime']);
    }

    private function getIsDwon()
    {
        // return !!self::readContentFormGet($this->config['DOWNTIME_URL']) == 'true';
        $channel = self::getChannelData();
        if($channel['state']== 1) {self::$isDown = false;return true;}
        if($channel['offline']== 1) {self::$isDown = true;return true;}
        return false;
    }

    public function downTime($data, $callback, $v=null, $knock=null)
    {
        // return json_encode($data);
        if (!$data)
            return json_encode(array("error" => "params error"));
        $datas = explode(',', $data);
        switch ($datas[0]) {
            case 'get':
                return $this->getDownTimeCaptcha($callback);
            case 'request':
                return $this->getDownTimeCaptcha();
            case 'getsignature':
                if (count($datas) < 2) {
                    return array("error" => "params error");
                } else {
                    $time = (int) $datas[1];
                    if ((bool) $time) {
                        return $this->getSignature($time);
                    } else {
                        return array("error" => "params error");
                    }

                }
            case 'verify':
                if ($v == null) {
                    return array("error" => "params error");
                } else {
                    return $this->downTimeCheck($callback ,$v, $knock);
                }
            default:
                return array("error" => "parms error");
        }
    }

    private function getCurrentTime() {
        return number_format(floor(microtime(true) * 1000), 0, '', '');
    }


    private function getSignature($time)
    {
        $now = $this->getCurrentTime();
        if (($now - $time) > $this->config['REQUEST_ABATE_TIME'])
            return null;
        $signature = md5($now.$this->key);
        return json_encode(array(
            'time' => $now,
            'signature' => $signature
        ));
    }

    public static function set($key, $value, $expire = 600)
    {
        $data = sanitize_text_field($_SESSION[$key]);
        return $_SESSION[$key] = array(
            'value' => $value,
            'create' => time(),
            'readcount' => 0,
            'expire' => $data['expire'] ? $data['expire'] : $expire,
        );
    }

    public static function get($key, $default = null)
    {
        $data = sanitize_text_field($_SESSION[$key]);
        $now = time();
        if (!$data) {
            return $default;
        } else if ($now - $data['create'] > $data['expire']) {
            return $default;
        } else {
            $_SESSION[$key]['readcount']++;
            return $data['value'];
        }
    }

    public function create_uuid($prefix = ""){
        $str = md5(uniqid(mt_rand(), true));   
        $uuid  = substr($str,0,8) . '-';   
        $uuid .= substr($str,8,4) . '-';   
        $uuid .= substr($str,12,4) . '-';   
        $uuid .= substr($str,16,4) . '-';   
        $uuid .= substr($str,20,12);   
        return $prefix . $uuid;
    }

    /**
     * 宕机模式验证
     *
     * @param [int] $time1
     * @param [int] $time2
     * @param [string] $signature
     * @param [string] $captcha
     * @return void
     */
    private function downTimeCheck($callback, $v, $knock)
    {
        $data = $this->getChannelData();
        $dtkey = $data['offline_key'];
        $imgs = $this->get($knock);
        unset($_SESSION[$knock]);
        $address = md5($v.$imgs);
        $url = DOWNTIME_URL.$dtkey.'/'.$address;
        $response = wp_remote_get($url);
        $res = $response['body'];
        $httpCode = $response['response']['code'];
        if($httpCode == 200) {
            $token = 'offline-'.$knock.'-'.$this->create_uuid().'-'.$this->getCurrentTime();;
            $this->set($token, $this->getCurrentTime());
            return $callback.'('.json_encode(array(
                "code" => '0103',
                "msg" => "",
                "token" => $token
            )).')';
        }
        else {
            return $callback.'('.json_encode(array(
                "code" => '0104',
                "msg" => "0104",
                "token" => "",
            )).')';
        }
        
    }

    private function normalValidate($server,$knock, $token, $sceneId)
    {
//        return false;

        if (!$token)
            return false;
        $ip = $this->getClientIp();
        $query = "id=$this->vid&scene=$sceneId&secretkey=$this->key&token=$token&ip=$ip";
        $url = $server.'?' . $query;
        $now = $this->getCurrentTime();
        $response = json_decode(self::postValidate($url, $query));
        return $response->success == 1 ? true : false;
    }

    public function getClientIp()
    {
        if (getenv('HTTP_X_FORWARDED_FOR')) {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
            $ips = explode(',', $ip);
            $ip = $ips[0];
        } else if (getenv('HTTP_X_REAL_IP')) {
            $ip = getenv('HTTP_X_REAL_IP');
        } else if (getenv('REMOTE_ADDR')) {
            $ip = getenv('REMOTE_ADDR');
        } else {
            $ip = '127.0.0.1';
        }

        return $ip;
    }

    private function downTimeValidate($token)
    {
        $strs = explode('-', $token);
        if (count($strs) < 2) {
            return false;
        } else {
            $time = (int) $strs[count($strs) - 1];
            // $signature = $strs[1];
            $storageTIme = $this->get($token);
            $now = $this->getCurrentTime();
            // return $time.'  '.($strs[count($strs)]);
            if ($now - $time > $this->config['VALIDATE_PASS_TIME']) {
                return false;
            } else {
                if ($storageTIme && $storageTIme==$time) {
                    return true;
                } else {
                    return false;
                }

            }
        }
    }

    private function getDownTimeCaptcha($callback = null)
    {
        $time = $this->getCurrentTime();
        $md5 = md5($time . $this->key);
        $captcha = substr($md5, 0, 3);
        $data = $this->getChannelData();
        $knock = md5($captcha . $$time . $data['offline_key']);
        $ul = $this->getImgUrl();
        $url = md5($data['offline_key'] . $ul);
        $this->set($knock, $url);
        return $callback===null?array(
            "time" => $time,
            "url" => $url,
        ): $callback.'('.json_encode(array(
            "time" => $time,
            "imgid" => $url,
            "code" => '0103',
            "knock" => $knock,
            "msg" => "",
        )).')';
    }

    private function getImgUrl()
    {
        $str = '0123456789abcdef';
        $data = '';
        for ($i=0; $i < 4; $i++) { 
            # code...
            $data = $data.$str[rand(0, 15)];
        }
        return $data;
    }

    private static function postValidate($url, $data)
    {
         $response = wp_remote_post( $url, array(
            'body' => $data
        ));
        return $response['body'];
    }

    private static function readContentFormGet($url)
    {
        $response = wp_remote_get($url);
        return $response['body'];
    }

    private function HMACSHA1($key, $str)
    {
        $signature = "";  
        if (function_exists('hash_hmac')) {
            $signature = hash_hmac("sha1", $str, $key, true);
        } else {
            $blocksize = 64;  
            $hashfunc = 'sha1';  
            if (strlen($key) > $blocksize) {  
                $key = pack('H*', $hashfunc($key));  
            }  
            $key = str_pad($key, $blocksize, chr(0x00));  
            $ipad = str_repeat(chr(0x36), $blocksize);  
            $opad = str_repeat(chr(0x5c), $blocksize);  
            $signature = pack(  
                    'H*', $hashfunc(  
                            ($key ^ $opad) . pack(  
                                    'H*', $hashfunc(  
                                            ($key ^ $ipad) . $str  
                                    )  
                            )  
                    )  
            );  
        }  
        $signature = str_replace(array('/', '+', '='), '', base64_encode($signature));
        return $signature;  
    }
    /**
     * 验证是否为手机号
     * @param $phone
     *
     * @return bool
     */
    public static function isPhoneNumber($phone)
    {
        return preg_match("/^1[3-9]\d{9}$/", $phone) === 1;
    }
}