Talos Vulnerability Report

TALOS-2023-1882

WWBN AVideo navbarMenuAndLogo.php user name cross-site scripting (XSS) vulnerability

January 10, 2024
CVE Number

CVE-2023-48730

SUMMARY

A cross-site scripting (xss) vulnerability exists in the navbarMenuAndLogo.php user name functionality of WWBN AVideo dev master commit 15fed957fb. A specially crafted HTTP request can lead to arbitrary Javascript execution. An attacker can get a user to visit a webpage to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

WWBN AVideo dev master commit 15fed957fb

PRODUCT URLS

AVideo - https://github.com/WWBN/AVideo

CVSSv3 SCORE

8.5 - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H

CWE

CWE-79 - Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)

DETAILS

AVideo is a web application, mostly written in PHP, that can be used to create an audio/video sharing website. It allows users to import videos from various sources, encode and share them in various ways. Users can sign up to the website in order to share videos, while viewers have anonymous access to the publicly-available contents. The platform provides plugins for features like live streaming, skins, YouTube uploads and more.

The PHP file view/include/navbarMenuAndLogo.php is vulnerable to an XSS issue due to improper sanitization of the user name.

    <?php
[1] if (!empty($advancedCustomUser->keepViewerOnChannel) && !empty($_SESSION['channelName'])) {
        $user = User::getChannelOwner($_SESSION['channelName']);
        ?>
        <li>
            <a class="navbar-brand"  href="#" onclick="avideoModalIframeFull('<?php echo User::getChannelLinkFromChannelName($_SESSION['channelName']); ?>');
                        return false;" >
[2]             <img src="<?php echo User::getPhoto($user['id']); ?>" alt="<?php echo User::getNameIdentificationById($user['id']); ?>"
                     class="img img-circle " style="height: 33px; width: 33px; margin-right: 15px;">
            </a>
        </li>
        <?php
    }

At [1], if keepViewerOnChannel and channelName are set, the user name for the current channelName is echoed at [2], using User::getNameIdentificationById:

    public static function getNameIdentificationById($id = "")
    {
        if (!empty($id)) {
            $user = new User($id);
            return $user->getNameIdentificationBd();
        }
        return __("Unknown User");
    }

    public function getNameIdentificationBd()
    {
        global $advancedCustomUser;
[3]     if (!empty($this->name) && empty($advancedCustomUser->doNotIdentifyByName)) {
            return $this->name;
        }
        if (!empty($this->email) && empty($advancedCustomUser->doNotIdentifyByEmail)) {
            return $this->email;
        }
        if (!empty($this->user) && empty($advancedCustomUser->doNotIdentifyByUserName)) {
            return $this->user;
        }
        if (!empty($this->channelName)) {
            return $this->channelName;
        }
        return __("Unknown User");
    }

Essentially, unless doNotIdentifyByName is set (it’s unset by default), the user name will be returned [3], which corresponds to the name field of the User object. The name field is originally set using setName:

public function setName($name)
{
    $this->name = strip_tags($name);
}

strip_tags is used to remove tags, which could be used to inject arbitrary JavaScript. However, since the user name is echoed inside an <img> tag, there’s no need to inject tags in order to execute arbitrary JavaScript.
For example, a privileged attacker could change their user name to someuser" onload="alert(1), which would execute alert(1) without using tags and thus bypass the strip_tag in setName.

To exploit this, an attacker can trick the administrator into browsing any page that includes navbarMenuAndLogo.php and sets the channelName field in session. An example of such page is view/modeYoutube.php, which includes view/include/navbar.php, which in turn includes view/include/navbarMenuAndLogo.php.

$_SESSION['channelName'] is set in view/include/navbar.php [4]:

    if (!empty($advancedCustomUser->keepViewerOnChannel)) {
        if (!empty($_GET['channelName'])) {
            _session_start();
[4]         $_SESSION['channelName'] = $_GET['channelName'];
        }
        if (!empty($_GET['leaveChannel'])) {
            _session_start();
            unset($_SESSION['channelName']);
        }
    }

Note that $advancedCustomUser->keepViewerOnChannel needs to be set, so exploitation of this vulnerability requires the non-default setting keepViewerOnChannel to be set in the CustomizeUser plugin.

Exploitation leads to a straightforward stored cross-site scripting issue (XSS) when visiting any page in the site that includes the navbar (including the main application page). This can be used by an attacker, in the worst case, to take over an administrator account, for example by tricking an administrator into visiting a specially crafted link.

Exploit Proof of Concept

This proof-of-concept calls alert(1):

$ curl -k $'https://localhost/objects/userUpdate.json.php' \
       -H 'Cookie: 84b11d010cced71edffee7aa62c4eda0=bir8alr05n4s0tjaqninjjnr66' \
       -H 'Referer: https://localhost/user' \
       --data-raw $'user=user1&pass=&email=user1@localhost&phone=&name=someuser" onload="alert(1)&about=&channelName=User1&donationLink=&analyticsCode='
{"error":false,"msg":"","users_id":2}

Trick the administrator into visiting the view/modeYoutube.php page by clicking the following URL, which will set the channelName in session:

https://localhost/view/modeYoutube.php?channelName=User1

Make sure to use the user channel name, in this case “User1”.

At this point, visiting any page (simply visiting https://localhost is enough) will lead to executing alert(1).

TIMELINE

2023-12-14 - Vendor Disclosure
2023-12-15 - Vendor Patch Release
2024-01-10 - Public Release

Credit

Discovered by Claudio Bozzato of Cisco Talos.