[314] in Best-of-Security

home help back first fref pref prev next nref lref last post

No subject found in mail header

daemon@ATHENA.MIT.EDU (Smart List user)
Sun Aug 17 00:17:30 1997

Date: Sun, 17 Aug EST  02:21:37 +1000 (EST)
From: Smart List user <slist@cyber.com.au>
Apparently-To: <miller@megahertz.njit.edu>
Apparently-To: <tomi@media.mit.edu>
Apparently-To: <soma@mist.ai.mit.edu>
Apparently-To: <instant@gnu.ai.mit.edu>
Apparently-To: <valgy@gnu.ai.mit.edu>
Apparently-To: <pjnesser@martigny.ai.mit.edu>
Apparently-To: <fdonovan@xolas0.lcs.mit.edu>
Apparently-To: <athena@glauke.lcs.mit.edu>
Apparently-To: <boyko@theory.lcs.mit.edu>
Apparently-To: <GALLEY@mitlns.mit.edu>
Apparently-To: <best-of-security-mtg@menelaus.mit.edu>
Apparently-To: <kcr@MIT.EDU>
Apparently-To: <endler@MIT.EDU>
Apparently-To: <mhpower@MIT.EDU>
Apparently-To: <hartmans@MIT.EDU>
Apparently-To: <jweiss@MIT.EDU>
Apparently-To: <adamf@csh.rit.edu>
Apparently-To: <ron@dl.kent.edu>
Apparently-To: <mtitchen@kent.edu>
Apparently-To: <mstgil@unt.edu>
Apparently-To: <alclar01@morehead-st.edu>
Apparently-To: <jtagnew@amherst.edu>
Apparently-To: <cvaughn@MATH.ORST.EDU>

7 remote from cheops
Received: from relay7.UU.NET by postbox.anu.edu.au with ESMTP
	(1.37.109.16/16.2) id AA183398493; Sun, 17 Aug 1997 02:21:33 +1000
Received: from honor.greatcircle.com by relay7.UU.NET with ESMTP =

	(peer crosschecked as: honor.greatcircle.com [198.102.244.44])
	id QQdcwf14331; Sat, 16 Aug 1997 12:20:59 -0400 (EDT)
Received: (majordom@localhost) by honor.greatcircle.com (8.8.5/Honor-List=
s-970308-1) id IAA26752 for firewalls-outgoing; Sat, 16 Aug 1997 08:11:26=
 -0700 (PDT)
Received: (mcb@localhost) by honor.greatcircle.com (8.8.5/Honor-970427-1)=
 id IAA26726 for firewalls@greatcircle.com; Sat, 16 Aug 1997 08:11:19 -07=
00 (PDT)
Received: from netscape.com (h-205-217-237-46.netscape.com [205.217.237.4=
6]) by honor.greatcircle.com (8.8.5/Honor-970427-1) with ESMTP id MAA0978=
2 for <firewalls@greatcircle.com>; Thu, 14 Aug 1997 12:14:08 -0700 (PDT)
Received: from judge.mcom.com (judge.mcom.com [205.217.237.53])
	by netscape.com (8.8.5/8.8.5) with ESMTP id MAA28507
	for <firewalls@greatcircle.com>; Thu, 14 Aug 1997 12:16:28 -0700 (PDT)
Received: from netscape.com ([205.217.243.101]) by judge.mcom.com
          (Netscape Messaging Server 3.0)  with ESMTP id AAA24497;
          Thu, 14 Aug 1997 12:16:26 -0700
Message-Id: <33F3598A.6DB73ACB@netscape.com>
Date: Thu, 14 Aug 1997 14:16:27 -0500
From: Bill Burns <shadow@netscape.com>
Organization: Netscape Communications
X-Mailer: Mozilla 4.02b8 [en] (X11; U; SunOS 5.5.1 sun4u)
Mime-Version: 1.0
To: fw-1-mailinglist@us.checkpoint.com, firewalls@GreatCircle.COM
Subject: ICMP inconsistencies in FW-1 (long)
Content-Type: text/plain; charset=3Diso-8859-1
Content-Transfer-Encoding: 8bit
Sender: avalon
Precedence: bulk

Overview:
During some routine testing of our Firewall-1 firewall we uncovered an
"inconsistency" in how Firewall-1 handles ICMP traffic.

Why I'm posting this to this mailing list:
I've found something that was inconsistent with how I thought this
complex firewall system worked and wanted to share my information with
the rest of the Internet security community.  I also wanted to share
(what I believe to be) a fix is.  I don't know of any current exploits
that uses this quirk, but I do know that it is behavior that was
unexpected.  I've already alerted Checkpoint to these findings and they
are aware that I'm posting this information.  They are reviewing my
INSPECT code but state that although they are aware of my findings they
know of no known exploits based on them.  [TT 11224]

I'd like the firewall community to help me "sanity check" my
observations and code, make any suggestions, and hopefully benefit from
any information I have gathered.

Goal:
My team was tasked with the goal of finding a way to securely let
internal users use VitalSigns' "NetMedic" product work through our main
firewall.  NetMedic is a clever application that helps analyze Internet
/ Web performance and help to identify bottlenecks along the entire
chain; from PC to webserver.  One of the more interesting statistics it
provides is the "hop count" to the web server you're browsing".  It does
this in real-time, so it's a very useful diagnostic tool.
(http://www.vitalsigns.com).   Plus it's just very cool.

Test Setup:
A test firewall was built and representative machines were placed on
either side of the firewall to accurately portray what our production
environment looks like:

- Checkpoint Firewall-1 v3.0a running on an Ultra Enterprise 2 with 128M
RAM with Solaris 2.5.1+patches
- a default ruleset of "deny all", including all the "checkbox"
protocols like RealAudio, VDOlive, ICMP
- no NAT was used (more on this)

The "external" side of the firewall was connected to an ISDN connection
back to the main office so that the PC could hit real web servers.  The
"internal" side of the firewall had only the PC on it.

A PC with Windows95 running NetMedic 1.2 and Netscape Communicator as
the web browser (NetMedic will work with Microsoft's IE as well as
Netscape Communicator)

Both the Solaris "snoop" utility as well as a Macintosh Ethernet sniffer
(EtherPeek) were used to analyze traffic on each side of the firewall.
EtherPeek was also used to generate traffic  from the external network
(more on this later).

How Microsoft tracert works: (example assumes the target is > 1 hop
away):
Source machine sends an ICMP type 8 packet ("ping") with a TTL value of
1.  Because this
ping packet will only live through one router, the first router responds
to the source machine
with ICMP type 11 (TTL exceeded).  The source machine then increments
the TTL value by 1
and issues another ICMP type 8 packet ("ping").  The second router to
the path of the target
machine responds with an ICMP type 11 (TTL exceeded) packet.  This
continues until the TTL
values are high enough to reach the target machine; in this case the
ping packet is replied to
by the target machine with an ICMP type 0 ("ping response") packet.

What we found:
Since we knew that Microsoft's trace routing utility (called tracert)
used ICMP exclusively to calculate hop counts, we knew to support
NetMedic's hop counting abilities the only protocol needed was limited
to "ICMP".   Since tracert "looked" a lot like ping, we thought we'd
start testing by just letting ping through the firewall.

Our initial assumption on how to accomplish this goal:

- Firewall-1's stateful inspection
- combined with checking the checkbox "allow ICMP"
- specifying that this ICMP rule be checked "before the last rule"
- and that a simple rule could be built into the GUI to allow "ping
traffic" (there's an example in the book)

What we noticed was that stateful inspection did not cover ICMP.  It was
perfectly clear by reading an example in the book on how to allow ping
through the firewall, but was not clear was if it was "stateful" or
not.  By reading the INSPECT code in $FWDIR/lib/base.def it became
apparent that ICMP was not statefully inspected.

What did that mean to us?  It meant that if we allow echo-request
packets to go out, we expect echo-reply packets to come back in.  But it
didn't send echo-request packets out, the firewall could still be
allowing echo-reply packets back in.  And if we weren't very, very
careful other kinds of ICMP packets could be allowed in.  (To be fair,
the "allow ICMP" checkbox does NOT allow the dangerous "ICMP redirect"
packets through -- this is explicitly stated in the INSPECT code.)

We were able to test these hypotheses in real-life by setting up a
suitable ruleset in FW-1 and watch the PC (internal network) ping the
Mac (external network).  When we stopped the PC pinging, we were STILL
able to shoot the captured echo-reply packets back to the PC.  In fact
we could send multiplied echo-reply packets back through the firewall
DURING ping sessions.  And even if we mangled the echo-reply packets
(i.e. make them the wrong sequence or ID number. or change the
destination address) we were still able to send them through the
firewall.   (Mind you, "ping" packets didn't pass, just the ping-reply
packets.)

The fact that we could not guarantee which ICMP packets would be passed
by our firewall concerned us greatly.  We didn't like the thought that
packets could be sent by an outsider without first being requested from
an insider.  This was not acceptable to us and was in violation of our
security policy.

We turned to writing our own stateful inspection INSPECT code to handle
ping and tracert.

[Note: To anyone thinking of writing INSPECT code from scratch just let
me say that on the surface it seems like a straightforward language, but
the learning curve is really steep.  Consult the manuals in the
beginning as a reference for some of the commands, but to really see how
this stuff works you've got to look at the *real* working code in
$FWDIR/lib/*.def  The manual isn't very clear on how to integrate the
GUI with the INSPECT code, nor does the syntax used in the book
accurately match what is actually used in real code.  Print out all the
INSPECT code you can, spread it out on the floor and eventually you'll
see how it works.  IN particular, look at the VDOlive code (xtreme.def)
and CoolTalk code (in base.def)]

What our code does:
This version of the INSPECT code just handles the ability to "ping"
statefully.  You've got to walk before you can run (as my manager
says).  Since NetMedic looks an awful lot like ping, I started with
ping.  There have been three major improvements in the code so far so
that it can handle NetMedic and UNIX traceroute as well.  But this is
simple enough that you'll get the point.

The code watches for outgoing ping packets and records the following
information:
- source and destination addresses
- the ICMP sequence number (useful to figure how which packets get
dropped)
- the ICMP ID number (which process on the source machine a packet
belongs to)
- allows a maximum of 5 seconds for this half-open state to exist
without an echo-reply

With the code in place external machines were unable to send unexpected
echo-reply packets back through the firewall.  Mangled packets (with
incorrect ID or sequence numbers) were also dropped.  In both cases,
unexpected echo reply packets also generated a log entry.  (And the PC
was still able to ping external machines. :)

Conclusion:
Even setting the FW up to permit ICMP and building appropriate rulesets
in the GUI does not mean that stateful checking of ICMP traffic is
performed.  To be able to track ICMP traffic you need to "roll your own"
INSPECT code.


Based on this ping code success, I went ahead and updated the code to
include the other applications we wanted.  Like was stated earlier, I
don't know of any exploits using echo-reply packets.  We just wanted to
be able to statefully watch the traffic coming through our firewall.
Thankfully, Firewall-1 gave us the ability to customize the software to
accommodate our security policy.

Checkpoint was very responsive to my notification of this issue and were
very helpful in assisting me to ensure that this did not appear to be a
flaw in Firewall-1.  Because there are no known exploits for sending
echo-reply packets to an unsuspecting host and in order to performance
as high as possible, they didn't see the justification to send ICMP
packets through their inspection engine.

I'm not arguing with their business or engineering decisions, I'm just
glad I can mold their product to fit my security policy.

I am continuing to work with them to further optimize my code and better
understand their INSPECT language.  (If my manager permits, my next goal
will be to write some INSPECT code to handle "Internet Quake"...we've
been getting a lot of demand for that one. :)

Other obscure notes:
With static NAT turned on for the internal network, FW-1 would correctly
pass echo-request and echo-reply ICMP types, but it did not correctly
translate the destination addresses of ICMP type 11 (time to live
exceeded).  It would pass the ICMP packet through to the internal
network, but leave the NAT static external IP address as the destination
address. [filed as TT0000012736]  The manual states that with "hide"
NAT, ICMP won't pass at all.

This version of the code doesn't include the code snippet from
Checkpoint's web page about defeating the "ping of death" packets.  It
was incorporated in subsequent releases.

If anyone sees any glaring errors or has any other comments about this,
I'd be more than happy to discuss them with anyone; either through the
mailing list of personal email.

Thank you,

Bill Burns
Electronic Security Architecture
Netscape Communications
shadow@netscape.com


 Here's the INSPECT code:
//
// Stateful ping/tracert v1.2 William D. Burns (shadow@netscape.com)
//
//PROPRIETARY SOURCE CODE OF NETSCAPE COMMUNICATIONS CORPORATION
//Copyright =A9 199x Netscape Communications Corporation. All Rights
Reserved.
//
// This is where the ICMP sequence number is, used for
//  tracking session-like information with ping,tracert

#define icmp_ip_seq [ 24 : 2, b ]
#define PING_Timeout 5
ping_table =3D dynamic {} expires PING_Timeout;

//
//  PING handling section
//
// Accept ping packets going to Internet
//        ping replies coming from Internet to initiator
// Reject ping replies not anticipated

//
// What a proper echo-request packet looks like
//
#define is_ping_request (                       \
  icmp, icmp_type=3DICMP_ECHO                           \
)
//
// What a proper echo-reply packet looks like
//
#define is_ping_reply (                         \
  icmp, icmp_type=3DICMP_ECHOREPLY                \
)

// if it looks like an echo packet,
//   record the session and allow the packet
//
#define ping_request_accept (                   \
  is_ping_request,                              \
  record <src,dst,icmp_ip_id; icmp_ip_seq> in ping_table        \
)

// if we get a echo_reply without an echo,
//   or the reply is not the right sequence number
//   that is a problem so drop it
//   (icmp_long is predefined in formats.def)
//
// Note: the delete looks like an error, but this
//   is the way is works.  Checking with the
//   vendor to see if this syntax is what they
//   intended.
//
#define ping_reply_intercept (                  \
  is_ping_reply,                                \
accept (                                        \
     ((ping_table [dst,src,icmp_ip_id] =3D icmp_ip_seq), \
     delete <dst,src,icmp_ip_id> from ping_table)       \
  or (log icmp_long, drop)                      \
  )                                             \
)

//This is what you you put in the prologue section
//  and what gets executed on a match for a ping
//
#define ping_code {                             \
        ping_request_accept;                    \
        ping_reply_intercept;                   \
}





home help back first fref pref prev next nref lref last post