The SYMDNS.SYS driver included in the Symantec firewall product line validates DNS and NetBIOS Name Service responses before allowing them through the firewall. As it turns out, the handlers for both types of packets have grave security issues, but this advisory focuses on NBNS packets and leaves DNS up to Barns and Karl. The intended protocol is determined by the source port of the UDP packet -- 53 for DNS, 137 for NBNS -- and after verifying that the incoming packet is marked as a response according to the header, it is passed off to the appropriate analysis routine, both of which perform similar but protocol-specific processing on the answer data contained therein (although no further validation takes place).
In the case of the NBNS routine, the questions in the packet are skipped, and the answers are only examined if they have Class 01h (INET) and Type 01h (A) or 20h (NB). For answers meeting these criteria, the name is first-level decoded, the IP addresses are stored in a list, and both are later recorded internally in a global array. (As a refresher: first level encoding represents each byte of a name as two letters from 'A' to 'P', which correspond to the high and low hexadecimal digits of the byte's value -- 'A' is 0, 'B' is 1, 'C' is 2, and so on. For example, "eEye" is represented in hexadecimal as 65h 45h 79h 65h, and is therefore encoded as "GFEFHJGF". See RFC 1001, Section 14.1, for more information.)
The first of many problems that make this vulnerability possible is that the first-level decoding routine will decode an amount of data corresponding to the length byte preceding the encoded name, making it possible to store up to 127 arbitrary bytes (plus a null terminator) into a 32-byte stack buffer provided by the main NBNS processing routine. Although this condition is insufficient to overwrite the return address directly (the buffer begins at EBP-118h, but only an 80h-byte write is possible), there is an index variable that can be overwritten in order to manipulate the IP address copying loop later in the function. The NBNS processing routine's stack frame can be represented as follows:
(saved EBP at EBP+0)
(saved EIP at EBP+4)
var_118 is the destination buffer passed to the first-level decode routine, and just about everything after it is initialized after the decoding overwrite occurs, or is otherwise useless: var_E8/var_88 is memset to 0; var_EC and var_F0 get wiped out; var_F4 is just an outer loop counter (infinite loop: DoS); and var_8 and var_4 aren't even reachable. The exception here is var_F8, which is initialized to 0 at the beginning of the function, used to index into a stack array (var_E8), and is not checked for any out-of-bounds values other than the exact size of the array in elements (18h). The fact that the variable is located immediately after the overflowable buffer just adds to the convenience.
Once the answer name has been decoded, the NBNS processing routine enters another loop to copy IP addresses from the response into var_E8. Since the contents of the list are supposed to be accumulated from across all answers in the packet, var_F8 is not reinitialized when the loop begins, and furthermore, the terminating condition of the loop is only that var_F8 equals 18h (no greater-than). As a result, once the variable has been overwritten with a sufficiently high value, "IP addresses" within the packet will be written onto the stack at [EBP-E8h+(var_F8*4)] until the answer's data length has been exhausted (up to roughly 64KB).
Because the length of the first-level encoded name must be at least 40h in order to touch var_F8, the routine that skips a length-prefixed name component will mistake the length byte for a compressed name pointer, and will only advance by two bytes instead of (length of name + 1). This means the data that normally follows the encoded name actually begins "inside" the name, but this doesn't matter because the first-level decoding routine does not validate that the name consists only of characters from 'A' to 'P'. Additionally, it does not check for compressed name pointers and will happily accept any value for the length byte. The result of this stack buffer overflow / consistent lack of validation combo is another UDP remote kernel vulnerability.