CVE-2022-32768,CVE-2022-32769
Multiple authentication bypass vulnerabilities exist in the objects id handling functionality of WWBN AVideo 11.6 and dev master commit 3f7c0364. A specially-crafted HTTP request by an authenticated user can lead to unauthorized access and takeover of resources. An attacker can send an HTTP request to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
WWBN AVideo 11.6
WWBN AVideo dev master commit 3f7c0364
AVideo - https://github.com/WWBN/AVideo
4.8 - CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L
CWE-862 - Missing Authorization
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.
To serve most types of requests that deal with objects modification, AVideo uses the id
parameter to identify the object that needs to be modified. In some instances, AVideo does not check if the object belongs to the user that is requesting the modification, leading to integrity issues in the platform. An attacker can exploit this issue to take over live schedules and take over playlists owned by other users. The issues described in this advisory are found in plugins that are disabled by default.
AVideo offers a plugin to stream RTMP videos over the network, called “Live”. By default this is disabled; an administrator can enable it in the plugin settings. An authenticated user needs video stream permission to trigger this vulnerability.
To add a live schedule, a request to plugin/Live/view/Live_schedule/add.json.php
can be made:
...
// [1]
if (!User::canStream()) {
$obj->msg = "You cant do this";
die(json_encode($obj));
}
...
// [2]
$o = new Live_schedule(@$_POST['id']);
$o->setTitle($_POST['title']);
$o->setDescription($_POST['description']);
//$o->setKey($_POST['key']);
$o->setUsers_id(User::getId()); // [3]
$o->setLive_servers_id($_POST['live_servers_id']);
$o->setScheduled_time($_POST['scheduled_time']);
$o->setStatus($_POST['status']);
$o->setScheduled_password($_POST['scheduled_password']);
//$o->setPoster($_POST['poster']);
//$o->setPublic($_POST['public']);
//$o->setSaveTransmition($_POST['saveTransmition']);
//$o->setShowOnTV($_POST['showOnTV']);
if(!empty($_REQUEST['users_id_company'])){
$myAffiliation = CustomizeUser::getAffiliateCompanies(User::getId());
$users_id_list = array();
foreach ($myAffiliation as $value) {
$users_id_list[] = $value['users_id_company'];
}
if(in_array($_REQUEST['users_id_company'], $users_id_list)){
$o->setusers_id_company($_REQUEST['users_id_company']);
}
}
// [4]
if ($id = $o->save()) {
$obj->msg = "{$_POST['title']} ".__('Saved');
$obj->error = false;
} else {
$obj->msg = __('Error on save')." {$_POST['title']}";
}
...
At [1] the code checks if the user is allowed to stream. At [2] a new live schedule is created, passing the id
parameter. If such id
exists, then the existing object is returned, otherwise a new live schedule is created. Then, several attributes are set and at [3] the user is set to the current user. Eventually, the live schedule is saved [4].
Since there are no checks to ensure the current user owns the live schedule id, any user that is allowed to stream can take over other users’ streams and change anything in them. The schedule will then disappear from the original owner view.
An attacker needs to know (or guess) the stream id. Guessing is trivial by default because ids are sequential.
If the id
is known (in this case 27
), an attacker can issue the following request to steal a live schedule:
curl -k 'https://192.168.1.200/plugin/Live/view/Live_schedule/add.json.php' -X POST \
-H 'Cookie: 84b11d010cced71edffee7aa62c4eda0=uot19510578r10nohk91j0sunb;' \
--data-raw $'id=27&title=stolen&status=a&scheduled_time=2022-06-08+19%3A35&description=newdesc'
AVideo offers a plugin to create playlists (or “Programs”), called “PlayLists”. Default playlists are “watch later” and “favourites,” but custom playlists can be created too. By default this is disabled; an administrator can enable it in the plugin settings.
To add a new playlist schedule, a request to objects/playlistAddNew.json.php
can be made:
...
require_once $global['systemRootPath'] . 'objects/playlist.php';
$plugin = AVideoPlugin::loadPluginIfEnabled("PlayLists");
if (empty($plugin)) {
die('{"error":"Plugin not enabled"}');
}
if (!User::isLogged()) { // [1]
die('{"error":"'.__("Permission denied").'"}');
}
if (empty($_POST['name'])) {
die('{"error":"'.__("Name can't be blank").'"}');
}
$obj = new PlayList(@$_POST['id']); // [2]
$obj->setName($_POST['name']);
$obj->setStatus($_POST['status']);
echo '{"status":"'.$obj->save().'"}'; // [3]
At [1] the code checks if the user is logged-in. At [2] a new playlist is created, using the id
passed as parameter. If such id
exists, then the existing object is returned; otherwise a new live schedule is created. At [3] the playlist is saved.
Since there are no checks to ensure the current user owns the playlist id, any logged-in user can take over other users’ playlists, read and change anything in them. The playlist will then disappear from the original owner view.
An attacker needs to know (or guess) the playlist id. Guessing is trivial by default because ids are sequential.
If the id
is known (in this case 5
), an attacker can issue the following request to steal a playlist:
curl -k --cookie '84b11d010cced71edffee7aa62c4eda0=uot19510578r10nohk91j0sunb' \
--data-raw 'id=5&name=newname' 'https://192.168.1.200/objects/playlistAddNew.json.php'
Vendor confirms issues fixed on July 7th 2022
2022-07-05 - Vendor Disclosure
2022-07-07 - Vendor Patch Release
2022-08-16 - Public Release
Discovered by Claudio Bozzato of Cisco Talos.