Exploit-DB #43501
Description: MiniUPnP MiniUPnPc < 2.0 - Remote Denial of Service
Type: dos
Platform: multiple
Date: 2017-05-11
Author: tintinweb

Exploit:
VuNote
======

    Author:     <github.com/tintinweb>
    Ref:        https://github.com/tintinweb/pub/tree/master/pocs/cve-2017-8798
    Version:    0.6
    Date:       May 1st, 2017

    Tag:        miniupnpc getHTTPResponse chunked encoding integer signedness error

Overview
--------

    Name:           miniupnpc
    Vendor:         Thomas Bernard
    References:     * http://miniupnp.free.fr/ [1]

    Version:        v2.0 [2]
    Latest Version: v2.0.20170421 [2][3]
    Other Versions: >= v1.4.20101221 [2] (released 21/12/2010; ~6 years ago)
    Platform(s):    cross
    Technology:     c

    Vuln Classes:   CWE-196, CWE-190
    Origin:         remote
    Min. Privs.:    ---

    CVE:            CVE-2017-8798


Description
---------

quote website [1]

>UPnP IGD client lightweight library and UPnP IGD daemon
>The UPnP protocol is supported by most home adsl/cable routers and Microsoft Windows 2K/XP. The aim of the MiniUPnP project is to bring a free software solution to support the "Internet Gateway Device" part of the protocol. The MediaServer/MediaRenderer UPnP protocol (DLNA) is also becoming very popular but here we are talking about IGD. ReadyMedia (formely known as MiniDLNA) is a UPnP Media Server using some UPnP code from MiniUPnPd.

miniupnp is part of many applications and embedded network devices

* P2P File Sharing software - e.g. qBittorrent
* Network Device Firmware
* Blockchain clients - e.g. EthereumCPP, bitcoind and forked coins


Summary
-------

*TL;DR - one-click crash miniupnpc based applications on your network*

#### Integer signedness error in miniupnpc allows remote attackers to
cause a denial of service condition via specially crafted HTTP response

An integer signedness error was found in miniupnp's `miniwget` allowing
an unauthenticated remote entity typically located on the
local network segment to trigger a heap corruption or an access violation
in miniupnp's http response parser when processing a specially crafted
chunked-encoded response to a request for the xml root description url.

To exploit this vulnerability, an attacker only has to provide a
chunked-encode HTTP response with a negative chunk length to upnp
clients requesting a resource on the attackers webserver. Upnp clients
can easily be instructed to request resources on the attackers webserver
by answering SSDP discovery request or by issueing SSDP service
notifications (low complexity, integral part of the protocol).


* remote, unauthenticated, `ACCESS_VIOLATION_READ` and heap corruption
* (confirmed) DoS; (unconfirmed) could also lead to RCE under certain
circumstances (multi-threaded?)


see attached PoC
see proposed patch

Details
-------

The vulnerable component is a HTTP file download method called
`miniwget` (precisely `getHTTPResponse`) that fails to properly handle
invalid chunked-encoded HTTP responses. The root cause is a bounds check
that mistakenly casts an unsigned attacker-provided chunksize to signed
int leading to an incorrect decision on the destination heap buffer size
when copying data from the server response to an internal buffer. The
attacker controls both the size of the internal buffer as well as the
number of bytes to copy. In order for this attack to succeed, the number
of bytes to copy must be negative.

attacker controls:
* `int content_length`
* `unsigned int chunksize`
* `bytestocopy` if `(int) chunksize` is negative (or at least < `n-i` ~ 1900 bytes)
* length of `content_buf` if `bytestocopy` is negative

In the end, the attacker controls
* `realloc(content_buf, content_length)`
* `memcpy(content_buf+x, http_response, chunksize)`


        client (miniupnpc)                         server (poc.py)
            |                                         |
            |                                         |
            | SSDP:  Discovery - M-SEARCH             |
        1.  | --------------------------------------> |
            |                                         |
            | SSDP:  Reply - Location Header          |
        2.  | <-------------------------------------- |
            |                                         |
            | SCPD:  GET (Location Header/xxxx.xml)   |
        3.  | --------------------------------------> |
            |                                         |
            | SCPD:  HTTP chunked-encoded reply       |
        4.  | <-------------------------------------- |
            |                                         |

1. application performs SSDP discovery via M-SEARCH (multicast, local network segment)
2. poc.py responds with the url to the xml root description requesting the application to navigate to the malicious webserver.
3. application requests xml root description url (taken from reply to M-SEARCH, Location Header) on malicious webserver (poc.py)
4. poc.py responds with a specially crafted http response triggering the heap overwrite in miniupnp

#### Source

`miniwget.c:236` [4]

*Note:* Inline annotations are prefixed with //#!

* A) 1. to 3. is the parsing of the chunksize
* B) 4. to 5. integer signedness error
* C) 6. integer wrapping
* D) 7. to 9. destination buffer size
* E) 10. heap overwrite with size in bytestocopy


```c
/* content */
if(chunked)                                         //#! 1) transfer-encoding: chunked
{
    int i = 0;
    while(i < n)
    {
        if(chunksize == 0)
        {
            /* reading chunk size */
            if(chunksize_buf_index == 0) {
                /* skipping any leading CR LF */
                if(i<n && buf[i] == '\r') i++;
                if(i<n && buf[i] == '\n') i++;
            }
            while(i<n && isxdigit(buf[i])                               //#! 2) copy hexchars to chunksize_buf
                 && chunksize_buf_index < (sizeof(chunksize_buf)-1))
            {
                chunksize