[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Thandy attacks / suggestions

Hi folks,

I met with Justin Cappos yesterday about our auto-updater draft design.
Justin did his PhD thesis on package management security, and recently
presented a paper at CCS on vulnerabilities and flaws in the package
management infrastructure for Red Hat, Debian, etc.

Overall he was very positive about our design. He thinks it is very
well adapted to our situation, and he wants to help us make it into a
"best of breed" for other groups in a similar context.

He had a number of suggested improvements. I've tried to capture them

1) Apparently python's urllib doesn't check SSL certs or cert chains.
So while we may think that handing it https://updates.torproject.org/
will mean it'll complain if the cert is wrong, apparently we'd be
mistaken. His suggested fix was to ship our SSL cert with the updater;
that's no fun if we change our cert or if we add a mirror with a cert,
though. He didn't have a second suggested fix. At least we know now.

2) Every time we list a hash (e.g. in the timestamp file), we should
also list a file length. Now we can handle "infinite file" attacks,
where a jerk repository just keeps giving us bytes, and we fill up our
disk. (As a bonus, it might also improve our odds a little if somebody
comes up with a fragile way to generate hash collisions, if it's a lot
harder to generate a collision of the same length.)

3) We still have a "trickle attack" to worry about -- the repository gives
us one byte of the file per minute. We should notice that the file isn't
coming in fast enough, and give up so we can retry somewhere/sometime
else. This sounds like a fine "future todo" item.

4) Our strategy for migrating to a new master key (or away from a
compromised one) is that we'll sign with all master keys for a while,
until everybody has migrated to the new set of master keys. This approach
can lead to a (perhaps theoretical) situation where the adversary strips
off some of the signatures: now clients who show up believing in a
certain set of master keys will accept the keylist, and clients who show
up believing a different set won't accept it. Perhaps some partitioning
can result? We don't have an exact attack. This vulnerability happens
because our signatures are independent of each other. We could instead
imagine a signature design where each signature is tied to the others,
so you can't strip some of them and still end up with a valid file. Not
worth worrying about yet imo unless a) somebody comes up with a real
attack or b) somebody comes up with a good clean alternative approach. :)

5) He wanted to make sure that we verify that the timestamp for each file
listed in the timestamps file matches the timestamp listed in that file.
That is, does timestamps->mirror_timestamp match mirrorfile->timestamp?

6) We have this paragraph in the spec when looking at the key list:
   The "ts" line describes when the keys file was updated.  Clients
   MUST NOT replace a file with an older one, and SHOULD NOT accept a
   file too far in the future.
This applies to the other files (timestamp file, mirror list, bundle
files) too, right?

7) We had a long discussion about the "what if the attacker gets a copy
of the timestamp key" worry. This issue seems to be the big remaining
question in the design: an attacker who can generate his own timestamp
file and either modify the repository or intercept client requests can
freeze clients in time, so they never know about updates and never realize
they're frozen. Since the timestamp file is only signed by the timestamp
key, he can also mix-and-match which hashes he puts in the timestamp file:
a keylist from time A, a mirror list from time B, a bundle from time
C. Some of these attacks are mitigated by having clients never replace
their current files with older files. But a newly bootstrapping client
can still be tricked into installing a package that's 18 months obsolete.

Some partial solutions:

A) Rotate the timestamp key every month. This limits the rollback window
to a month, if we put an expiration time in the timestamp key. This means
the master keys need to make and sign a new key list every month.

A2) Add another layer of indirection, so there's a timestampsigning key
that signs the timestamp key. That timestampsigning key is listed in
the key file, and it's kept offline. Whoever controls it still generates
a new timestamp every month, but now all the master keys don't need to
be bothered.

B) Put expiration times in the mirror file and bundles too.  Otherwise an
attacker who gets this month's timestamp key can still tell you to use
a mirror file and/or bundle from last year, so long as the signing keys
for those are still in the key list. We could make the expiration times
for those longer, if we want to accept longer attack windows. We should
probably put an expiration time in the key file too, especially if we
go with "A2" above where an attacker can take an old key file with a
compromised timestampsigning key, generate a fresh timestamp key, and
look legit.

Alas, I'm wary of anything that causes clients to decline to update if
we fail to get all the right signatures happening every month. Each of
the above steps adds a lot of recurring hassle.

C) We should stop letting every mirror serve the timestamp file, but
instead serve it from a smaller more trusted subset of the mirrors
(maybe all the ones with the "official" flag set). It's tiny anyway,
so the only issue this introduces is less robustness in the face of an
attacker who knocks down mirrors. I'm not sure how big a change this is
from the spec, which says:
  Every mirror is a copy of some or all of the directory hierarchy
  containing at least the /meta, /bundles/, and /pkginfo directories.

D) We can ship the initial installer with static copies of the meta
files (or just timestamps, but using the files seems simpler), so if
you have a recent installer, you can't be bootstrapped into something
older than those.

Other options?

Overall, I'd say we should aim to resolve #1, #2, #5, #6, and #7C (and
maybe #7D), and keep the rest as open research and future todo items.

Lastly, quoting Justin: "Be aware that when a client downloads files and the
hashes do not match what is in the key file, this is not necessarily
an attack. The files could have been updated during the transfer and
the client might have a mix of old / new files. Assuming you do mirror
updates "atomically" using move and you don't do more than one update
in the amount of time a client is likely to take to do the transfer,
the problem can be fixed either by re-retrieving the key file when you
have a hash mismatch or downloading files by hash instead of name. The
latter does have staleness problems though."