RE: CBV

Mark Shewmaker <[email protected]>
Newsgroups gmane.mail.spam.srs.general
Message-ID <[email protected]>
On Fri, 2004-04-30 at 11:24, Seth Goodman wrote:
> Let me try to address both Tony's and Wayne's questions at the same time.
> Wayne's second point is a valid objection about mailing lists breaking
> content checks.  This is a real problem today and it breaks any content
> check, including S/MIME.

I don't think these are valid objections.

Mailing lists shouldn't be sending out emails to subscribers using the
same MAIL FROM given by the original sender anyway, so even if they have
edited the message contents before sending them to their subscribers,
they'll have created a new MAIL FROM to go with that edited content.

As far as MS exchange and other MTA's munging the body of emails and
thus causing checksums to become invalidated--well, I would consider it
a feature that corrupted emails can be detected.

Looking at corrupting MTA's from the viewpoint of both Senders and
Receivers:

Receivers:  If receiving machines are behind a corrupting MTA, then 
            those admins will be aware of their broken mail server.

            They'll simply have to configure their server to ignore
            messages with corrupted checksums until they get their
            broken MTA fixed.

            If that's politically difficult, well, they aren't any
            worse off than today, and as everyone else adopts workable
            solutions, it will become politically easier to push for
            an actual fix to their broken MTA.

Senders:  Senders who are behind a corrupting MTA will be unlikely to
          tell people to verify checksums in the first place, up until
          they get their broken MTAs fixed.

Minor rant:  In both cases it will become easier for technical types
             to point manager types to real business reasons to fix
             these technical problems if the problems cause them to
             miss out on the ability to detect forgeries, reject likely
             spam, and lower help desk costs.

> Though something ultimately needs to be done about
> this in general, let's assume that nothing changes and we have to deal with
> the status quo.  For the purpose at hand, which is preventing a harvested
> SES address from being used for spoofing, I will change my proposal and
> suggest that we only need to protect the headers, not the body content to
> avoid Wayne's valid objection.

Except for being prepared ahead of time for any future SMTP extension
that allows body headers to be sent before the rest of DATA, I don't see
any advantage in limiting the checksum to body headers.

More below.

> In Wayne's exploit of SES, the spammer harvests signed addresses from
> responses sent from general sales accounts or other loosely administered
> accounts at large sites.  Since this method of exploit is now known, you can
> protect yourself against it by limiting the outgoing mail to a single
> recipient and include a hash in the MAIL FROM: that protects the same
> headers that S/MIME would protect.  Please correct me if I have these wrong,
> but I believe that these are To:, cc:, bcc:, From:, Sender: and Date:.  With
> a single recipient on the outgoing message and a hash that protects these
> headers, the signed return path would only be useful for the spammer to spam
> himself.

I don't think I'd be the only one to object to solutions that disallow
multiple recipients in the envelope headers.

> Wayne's first point was that we couldn't really protect the content with a
> checksum.  I certainly agree with that and I proposed a SHA-1 hash rather
> than a checksum to fix this.  If we are protecting only headers and not the
> message body, I think it becomes an intractable problem to synthesize a
> group of headers that generates the same SHA-1 hash as the original message
> headers.

I disagree with the implication that an attacker would effectively find
it any easier to find a collision by adding/changing random characters
in the full message body versus adding/changing random characters in a
limited set of message body headers.

Remember that for a good hash, when you change one bit of the data being
hashed, there's a 50% chance that each bit in the hash output is
flipped.

You don't get any advantage when searching for a hash-collision in
altered 10M files versus 10k files, if a hash collision is your only
goal.  (In fact, it's probably slightly easier, given that the hash will
have less data to have to, well, hash.)

The attacker could simply limit the search to changing and testing bits
in *any* of the headers that are looked at.  If you're truncating the
hash to four characters then there's more than enough space in even
these few headers in which one could find a collision.  (Most users
wouldn't notice a CC: to "dfb89q3n028 <[email protected]>", just as they
wouldn't notics an html comment of "dfb89q3n028bas98hjg" were it
embedded in the message body instead.)

BTW, I think four characters is not nearly enough..

If the hash data is truncated to four characters, (as you suggest in
another message I've quoted below) then you should expect a 50%
likelyhood of finding a hash collision by going through every
just-as-many-bits changes as bits in the truncated hash output.  In this
case that's 4 characters multiplied by 6 bits per character, or 24 bits,
meaning 16 million tests--pretty easy to run through, and no matter if
the data being hashed is limited to a few headers or consists of the
entire body, you're still merely cpu bound.

I'm typing this email on a 1.6GHz Athlon, where doing an sha1sum of
/etc/inittab took me .002 seconds.  Making the simplifying assumption
that I can do any sha1sum in .002 seconds means that in less than 9
hours and twenty minutes I can test 64^4=2^24=16777216 combinations of
data, for which I would expect a 50% likelyhood of coming across any
specific truncated-to-4-base-64-characters hash I wanted to find.

(In reality the time should be much less, as I wouldn't be actually
loading and dynamically linking the same sha1sum program 64^4 times, but
the point is that this is very doable.)

In any event, four characters is not possibly enough.

Truncating less would obviously improve things, perhaps having the SES
format allow for a variable number of characters for the
verifiable-SES-hash section, and just including enough characters so
that the cpu bound process is intractable at any given time.

However, if SES addresses aren't SRS rewritten, (I'm not yet convinced
that's a good idea in most-people-do-SRS-world, even though I am
admittedly a proponent of whitelisting instead of SRS), then there
shouldn't be any problem with simply increasing the verifiable-SES-hash
section as close as possible to the full 160-bits that sha1 produces. 
(Which takes 27 base-64 characters.)

Which brings me to a curve ball of my own to throw into the mix.

Quoting out-of-order the SES format you suggest:

>SES0=HHHH=TT=hhhh=local-part@domain
>
>where
>   HHHH = first four base 64 digits of the
>          SHA-1 hash of the remainder of the
>          address prepended with the hash
>          secret (MSA login password) for
>          local-part@domain
>
>   TT   = first two base 32 digits of the UNIX
>          integer day number mod 1024 (same as SRS)
>
>   hhhh = first four base 64 digits of the
>          SHA-1 hash of the specified header
>          lines

Working off an assumption that SES addresses aren't ever rewritten by
SRS forwarders, but instead gets passed directly through, (I think this
is what's being proposed by the SES modifier), I have a completely
off-the-wall idea for altering SES..

1.  Imagine an SES-enabled MTA sends out emails with the following 
    mail_from format, slightly different from the above:

    SES0=H27=T4=L27=local-part@domain

    Or:

    SES0=   Unchanged.
    H27=    A 27-character base-64 representation of all 160 sha1
            bits of all of the following:  ("SES0", local secret,
            T4, C27, local-part@domain).
    T4=     A 4-character base-64 representation of a 32-bit time_t,
            the number of seconds since the epoch.
    L27=    A 27-character base-64 representation of all 160 sha1
            bits of all of the following ("SES0", local secret, TT,
            local-part@domain.)

    For completeness:

    B27=    A 27-character base-64 representation of all 160 sha1
            bits of all of the following ("SES0", TT, 
            local-part@domain, message body.)

            Note that C27 is not included in this mail_from, but
            it is included in the computation of H27.

2.  Doing the math on the above to look at character-lengths,
    two 27-character hashes, plus the remaining "SES0==TT=" text
    adds up to 66 characters before we include the original, unSESed 
    local-part.

    But we're not supposed to make local-parts that are larger than
    64 characters, and we can't exactly say that the included local-part
    has to be shorter than negative two characters long.

    So, change the format definition again and say that in making a new
    mail_from of the format SES0=H27=T4=L27=local-part@domain, that
    the H, T, and L components can be made using "up to" 27, 4, and 27
    characters.

    So, the SES sender will truncate H, T, and L such that the total
    new local-part doesn't exceed 64 characters in length.

    It doesn't particularly matter what algorithm is used, merely that
    given a length of a local-part and a T4, that the SES-creating-code
    used will *always* come up with the same H, T, and L lengths.

    A side implication is that any particular local-policy decisions
    on minimum acceptable H, T, and L lengths will translate into a
    local-policy maximum size of an unSESed localpart.

    (For instance, having H, T, and L be required to be at least
    4, 2, and 4 characters each results in a maximum local-part of
    46 characters.)

3.  Recipients who do simple CBVs will submit this 

    SES0=H27=T4=L27=local-part@domain

    for validation.

    In other words, they're submitting for CBV the same mail_from
    line they received.

    The sending-machine can look at the local-part and its policy,
    and figure the needed lengths of H, T, and L, and figure out
    whether the CBV's given local-part@domain and T match up with
    its given L, *ignoring H27 altogether*.

    If there's a match, then the CBV will succeed.

    Note that as a protection against replay attacks, the sending
    machine could note how many CBVs it's recently been requested to
    do for any particular T, L, and local-part@domain combination,
    perhaps slowing down the response to CBVs with that combination
    after a time, perhaps even invalidating that combination after
    some threshold of number/timing of CBVs have been made.

    (This is vaguely similar to unix logins slowing down after a
    unsuccessful login attempts.)

    This is a Sender-side protection against replay attacks.

    This protection against replay attacks requires a database
    of sorts for the MX machines, but it can be pretty ephemeral,
    keeping stat info that ages out for instance.  That would
    protect against replay attacks of a million copies of the same
    mail_from within a half-hour interval, but not replay attacks
    of large numbers of separately harvested mail_froms.

    A more extensive database, keeping track of the number of
    recipients for any T, L, local-part@domain combination can
    help tune the triggering of CBV-response slowdown and lockouts.
    (If you know you only had one recipient but had 10000 callbacks,
    then something is probably wrong, though it's conceivable that
    legitimate alias expansion forwarding is being used.) 

4.  Recipients who are willing to do body checks can submit an
    alternative mail_from of the format:

    SES0=H27=T4=B27=local-part@domain

    This is the same as the mail_from that the sender sent,
    except the L section is replaced with the body checksum B.

    When the sending machine receives a CBV of that format, it
    computes the H checksum that it would have made sent out,
    were it to have sent out an SES0 address with the included
    T, B, and local-part@domain, (taking into account the
    local secret applicable for that T and local-part@domain
    of course.)

    Note that the sending machine, given local-part@domain,
    will know how many characters it would have put in its H27,
    so even if it only sent out an H10 instead of H27, and the
    recipient only has an H10 to send back, the Sender will
    see that that smaller H10 is a legitimate length to receive
    for a CBV, and it will simply do compare the first 60 bits
    of the would-have-been-H27 sha1 hash, (H10 gives 60 bits.)

    This check protects recipients from replay attacks,
    even if thousands of other recipients are falling victim
    to replay attacks and only do normal, non-checksumming CBVs. 

    It also requires no database on the Sending machine side of
    things.

5.  Since I didn't specify that CBV checks from (3) or (4) have
    any different format, the Sending machine has to potentially
    do two tests if it receives an [LC]27 of 27 actual characters,
    and the length of the local-part given would have caused it
    to have sent out an L27 of 27 characters.

    So it would have to do the test in 3, and if that failed, do the
    test in (4), returning success if either succeeded or failure if
    both failed.

    Of course, if the length of the local-part meant that the Sending
    machine would have truncated L27 below, err 27 characters, then
    the receipt of a mail_from with a full B27 means that test (3)
    can be skipped.

6.  A full H27 and B27 means the mail_from local part is more than 64
    characters, which is not nice according to rfc2821.

    One solution to that bit of awkwardness is to take a server
    advertising SES capability in its SES string to be understood
    to be claiming that it can *accept* local-parts that are not just
    64 characters, but 64+2*27+12=130 characters.  (That accounts for
    an H27, a T4, and a B27.)

    Recipient machines who want to do SES body checks can then only
    do them if they know that their outgoing MTAs can deal with that
    length of local-parts, and their incoming MTAs don't corrupt message
    bodies.

This alternative way of doing SES allows for body checks to be done or
not done on either side, while using as many characters as possible for
any given original local-part.

(Note that even if the sender doesn't send out a full H27 but instead
truncates the sent hash down to an H4, an attacker trying to modify a
message such that their mail-from (with C27) matches to a valid H4 can't
just compute themselves through all 16 million H4 combinations, but
would instead have to ask the server to verify each of these in turn,
something that should be relatively easy to detect, and even thwarted by
increasing incoming CBV delays after some threshold of
bad-CBVs-per-unit-time.)

(Now my brain hurts.  Although I think something like this is a better
way of doing SES, in that it accounts for the problems folks point out
with it such as replay attacks, I'm not sure if a scheme of this
additional complexity would ultimately help or hinder spf adoption in
the long run.  I'm also not sure how it would or should interact with
VERP.)

(I'm also not sure whether I think that the necessary assumption, that
SES addresses should never be rewritten with SRS, is a good idea or
not.)

Any thoughts?

-- 
Mark Shewmaker
[email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.