zlacker

Detecting the use of "curl | bash" server-side

submitted by rubyn0+(OP) on 2018-07-29 01:44:54 | 500 points 145 comments
[view article] [source] [go to bottom]

NOTE: showing posts with links only show all posts
◧◩
4. AgentM+X1[view] [source] [discussion] 2018-07-29 02:20:54
>>Sir_Cm+E1
The idea is to distinguish between "curl http://x" and "curl http://x | bash", in order to only give malicious content when the user pipes it straight to bash (presumably they aren't looking at the content in this case).
◧◩◪
12. api+B2[view] [source] [discussion] 2018-07-29 02:34:37
>>vbezhe+p2
We came up with a way to do gpg verified curl | bash for ZeroTier. It still works without gpg too. Scroll down to Linux.

https://zerotier.com/download.shtml

15. michae+93[view] [source] 2018-07-29 02:46:39
>>rubyn0+(OP)
On the evading detection side, one other simple way to avoid this is to add sponge[0] between curl and bash in the pipeline, i.e. curl ... | sponge | bash. sponge consumes all input until EOF before outputting anything, stopping bash from executing a partially downloaded script.

[0] https://linux.die.net/man/1/sponge

◧◩◪◨⬒
30. cjbpri+05[view] [source] [discussion] 2018-07-29 03:20:26
>>sigjui+a4
We're comparing the security properties of

`curl https://somesite.com/foo.sh | bash`

with

`curl https://somesite.com/foo.deb`

and

`curl https://somesite.com/apt.key | sudo apt-key add - && sudo apt-get update && sudo apt-get install some-software`

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.

◧◩◪
32. Waterl+q5[view] [source] [discussion] 2018-07-29 03:30:35
>>smt88+F4
"Lazy" isn't a bad thing. When I see a curl-bash command from a reputable site, I'm not about to waste my time evaluating it. Consider step one to three from this site https://docs.aws.amazon.com/AmazonECS/latest/developerguide/... or get-pip instructions from this one: https://packaging.python.org/tutorials/installing-packages/

But I agree with your sentiment. If the exact same step was to `apt install ecs-cli` I would just do that and not feel any inconvenience about it.

◧◩
34. skunkw+G5[view] [source] [discussion] 2018-07-29 03:37:14
>>michae+93
If you're on a Mac or a system that doesn't have sponge installed by default, use moreutils to install.

https://joeyh.name/code/moreutils/ https://rentes.github.io/unix/utilities/2015/07/27/moreutils...

◧◩
37. Cobras+U5[view] [source] [discussion] 2018-07-29 03:42:16
>>Waterl+12
> when it's coming from a very prominent trusted source like...Amazon AWS.

Be very careful here. https://installation.s3.amazonaws.com/setup.sh looks like a legit URL, but it's just some guy with an S3 bucket named "installation".

◧◩◪
41. Spivak+G6[view] [source] [discussion] 2018-07-29 03:59:18
>>smackt+z2
If you're installing software off some random website then you're already hosed no matter what the install process looks like.

Say you already trust the website you're downloading from, is there an increased security risk doing curl | bash as compared to rpm --import https://example.com/RPM-GPG-EXAMPLE && yum install https://example.com/example.rpm

No matter what you're putting 100% faith in the the server and the TLS connection. There are a lot of reasons to prefer packages, but I don't think security is one of them.

◧◩
51. Spivak+N7[view] [source] [discussion] 2018-07-29 04:27:14
>>megama+I2
(Invoke-WebRequest https://example.com/install.ps1).Content | Invoke-Expression
◧◩◪◨
58. schoen+P8[view] [source] [discussion] 2018-07-29 04:52:43
>>cjbpri+t4
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

curl https://somesite.com/apt.key | sudo apt-key add - && sudo apt-get update && sudo apt-get install some-software

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.

62. homako+S9[view] [source] 2018-07-29 05:22:39
>>rubyn0+(OP)
I have proposed a solution to this: have the snippet self-hashed and verify with multiple sources. eg:

A=$(curl -L https://get.rvm.io);echo "$A" | shasum -a 256 | grep -q 05b6b5f164d4df5aa593f9f925806fc1f48c4517daeeb5da66ee49e8562069e1 && (echo "$A")

◧◩◪◨⬒⬓⬔
78. geocar+0e[view] [source] [discussion] 2018-07-29 06:56:26
>>huevin+8b
> 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.

https://pydio.com/en/docs/v8/ed-debianubuntu-systems

https://docs.docker.com/install/linux/docker-ce/ubuntu/#inst...

https://www.spotify.com/uk/download/linux/

https://www.elastic.co/guide/en/apm/server/current/setup-rep...

https://ring.cx/en/download/gnu-linux

http://docs.grafana.org/installation/debian/

https://support.plex.tv/articles/235974187-enable-repository...

https://stack-of-tasks.github.io/pinocchio/download.html

http://download.mantidproject.org/ubuntu.html

https://docs.microsoft.com/en-us/cli/azure/install-azure-cli... (!!!)

85. growth+tg[view] [source] 2018-07-29 08:02:59
>>rubyn0+(OP)
> a knowledgable user will most likely check the content first

Really? Are they going to read every line of code and every line of code in every dependency that the install script installs?

The bash detection is clever but I think its a solution to a problem that doesn't exist.. Its already very easy to install hide malicious code in plain sight, why go to all this trouble to detect if the user is piping to bash?

For example, see how easy it is to publish a fake npm package or a .deb package:

https://hackernoon.com/im-harvesting-credit-card-numbers-and...

https://github.com/ChaitanyaHaritash/kimi

88. jwilk+ji[view] [source] 2018-07-29 08:55:40
>>rubyn0+(OP)
(2016)

Previous discussion: https://news.ycombinator.com/item?id=11532599

89. ithkui+3j[view] [source] 2018-07-29 09:15:44
>>rubyn0+(OP)
I wish there was a standard way to check a checksum, so that download instructions could just include that in the snippet to copy paste.

I wrote a tool that could be used like that but it's useless if its not ubiquitous (https://github.com/mmikulicic/runck)

◧◩
94. pcl+qk[view] [source] [discussion] 2018-07-29 09:50:28
>>ithkui+3j
I've got a similar python script in my collection of scripts:

    $ curl <url> | pipe-checksum <expected> | bash
https://gist.github.com/pcl/64bd2f56695fcf8e1fad51443aab1f1e
◧◩◪◨⬒⬓
96. fulafe+dl[view] [source] [discussion] 2018-07-29 10:16:51
>>dredmo+pg
Yeah, if there are signatures then it doesn't matter. But often both are a miss.

Eg the key from https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-... doesn't have signatures, and isn't on the keyservers.

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.

◧◩◪◨⬒⬓⬔
97. dredmo+Bl[view] [source] [discussion] 2018-07-29 10:26:47
>>Dylan1+Hk
See what keys have signed a given key. See Debian maintainer keys as an example.

This is ... not everything that it could be, and is approaching 30 years old, technology built for a vastly different world.

But this is the basis of the GPG / PGP Web of Trust.

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

http://www.pgpi.org/doc/pgpintro/

http://www.rubin.ch/pgp/weboftrust.en.html

(I've addressed this point ... a distressing number of times on HN: https://hn.algolia.com/?query=dredmorbius%20web%20of%20trust... 0

◧◩
101. e12e+Gm[view] [source] [discussion] 2018-07-29 10:54:28
>>ithkui+3j
Since copy-pasting to the terminal is also unsafe[1], it's not really a solution...

At any rate - code-signing doesn't really help if the author is the attacker.

[1] http://thejh.net/misc/website-terminal-copy-paste

◧◩◪◨⬒
102. e12e+7n[view] [source] [discussion] 2018-07-29 11:02:52
>>schoen+P8
> This is particularly so when someone may be able to compromise the software publisher's infrastructure

Indeed. While this particular venue wouldn't have worked for:

https://wiki.gentoo.org/wiki/Project:Infrastructure/Incident...

(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).

◧◩◪◨
103. e12e+co[view] [source] [discussion] 2018-07-29 11:20:15
>>api+B2
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?

  #!/bin/bash
  sudo much_evil
  <<ENDOFSIGSTART=
  -----BEGIN PGP SIGNED MESSAGE-----
  Hash: SHA256

  ENDOFSIGSTART=
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).
◧◩◪◨
120. fragme+8H[view] [source] [discussion] 2018-07-29 15:51:44
>>Spivak+G6
Security is one of them.

When RPM-GPG-EXAMPLE and example.rpm are both coming from https://example.com it's less clear. When example.com is coming from a mirror repository, or being emailed around (yes, this happens), package signing asserts that example.rpm was signed by the signatures in RPM-GPG-EXAMPLE, which has a strong (but not bullet-proof) connection as being built by example.com.

From that example, we can see that package signing also protects from someone who's able to break into the main example.com webserver but not example.com's build system - if the attackers did not get into the build system and example.rpm has a valid signature then despite the webserver being broken, the rpm file can still be trusted, assuming the webserver did not have a copy of the private key used for build signing. If we loaded https://example.com/RPM-GPG-EXAMPLE before the webserver was broken into, and then the webserver was broken into and a malicious RPM-GPG-EXAMPLE and example.rpm were uploaded, it would be noticed. (Examining changes to RPM-GPG-EXAMPLE are, unfortunately, left to the reader as an exercise.)

Still, while it's true that loading the file from https://example.com/RPM-GPG-EXAMPLE relies on TLS, but there are methods available to confirm that the file's contents are valid, that don't rely on TLS, if the security folk at example.com are doing their job.

Finally, TLS is not an all or nothing game. Or rather, the certificate used to sign the https connection does not have to be blindly trusted, and in the case of sketchy root certificates, even if https://example.com loads fine in a web browser, it does not mean it should necessarily be trusted. Certificate Transparency (eg crt.sh) is a proper lever when working with example.com.

Security is complicated and there are no silver bullets.

`curl | sudo bash` is batshit though.

◧◩
133. setham+Ln1[view] [source] [discussion] 2018-07-30 00:57:09
>>charle+gc
Hm. I tried and it does not seem to work. You can view my attempt at https://github.com/sethgrid/exploit. Chances are that I am ignorant of something. If someone knows what am doing wrong, please let me know!

The code starts to send chunked data and polls for a return curl call from the downloaded script. If the script's curl call calls home, the download will chunk out "bad" bash.

What I see happening is the downloaded script does not fully run until fully downloaded.

[go to top]