the-tcpdump-group / tcpdump

the TCPdump network dissector
https://www.tcpdump.org/
Other
2.7k stars 842 forks source link

CVE-2016-7975 Possible crash caused by option 20 (SCPS-TP) #516

Closed rbgarga closed 7 years ago

rbgarga commented 8 years ago

We have a software on pfSense, called filterlog [1] and this software is basically made using part of tcpdump code. We received an email from Patrik Lindquist patrik.lundquist@gmail.com reporting a crash on filterlog and after a quick look at tcpdump code I believe this same problem may occour on it so I decided to come here and share all investigation he did. Following you can see his email content:

what seemed to be a rarely occurring odd bug turned out to be quite interesting.

Once I had caught the bug with a filterlog debug build (attached) I began analyzing the TCP options in the TCP SYN packet. Filterlog crashed on option 20 (0x14).

0x02 0x04 0x05 0xac = MSS = 1452
0x01                = NOP
0x03 0x03 0x02      = Window Scale = 2
0x01 0x01           = NOP NOP
0x14 0x02           = SCPS Capabilities   <--- !!!
0x00 0x00 0x00 0x00 = EOL

https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml

SCPS-TP is a space communications version of TCP and quite unexpected on the internet.

https://en.wikipedia.org/wiki/Space_Communications_Protocol_Specifications

– TCP for Transactions (RFC 1644, reference [13])—reduces the handshaking necessary to start a TCP connection and provides ‘reliable datagram’  operation to handle command-response traffic, for very long delay environments in which it is desirable to begin data transfer without waiting for a connection handshake;

http://public.ccsds.org/publications/archive/714x0b2.pdf

See section 3.2.3 on page 20 in the PDF.

SCPS Capabilities Option shall be sent in a i TCP SYN packet and shall be four fields of one byte each and begin with 0x14 0x04 (Kind=20, Length=4).

The offending packet has curiously omitted the two mandatory fields Capabilities Option Bit-Vector and Connection ID and have accordingly adjusted the option length to 0x02, which breaks the SCPS-TP standard but follows the TCP Options standard in general.

The packet will therefore pass TCP option parsers that don't specifically care about SCPS-TP.

So why does filterlog crash, or even care about SCPS-TP? See sysutils/filterlog/files/print-tcp.c.

1. TCPOPT_AUTH is incorrectly defined to option 20 while TCP-AO actually is option 29. This in itself isn't a problem since only the option kind is logged and the option length is correct.

#define TCPOPT_AUTH             20      /* Enhanced AUTH option */

2. The switch case for TCPOPT_AUTH incorrectly subtracts 3 from the option lenght to account for the Kind and Length bytes already parsed, but that's only 2 bytes to account for!

                        case TCPOPT_AUTH:
                                datalen = len - 3;
                                break;

Variable datalen becomes (u_int)-1 which is then added to the packet parsing pointer cp which results in a segmentation fault when next option is read (opt = *cp++). What's really interesting about this is that a SCPS Capabilities option adhering to the standard is 4 bytes long and won't trigger this bug (Connection ID would be parsed as next option instead). This shortened SPCS option is crafted for a reason.

Going through all saved core dumps I've been able to extract these offending log lines (ending at the segmentation fault):

October 2015 from Cairo, Egypt
"5,16777216,,1000000103,re0,match,block,in,4,0x0,,115,7362,0,none,6,tcp,52,41.237.143.7,XXX.XXX.XXX.XXX,58234,35953,0,S,2646335879,,8192,,mss;nop;wscale;nop;nop;enhanced auth;"

November 2015 from Islamabad, Pakistan
"5,16777216,,1000000103,re0,match,block,in,4,0x0,,112,26601,0,none,6,tcp,52,119.157.53.146,XXX.XXX.XXX.XXX,58481,58915,0,S,1409997622,,8192,,mss;nop;wscale;nop;nop;enhanced auth;"

April 2016 from Lahore and Islamabad, Pakistan
"5,16777216,,1000000103,re0,match,block,in,4,0x0,,112,21043,0,none,6,tcp,52,117.102.50.108,XXX.XXX.XXX.XXX,62913,31333,0,S,95784044,,8192,,mss;nop;wscale;nop;nop;enhanced auth;"

"5,16777216,,1000000103,re0,match,block,in,4,0x0,,114,2525,0,none,6,tcp,52,39.40.65.28,XXX.XXX.XXX.XXX,53809,12005,0,S,1809709480,,8192,,mss;nop;wscale;nop;nop;enhanced auth;"

"5,16777216,,1000000103,re0,match,block,in,4,0x0,,110,31622,0,none,6,tcp,52,182.181.202.230,XXX.XXX.XXX.XXX,52750,63764,0,S,3757264999,,8192,,mss;nop;wscale;nop;nop;enhanced auth;"

"5,16777216,,1000000103,re0,match,block,in,4,0x0,,110,9887,0,none,6,tcp,52,182.181.158.21,XXX.XXX.XXX.XXX,53052,30122,0,S,2824624414,,8192,,mss;nop;wscale;nop;nop;enhanced auth;"

The big gap between November and April is probably partly because filterlog crashed again and I didn't notice. It looks like a coordinated effort where they try to turn off logging.

I've attached a small patch that fixes the immediate problem but filterlog needs an overhaul to better handle lengths. Next time someone might be lying about the option length, but I think this will do for a pfSense 2.3.1 release since bigger changes need more testing.

I also removed some code that does nothing and makes the option handling look unfinished.

I've been running a patched filterlog since Sunday and clog -f /var/log/filter.log | grep scps in a shell but I haven't seen any new attack yet. Would be great if you can throw some generated packets at the patch.

Regards,
Patrik

[1] https://github.com/pfsense/FreeBSD-ports/tree/devel/sysutils/filterlog/files

infrastation commented 8 years ago

Nice analysis. Could you confirm this reproduces on the latest master branch build of tcpdump? Would it be possible to have a copy of the patch and a packet that triggers the crash? Thank you.

pLuster commented 8 years ago

tcpdump has wrong value for TCP Auth but the switch case isn't broken, as in filterlog. So no crashing.

I've extracted two libpcap callback packet buffers from core dumps that should be possible to test with, but I don't have any proper SCPS-TP packet to test with.

packet1.bin.gz packet2.bin.gz

pLuster commented 8 years ago

I've finally gotten around to create a proper pcap file out of the libpcap buffer dumps.

Wireshark correctly identifies the TCP option as SCPS.

scps-packets.pcap.gz

infrastation commented 7 years ago

The first problem you have described is now addressed with the change you have proposed (PR #517) and commit 87dba33 addresses the second problem, thus I am closing this issue as fully resolved. Thank you for such a thorough analysis and feel free to contribute more bugfixes in future.

infrastation commented 7 years ago

The summary for this issue is as follows.

Handling of TCP-AO in tcp_print() before 4.9.0 had several bugs, some of which could cause a buffer over-read in different ways. Hanno Böck had discovered some of those ways by means of fuzzing in 2015 (addressed in commits 3e00e6a, 6b8ed96, ec88d36), you have discovered another by means of analysis in 2016 (addressed in commit 91161b8). All of those over-read issues were collectively designated as CVE-2016-7975. Non-security bugs were addressed in commits 2857c0b and 4804e66. All those bugfixes are available in version 4.9.0.

Thank you once again for this report, please send any future security reports to security@tcpdump.org.