Zephyr OS IP packet handling does not properly drop IP packets arriving on an external interface with a source address equal to 127.0.01 or the destination address.
Most routers will drop such IP packets before they reach the destination address, but if not, then Zephyr OS should drop any IP packet arriving on an external interface with the source address 127.0.0.1 or address equal to destination address.
This work for both IPv4 and IPv6 interfaces with TCP and UDP connections. This is now tested only in native simulator (native_sim) with ethernet interface, but the code executed is not dependent on the interfaces and behavior should be same e.g., over WLAN.
IP packet with localhost source address can be used to bypass the host side IP address-based access control like Project Zero has shown: https://googleprojectzero.blogspot.com/2015/01/finding-and-exploiting-ntpd.html.
In addition, those makes test target more vulnerable for DoS attacks since answers are handled by loopback interfaces.
In Zephyr OS there is also a bug causing kernel to crash in this kind of situations. The crash is reproduced with IPv4 and IPv6 packets over TCP connection against echo_server and dump_http_server_mt test targets.
[00:01:13.200,000] net_ipv4: net_ipv4_input: (0x80bd9c0): IPv4 packet received from 127.0.0.1 to 192.0.2.1
[00:01:13.200,000] net_pkt: net_pkt_write: (0x80bd9c0): pkt 0x80c4c1c data 0x80c7c14 length 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4c1c skip 20
[00:01:13.200,000] net_conn: net_conn_input: (0x80bd9c0): Check TCP listener for pkt 0x80c4c1c src port 4242 dst port 1559 family 1
[00:01:13.200,000] net_conn: net_conn_input: (0x80bd9c0): No match found.
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4c1c skip 20
[00:01:13.200,000] net_pkt: pkt_alloc_with_buffer: (0x80bd9c0): On iface 0x80baf00 size 20
[00:01:13.200,000] net_pkt: pkt_estimate_headers_length: (0x80bd9c0): HDRs length estimation 48
[00:01:13.200,000] net_pkt: net_pkt_alloc_buffer_debug: (0x80bd9c0): Data allocation maximum size 68 (requested 20)
[00:01:13.200,000] net_pkt: pkt_alloc_buffer: (0x80bd9c0): TDATA (?) [0] frag 0x80c74b8 ref 1 (net_tcp_reply_rst():1178)
[00:01:13.200,000] net_pkt: net_pkt_write: (0x80bd9c0): pkt 0x80c4bd8 data 0x80c7c80 length 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_write: (0x80bd9c0): pkt 0x80c4bd8 data 0x80c7c94 length 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_write: (0x80bd9c0): pkt 0x80c4bd8 data 0x80c7c80 length 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 12
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 8
[00:01:13.200,000] net_pkt: net_pkt_write: (0x80bd9c0): pkt 0x80c4bd8 data 0x80c7c94 length 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_tcp: tcp_send: (0x80bd9c0): RST Seq=3235108224 Len=0
[00:01:13.200,000] net_pkt: net_pkt_ref_debug: (0x80bd9c0): TX [10] pkt 0x80c4bd8 ref 2 (tcp_send():327)
[00:01:13.200,000] net_core: net_send_data: (0x80bd9c0): Loopback pkt 0x80c4bd8 back to us
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_ipv4: net_ipv4_input: (0x80bd9c0): IPv4 packet received from 127.0.0.1 to 192.0.2.1
[00:01:13.200,000] net_pkt: net_pkt_write: (0x80bd9c0): pkt 0x80c4bd8 data 0x80c7c94 length 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_conn: net_conn_input: (0x80bd9c0): Check TCP listener for pkt 0x80c4bd8 src port 1559 dst port 4242 family 1
[00:01:13.200,000] net_conn: net_conn_input: (0x80bd9c0): [0x80bd578] match found cb 0x808afba ud 0x80bc340 rank 0x78
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_pkt: net_pkt_skip: (0x80bd9c0): pkt 0x80c4bd8 skip 20
[00:01:13.200,000] net_tcp: tcp_in: (0x80bd9c0): RST Seq=3235108224 Len=0 [SYN_RECEIVED Seq=3006520478 Ack=3235108224]
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TX [10] pkt 0x80c4bd8 ref 1 frags 0x80c74b8 (tcp_in():3084)
[00:01:13.200,000] net_tcp: tcp_conn_close_debug: (0x80bd9c0): conn: 0x80cafcc closed by TCP stack (tcp_in():3142)
[00:01:13.200,000] net_tcp: tcp_conn_close_debug: (0x80bd9c0): SYN_RECEIVED->CLOSED
[00:01:13.200,000] net_tcp: tcp_conn_unref: (0x80bd9c0): conn: 0x80cafcc, ref_count=1
[00:01:13.200,000] net_conn: net_conn_unregister: (0x80bd9c0): Connection handler 0x80bd578 removed
[00:01:13.200,000] net_ctx: net_context_unref: (0x80bd9c0): Context 0x80bc340 released
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TX [10] pkt 0x80c4c60 ref 0 frags 0x80c7480 (tcp_send_queue_flush():518)
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TDATA (?) [0] frag 0x80c7480 ref 0 frags (nil) (tcp_send_queue_flush():518)
[00:01:13.200,000] net_pkt: net_pkt_frag_unref_debug: (0x80bd9c0): TDATA (?) [0] frag 0x80c7480 ref 0 (net_pkt_unref_debug():597)
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TX [11] pkt 0x80c4ca4 ref 0 frags (nil) (tcp_conn_unref():586)
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): RX [13] pkt 0x80c4820 ref 0 frags (nil) (tcp_conn_unref():589)
[00:01:13.200,000] net_core: processing_data: (0x80bd9c0): Consumed pkt 0x80c4bd8
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TX [12] pkt 0x80c4bd8 ref 0 frags 0x80c74b8 (tcp_send():374)
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TDATA (?) [0] frag 0x80c74b8 ref 0 frags (nil) (tcp_send():374)
[00:01:13.200,000] net_pkt: net_pkt_frag_unref_debug: (0x80bd9c0): TDATA (?) [0] frag 0x80c74b8 ref 0 (net_pkt_unref_debug():597)
[00:01:13.200,000] net_core: processing_data: (0x80bd9c0): Dropping pkt 0x80c4c1c
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TX [13] pkt 0x80c4c1c ref 1 frags 0x80c749c (processing_data():174)
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TX [13] pkt 0x80c4c1c ref 0 frags 0x80c749c (tcp_send():374)
[00:01:13.200,000] net_pkt: net_pkt_unref_debug: (0x80bd9c0): TDATA (?) [0] frag 0x80c749c ref 0 frags (nil) (tcp_send():374)
[00:01:13.200,000] net_pkt: net_pkt_frag_unref_debug: (0x80bd9c0): TDATA (?) [0] frag 0x80c749c ref 0 (net_pkt_unref_debug():597)
work: 0x80cb060 work->handler: (nil)
ASSERTION FAIL [handler != ((void *)0)] @ WEST_TOPDIR/zephyr/kernel/work.c:650
@ WEST_TOPDIR/zephyr/lib/os/assert.c:43
[00:01:13.200,000] os: >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0
[00:01:13.200,000] os: Current thread: 0x80bd9c0 (unknown)
[00:01:13.200,000] os: Halting system
Exiting due to fatal error
This was found using Defensics, if further details for reproduction are required - please let us know
Result of exploitation could lead to instability (i.e., crash) or denial of service attacks.
Summary
Zephyr OS IP packet handling does not properly drop IP packets arriving on an external interface with a source address equal to 127.0.01 or the destination address.
Details
Most routers will drop such IP packets before they reach the destination address, but if not, then Zephyr OS should drop any IP packet arriving on an external interface with the source address 127.0.0.1 or address equal to destination address.
This work for both IPv4 and IPv6 interfaces with TCP and UDP connections. This is now tested only in native simulator (native_sim) with ethernet interface, but the code executed is not dependent on the interfaces and behavior should be same e.g., over WLAN.
IP packet with localhost source address can be used to bypass the host side IP address-based access control like Project Zero has shown: https://googleprojectzero.blogspot.com/2015/01/finding-and-exploiting-ntpd.html.
In addition, those makes test target more vulnerable for DoS attacks since answers are handled by loopback interfaces.
In Zephyr OS there is also a bug causing kernel to crash in this kind of situations. The crash is reproduced with IPv4 and IPv6 packets over TCP connection against echo_server and dump_http_server_mt test targets.
Below are debug logs from such a crash:
PoC
This was found using Defensics, if further details for reproduction are required - please let us know
Impact
Result of exploitation could lead to instability (i.e., crash) or denial of service attacks.
Patches
embargo: 2024-03-14
For more information
If you have any questions or comments about this advisory:
Credit
Synopsys Cybersecurity Research Center (CyRC) Researcher: Kari Hulkko