Neat! But it's not obviously a bad idea. You have a TLS connection with the site you're downloading from. `curl | bash` is no worse than downloading a .dmg or .deb from the same server would be.
> You have a TLS connection with the site you're downloading from. `curl | bash` is no worse than downloading a .dmg or .deb from the same server would be.
This site's argument is that the software publisher can selectively attack users during a live software install, in a way that they don't stand a chance of detecting by inspection (or of having proof of after the fact).
I mean, I guess I see them making a three-stage argument:
1) Distributing software via bash script is a bad idea
2) Sensible people review the bash scripts they downloaded before running them
3) But haha! Here is a clever trick that evades that review.
And I'm not persuaded by 3) being interesting because I already rejected 1) and 2), and I consider 3) to just be proving my point -- you (for all you!) are not competent to perform a very brief but somehow thorough security review of a shell script that probably has further dependencies you aren't even looking at, and the actual reasoning to apply when deciding to install software this or any way is purely "Do I trust the entity I have this TLS connection open with to run code on my machine?".
I agree with im3w1l's point: if everyone runs the same install script, it's a lot riskier for the publisher to attack everywhere. If people run individualized scripts, it's a lot less risky.
I think there's a difference between trusting an organization's code that is published to the general public, and trusting an organization to send you arbitrary code in a specific moment. Only software distribution methods can enforce this kind of distinction, and curl | bash by itself doesn't, particularly in light of the article's technique.
I tried to discuss this distinction in some of my reproducible builds talks. There's a difference between trusting Debian to publish safe OS packages, and trusting Debian to send you a safe package when you run a package manager if the package could easily be different every time. This is particularly so when someone may be able to compromise the software publisher's infrastructure, or when a government may be able to compel the software publisher to attack one user but other users.
Instead of your (1) and (2) above, how about this?
1) Distributing software via a method that can single out particular users and groups to receive distinctive versions is a bad idea: it increases the chance that some users will actually be attacked via the software publication system.
2) We might think that curl | bash isn't particularly egregious this way, because there are various ways that publishers might get caught selectively providing malicious versions. This is especially so because the publishers can't tell whether a curl connection is going to run the installer or simply save it to disk. That makes the publishers (or other people who could cause this attack to happen) less likely to do it.
3) But haha! Here is a clever trick that restores the publishers' ability to distinguish between running and saving the installer, and in turn breaks the most plausible ways that publishers could get caught doing this.
Edit: Elsewhere in this thread you suggested that the likeliest alternative is something like
I think I'd agree that this has some of the same problems, although it might have some advantages because of the potential decoupling between the distribution of the signing key and the distribution of the signed package. As another commenter pointed out, you could try to use a different channel to get or verify the key, and some users actually do; also, you'll have a saved copy of the key afterward.
I agree that the distributor having control over offering different artifacts to different individuals is very risky.
I was assuming that the sites that you might `curl | bash` from are third-party sites (i.e. not your Linux distribution) that you don't have an existing trust relationship with, which makes it impossible to avoid this capability. That's the situation people use curl | bash in.
So I think this ability to individualize artifacts would still be present if we were receiving a .deb or apt key instead from that site.
> you'll have a saved copy of the key afterward
Yes, though since dpkg post-install scripts can modify arbitrary files (right?), you can't trust that any files on your disk are the ones that existed before the compromise. So couldn't the malicious key verify the malicious package, which then overwrites the copy of the package and key on-disk with the good versions that were given to everyone else?
> So I think this ability to individualize artifacts would still be present if we were receiving a .deb or apt key instead from that site.
I guess we need some other infrastructure or social practice on top in order to compare what different people see, and/or allow the distributor to commit to particular versions. (Then having the distributor not know whether someone is blindly installing a particular file without verification is necessary, but not sufficient, to deter this kind of attack.)
(a compromise of github itself would be needed) - it's easy to imagine one of the many mirrors of Debian to suffer from compromise. But as they just push signed debs, the damage would be limited (not trivial, there could conceivably be bugs in apt/dpkg/gnupg etc).
If you are running the same script as everyone else, then then there is a good chance someone else will notice if something is off. If everyone is potentially given their own personalized script then this safety in numbers strategy doesn't work.
If you know you are running the standard scripts that everyone runs, then it also makes a post-breach investigation more easy. You know the exact scripts you ran as opposed to knowing "well I curl | bashed from these sites so one of them might be bad".
There's nothing stopping people from being served different content with packages. Hell, n users could receive n different packages which all pass the GPG check. And since you're getting your checksum from the same site it would look like it had the right checksum too. You would have to find other people you trust to compare it to but since everything appears to be above board why would you even think to do that?
Either you trust the entity you're downloading software from or you don't.
Linux/BSD distribution mirrors don't control the package signing keys, maintainers do. Similarly, Google doesn't possess the ability to push out updates for third-party apps, without fundamentally redesigning the OS with a platform update, because the signing keys are owned by the app developers, and the existing OS rejects updates signed with different keys. In both of these situations, the key owners lack the ability to selectively push out signed updates, unless they also control the distribution infrastructure.
The argument is predicated in the assumption that some subset of people are checking the installer before running it, whether that installer be a shell script or a binary package.
With the binary packages you don’t have any way to tell if the consumer is going to inspect it or not, so even if you send the malicious code to only a subset of people, there is a risk of detection.
The technique in the post allows you to distribute the malicious code only to people who aren’t inspecting it with a much higher success rate.
Personally I’m dubious that anyone is inspecting any installers with enough expertise and scrutiny to protect the rest of us, so the differences between the install methods in this regard are negligible.
>in a way that they don't stand a chance of detecting by inspection (or of having proof of after the fact)
What do you mean? They could `tee` curl output to a file (or elsewhere, for archives). They could also suspend passing the output to bash until they've verified the output (perhaps they would run a hash function and compare the result).
Alice and Bob are both installing something on their computers. It is available as both a .deb and via "curl | bash". It is not malicious...but it does turn out to have a serious bug.
They both install, and both hit the bug and find that it has completely and utterly broken their network configurations bad enough that they have no network access at all.
Alice installed via the .deb. She can look at the scripts in the .deb and see what it was messing with, which gives her a big head start on figuring out how to fix it at least enough to connect to the network backup server and fully restore her network configuration.
Bob installed via "curl | bash". Bob is now left using find to look for recently changed configuration files, and paging through the out of date O'Reilly books he has from the old days when programmers owned physical books, trying to remember enough about network configuration to recognize what is wrong.
Trustworthy sites do not serve you malicious code. They often will, however, serve you buggy code.
The difference is that you can inspect it before you run it if you download it. If you pipe it into bash you don’t know what you’re getting, even if you previously inspected the data provided by that URL.
I don't feel the need to review the source code for every install script I run.
I don't read the source code for almost any of the code on my machine today. In most cases where I see `curl | bash`, I'd probably already be screwed even if I review it. Most install scripts and up doing "hit website, install thing" anyways - am I reviewing the second stage install script also?
That's a way in which "curl | bash" distributed software is better than .deb/.dmg distributed software, right? Because you have the potential to inspect the script first, if you have some kind of ridiculous confidence in your ability to perform security review of an entire software product in the moments before you decide to install it.
But it's never presented in that way, as a feature. It's presented as a terrible way to distribute software.
It doesn't take ridiculous confidence to analyze shell scripts. In the hundreds of scripts I have read, few were more than 100 lines long. It shouldn't take more than 60 seconds (probably 30 or less) to mentally build a list of all possible operations a short script can perform. Bourne shell scripts don't have much room to hide surprising behavior, and when they do, it immediately stands out. If they are permanently installed, and invoked later by other parts of the system, then they may need more probing, but we're talking about installation scripts.
.deb and .dmg can be easily extracted. The former is just an `ar` archive containing tarballs, which you can (and should) extract to read the install scripts. (.dmg specifics escape me, since I only dealt with them one time, years ago.)
Binary code isn't inscrutable. Some good tools for this are, among many, many more, IDA, Hopper, and radare2. How long this takes depends on what your goals are, how comprehensive you are, and the program complexity. I don't think I've yet spent years on one project, fortunately, but the months-long efforts, for undoing some once-prominent copyright protection systems, were pretty brutal. Smaller programs have taken me just several hours to appropriately examine.
deb/rpm is better because it's usually signed by maintainer with GPG keys. I think that it's harder to steal keys from maintainer than to infiltrate web server.
Quote(trying to fit it to narrow widt, for others on mobile):
curl -s \
'https://pgp.mit.edu/pks/lookup?op=get&search=0x1657198823E52A61'
| gpg --import \
&& if z=$(curl -s 'https://install.zerotier.com/' | gpg);
then echo "$z"
| sudo bash;
fi
It's interesting - it tries to import a given gpg key from keyserver, then grabs a gpg armored text file with a bash header - with the gpg header wrapped in a here-document:
#!/bin/bash
<<ENDOFSIGSTART=
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
ENDOFSIGSTART=
I'm unsure, but I think you could just stick your malicious code before the signature?
So it really isn't any better, as far as I can tell. There's also a trade-off between scripts that can be typed (curl https://i.com.com) and need copy-pasting - as copy-pasting also isn't safe - even if that's a somewhat different attack vector (compromising the web site, altering js depending on visitor).
I don't think there are very meaningful differences in the security properties -- I don't think it's more difficult to become compromised by one than by one of the others.
No, you're deliberately choosing a bad way to get a key to try to prove your point. You shouldn't be fetching a key from the site that might be compromised.
> You shouldn't be fetching a key from the site that might be compromised.
You shouldn't, but people do, and are being directed to do so increasingly as Linux becomes more popular. Software developers want to be software publishers so bad that they're just going to keep pushing, and therein lies the risk: If people get the impression that packages are somehow more secure than shell scripts, then these kinds of attacks will simply become more prevalent.
To you it's obvious that packages aren't more secure, it's how you get them that makes their normal use more secure. That's apparently too subtle a point for even big companies like Microsoft.
1. Walled Garden: Developers don't self-publish. Call it an app store, call it everything-in-apt.
2. Encapsulate everything so that developers can't do anything. Don't use anything unless it comes in a docker instance. Or a FreeBSD jail. Or something else. Qubes maybe.
No, there's no effective difference between those examples, apart from maybe post mortem analysis. It's also a poor method of key discovery, as hueving said.
Where do you get the keyserver ID? From the website? You're back to square one, because anyone can upload anything to a keyserver. If they can modify the website (change files, etc) they can also change the keyserver ID they're telling people to use.
The "antipattern" is letting/expecting software developers also be software publishers.
This is a good point, which should be brought up more. Although you probably meant key id or key fingerprint, not keyserver ID, which would imply something else.
You're supposed to do additional verification of PGP keys, either through attending key signing parties (who does that in 2018?), checking the signatures of people you already trust, or comparing as much out-of-band information as you can.
It's not terribly hard to create a plausibly trusted keyring from scratch that depends on only 1 of 3 websites being legitimate. For example:
All keys are cross signed as shown by gpg2 --list-signatures.
If this sounds like a pain in the ass, it's because it is, and GPG could be so much better.
Ironically, if you can't acquire the developer's public signing key, it might be best to install software directly from their website, if no trusted repositories are available. If you can acquire their signing key, it's probably best to not install software directly from their website, in order to avoid selective distribution attacks. Sort of unintuitive.
Public keyservers are well-known, and in a different security domain than the download server. Without breaking in, a rogue party can't delete or replace keys from the keyservers.
Aren't keyserver lookups usually keyed off a 32-bit key ID though? (Whose space isn't big enough to avoid someone brute-force generating a key with a certain key ID s.t. you think you got the right key.) You're supposed to check the fingerprint, but you need to get the fingerprint, and for that you need a secure channel, and you're right back to square one.
Of course an unsigned key missing from the keyservers still has the advantage that on subsequent installs/updates, the previously downloaded key persists.
And you can keep the initially downloaded key in your CI configs.
dpkg doesn't stop you overwriting system files in a post-install shell script, as far as I know? Which is the way that a malicious package would choose to do it. I don't think dpkg performs any meaningful security review in the way you describe.
Would you like me to craft you a .deb/.rpm which totally trashes your system? Packages can and very often do leverage the ability to run arbitrary scripts but nothing says I can't do serious damage even without that.
Oh, yeah - good luck getting the average layperson or even many sysadmins to inspect this - because very few people actually know how to review scriptlets in an RPM (rpm -qp —scripts package.rpm, isn’t this nice and obvious?). Nobody bothers for packages distributed via yum repositories either, because manually downloading packages to review them defeats the purpose, right?
Yeah, everything is vulnerable at the end of the day - but at least with packages one is less likely to get seriously messed with, just not impervious to it.