[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [OPSEC] review for draft-ietf-opsec-ip-security-01
Hi Fernando,
sorry for delay with the reply...
inline.
On Fri, 28 Aug 2009, Fernando Gont wrote:
Hello, Andrew,
"3.3. TOS ..." -> RFC1349 is obsoleted by the RFC2474 (DSCP), so this
chapter needs a rewrite.
[....]
If I understand the relation of the RFCs correctly, we should be
discussing the semantics of this byte in terms of RFC2474, not RFC1349.
However, from the security point of view, since we do not know how a
particular end node interprets it, it may be even a good idea to look at
the relationship between both of the semantics.
The current text implies the ToS/Precedence is the current standards
definition - which is AFAIK not the case.
Agreed. I will swap the DSCP and TOS sections... and will think a little
bit about the relationship of these two semantics.
Thanks! And maybe somehow crossreference them, if it's not possible to put
them closer ?
9kb limit - the document should have some specific references to the
stacks that have it. Also, probably the reference to the RFC1122 (at
least for the terminological definition of the EMTU_R?)
Rather than stating that there are stacks that *have* this limitation,
the I-D states that virtually all stacks *can* reassemble datagrams of
at least 9KB.
Re-reading it, it looks ok - it sounds more like a back-up for the
reasoning for a given stack to be prepared to receive the datagrams of
9K that were fragmented by the other side, so it's ok.
Good. No changes here, then.
[Page 11]:
"3.5.2. Possible security improvements"
TODO - discussion of a quality of IP ID of being able to provide a
"fingerprint" of the remote host.
You mean you could fingerprint the host by "figuring out" the algorithm
used to set the IP ID, or what?
I used this technique several times to understand whether the particular
packet was sent by a host, or by someone sending a packet on its behalf.
Isn't this already addressed by the "count number of systems behind a
NAT" and "fingerprinting physical devices" stuff?
yeah, though for the everyday diagnostics, it's a bit too much math in
those. May be good to say that for diagnostic purposes it should be
possible to revert the behaviour to the "sequential" IP ID allocation, but
that's not anything strong from my side - after all, it is more of a
parlor trick to avoid looking at the traffic at two points at once.
[Page 24]:
"Enforce a limit on the maximum number of options" - to me this looks a
bit of a dangerous recommendation in this form, as it would cause
arbitrary hard limits set by middle devices, resulting in creation of
"IP Option MTU". (Not that anyone is adding a lot of IP options anyway
these days, so it is more a theoretical nitpick :-)
Well, just pick a very large limit that will never limit anything, and
that's it.
"never limit anything" for a particular environment that I see that I
pick for. And if you send me the options you can never be sure whether I
am going to process them or I am going to persistently drop them.
Well, this limit is not meant to knock down legitimate uses. e.g., do
you see any real traffic with more than four IP options?
Realistically, I don't think IP options are a huge innovation vehicle,
because of the performance hit they impose in a lot of implementations.
Having the limit implies the overhead of processing the options, whereas
rate-limiting the processing of those packets cuts them off earlier. You
don't have to first do all the work and then then say "oops, too much".
That aside, this may already be the case with packet scrubbers deployed
on the path to destination...
With the packet scrubbers, all bets are off. I'm talking the conventional
routers.
Rate-limiting alone should be fine - as it allows the options still to
be processed when not under load, whereas the upper bound puts a hard-stop.
You mean you'd rate limit the processing of packets that contain options?
I'm not necessarily arguing against this, but this would sort of open
the door to a new attack: just send packets with options to DoS any
traffic that carries options. Whereas imposing a limit on the number of
options would hurt the traffic that's using a "surprisingly" large
number of options.
I might argue that one might want to do both.
see above - the figuring out the number of options is in itself work.
Though, theoretically, might also be performed in the accelerated path.
Basically it all boils down to how the implementation processes the
options in the first place - if any option processing is as efficient as
the traffic without the options, there is no reason either to rate limit
or limit the number of options. You do need to rate limit the flow to the
components that have limited computing power.
[Page 31]:
LSRR, SSRR and RR options - can their restrictions be combined as much
as possible ? To me they look largely similar, and the repetition is a
cause for potential mistakes, IMHO.
I agree that repetition is a potential source for mistakes, and that
conceptually speaking, they *could* be combined. However, I think it's
useful to be able to read whatever you need to know about each option in
a single section. And that of having "repeated" stuff allows me to use
"descriptive "acronyms" for each option ("LSRR.length" vs.
"SSRR.length", etc.). Please let me know if you feel strongly about this
change.
Ok, let's see. Copypasting from the draft.
valid LSRR:
LSRR.Length >= 3
LSRR.Offset + LSRR.Length < IHL *4
LSRR.Pointer >= 4
LSRR.Pointer % 4 == 0
empty LSRR:
LSRR.Pointer > LSRR.Length
can write LSRR:
LSRR.Length - LSRR.Pointer >= 3
valid SSRR:
SSRR.Length >= 3
SSRR.Offset + SSRR.Length < IHL *4
SSRR.Pointer >= 4
SSRR.Pointer % 4 == 0
empty SSRR:
SSRR.Pointer > SSRR.Length
can write SSRR:
SSRR.Length - SSRR.Pointer >=3
valid RR:
RR.Length >= 3
RR.Offset + RR_Length < IHL *4
RR.Pointer >= 3 <------------- wrong ?
Yes, this is a bug. It should be:
RR.Pointer >= 4
RR.Pointer % 4 == 0
full RR:
RR.Pointer > RR.Length
additional RR validity check:
RR.Pointer - RR.Length >= 3 <---- valid if Pointer is bigger than
length + 3 ?
Good grief! It seems I screw up when I converted the nice PDF into the
IETF I-D.
It should be RR.Length - RR.Pointer >=3
It means that there is room to store a 4-byte IP address. (the check
looks ugly because RR.Pointer starts with "1" ("1" when it points to the
beginning of the option, and 4 when it points to the beginning of the
option area)
from what I read in the RFC791, the smallest possible value for the
pointer is 4, quote from page 17:
"The option begins with the option type code. The second octet
is the option length which includes the option type code and the
length octet, the pointer octet, and length-3 octets of route
data. The third octet is the pointer into the route data
indicating the octet which begins the next source address to be
processed. The pointer is relative to this option, and the
smallest legal value for the pointer is 4."
The RR ones that I marked with the arrow are interesting:
"The pointer field is relative to this option, with the minimum legal
value being 4. Therefore, the following check should be performed:
RR.Pointer >= 3
"
-----> So this looks like a bug, the value should be 4, not 3 ?
Yes.
and then call this from the option processing where needed.
Currently the reader has to first spot that the checks are pretty much
the same, then write them down close by to verify this = extra cognitive
load for the reader. And, appears, for the writer as well :-)
So, yes, I'm rather strongly in favour of joining whatever can be joined.
Ok. how do you propose to do this? For LSRR and SSRR, this would be
easy: just document the checks for one of them, and include a pointer
to those checks in the other option.
For the RR option, one could say "implement the same checks, but do not
enforce the SSRR.Length - SSRR.Pointer >= 3 check". But that would look
ugly.
(and, if you had to code these, you'd need to indicate whether its a
XSRR option or a RR option, because of this last check that applies only
to XSRR options).
Thoughts?
As per the equations I wrote above, there is a higher-order operation that
is common and can be abstracted - i.e. the checks look pretty much the
same for the most part, and only tiny pieces differ. So, describe the
limitations, and enclose the higher-order check algorithm, and how it is
invoked for each of the options.
[Page 42]:
Man in the middle threat mention for DSCP: is this the only field for
which the MITM attacks are a concern ?
[....]
http://tools.ietf.org/html/draft-ietf-opsec-ip-security-00:
" However, if this moderate congestion turned into heavy congestion,
routers should switch to drop packets, regardless of whether the
packets have the ECT codepoint set or not.
A number of other threats could arise if an attacker was a man in the
middle (i.e., was in the middle of the path the packets travel to get
to the destination host). For a detailed discussion of those cases,
we urge the reader to consult Section 16 of RFC 3168.
"
^------
ECN/DSCP and ToS (if the ToS is there at all) should definitely sit
somewhere together IMHO.
The MITM attack is mentioned only for ECN because MITM attacks *are*
mentioned in the ECN spec. I'm more of the idea to delete MITM
discussions, rather than adding more of it.
e.g., we'd have to add stuff on the IP ID discussion (if there's a MITM,
an attacker could spoof packets with the same IP ID, and cause
reassembly to fail), an attacker could rewrite the contents of the IP
source route options, etc. I'd personally avoid getting into this. :-)
Thoughts?
if there's MITM all bets are off with IP, imho :-) Similar to vanilla TCP.
[Page 51]:
The sequence# check: should here be a reference to the section 3.4.3 of
rfc2406 as a pointer to what constitutes the "valid sequence#" ?
Would just a pointer (reference) address your comment?
yes, reference is ideal.
Good. Will do.
Step three: should there be more specifics about some randomization for
the process of dropping ?
Hints? (Argue something like "it's recommended that fragments are
flushed on a random basis" or the like?)
Probably. One question about this algorithm in general - is this
something that works and tested in real life with code, or it is
something we think may work if implemented ? If the former, there should
be references to the implementation, if the latter - maybe this deserves
a separate doc, and a a good scrutiny of IPSEC people ?
The separation of reassembly into separate protocols has not been
implemented, AFAIK. So it would be "the latter". However, this document
*has* been reviewed by Ran Atkinson (author of RFC 2401). Further thoughts?
well, if the IPSEC folks don't have any comments - up to them. I still
think that putting the big lock on the door (AH/ESP) and leaving the
window (UDP/4500) wide open, is more of a security theatre than a real
protection. Combined with bugs which will inevitably result from the
separate codepaths (read: $$$ for development and testing), I think
the collateral damages are worse than the possible wins.
Also - this algorithm omits the frequently used NAT-T (essentially IPSEC
over UDP/4500)
Could this really be incorporated in the algorithm?
That's what I wonder. :-)
I would argue against this one. You cannot separate this traffic into a
different queue, because you might receive a non-first fragment first.
And, IIRC, linux sends the last fragment *first*.
right.
I really think now that this piece should be
looked at by the IPSEC people, even if to say "We don't need this
because we never fragment".
Realistically, that's pretty much the case, because if you need to
reassemble the fragments before decryption, you're playing in a much
lower league performance-wise. So, this text might be redundant altogether.
Well, the bottom-line of this document is "you should not rely on
fragmentation.... but if you do, here's how you could improve the
security of the process".
As I said - I think the penalty that it brings in terms of additional
costs weights more than the positive sides of it.
[Page 52]:
"virtually impossible" - I'd replace this with "harder" :) And, as the
MITM is mentioned for DSCP, I'd not make the task easier for IPSEC
specifically :) the algorighm which is supposed to protect IPSEC should
be able to resist the on-path attacker.
Well, I don't think you could protect IPsec traffic that relies on
fragmentation. If a have access to the IPsec fragments, I could simply
forge fragments that would lead to a failure in the reassembly process.
Ok. So I have a growing conclusion that then the more complex reassembly
algorithm would be useless then. Either use the system-standard one, or
don't fragment, period. Less bugs :)
One might argue that you could allow IPsec traffic from a single host
(by means of a fw) and allow non-IPsec traffic from anywhere else. In
this case, the algorithm might be of help.
So this implies a wide change in the fragment handling for a very specific
scenario. And in that case one might apply other situation-specific tweaks
- if you know your peer and you know its behaviour, most of the times you
can tune it to avoid fragmentation whatsoever.
[Page 53]:
"Additionally, given that many middle-boxes such as firewalls create
state according to the contents of the first fragment of a given
packet, it is best that, in the event an end-system receives
overlapping fragments, it honors the information contained in the
fragment that was received first."
received first if there was a box behind the middlebox that has
reordered the packets afterwards, or if there was no such box ? :-)
Not sure what you mean.
I meant that I do not really see the logic here. You have a middlebox
that forwards the "fragmentA", then "fragmentB". On the way to you they
get reordered. You keep the "fragment B". But according to your
statement the firewall keeps the state according to "fragmentA". So
we're doing exactly the opposite of what you intended to say ?
If a host receives fragmentA (first) and fragmentB (second) and they
overlap, they should use the contents of fragmentA.
(the referenced RFCs should how you could bypass a firewall if the host
uses fragmentB instead of fragmentA).
Does this make sense now?
Yes.
If the two received fragments contain conflicting information, we do not
have enough info to discern which of the two is "correct", IMHO. So, we
should mark the corresponding packet as "bad",
Isn't this more aggressive than what the existing text recommends?
to an extent. But it's also more predictable - you get packet lost, not
corrupted. Else if you reassemble, either the upper layer detects the
error (so we still have the same problem, but at an upper layer), or it
does not - at which point we are unsure whether there is no error
because the upper layer check is weak, or because we actually
reconstructed the original packet..
OTOH with the "drop if suspicious" idea, there's an easy DoS vector...
You're right. Scratch this.
So... should keep the next "as is"?
yup. Maybe just include some discussion that if we have two fragments,
in the absence of a stronger error check for the contents of the entire
PDU that those fragments belong to, it is impossible to say which one is
"good" and which one isn't.
treat the reassembly as
usual, and then drop it with an auditable event. (not drop immediately
in order to avoid the DoS where colliding fragments would be dropped and
cause the accumulation of the remaining fragments till the max
reassembly timeout occurs).
I agree with this "remaining fragments thing". However, obvious
question: how long should we wait? This might close one door of attack,
but open another one....
same as for regular reassembly. The fact that you have two colliding
fragments, does not matter - you could as well receive two spoofed
fragments for different IP IDs, and there you can't be sure if they are
spoofed or not. So I'd treat these cases functionally the same.
Thinking out loud: One might argue that if there are two many incomplete
fragments in the queue, one should flush them all (or at least quite a
few of them) -- if not, an attacker could simply trash the whole IP ID
space. Then legitimate fragmented traffic would complete the reassembly
processs with the spoofed fragments, thus leaving a (later arriving)
legitimate fragment in the fragment queue, which would keep the IP-ID
space trashed.
Thoughts?
Again, because there is no way to determine a "legit" vs. "non-legit"
fragments, it is technically impossible to tell an attack from just a
higher rate of fragments that arrive, due to some other anomaly. If it was
a network anomaly as opposed to malicious activity, then we end up
throwing away the packets that would have been correctly reassembled.
(Read: applications people will get unhappy :-)
[Page 54]:
sending with high precedence values: ingress filtering ?
ingress-filtering based on the IP addresses, you mean?
Yes, I mean that this is not the business of the host to deal with this
- especially that there's no real recommendation: "yeah. They say you
should not drop this. but bad stuff is easy to do. So, be bear aware!"
I will add a note on ingress filtering here.
(Also, with the DSCP/ToS duality, worth doublechecking on how does it
translate to real forwarding devices?)
mmm... not sure what you mean.
i.e. how much of a problem it really is, and whether it is something
that was shown practically possible, or is more a theory.
Are you referring to TOS (specifically), or TOS+Precedence?
either/both.
[Page 55]:
Address resolution: the passage about storing the packets for a long
time on the router - isn't it something that should be directly
discouraged, precisely because of its big impact ?
What specific behavior would you recommend?
This is not about recommending, but rather about the practical
behaviour. AFAIK, the router would in practice throw such packets down
the drain. Or there exist a real-world routing device that actually
holds all the packets for an unresolved L2 adjacency ?
A unix-like box operating as a router would do this, IIRC. Nevertheless,
there are too many devices around. And some might be doing this -- hence
the discussion. (it *is* noted that it's a usual implementation approach
that the device drop the packet that elicited the address resolution
before engaging in arp).
Ok, let's leave this one as is.
thanks,
andrew