Python malware starting to employ anti-debug techniques
jfrog.com
jfrog.com
Why will it be "useless". Explain your reasoning please.
That being said, I don’t think PyPI would be «useless» - this was the state a few years ago, and we had to compile all the libraries ourselves. I don’t want to go back.
It's a convenience/security trade-off, I see.
The only solution I've ever seen to that requires investing trust in an "authority" which then becomes corrupt and censorial. One simply expands the dilemma to a triad; security/freedom/convenience.
If I am not mistaken the PyPI "Cheese Shop" is owned by the Python Software Foundation, a 501(c3) nonprofit organisation which constitutionally values Software Freedom highly. It seems natural that convenience would be sacrificed if security is of concern.
But there is a tradeoff between having things thoroughly vetted and tested, and moving fast.
- security
- freedom
- convenience
- speed/newness
Who can build me a UI with four sliders that selects the packages I
can install? Bonus: when I move a slider it highlights all the
potential packages that changed status with reasons why they are now
included/excluded.But none of that is a call to give up. We just need to think seriously about the problem we face.
At best I suppose we could put in place checks to get low hanging fruits. But we are, after all, allowing a turing complete and highly dynamic language to execute.
> or just disallow unfamiliar .pth files from being installed altogether
That would kill the entire plugin ecosystem.
Now, the next thing could be to have a permission system, requesting access to the network, fs, .pth, etc. It would not be a bad idea, given that we are, after all, installing things that are as powerful as apps.
But it would be a gigantic effort, and users still would just accept without reading, like they do with apps.
But I've made a ton of web apps and tools anyway, including a little process launcher that plays the role of poor man's Docker.
It'd be nice if those popular systems had a pure Python capability anyway, similar analogy being software rendered 3D back in the day.
It essentially bans binary blobs yet it is very useful.
Providing a build env for that would make it prohibitively complicated and expensive, and basically would mirror github CI.
That's the reason continuum is making money: they sell a python package distribution channel that is checked and locked.
The most obvious (but not necessarily easiest) approach is to phase out setup.py and move everything to the declarative pyproject.toml approach. This is not just better for metadata (setup scripts make it really hard to statically infer what deps a lib has), it also allows for better control over what installers/toolchains run on install.
Attackers still have quite a lot of latitude during the build phase, but at least libraries have the option to specify declaratively what permissions they need (and presumably the user has the option to forbid them).
Also eval/exec are terrible and I wish there were a mode to disable their usage, but I don't know if the python runtime has some deep dependency on it. Maybe there's a way to restrict it so that only low level frames can call the eval opcode.
The hardening could mitigate on-compilation hacking.
Obviously, this leaves "compile in the backdoor and wait for the user to fall into it" but at least this isn't an issue of compiling on the user's computer and it isn't a issue of binary blobs. And possibly there's a greater chance of detection if actual source code has to be available to compile.
You can use audit hooks in the sys module (as long as you load it first) to disable eval/exec/process spawning or even arbitrary imports or network requests.
Even then, that only pushes the problem down a layer: you’re still fundamentally installing third party code, which can do whatever it pleases. The problem then becomes one of static analysis, for which precision is the major limitation (in effect, just continuing the cat-and-mouse game.)
In fact, most packages are now wheels, which are not sources: they are compressed, and may contain binaries for compiles extensions, something extremely popular (the scientific and AI stacks exist only because of this).
Some packages need to be compiled after the fact, something that setup.py will trigger, and some even embed a fallback compiler, like some cython based packages.
Also, remember there is very few people working on pypi, there is no moderation, anybody can publish anything, so you would need a bullet proof automated heuristic. That's either impractical, or too expensive.
If you want a secure package distribution platform, there are commercial ones, such as anaconda. You get what you pay for.
The problem is a failure to understand security.
1. https://github.com/ossillate-inc/packj flags malicious/risky packages.
The only surprising thing about this article is the claim that these type of malware haven't been spotted in pypi before. That would suggest that there isn't much of credible actors trying to spread through pypi at all.
Some of that self-modifying and anti-defeat code back then were truly works of art, and squeezed into mind-bogglingly small memory and cpu foot prints, and the malware authors will have a field day re-implementing their future cousins in spirit, and some of the greybeards amongst the white hats will get to relive their 8-bit glory days hunting and defeating them.
The article gave a description of a really super primitive technique compared to the last generation of those anti-piracy techniques, but I still see a family resemblance.
We're also talking about layers of dependencies. It's a ridiculous approach.
It's one thing if I were paid by my employer to re-invent the wheel, but for personal projects... I don't have that much free time for them in the first place any more, I want to get shit done and not shave yaks all day. When I want a good grind, I'll pack out Factorio or one of the LEGO Switch games...
There are always risks associated with building on other people's land, platforms, and codebases. However, there are also risks when reinventing the wheel. Both perspectives have advantages, disadvantages, and use cases.
This is exactly what I'm starting to work through. After 6 years of Python, I've finally hit the limit of what I can do with it. Now I'm working to rebuild an algorithm in C to reconnect to the Python application.
"One does not simply write sklearn or pytorch from scratch."
I also agree with this. Would either be in a product though? Personally, if it's not a product, I wouldn't mind dependencies.
I'd be prepared to be a bit of blind money that other industry tools use a similar setup where the python libraries permit an exceptional cadence of development and help place those vendors products at the pointy end of the market.
How they manage dependency security isn't super clear. They're always a couple of version behind, so perhaps it's a CI/CD QA/QC thing which also includes security.
If you import numpy might as well import the entire scipy ecosystem
Why do you need numpy for web?
Edit: I will concede that there is no point in retooling ML. Web is an entirely different circumstance though.
At this point isn't it easier and just as safe to manually review the code, pin the hash in a lockfile, and manually review the rare changes than it is to rewrite everything?
In my case, replacing Flask is purely preference.
Xarray to read, numba for calcs in xarray, pandas to leave it sitting in a dataframe, numpy as pandas preferred math provider. You could write the api componentry from there, sure. Or you could use a library that has had the pants tested off it and covered most of the bugs you are likely to accidentally create along the way.
There's no compelling reason to write everything from scratch. If everyone was taking that approach then there would be no reason to have an ecosystem of libraries, and development would grind to a halt because we, as a collective of people programming, are not being efficient.
In what circumstance could that be profitable? Even if you batched data, any number of concurrent users would gobble resources at an incredible rate.
Also, it's a particularly arrogant point of view to assume that because you cannot see a reason for something to exist that its development is invalid both now and into the future. You've also assumed the data is user defined.
I can also guarantee you that user concurrency is not an issue after some recent load testing, with load capabilities surpassing expected user requests by several orders of magnitude whilst on minimum hardware.
Maybe it is arrogant. That entirely depends on whether or not a product or service uses this specific approach -- successfully. Do you have an example?
Edit: I also want to clarify that my comment doesn't suggest that the underlying technology is bad or without use cases; only that it isn't suited for remote (online) processing. It would be way cheaper to manipulate data like that locally.
Taking that scientific data and making it available in report format for those which need it that way, when the underlying data changes at a minimum once per day, is the more important aspect.
The API is currently returning queries in about 0.1 to 0.2s. They are handled async right the way through. It's fast, efficient, and the end result whilst very early in the piece is looking nice. Early user engagement has been overwhelmingly positive.
Where it will be shared is among those with an interest in the specific space. That includes government agencies, land managers, consultancies etc. At no cost to them, because what the outputs can help offset in terms of environmental cost dwarves dev cost.
With that being said, good luck. I hope you succeed. I'd be very interest to read about it. Do share when its public.
Link me your reimplementations of tensorflow, numpy, and django (with similar features and same or better performance) and we can talk.
"I will concede that there is no point in retooling ML. Web is an entirely different circumstance though."
Edit: I just realized the way I use votes isn't necessarily the same and no one is wrong in their understanding.
Your reply connected the dots. Thank you.
A better solution imho would be project level capabilities, so you can pull in a dependency but restrict its lib/syscall access, so it would not compile when it turns malicious.
Maybe it will solve at least something, maybe some day.
Imagine if PyPi could take pure source code, and run a standardized wheel build for you. That pipeline would include running security linters on the source. Then you can install the escrow version of the artifact instead of the one produced by the project maintainers.
You can even have a capability model - most installers should not need to run onbuild/oninstall hooks. So by default don’t grant that.
This sidesteps a bunch of supply-chain attacks. The cost is that there is some labor required to maintain these escrow pipelines.
With modern build tools I think this might not be unworkable, particularly given that small libraries would be incentivized to adopt standardized structures if it means they get the “green padlock” equivalent.
Libraries that genuinely have special needs like numpy could always go outside this system, and have a “be careful where you install this package from” warning. But most libraries simply have no need for the machinery being exploited here.
My personal experience with any situation where I need to get some crusty random python library to run has always been a situation with a lot of "-y"ing, swearing, and sketchy conda repositories. Usually it's code that was written years ago and does some very particular algorithm that's essential, so any warnings in the pipeline basically becomes ignored by the sheer difficultly of the task.
What does it mean for a package to have been signed with the key granted to the CI build server?
Does a Release Manager (or primary maintainer) again sign what the build farm produced once? What sort of consensus on PR approval and build output justifies use of the build artifact signing key granted to a CI build server?
How open are the build farm and signed package repo and pubkey server configurations? https://github.com/dev-sec https://pulpproject.org/content-plugins/
Conda > Adding packages > Running unit tests: https://conda-forge.org/docs/maintainer/adding_pkgs.html#run...
From https://github.com/thonny/thonny/issues/2181 :
> * https://conda-forge.org/docs/maintainer/updating_pkgs.html
> Pushing to regro-cf-autotick-bot branch¶ When a new version of a package is released on PyPI/CRAN/.., we have a bot that automatically creates version updates for the feedstock. In most cases you can simply merge this PR and it should include all changes. When certain things have changed upstream, e.g. the dependencies, you will still have to do changes to the created PR. As feedstock maintainer, you don’t have to create a new PR for that but can simply push to the branch the bot created. There are two alternatives […]
nektos/act is one way to run a github-actions.yml build definition locally; without CI (e.g. GitLab Runner, which requires ~--privileged access to the docker/Podman socket) to check whether you get the exact same build artifacts as the CI build farm https://github.com/nektos/act
A Multi-stage Dockerfile has multiple FROM instructions: you can build 1) a container for running the build which has build essentials like a compiler (GCC, LLVM) and packaging tools and keys; and 2) COPY the build artifact (probably one or more signed software packages) --from the build stage container to a container which appropriately lacks a compiler for production. https://www.google.com/search?q=multi+stage+Dockerfile
Are there guidelines for excluding entropy like the commit hash and build time so that the artifact hashes are exactly the same; are reproducible on my machine, too?
I clearly get the security risks associated with random libs available for Python. Is this also the case for other languages like Java? Are the dependencies available to them also a relative free-for-all, or are bugs mostly accidental?
Thanks!
That's a difficult enough problem to deal with already, but with Python, it's possible to execute code at install time of such a 3rd party library (basically, when you do a 'pip install stuff'). So, you might never have run the application you installed, but you'd still have executed whatever malware was hiding. This is not the case for a lot of other languages. Also, Python allows the execution of code when you have an `import stuff` statement, which is also not the case in other languages, often. But this is not directly related to this, just another 'Python-specific' attack vector.
Basically if the library uses eval() it's probably a good idea to avoid it if possible.
My favorite case was when a newbie coder used eval() to evaluate something that looked json-ish, which, came from an api request.
It seems you can’t run bandit on deps, but perhaps if you fork them and build yourself?
If you are security conscious, having a rule that you can only install from a local pypi with packages you have forked would be a more defensible perimeter. But, a maintenance pain for sure.
For example here's Python dataclasses in the standard library using exec() to create the `__init__` and other methods that go on your dataclass:
https://github.com/python/cpython/blob/main/Lib/dataclasses....
Here's Pydantic using it for a jupyter notebook check:
https://github.com/pydantic/pydantic/blob/594effa279668bd955...
here's Pytest using it to rewrite modules so that functions like assert etc. are instrumented by pytest:
https://github.com/pytest-dev/pytest/blob/eca93db05b6c5ec101...
Here's the decorator module using it (as is the only way to do this in Python) to create a signature matching decorator for an arbitrary function:
https://github.com/micheles/decorator/blob/ad013a2c1ad796996...
All of these libraries are completely secure as eval/exec are used with code fragments that are generated by the libraries, not based on untrusted input.
eval() /exec() are not running executable files, just Python code, the same way all the rest of the package is already doing.
I always wondered if we could just use this against the malware. E.g. just run a useless process which is named/looks like a debugger and the malware stops itself. Of course that's nothing to be relied on on its own but maybe as an additional layer of defense?
https://www.theverge.com/2017/5/13/15635050/wannacry-ransomw...
This is neither interesting nor new and was already implemented 20 years ago by script kiddies.
What's next? A VBS Trojan that takes commands via Matrix instead of IRC?