1. 36
  1. 6

    We’re vulnerable the same way whenever we download an unsigned package, tarball or even clone an SCM repository. With that being said, I still never copy-paste these commands. Instead, I download the script, take a short look at it and only then execute it. As much as I’d like to say I do the same for every line of code of the above mentioned tarballs, I simply don’t. And I don’t analyze the downloaded scripts thoroughly either.

    Don’t get me wrong: I hate commands of this form. The last time I encountered one, however, my thought process was similar to what I outlined above. But you obviously have a good point with truncated content (unless it’s somehow dealt with, as @bdesham pointed out) and disadvantages of not using standard package managers.

    Overall, I agree with you – it’s just that the same arguments can be applied to many other areas.

    1. 3

      The curlpipe pattern has always bugged me, for a variety of reasons that I could whine at length about.

      But the biggest problem I have with it, aside from the security issues, aside from the presumptuousness of “give us root on your system and just trust us,” is that if something goes wrong with the “install”, the script could be doing something that will be difficult or impossible to back out of later. I get that it’s totally possible for a poorly-written .deb package to rm -rf / upon install but at least with a Debian package, I know for sure that I can fully evaluate everything that it’s going to do to my system, and I know that at the very least, I stand a much greater chance of being able to fully uninstall the package with apt remove.

      With a curlpipe script, I have to literally read code to figure out what it’s doing and more often than not, I come away so disgusted with the quality of the installer script that I don’t have much hope left for the thing that it’s actually installing.

      1. 1

        Can’t an attacker just replace the hash with their malicious hash?

        1. 1

          There’s only one hash. Most curl attacks use the user-agent, timing attacks, etc., so if the returned script is malformed or malicious, the hash would not match whatever’s advertised on the website. This is only applicable when you read the script before piping it to sh. If you pipe scripts without reading, it’s a lost case and there’s no way to stop anybody.

        2. 1

          Is there any threat model where curl-hashpipe-sh is safer than straight curl-sh (with HTTPS and basic partial-content precautions)?

          1. 1

            It makes sense when your browser’s connection to the package website is trustworthy but the connection you’re curling from isn’t trustworthy.

            Which, like, when does that happen? I put my browsers on jank WiFi more often than my servers, and if I can’t trust my server’s upstream why do I trust the install image or RAM?

          2. 1

            I started writing something similar a while ago but never finished it: https://github.com/zimbatm/curlsh

            The tricky bit is that because curl and bash are available almost everywhere, they are being used for bootstrapping. So that tool would also have to be distributed widely.

          3. 8

            Man-in-the-middle attacks can be an issue with anything you get from the interwebz, and hardly unique to curl .. | sh.

            Hidden text attacks can be an issue in the general sense, but I am copying the text from a trusted source. Rust, Yarn, etc, are large projects and I trust that they don’t have hidden shenanigans with shell commands in their installation instructions. (aside: zsh never executes pasted text immediately. bash should do this too! Every shell should)

            The same applies to User-Agent based attacks. Sure, it’s possible. But do you really think Docker is going to do that? I am already trusting Docker with running code.

            The security concerns over this seem extremely unrealistic and hypothetical. Just because you’re “running a command from the internet” doesn’t mean it’s not secure. It’s a trusted source and it’s https. If you would copy random commands from random websites, then sure, we’d have na issue. But that’s not what is happening here.

            None of this strikes me as more dangerous that the traditional tar xf .... && cd dir && make, or pip install, gem install, go get, etc. Hell, if a project uses GNU autotools then the configure script or generated Makefiles are as good of a place to hide something nefarious as anything. But in practice this is not really an issue, as people tend to install software from trusted authors/vendors.

            Partial content can be an issue, I suppose. Has this ever been reported? Most of these scripts seem small enough that the odds of this are vanishingly small. The Docker script doesn’t have this problem by saving it to disk first; so if you’re really concerned it’s a simple fix.

            The not knowing what the script is going to do strikes me as the only good reason on this list, and is indeed also the main reason I avoid scripts like this. But that’s just a personal preference and not a security issue. It’s also not fundamentally different from the traditional make && sudo make install, and I don’t see people writing articles about the dangers of that.

            1. 1

              Your argument about make install being as bad as curl|sh doesn’t take into account that the Makefile is part of an opensource project repository, and as such has (most likely) been reviewed by the community working on this project. The install.sh script though is not part of any repository usually, and lives only behind the webserver. Maybe it has bugs, malicious code or whatever, and your only option there is to mail the devs and hope they’ll do something about it quickly. The issue will most likely not appear publicly.

              I’ve always seen these scripts as a “weak point” in a FOSS project.

              1. 10

                The install.sh script though is not part of any repository usually, and lives only behind the webserver.

                Well, let’s check the examples the article provided:

                So for literally all the examples the OP provided is the source in git in the locations where you would expect it (main repo or the repo for the website).

                1. 3

                  Ah, good call! It is not that bad after all :)

            2. 7

              You can add Nix to the list of offenders. I actually did read the script first (okay, fine, I skimmed it) and I noticed that it at least has protection against the “partial content” problem the OP mentions. The entire script is wrapped in { and }, which means that if it ends up only half-downloaded you’ll get a syntax error and none of the commands will be run.

              Overall, though, yeah—I agree that this is a disturbingly common practice.

              1. 15

                Yeah, it is true. I don’t love that Nix uses a curl|sh install. However. Something interesting about this list is three out of the five concerns (hidden text, user agent sniffing, not knowing what the script will do) are predicated on the remote server being malicious. As you noticed we’re not subject to the partial content problem, and the fifth (not using TLS) is a complete failure of applying basic security.

                One alternative was publishing instructions which included sha256 verification. However if you trust the website to give you the right hash, you can trust the website to give you the right script.

                Another alternative is publishing GPG verification installations, which is an option listed immediately below the curl|sh instruction, in bold text, on https://nixos.org/nix/ (click Get Nix.) But still, unless you have a WoT connection to Eelco (who signs our releases and also invented Nix) what does it even mean?

                Going back to the list of concerns – the only ones at concern here is not knowing the script (yes, please do download and read the script) or not trusting Nix’s install code in the first place. Frankly, if you don’t trust nixos.org to distribute a clean and safe install, you probably don’t want to use Nix at all.

                I’m not thrilled at the article saying that by simply having these instructions present that we are cutting corners – we’ve pretty carefully considered the implications of this mechanism of installation and have explored alternatives. Yes, being packaged in a distro’s package manager is a great route for many pieces of software. Many distributions provide packages for Nix at this point, but for some time Nix’s /nix directory was a non-starter for breaking FHS.

                If you have suggestions on how to improve the security of the Nix installation, I would be happy to hear about it.

                1. 1

                  All you need to do is change the bit that says curl https://nixos.org/nix/install | sh to just be a link to the script https://nixos.org/nix/install. Telling people that they can download it and use it to install nixos.

                  1. 2

                    I don’t think this makes any meaningful difference. If the user doesn’t check any checksums or signatures or read and understand the script, then you’ve just made the user part of the automated process. If the user is savvy enough to do a meaningful check on the script before executing it, they can see curl https://nixos.org/nix/install | sh and decide to download the script to a file instead.

                    1. 1

                      the difference is that you’re explicitly encouraging and condoning a bad practice

                      1. 0

                        Do you read all Makefiles before you run make? Or all setup.pys before you run pip install?

                  2. 1

                    Everything you say is true. And please understand that I wasn’t trying to slag on Nix so much as point out that it’s another prominent project that uses this pattern.

                    However if you trust the website to give you the right hash, you can trust the website to give you the right script.

                    Totally fair point.

                    unless you have a WoT connection to Eelco… what does it even mean?

                    I don’t have a WoT connection to the guy who signs Nginx releases, either. In fact, his key is the only key in my GPG keychain on my web server. The important thing is that every release is signed with that key. If I downloaded a release and found that it was signed by a different key that purported to be from the same person, I would hold off on that version until I could figure out what was going on. (I know this is a much weaker form of security than PGP was supposed to give us, but it’s what I’ve got.) Of course, the same is true of Nix.

                    My main worry with curl | sh installs is that they usually redirect to some GitHub URL that points to the project’s master branch. All it would take to compromise this installation procedure would be for one bad commit to make it to master somehow. Some projects merge to master a lot. Maybe the only actionable advice I have here (and I don’t know whether this is applicable to Nix or not) is that if you’re going to offer a download script to be piped into sh, host it somewhere that is immune from random, malicious PRs on GitHub.

                    By the way, I did install and start using Nix. I recognize that if you wanted to install malware on my machine, you have several more subtle options at your disposal than serving me a bad install script :-) The same goes for projects like Docker. What baffles me is ordinary programs like Calibre (which I do use) recommending piping wget --no-check-certificate into sudo sh 😱

                2. 4

                  Another funny attack is to add a sleep 5 in the script. Then on the server side, detect if the body stream is paused. If yes, it means that bash is evaluating the file => inject payload.

                  1. 3

                    Incidentally, this is not a new idea. People have been doing it as far back as 1994 with telnet|sh.

                    Looking at a 20+ year history of this, I don’t think we’re ever going to get people to stop doing it.

                    1. 3

                      possibly more importantly, how frequently has this actually ever been used as a vector of attack? I imagine a good portion of people at any given moment aren’t actually piping it to sh, and are in fact reading the file. Much like herd immunity I imagine herd knowledge protects the group even if many individuals don’t know how to prevent this themselves.

                      1. 4

                        I imagine a good portion of people at any given moment aren’t actually piping it to sh, and are in fact reading the file

                        I’d argue that a good portion of people (perhaps even the vast majority) are doing the exact opposite, and not reading the file before executing it. They want to get the thing up and running as fast as possible because <reasons>, and curl|sh is a fast way to do that.

                        1. 1

                          Here’s the thing, if there are a few brave souls who read before using they can tell others which ones are indeed malicious. curl|sh is not good practice, but I sincerely doubt it will be going away any time soon. Perhaps cert signed scripts are our way out.

                        2. 2

                          One IRC cesspool, #linux.fi, known for its notoriously off-putting and hostile attitude to n00bs had a vpenis.sh script in its topic, wget -q -O - http://.../vpenis.sh.

                          Most of the time it’d look at your cpu, ram and hard drive info to give you a virtual penis length in centimeters, but occasionally it’d be a rm -rf variant.

                          From the people who’d give that command as general advice as well, from the birth country of the kernel.

                          But maybe that’s not widespread or current.

                          1. 4

                            I once pasted a fork bomb in IRC. It wasn’t with any malicious thought; we were just discussing resource limits and I mentioned something like I just want to prevent stuff such as :(){ :|:& };:”. 20 seconds later there were a few “nick left the room (connection timed out)” messages, and a minute later people rejoined with “wtf was that?!”

                            Luckily it was a small/friendly channel where everyone knew everyone so a quick “oops, sorry ’bout that” fixed it :-)

                      2. 4

                        You gave examples of “bad” commands, which is good, but I didn’t see any examples of “good” commands. This would make it difficult for the offenders to fix if they don’t know how to fix it.

                        1. 5

                          Safe, trustworthy software distribution is hard, and the mechanisms to do it right are diverse across platforms (unlike curl | sh …).

                          The Right Way is usually something along the lines of…

                          • Provide a self-contained package appropriate for the user’s platform
                          • Along with a hash that the user can use to check the download
                          • Or better yet, signed with a key which is verifiably owned by the developer
                          • And in the best case, distributed and vetted by the platform’s official package manager or App Store

                          All of which greatly improve’s user confidence in your software, but is a ton of work and probably a lot slower than just curling that shell script.

                          (fwiw, I’m the kind of person who will build and sign an rpm to distribute a one-file script, but I get why people find the whole process tedious…)

                          1. 2

                            But then, hashes hosted on the same server as the file to download do not protect against any malicious action, RPM or DEB is less likely to be inspected before installation (that already runs arbitrary code) than a plain curl-to-sh script that can be downloaded, and fraction of users that will meaningfully verify signing key identity via independent means is low enough that Yarn providing signatures at all more or less saturates the real benefits.

                            Oh, and by the way Yarn provides Debian packages, which is actually worse than their curl-to-sh option because adding their repository makes you vulnerable to future infrastructure intrusions, not just currently ongoing ones.

                            Judging from «it has green padlock, it is safe!» around HTTPS, things like co-hosted hash can make the overall situation slightly worse.

                          2. 1

                            I don’t think there is a good command of the form curl ... | bash. It’s always a way to get a short term boost in downloads while polluting the commons for everyone.

                            https://en.wikipedia.org/wiki/Tragedy_of_the_commons

                            1. 0

                              You engage with trustworthy distributions to have your software packaged.

                            2. 4

                              What’s wrong with the docker one?

                              curl -fsSL https://get.docker.com -o get-docker.sh
                              sh get-docker.sh
                              
                              • Passes “Standard man-in-the-middle attacks”
                              • Passes “Hidden text attacks”
                              • Passes “User-Agent based attacks”
                              • Passes “Partial content returned by the server”

                              To be fair…

                              • Fails “A simple matter of not knowing what the script is going to do”

                              … though I think any software that you run without reading every line of source code (and every dependency-even if you trust the software authors, dependencies get hacked often) is vulnerable to the same thing.

                              1. 2
                                • Passes “Standard man-in-the-middle attacks”

                                Yes.

                                • Passes “Hidden text attacks”

                                You are always vulnerable to that attack when you copy and paste something into the terminal, even if it was just a url.

                                • Passes “User-Agent based attacks”

                                If you inspect the script in between, yes.

                                • Passes “Partial content returned by the server”

                                Depends if curl will create a partial file or not, I don’t know if in this particular case it can happen. It certainly can when piping. Anyway that would have to be coupled with you not noticing an error and running a partial script anyway in this case.

                                1. 1

                                  Also, assuming GitHub doesn’t have an XSS vulnerability, you’re automatically safe against user-agent based attacks and hidden text attacks if the command only connects to github servers. curl git.io/some_short_url | bash

                                2. 2

                                  I use a very simple trick to fix this: https://github.com/awalgarg/curl-tap-sh

                                  1. 2

                                    People argue a lot about the ethical issue of running the curl|sh line, but I never see a complain about what these install.sh scripts actually do. I started wondering because at work we use chef, which does that, and even though they provide packages for a fair amount of distro, we still use the curl|sh line.

                                    I took a close look at it, and this heavy script’s job is to detect your current distro, install the chef.io repository for this distro, and then install it through your package manager. Given this information, I wonder what is the point of providing the curl|sh over saying “Install it through your package manager”.

                                    I wonder if all of these scripts do it like this though.

                                    1. 4

                                      Many do, and that’s my complaint: they’re shipping tools ostensibly aimed at developers/ops (eg docker) but also saying “we think you’re too stupid to add a 1 line source file and keyring for apt”.

                                      It also normalises the concept, and thus places that dont just setup an apt repo get the benefit of that normalisation.

                                      1. 2

                                        Usually it is not too stupid, but certainly too lazy.

                                    2. 2

                                      It would be nice if shell scripts could be signed as powershell scripts are.

                                      1. 2

                                        That just validates who authored the script - not that it is secure

                                        1. 1

                                          What do you have that validates the programs on your machine are secure?