Wireshark-bugs: [Wireshark-bugs] [Bug 5722] New: Crash in 6LoWPAN on 32-bit systems
Date: Wed, 23 Feb 2011 13:53:09 -0800 (PST)
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5722 Summary: Crash in 6LoWPAN on 32-bit systems Product: Wireshark Version: 1.4.3 Platform: All OS/Version: All Status: NEW Severity: Critical Priority: Low Component: Wireshark AssignedTo: wireshark-bugs@xxxxxxxxxxxxx ReportedBy: gerald@xxxxxxxxxxxxx Created an attachment (id=5973) --> (https://bugs.wireshark.org/bugzilla/attachment.cgi?id=5973) Capture file demonstrating the crash. Build Information: Paste the COMPLETE build information from "Help->About Wireshark", "wireshark -v", or "tshark -v". -- Paul Makowski discovered that we could crash on 32 bit systems while reading a malformed 6LoWPAN packet. Here's his writeup: __TIMELINE__ Feb 4th, 2011: Report sent to security@xxxxxxxxxxxxx at request of employer. Feb 7th, 2011: Gerald Combs responded, issued correction regarding assertion failures only causing warnings by default. Feb 11th, 2011: Reviewed the problem; second revision of this report sent to security@xxxxxxxxxxxxx. __TITLE__ packet-6lowpan.c contains an off-by-one error which may be used to cause a denial of service (stop packet capture or dissection of .pcap). __BUG TRACKING__ CVE: N/A (0day) __REPORTED BY__ Paul Makowski (my.hndl@xxxxxxxxx), working for SEI/CERT __AFFECTED VERSIONS__ Vulnerable: Wireshark 1.4.x branch (stable), tested against SVN 35916 Not Vulnerable: Wireshark 1.5.x branch (dev), tested against SVN 35917 Untested: Wireshark < 1.4 __ATTACKER CAPABILITIES__ An attacker may cause packet-6lowpan.c to request an ep_alloc()'ed buffer that is 1 byte too small. When a write is later performed on this buffer, the attacker has limited control over the byte written beyond the end of the buffer. Within Wireshark trunk-1.4 SVN 35916, the extra byte clobbers the first byte in the ep_ buffer's canary value, causing a call to g_error() when the buffer is later freed and leading to a denial of service condition. Within Wireshark trunk(1.5) SVN 35917, an exception is generated for the condition and handled appropriately. packet-6lowpan.c still faults, but doesn't cause a crash. __SUMMARY__ dissect_6lowpan_iphc() in /epan/dissectors/packet-6lowpan.c trusts user supplied data when incrementing 'offset'. It is possible for the user to increment 'offset' to a value greater than tvb->length and/or tvb->reported_length, forcing the dissector to attempt dissection out of bounds. If 'offset' is greater than tvb->length or tvb->reported_length, then tvb_length_remaining() or tvb_reported_length_remaining() will return -1 respectively. If tvb_length_remaining() returns -1, then a buffer is allocated 1 byte too short, leading to a partial overwrite of the heap canary. __PROPOSED FIX__ The bug may be triggered in multiple ways due to the fact that packet-6lowpan.c trusts user input when making decisions regarding how far to increment the 'offset' value. dissect_6lowpan_iphc() handles a number of different ways to decompress items and increment 'offset' based on user input. Therefore, it may make the most sense to check the value of 'offset' against tvb->length and/or tvb->reported_length after each increment whose magnitude is derived from user input. If 'offset' is greater than either of these values, the packet should be considered an invalid 6LoWPAN packet and reported as such, rather than causing a crash. __DETAILS__ ------------------------------------ Wireshark 1.5 (dev) - not vulnerable ------------------------------------ // from /epan/dissectors/packet-6lowpan.c: tvb_memcpy(tvb, &ipv6.ip6_dst.bytes[sizeof(ipv6.ip6_dst) - length], offset, length); // from /epan/tvbuff.c: check_offset_length(tvb->length, tvb->reported_length, offset, (gint) length, &abs_offset, &abs_length); int exception = 0; if (!check_offset_length_no_exception(tvb_length_val, tvb_reported_length_val, offset, length_val, offset_ptr, length_ptr, &exception)) { DISSECTOR_ASSERT(exception > 0); THROW(exception); } check_offset_length_no_exception() calls compute_offset_length(), which computes: end_offset = *offset_ptr + *length_ptr; // end_offset holds 17, which is greater than tvb->length and tvb->reported_length ... *exception = ReportedBoundsError; // an exception is registered An exception is THROWn, which is then caught by dissect_6lowpan_iphc(), causing the packet to be flagged as invalid and exiting dissection before the 1 byte out-of-bounds write. ----------------------------------- Wireshark 1.4 (stable) - vulnerable ----------------------------------- Ref: /epan/dissectors/packet-6lowpan.c, http://wiki.wireshark.org/Development/Canary Wireshark 1.4 lacks this additional exception checking, so dissection procedes. tvb_length_remaining() is used to calculate the required size of an ep_alloc()'ed buffer: nhdr_list = (struct lowpan_nhdr *)ep_alloc(sizeof(struct lowpan_nhdr) + tvb_length_remaining(tvb, offset)); If 'offset' > tvb->length, tvb_length_remaining() returns -1 which is added to sizeof(struct lowpan_nhdr), causing an allocation 1 byte too small for nhdr_list. Several lines later, the return value of tvb_reported_length_remaining() is written to the last field (a 32bit value) in the nhdr_list struct: nhdr_list->reported = tvb_reported_length_remaining(tvb, offset); nhdr_list is a lowpan_nhdr: struct lowpan_nhdr *nhdr_list; lowpan_nhdr is defined as such: /* Structure used to store decompressed header chains until reassembly. */ struct lowpan_nhdr { /* List Linking */ struct lowpan_nhdr *next; /* Next Header */ guint8 proto; guint length; guint reported; }; Since nhdr_list is 1 byte too short, this last byte (which will be 0xff unless the attacker can desynchonize tvb->length and tvb->reported_length) will be written over the first byte of the ep_ buffer's heap canary. Before nhdr_list->reported = tvb_reported_length_remaining(tvb, offset); 0x03421163 00 ff ff ff ff 02 00 00 .ÿÿÿÿ... <-- 4B of 0xff written previously via nhdr_list->length = tvb_length_remaining(tvb, offset); 0x0342116B 7a d6 f2 0a 0f e3 93 44 zÖò..ãD <-- canary After nhdr_list->reported = tvb_reported_length_remaining(tvb, offset); 0x03421163 00 ff ff ff ff ff ff ff .ÿÿÿÿÿÿÿ <-- 4 additional bytes of 0xff written, the last clobbering the canary 0x0342116B ff d6 f2 0a 0f e3 93 44 ÿÖò..ãD <-- canary, 1st byte clobbered When Wireshark attempts to free this buffer (it will after processing the packet), the canary is checked against mem_canary (the correct value). Since 'canary' is corrupted, Wireshark will call g_error() and abort. -- Configure bugmail: https://bugs.wireshark.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.
- Follow-Ups:
- [Wireshark-bugs] [Bug 5722] Crash in 6LoWPAN on 32-bit systems
- From: bugzilla-daemon
- [Wireshark-bugs] [Bug 5722] Crash in 6LoWPAN on 32-bit systems
- Prev by Date: [Wireshark-bugs] [Bug 5721] add "swap" feature to switch between two packet
- Next by Date: [Wireshark-bugs] [Bug 5722] Crash in 6LoWPAN on 32-bit systems
- Previous by thread: [Wireshark-bugs] [Bug 5721] add "swap" feature to switch between two packet
- Next by thread: [Wireshark-bugs] [Bug 5722] Crash in 6LoWPAN on 32-bit systems
- Index(es):