oss-sec mailing list archives

Travis CI MITM RCE


From: Jakub Wilk <jwilk () jwilk net>
Date: Sat, 25 Aug 2018 23:49:23 +0200

Travis CI <https://travis-ci.org/> is a popular continuous integration service used to build and test software projects hosted at GitHub. (Travis itself is free software, but the primary reason I'm writing this is mail is that the service is used by many free software projects.)

I discovered multiple bugs in the way Travis CI uses APT and GnuPG that defeat the package authentication mechanism. As a consequence, the bugs allow man-in-the-middle attackers to execute arbitrary code in the context of a Travis build that uses the APT add-on.

This is probably not a big deal if use Travis CI only for running tests. But Travis also supports deployment (grep for “Deployments and Uploads” on <https://docs.travis-ci.com/>); if you entrust Travis with any secrets, this is bad news for you.

Here are the bugs details:

------------------------------------------------------------------------

1) On 2015-04-13, the “--force-yes” option was added to apt-get invocations: https://github.com/travis-ci/travis-build/pull/424

This option name doesn't sound very dangerous, but it makes APT assume the “yes” answer to all questions, including the question about installing packages that couldn't be authenticated…

On 2017-10-12, I reported this bug to the Travis CI security team.

On 2018-07-05, --force-yes was replaced with --allow-downgrades --allow-remove-essential --allow-change-held-packages: https://github.com/travis-ci/travis-build/pull/1422

I'm not sure how could this change possibly work, because APT in the Ubuntu versions Travis CI supports (precise, trusty) doesn't have these options… So a few days later --force-yes was added back: https://github.com/travis-ci/travis-build/pull/1433

------------------------------------------------------------------------

2) On 2017-10-12, code was added to refresh an expired signing key: https://github.com/travis-ci/travis-build/pull/1192

The code used 32-bit key ID to retrieve the key from the keyserver. I reported this on 2017-12-06: https://github.com/travis-ci/travis-build/pull/1269

My patch was not accepted. Instead, more generic code to refresh expired keys was added: https://github.com/travis-ci/travis-build/pull/1290

The new code looks like this:

   apt-key list | awk -F'[ /]+' '/expired:/{printf "apt-key adv --recv-keys --keyserver keys.gnupg.net %s\\n", $3}' | 
sudo sh

The “apt-key list” format varies with GnuPG version, but on Ubuntus Travis supports, it uses… 32-bit key IDs.

(For extra fun, this code happily executes code embedded in user IDs. I don't believe this is exploitable on Travis CI, though.)

Apparently some joker already exploited this bug to add their own key to the APT keyring <https://travis-ci.org/jwilk/testbed/jobs/420519943>:

  $ apt-key list | grep -A1 -w A15703C6
  pub   4096R/A15703C6 2016-01-11 [expires: 2020-01-05]
  uid                  MongoDB 3.4 Release Signing Key <packaging () mongodb com>
  --
  pub   1024R/A15703C6 2016-06-25
  uid                  Totally Legit Signing Key <mallory () example org>

I can neither confirm nor deny that it was me. It might be a mere coincidence that I wrote a tool to brute-force 32-bit key IDs:
https://github.com/jwilk/stopgp32

------------------------------------------------------------------------

3) For many repositories in the APT source whitelist <https://github.com/travis-ci/apt-source-whitelist>, the signing key is downloaded over HTTP. For example:

 {
   "alias": "cassandra",
   "sourceline": "deb \"http://www.apache.org/dist/cassandra/debian\"; 39x main",
   "key_url": "http://ha.pool.sks-keyservers.net/pks/lookup?search=0xA278B781FE4B2BDA&op=get";
 },

--
Jakub Wilk


Current thread: