Cisco RV Series multiple vulnerabilities

Abstract

Multiple vulnerabilities have been found in Cisco RV Series devices that allows an attacker to overwrite/create arbitrary files, execute arbitrary commands, and execute Cross-Site Request Forgery attacks.

Affected versions

These following Cisco RV Series devices are affected by these issues:

  • Cisco RV120W Wireless-N VPN Firewall running firmware prior to 1.0.5.9
  • Cisco RV180 VPN Router and Cisco RV180W Wireless-N Multifunction VPN Router running firmware versions prior to 1.0.4.14
  • Cisco RV220W Wireless Network Security Firewall running any currently available release

See also

Fix

Please consult Cisco advisory cisco-sa-20141105-rv for fix information.

Introduction

Multiple vulnerabilities have been found in Cisco RV Series devices that allows an attacker to overwrite/create arbitrary files, execute arbitrary commands, and execute CSRF attacks.

Insecure handling of file uploads

The admin pages of the affected devices are created using LUA scripts. It has been discovered that the affected devices use a cookie named TeamF1Login in an insecure manner. The cookie value is used as a path name for storing the uploaded file. No input validation is done on the cookie value. Consequently, an attacker can set this to any value and thus create files in arbitrary locations.

It should be noted that:

  • the web server (thttpd) runs as root;
  • existing files will be overwritten;
  • this issue can be exploited by unauthenticated users.

/pfrm2.0/share/lua/5.1/cgilua/post.lua

local function fileupload (filename)
	-- create a temporary file for uploading the file field
	--local file, err = tmpfile()
	
	-- Adarsh 7/16/07
	local filename = mycookieget("TeamF1Login")
	local file, err = myopen("/tmp/" .. filename, "wb")
	
	if file == nil then
		discardinput(bytesleft)
		error("Cannot create a temporary file.\n"..err)
	end      
	local bytesread = 0
	local boundaryline = "\r\n"..boundary
	local out = function (str)
		local sl = strlen (str)
		if bytesread + sl > maxfilesize then
			discardinput (bytesleft)
			error (format ("Maximum file size (%d kbytes) exceeded while uploading `%s'", maxfilesize / 1024, filename))
		end
		file:write (str)
		bytesread = bytesread + sl
	end
	if readuntil (boundaryline, out) then
		file:seek ("set", 0)
		return file, bytesread
	else
		error (format ("Error processing multipart/form-data.\nUnexpected end of input while uploading %s", filename))
	end
end

Command injection in diagnostics tools

The admin pages contain a couple of network diagnostic tools, such as the ability to perform an ICMP ping. Entering special characters in the different forms renders the following error message:

Invalid IP Address/Domain name:Domain/WAN (Internet) must contain only alphanumeric letters, '.' and '-'.

It appears that this check is not enforced server side. Sending the request directly can be used to submit & execute arbitrary commands, which will be executed with root privileges. A valid session is required to access the diagnostics tools.

/pfrm2.0/var/www/diagnostics.htm

if (ButtonType and ButtonType == "ping") then
	local inputTable = web.cgiToLuaTable(cgi)
    
	local throughVpn = false
	local ipToPing = string.sub(inputTable["ping.ip"], string.find(inputTable["ping.ip"], '[%a%d\.:]+'))
	local pingfile = db.getAttribute("environment", "name", "PING_FILE_NAME", "value")    
	local pingprog = ""
	if (inputTable["ping.throughVpn"] ~= nil and inputTable["ping.throughVpn"] == "1") then
		throughVpn = true
	end
    
	-- ping    
[...]
		else
			pingprog = db.getAttribute("environment", "name", "PING_PROGRAM", "value")
			options1 = " 2>&1 "
			local cmd_ping = pingprog .. " " .. ipToPing
			globalCmdOutput = util.runShellCmd(cmd_ping, pingfile, "/tmp/pingErr.txt", options1)
			STATUS_CLASS = INFO_CLASS 
			statusMessage = (trStrings["11307"] or 'i18nHTMLMissing') .. " " .. ipToPing
		end
	end
	web.goToPage(NextPage, true, true)

GET requests can be used to bypass Referer check

Whenever a POST request is send to the application, a check is performed on the Referer header. If the Referer is empty or contains an external page, an error message is displayed (401 Unauthorized). It appears that this check is not performed for GET requests. GET & POST parameters are interchangeable and since the Referer check is the only measure against Cross-Site Request Forgery (CSRF) attacks, it is possible to execute CSRF attacks using specially crafted URLs. For example the following URL adds an admin account to the user database:

https://192.168.2.1/platform.cgi?thispage=diagnosticsAP.htm&button.ping.diagDisplayAP=Ping&ping.ip=-h+ 2%3e%2fdev%2fnull%3b%2fpfrm2.0%2fbin%2fsqlite3+%2ftmp%2fsystem.db+%22INSERT+INTO+%5c%22users%5c%22+VALUES%28%5c%22 admin%5c%22%2c%5c%22admin%5c%22%2c0%2c%5c%22admin%5c%22%2c10%29%3b%22

Questions or feedback?