I have discovered yet another vulnerability in Inteno’s IOPSYS firmware - but I believe this to affect all OpenWRT or LEDE based routers that ship with the printer server p910nd. Any authenticated user can modify the configuration for the printer server in a way which allows them to read and append to any file as root. This leads to information disclosure and remote code execution. This vulnerability has been assigned the CVE ID: CVE-2018-10123.

I’ve written reports for vulnerabilities on Inteno’s devices before (1, 2, 3). I recommend reading the first post as it describes how one can call functions on the router - including ones which may not be listed in the admin panel.

While looking through the configurations an authenticated user can modify, I noticed a section for p910nd. According to the OpenWRT wiki, it is a lightweight daemon responsible for basically being the gateway between a device connected to the router and a printer connected to the router. It is disabled by default, but can easily be enabled in the admin panel. By default, the section looks like this:

> { "jsonrpc" : "2.0" , "method" : "call" , "params" :[ "0123456789abcdefgh0123456789abcd" , "uci" , "get" ,{ config: "p910nd" }], "id" : 0 } < [ ... ] { ".anonymous" : True , ".type" : "p910nd" , ".name" : "cfg02f941" , ".index" : 0 , "device" : "/dev/usb/lp0" , "port" : "0" , "bidirectional" : "1" , "enabled" : "0" }

What intrigued me was the device value. This makes sense in an administration perspective, but the average end user should not be able to change this. I was interested in what would happen if we pointed p910nd towards something else - perhaps a file? Having SSH access for testing purposes, I created a test file:

# cat > /tmp/test << EOF > Testing123 > EOF

I enabled p910nd and changed device to point to our newly created file:

> { "jsonrpc" : "2.0" , "method" : "call" , "params" :[ "0123456789abcdefgh0123456789abcd" , "uci" , "set" ,{ config: "p910nd" , type: "p910nd" , values: { enabled: "1" , device: "/tmp/test" }}], "id" : 1 } > { "jsonrpc" : "2.0" , "method" : "call" , "params" :[ "0123456789abcdefgh0123456789abcd" , "uci" , "commit" ,{ config: "p910nd" }], "id" : 2 }

As per the documentation, the service listens on port 9100. I used netcat to connect to that port:

$ ncat 192.168.1.1 9100 Testing123

I was instantly greeted with the contents of the file. I modified the permissions on the test file to see whether we could could read files with root-only access:

# chmod 600 /tmp/test # ls -al /tmp/test -rw------- 1 root root 11 Apr 14 23:23 /tmp/test

Again, we could successfully read the file:

$ ncat 192.168.1.1 9100 Testing123

This makes sense, as the p910nd daemon runs as root on the system. The config also had a value called bidirectional , which was set to 1 . Does this mean that we can write to files as well? I typed another test string within netcat to see whether it would be appended to the file. I also pressed enter, to make sure that the string was being sent:

$ ncat 192.168.1.1 9100 Testing123 foobar

Checking whether the file changed at all:

# cat /tmp/test Testing123 foobar

Indeed, even writing to files is possible! This enables an attacker to easily gain access to the system. For example, one could add a user to /etc/passwd with UID 0 and a known password.

After a bit of testing, I also concluded that the file an attacker wished to write to had to already exist - simply changing the device value to a nonexistant file did not create the file. However, an attacker could still just append to a script that gets executed as root and add whatever code they wish to have executed.

I wrote a proof of concept that appended a line to the /etc/init.d/p910nd script, which on execution would overwrite /etc/dropbear/authorized_keys with my SSH key, allowing me to easily SSH in as root. This script would get executed every time a change was committed through UCI, which uses it to restart the service. The script in action:

If you have an Inteno router with restricted access, you can use this PoC to add your own SSH key and log in as root. It may also work with other routers that have p910nd bundled and use the jsonrpc protocol to communicate - you may have to change the IP to also have /ubus at the end. If it uses a different protocol, a different PoC is needed.

This PoC requires Python 3.6 and a module called websocket-client which you can install by evoking pip install websocket-client . First comment details usage instructions. As always, this exploit can be found on the inteno-exploits repository alongside other exploits I’ve written for IOPSYS devices. The repository also includes an alternative version which simply drops to a root shell on the remote machine, bypassing any SSH key shenanigans.