On Dec 01, 2022, a stack overflow vulnerability CVE-2022-23093 was found in the FreeBSD operating system (all supported versions) ping utility. The issue is a buffer overflow vulnerability affecting the “pr_pack()” function in ping(8). The flaw can be leveraged to cause a stack overflow, which could lead to a crash or trigger remote code execution in ping.
What is the issue?
The following vulnerability details were published in the FreeBSD security advisory
Ping reads raw IP packets from the network to process responses in the pr_pack() function. As part of processing a response ping has to reconstruct the IP header, the ICMP header and if present a “quoted packet,” which represents the packet that generated an ICMP error. The quoted packet again has an IP header and an ICMP header.
The pr_pack() copies received IP and ICMP headers into stack buffers for further processing. In so doing, it fails to take into account the possible presence of IP option headers following the IP header in either the response or the quoted packet. When IP options are present, pr_pack() overflows the destination buffer by up to 40 bytes.
What versions are impacted?
This vulnerability impacts all currently supported versions of FreeBSD.
What can you do to protect yourself?
If you are a FreeBSD customer, we encourage you to take the following steps at the earliest:
Check to see if your current version is vulnerable. Update to the most recent patched version available In cases where upgrade is unfeasible or not possible, backporting the patch to your current version may be possible, and other mitigating measures can be put in place such as blocking ICMP packets with IP Options via stateful firewalls, restricting ping usage on vulnerable hosts to protected accounts, and implementing a holistic security posture with defense in depth to detect and respond to abnormal activity on hosts.
Zscaler’s cloud is not at risk
After a thorough investigation, ThreatLabz determined that Zscaler platform service components have not been impacted by this vulnerability. You can read the ThreatLabz trust post here.
Additionally, the Zscaler platform is built on a holistic zero trust architecture that offers defense-in-depth against supply chain and compromised user attacks, mitigating incidents such as this in the following ways:
Eliminates lateral movement: Zscaler connects users directly to apps, not the network, to limit the blast radius of a potential incident. Shuts down compromised users and insider threats: If an attacker gains access to your identity system, we can prevent private app exploit attempts with in-line inspection and detect the most sophisticated attackers with integrated deception. Stops data loss: Zscaler inspects data-in-motion and data-at-rest to prevent potential data theft from an active attacker.
The ping utility invoked with an IPv4 target (IPv4-host or IPv4-mcast-group) uses the ICMP protocol’s mandatory ECHO_REQUEST data gram to elicit an ICMP ECHO_RESPONSE from a host or gateway. ECHO_REQUEST datagrams (“pings”) have an IP and ICMP header, followed by a “struct timeval” and then an arbitrary number of “pad” bytes used to fill out the packet. “ping reads raw IP packets from the network to process responses in the pr_pack() function. As part of processing a response ping has to reconstruct the IP header, the ICMP header and if present a “quoted packet,” which represents the packet that generated an ICMP error. The quoted packet again has an IP header and an ICMP header”, the FreeBSD Project wrote in a security advisory. “The pr_pack() copies received IP and ICMP headers into stack buffers for further processing. In so doing, it fails to take into account the possible presence of IP option headers following the IP header in either the response or the quoted packet. When IP options are present, pr_pack() overflows the destination buffer by up to 40 bytes.”
The ping utility runs in userspace. When a user runs the ping command, it invokes the binary at /sbin/ping. The code is available on the FreeBSD source. The vulnerable function, pr_pack() prints out the ICMP packet response information to stdout, similar to the familiar string:
64 bytes from 18.104.22.168: icmp_seq=1 ttl=57 time=86.4 ms
On the network, the ICMP packet (both request and response) looks like this:
The headers in the diagram above are the IP headers, with an optional Options field. In an attack case, these IP Options are enabled and filled with non-null bytes.
In some cases, for example, if an ICMP packet is malformed or deliberately modified en route to the destination host, and the IP Options are enabled in the original echo request, the vulnerable pr_pack() fails to allocate enough space on the stack to account for the presence of IP Options, instead overflowing the stack.
In these error cases, the response from the destination host may also include a “quoted packet” in the data section (which tracks which packet specifically caused the ICMP error), and the pr_pack() function similarly overflows the stack in the case that the quoted packet has ICMP headers.
The buffer overflow occurs in line 1156 and line 1161 in the pr_pack() function (defined in ping.c) here:
The value of hlen is calculated without checking for the IP options header, assuming the standard IP packet header length of 20 bytes. The memcpy into the icp struct leads to the buffer overflow.