Two malicious Python libraries caught stealing SSH and GPG keys(zdnet.com)
zdnet.com
Two malicious Python libraries caught stealing SSH and GPG keys
https://www.zdnet.com/article/two-malicious-python-libraries-removed-from-pypi/
317 comments
This is part of why I install my Python dependencies from downstream Linux distro repos. I never use virtualenv. If a distro is missing a package I need, it's a simple process to put it together, and the additional steps and checks built into the process stop close to 100% of these issues. Getting a human here also lets you do things like patch out telemetry or other anti-features.
Software repositories without a human review process are a bloody stupid idea.
Software repositories without a human review process are a bloody stupid idea.
So they caught the guy using a cliched I-vs-l typosquatting scheme and lazily writing the malicious code in Python; we can presume they haven't caught the guy who took the trouble to put their malicious code in a pre-compiled C extension.
Reminds me of the fraudulent scientific papers that get caught using really dumb fakes (e.g., microscopy pictures that are copies of one another re-zoomed and rotated); we catch the dumb ones, but presumably not all malicious actors are dumb, so there must be a lot more fraudulent work out there.
For that matter, isn't there a reasonable systematic way to catch out typosquatters simply based on text analysis? Any library name that's a short edit distance from a popular library should have been carefully reviewed from the start; there's no excuse for "jeilyfish" to have lasted more than a couple of days.
Reminds me of the fraudulent scientific papers that get caught using really dumb fakes (e.g., microscopy pictures that are copies of one another re-zoomed and rotated); we catch the dumb ones, but presumably not all malicious actors are dumb, so there must be a lot more fraudulent work out there.
For that matter, isn't there a reasonable systematic way to catch out typosquatters simply based on text analysis? Any library name that's a short edit distance from a popular library should have been carefully reviewed from the start; there's no excuse for "jeilyfish" to have lasted more than a couple of days.
This will keep happening, and not only will SSH And GPG keys be the target, but any interesting data will be stolen.
And the problem is much larger than these typosquatting attacks. Abandoned Github projects taken over my malicious users, rogue Maven/npm/PyPI/what have you repositories, hacked accounts on any website that is used for distributing programs, feature branches in open source projecs that are automatically built on CI servers in side corporate networks, the possibilities to grab data and send it to somewhere on the internet are endless.
One security measure that somehow grew out of fashion over the last years, is at least on application servers, to disallow any outgoing network traffic, especially to the internet (at least any cloud environment I see nowadays allows it by default). This would largely prevent these sorts of attacks from being able to actually send anything out, but also prevent XXE attacks from happening, prevent reverse connections to an attacker host from being set up, make SSRF attacks harder to verify, and so on.
I strongly recommend whitelisting only the network traffic that your application actually needs.
And the problem is much larger than these typosquatting attacks. Abandoned Github projects taken over my malicious users, rogue Maven/npm/PyPI/what have you repositories, hacked accounts on any website that is used for distributing programs, feature branches in open source projecs that are automatically built on CI servers in side corporate networks, the possibilities to grab data and send it to somewhere on the internet are endless.
One security measure that somehow grew out of fashion over the last years, is at least on application servers, to disallow any outgoing network traffic, especially to the internet (at least any cloud environment I see nowadays allows it by default). This would largely prevent these sorts of attacks from being able to actually send anything out, but also prevent XXE attacks from happening, prevent reverse connections to an attacker host from being set up, make SSRF attacks harder to verify, and so on.
I strongly recommend whitelisting only the network traffic that your application actually needs.
At pypistats.org download numbers of the last half year can be found.
* python3-dateutil has 271 downloads from non-mirrors in last month[1]
* jeilifish has only 106 downloads from non-mirrors in last month[2]
[1]:https://pypistats.org/packages/python3-dateutil
[2]: https://pypistats.org/packages/jeilyfish
* python3-dateutil has 271 downloads from non-mirrors in last month[1]
* jeilifish has only 106 downloads from non-mirrors in last month[2]
[1]:https://pypistats.org/packages/python3-dateutil
[2]: https://pypistats.org/packages/jeilyfish
In the end I think the solution to these issues will be something like what's promised by the Bytecode Alliance[0]. The idea is you give each package its own WASM sandbox with granular control over its permissions.
That solution also has the benefit of allowing you to call a package from any language from your language of choice.
I highly recommnend reading their the article introducing the idea, its very convincing:
[0] https://bytecodealliance.org/articles/announcing-the-bytecod...
That solution also has the benefit of allowing you to call a package from any language from your language of choice.
I highly recommnend reading their the article introducing the idea, its very convincing:
[0] https://bytecodealliance.org/articles/announcing-the-bytecod...
Package management and curation are the Achilles heel of open source. Abandoned packages, typo and letter substitutions, maliciously crafted pull requests and so on are all going to go up in frequency until the environment is hardened enough that the bulk of these attempts fail. That's a long way to go, and the number of capable maintainers and curators is relatively small.
Some environments (Python, Node) are more susceptible to this sort of trickery than others.
Some environments (Python, Node) are more susceptible to this sort of trickery than others.
You know allowing people to upload libraries with highly conflicting names to existing ones is almost reckless.
There is a bunch of stuff PyPi could do short of full curation that would make this much harder.
A better solution is for languages to provide a kind of "module sandboxing" where modules need to declare the capabilities they need, and the runtime prevents them from accessing anything else.
In this case, the module would have needed to request the ability to make an outgoing TCP/IP connection - and that request should raise red flags for a date parsing utility.
There is a bunch of stuff PyPi could do short of full curation that would make this much harder.
A better solution is for languages to provide a kind of "module sandboxing" where modules need to declare the capabilities they need, and the runtime prevents them from accessing anything else.
In this case, the module would have needed to request the ability to make an outgoing TCP/IP connection - and that request should raise red flags for a date parsing utility.
"pip" has a usability problem. It should do a lot more at preventing this kind of thing. When using pip, it's not easy to tell information like the release date, how many versions have been released, and so on.
Since such info is available from PyPI API, I wrote my own "pypisearch" script to sort by latest release date and include number of releases to weed out packages that seem useful but are old or rarely released. I should probably integrate PGP signing info too into it.
Since such info is available from PyPI API, I wrote my own "pypisearch" script to sort by latest release date and include number of releases to weed out packages that seem useful but are old or rarely released. I should probably integrate PGP signing info too into it.
> The first is "python3-dateutil," which imitated the popular "dateutil" library. The second is "jeIlyfish" (the first L is an I), which mimicked the "jellyfish" library.
These two have been caught. How many haven't yet been caught?
Traditional Unix file permissions are pretty much a joke for the way developer computers get used (one user - does everything). Real process sandboxing is needed.
Traditional Unix file permissions are pretty much a joke for the way developer computers get used (one user - does everything). Real process sandboxing is needed.
I get the python3-dateutil because you might think it's an updated version of the standard library.
But how does jellyfish with a different char for L work? Someone would need to copy and paste it. But if they go to pypi, it won't have many installs.
Unless they started writing tutorials with:
"okay now just pip install X"
But how does jellyfish with a different char for L work? Someone would need to copy and paste it. But if they go to pypi, it won't have many installs.
Unless they started writing tutorials with:
"okay now just pip install X"
Article points out Gitlab account olgired2017 (https://gitlab.com/olgired2017). I think it will be interesting if GitLab shares his/her list active session details like ipaddress, browser, date and time from their site logs (profile/active_sessions).
What's the best information source for me to follow to keep up to date on these kinds of library vulnerabilities?
I would make a feed of the homepages for all the libraries I know I use, but that won't help me with the libraries I use without knowing.
If you want a concrete hardening step to avoid this attack, try using a hardware PIV/CAC device (e.g. a Yubikey) as the only copy of your private keys.
This is very easy to setup on MacOS High Sierra or later (https://support.apple.com/en-us/HT208372):
1. Generate the key: https://developers.yubico.com/yubico-piv-tool/Actions/key_ge...
2. Use "ssh-keygen -D /usr/lib/ssh-keychain.dylib" to extract the public key fingerprint to put in your authorizes keys list.
3. Add this line to your SSH config file to tell the client to attempt to login using the key on your device: “PKCS11Provider=/usr/lib/ssh-keychain.dylib“
On Windows, Putty-CAC supports this and can reportedly be used with Git: https://piv.idmanagement.gov/engineering/ssh/#ssh-using-putt...
This is very easy to setup on MacOS High Sierra or later (https://support.apple.com/en-us/HT208372):
1. Generate the key: https://developers.yubico.com/yubico-piv-tool/Actions/key_ge...
2. Use "ssh-keygen -D /usr/lib/ssh-keychain.dylib" to extract the public key fingerprint to put in your authorizes keys list.
3. Add this line to your SSH config file to tell the client to attempt to login using the key on your device: “PKCS11Provider=/usr/lib/ssh-keychain.dylib“
On Windows, Putty-CAC supports this and can reportedly be used with Git: https://piv.idmanagement.gov/engineering/ssh/#ssh-using-putt...
Does anyone know of a way of running something like “little snitch” on Heroku so that you can whitelist outgoing connections?
That seems like a possible way of mitigating this type of issue.
That seems like a possible way of mitigating this type of issue.
I have been working on a Node.js library (very much work in progress and progressing slowly due to lack of time) that integrates libseccomp to be used programmatically inside Node.js whether at library or application level. For me at the moment it's kind of an experimental idea as it can be quite tricky to get everything right and in order without the kernel killing the process by mistake, but at least I think for some of the cases in the category that this issue is in, it will help mitigate it. I believe libseccomp already has official bindings for Python, as well as third party bindings for other languages, but this kind of work has been very successful in OpenBSD with pledge and I think it has been overlooked in dynamic programming languages and Linux in general.
> "jeIlyfish" (with an upper case I) and "python3-dateutil" (not "dateutil").
Libraries should take lessons from writing safety critical code. If you identify libraries visually by name, the main problems are:
* easily misread characters like 1 (one) and l (lower case L), 0 and O, 2 and Z, 5 and S, or n and h.
* identifier names that differ only by on or few characters, especially if they are long.
It's possible to enforce a set rules that make identifier names are visually distinguishable and string distance measure to check all new libraries that are added against old names.
Libraries should take lessons from writing safety critical code. If you identify libraries visually by name, the main problems are:
* easily misread characters like 1 (one) and l (lower case L), 0 and O, 2 and Z, 5 and S, or n and h.
* identifier names that differ only by on or few characters, especially if they are long.
It's possible to enforce a set rules that make identifier names are visually distinguishable and string distance measure to check all new libraries that are added against old names.
Anyone here not encrypting their private keys?
Also known_hosts file is a double edged sword. It's pretty sensitive in combination with a private key.
Also known_hosts file is a double edged sword. It's pretty sensitive in combination with a private key.
Does anyone know where this was officially announced? I don't see anything at https://mail.python.org/archives/list/security-announce@pyth...
One thing I've always thought would be a good idea is a tool (either local or part of the pip/other packet manager download process) that greps and prints out all URLs and IP addresses within the code, including common encodings. Additionally, any lines that uses any transfer protocols (like HTTP requests) should be highlighted too as IP/urls can be encoded. Any HTTP request, for example, to suspiciously encoded URLs could raise flags.
The official library itself could have a "urls" file which has a list of urls that are expected and so anything that doesn't match can be questioned.
Whilst this won't solve the issue 100%, it raises the difficulty barrier to implement outgoing network calls.
The official library itself could have a "urls" file which has a list of urls that are expected and so anything that doesn't match can be questioned.
Whilst this won't solve the issue 100%, it raises the difficulty barrier to implement outgoing network calls.
Could Python be retrofitted with import flags, much like the openbsd pledge? Eg you could import a library but not permit file io or network access -- that would snipe these kind of attacks, and it would be a reasonable restriction for many libraries
To search your own projects for the malicious libraries:
pip3 freeze | grep -i jeIlyfish
pip3 freeze | grep -i python3-dateutil
pip3 freeze | grep -i jeIlyfish
pip3 freeze | grep -i python3-dateutil
Original source: https://github.com/dateutil/dateutil/issues/984
Another insidious exploit is to hijack the maintainer's package manager account and push the code directly there, bypassing the repository altogether. It doesn't rely on you installing a new package since the hijacked package in question is already a dependency of yours.
I got into a habit of checking both the package manager and the project's repository before updating any given dependency.
https://news.ycombinator.com/item?id=20377136
I got into a habit of checking both the package manager and the project's repository before updating any given dependency.
https://news.ycombinator.com/item?id=20377136
Would sticking to the OS upstream package manager be a safer option compared to installing from pypi directly?
How often does something like this happen with packages in the CentOS, epel, or Debian repositories?
How often does something like this happen with packages in the CentOS, epel, or Debian repositories?
Ideally programming languages should include capability-based access control, so that a random library that is supposed to do X, can't do Y.
Until then, we need to vet our dependencies. Check out https://github.com/crev-dev/cargo-crev/tree/master/cargo-cre... for a distributed review system we're working on.
Until then, we need to vet our dependencies. Check out https://github.com/crev-dev/cargo-crev/tree/master/cargo-cre... for a distributed review system we're working on.
I am curious when the hackers will start stealing ~/.kube/config. In the default Kubernetes install on-premise, a token or admin certificate is just laying there, unprotected and adding a passphrase to the cert is not supported. Some are using an oauth identity provider or other mechanisms but that unnecessarily complicates the setup and smaller k8s clusters could be stolen this way...
I don't see a solution other than every application being launched in a separate container, exposing only what the user explicitly gives access to, similar to how mobiles applications require permissions. We have the technology, eg. cgroups & unshare on Linux; what's missing is something that plumbs all these brittle pieces into a secure application launcher made for desktop (rather than server/cloud) usage.
Best practice: Don't use pip search && pip install. Search for the project site and copy & paste the pip install instructions.
Microsoft has started adding short life VMs. No idea if that's good. Both MS and Apple offer their App stores with more locked down experiences though I'm sad they conflate app security and app markets.
Basically anytime I run any software, everytime I run "make" or "npm install" or "pip install" or download a game on Steam etc I'm having to trust 1000s of strangers they aren't downloading my keys, my photos, my docs, etc...
I think you should be in control of your machine but IMO it's time to default to locked down instead of defaulting to open.