Please be careful when revoking tokens. It looks like the payload installs a dead-man's switch at ~/.local/bin/gh-token-monitor.sh as a systemd user service (Linux) / LaunchAgent com.user.gh-token-monitor(macOS). It polls api.github.com/user with the stolen token every 60s, and if the token is revoked (HTTP 40x), it runs rm -rf ~/.
> Malware can make a fake unprivileged sudo that sniffs your password.
Not on my Linux workstation though. No sudo command installed. Not a single setuid binary. Not even su. So basically only root can use su and nobody else.
Only way to log in at root is either by going to tty2 (but then the root password is 30 characters long, on purpose, to be sure I don't ever enter it, so login from tty2 ain't really an option) or by login in from another computer, using a Yubikey (no password login allowed). That other computer is on a dedicated LAN (a physical LAN, not a VLAN) that exists only for the purpose of allowing root to ssh in (yes, I do allow root to SSH in: but only with using U2F/Yubikey... I have to as it's the only real way to log in as root).
It is what it is and this being HN people are going to bitch that it's bad, insecure, inconvenient (people typically love convenience at the expense of security), etc. but I've been using basically that setup since years. When I need to really be root (which is really not often), I use a tiny laptop on my desk that serves as a poor admin's console (but over SSH and only with a Yubikey, so it'd be quite a feat to attack that).
Funnily enough last time I logged in as root (from the laptop) was to implement the workaround to blacklist all the modules for copy.fail/dirtyfrag.
That laptop doesn't even have any Wifi driver installed. No graphical interface. It's minimal. It's got a SSH client, a firewall (and so does the workstation) and that's basically it. As it's on a separate physical LAN, no other machine can see it on the network.
I did set that up just because I could. Turns out it's fully usable so I kept using it.
Now of course I've got servers, VMs, containers, etc. at home too (and on dedicated servers): that's another topic. But on my main workstation a sudo replacement function won't trick me.
> Realistically if you have installed malware, you need to do a full wipe of your computer anyway
You might be the exception to this sentiment. But out of curiosity, after all that setup would you feel confident trying to recover from malware (rather than taking the “nuke it from orbit” approach?).
> But out of curiosity, after all that setup would you feel confident trying to recover from malware (rather than taking the “nuke it from orbit” approach?).
Oh no, I'd still nuke everything from orbit should I find anything indicating a local exploit succeeded. But the thing is: if on one system a local exploit has less probability to give root, then the probability that on that same system I'd know I need to nuke everything from orbit would be higher than on a system where root is easier to obtain.
I was however answering to the part about subverting sudo: and I both agree (it's totally trivial to abuse sudo) and disagree ("everybody uses sudo") with the part about sudo.
I agree. My surreptitious goal was to emphasize to anyone reading along: this person has put in the extra effort, but even they will not try to recover a compromised system. It is just too risky.
In my case I use QubesOS so sudo is useless even if present since every security domain is isolated by hypervisor.
For servers, sudo or a package manager etc should not exist. There is no good reason for servers to run any processes as root or have any way to reach root. Servers should generally be immutable appliances.
Thanks for sharing this, that seems like a very cool setup. I have a very old good-for-almost-nothing laptop that would be perfect for this, might just have to copy you!
FYI, in English the phrase "since years" is grammatically incorrect and sounds unnatural to a native speaker's ears. The correct phrase would be "I've been using that setup for years."
I don't think I've ever heard a native speaker say it, but I could definitely imagine it coming out of a native speaker's mouth with that pregnant pause, specifically. Like an acknowledgment that you're about to say something a bit grammatically awkward.
I only mentioned it because I used to think correcting people's English was rude, until I had a long work engagement with a French guy whose English was pretty good but not quite native. He insisted that I correct his written English if I saw a mistake (i.e. in documentation, proposals, etc.), otherwise he wouldn't learn where it was wrong and how to improve it.
To my ears it “since years” sounds like it’s missing an “ago” after it (or like the GP said “for years” sounds even more natural).
It makes me think of another similar one: I've noticed that British English speakers will say e.g. "the new iPhone will be available from September 20th"
To my ears that sounds like it's missing an “onwards” after it (or “starting September 20th” would sound even more natural).
Is the meaning different? I'm struggling to see how "from September 20th" would have a different implication to "starting from September 20th" (or similar) given the context.
Are root logins only allowed from that particular LAN? Because ssh localhost is a thing.
I would say that the inability to obtain a session with elevated privileges from a normal session is key. The problem with sudo is that it gives the same shell some superpowers, so it's exploitable. Even ssh might be impenetrable, if not for the /dev/<pid>/fd of the ssh invocation, and even that can only read.
> Why disallow password login when you have 30 char password?
I only disallow password login over SSH. It's still technically possible to log in at a virtual console (like tty1 / tty2 / etc.) using a password (btw only root has a 30 characters password).
Usually you do not allow to directly log in as root by SSH: but in my case it's basically the way I want it done. So I allow root to log in by using SSH but only with a Yubikey.
You don't even really need that; you just need to wait until the user runs `sudo` and then you also run `sudo` after they authenticate. Now you're root, boom. It doesn't get you the password, but once you're root you can backdoor to your heart's content and then you probably don't need it.
Alternately, run `sudo --non-interactive --validate` over and over until it succeeds. For some reason, using noninteractive doesn't log to the auth log/journald the way trying and failing to actually run a command would.
Edit: the loop only works assuming you can run this sudo command in the background in the user's shell so that you can pick up the same sudo session when they auth, which is honestly unlikely. Easier to wrap sudo in a command that just also runs sudo and then immediately runs something else.
Ok, so the malware runs a keylogger / clipboard logger, gets the password and runs sudo on it's own. Or replaces your shell by putting exec ~/hackedbash into your bashrc
Password on sudo is only useful if you detect the infection before you run sudo
Physical attestations are hard to solve, I think it would be nice if all TPMs in laptops had this. Then the problem becomes how do you automate stuff that needs to be done.
At least my password won't leak as often with yubikey, but the attacker can still hack my shell to execute fake sudo. Even if I type /bin/sudo explicitly, there is ptrace, LD_PRELOAD or just replacing the entire bash binary.
In practice yubikey sudo keeps you much safer today, as almost nobody uses it and malware won't be prepared for it
Yes, that would be one potential solution. But I have certainly never done it and bet >99.999% of the world's use of sudo is through 'sudo'.
Plus you only need one slip-up and you're hosed. Even people who try to almost always use '/usr/bin/sudo' will undoubtedly accidentally let a 'sudo' go through. Maybe they copy/paste a command from somewhere (after verifying that it's safe of course) and just didn't think of the sudo issue then and there.
The real problem is that there should be at least 2 levels for sudo, one for installing software and another that really allows someone to compromise the entire system, both layers should be separate to mitigate risk. At least the most secure layer should allow you to perform secure recovering and diagnosis
The old bin user is an idea that could be modernized with a new two level sudo concept, the higher one for recovery and diagnosis, already done in Chromebook and other solutions
bin passwords I will always remember: At the University of Maryland CS department systems the bin password was "fuck,you", and there was a devout Christian student on staff who had a problem with that, so we had to change it (to something harder to remember, I just can't recall).
If you set the appropriate linux capabilities flag on a binary such as sshd at bootup then unprivileged users can bind to 22, no problem.
setcap 'cap_net_bind_service=+ep' /usr/sbin/sshd
Could even run it as a daemon unprivileged from a home directory with "systemd --user"
That said if you have multiple users and want every user to have their own sshd reachable on port 22 on the same machine you probably want to listen on vhost namespaced unix sockets and have something like haproxy listen on port 22 instead. Haproxy could of course also run unprivileged provided it has read access to all the sockets.
The way many including me manage systems without root privileges at runtime is by compiling immutable rootfs images that run in ram with kernel, init, mounting filesystems and assigning any users and privilege assignments, then drop to user privs.
That stuff needs to change very seldom, so when you do need to change it you just generate a new tiny rootfs image in a few seconds and reboot to pivot to it or maybe have a kexec trigger if you are feeling fancy.
For my primary workstation the entire disk is my home partition and I boot my latest rootfs from a flash drive. In other cases network boot.
For that you really only need CAP_NET_BIND_SERVICE.
The bigger issue is that if you want to install or update system-wide packages, many of those will be used by privileged processes. Suppose you want to update /bin/sh. Even if the only permission you had is to write binaries, that'll get you root.
Why not make a proper link /sudo so you don't have to type out the full path every time, which is very inconvenient? (but the fact that such workarounds are needed still means it's a theater)
It should be a way to make system env vars (profile.d or simlar) as readonly so every users' shell had these set to empty values and unable to change them.
Yes; I'm aware, but for some environments writting a custom shell as the one for SDF would be an easier task. Or maybe a really restricted "ash" called "rash" -because it is- with maybe autocomplete and that's it. Hardcoded $PATH and the like.
Anything that can be modified by an attacker can not be used to secure the sudo command. This is a recursive requirementor hierarchy for secure systems.
I mean, this is basically why you press Ctrl-Alt-Del to log in on Windows NT and Win2k - because it's a keystroke that malware couldn't trap, so they can't put up a fake login screen because the OS will override it anyway.
1. shells support the notion of privileged commands, that can't be overridden with PATH manipulations, aliases or functions.
2. Sudo (or PAM actually) can authenticate with your identity provider (like Entra ID) instead of a local password. Then there is nothing to sniff and you can also use 2FA or passkeys.
Neither would actually help in this case though. Malware could manipulate both of those as an unprivileged user to run malicious code the next time you elevate privileges.
Remember that malware can replace or modify your shell
No? The shell must be listed in /etc/shells, it can't be an arbitrary command. And after elevating privileges you have to run the malware (which could only be written to home or tmp) for it to work, but sudo already scrubs the environment.
So the main danger is that you're not running the real sudo.
I have an idea that I hope to implement one day to make sudo actually secure:
1. Authenticate with passkeys (webauthn) instead of passwords.
2. Sudo can only run an interactive root shell, not arbitrary commands. The session is time-bound, and the TTY output is recorded for auditing purposes.
This combination makes intercepting sudo largely useless. Passkey authentication cannot be replayed or relayed. The fact that sudo can only open an interactive shell makes it impossible for a sudo wrapper to pass a malicious to sudo. This way we're not dependent on whether the unprivileged shell is secured properly. It also solves approval fatigue (compared to running sudo separately for every command).
----
EDIT: now that I think about it: an attacker can still edit .bash_profile and reexec the shell in a malicious terminal emulator. Then when the user gets a sudo root shell, the malicious terminal emulator can inject malicious commands.
Looks like the only good way is to get a root privileges via a separate user account that doesn't have malware, and that also can't easily install malware (e.g. accidentally running npm, forgetting that that's not safe).
Endless ways, which is why I do not understand why sudo is ever used anymore, especially in production.
You do not need root to do anything in Linux these days anyway between Namespaces and Capabilities so there is really no reason for root to be accessible at all or have any processes running as root post boot.
Plenty of package managers can install to an arbitrary directory like ~/.local. Each user, or even each project, can have its own rootfs full of software.
The only things I tend to have running at the system level are a kernel and init and maybe openssh.
How would that help? Unless you happen to check the dotfiles git diff before running _anything_. I guess this could be put in prompt or some cron job to detect diffs but I bet absolutely nobody does this.
I had an idea to always run 2 users, the "main" one (or more) and a "project one"... one could sudo to the project user, but that one could not sudo out... (npm would only be installed for the project user).
Sure, without exploits they can steal your api keys, read your personal data, and access your browser data. With exploits they can update packages on your computer too.
Any application running as a user with sudo access and RW permissions on the users home folder effectively has root permissions, it'll just take a little longer to get it.
That's why Flatpaks sandbox doesn't exist if the application has access to the home folder.
And I'm increasingly concerned that one could vibe-code a massive payload that does all of these at once - including subtle things like trying to get itself installed into personal projects and forks, so it can persist across a system wipe. We're only seeing the beginning of these attacks.
Next easy attack vector is (non-rootless) docker run with rootfs mount, many are in docker group even when sudo is protected.
Also, most sensitive data is in the user scope anyways (on a PC).
You should always run dev stuff in containers to start with.
And when your system is compromised, reprovision from a higher scope, too many places to hide backdoors
It’s like if a bandaid fell into the soup pot. You could solve the problem by (A) fishing it out and giving the soup a good boil; or (B) new soup please!
You seem to be interpreting "please be careful when..." as "don't". I'm not sure how that interpretation makes any sense. Obviously they just mean, first kill the service (or better yet, shutdown the machine entirely) and then revoke the token...?
Make sure to have an up-to-date backup, that's offline, or at least not mounted on the affected computer.
Check for the dead-man switch, and if present, disarm it.
Only then revoke the tokens. Instead of immediately revoking the tokens, like one would normally do. Nobody is suggesting to keep the compromised tokens active longer than necessary.
I'm not quite sure of what this really accomplishes, like is it just M.A.D.? Like at that point the creds have been stolen and the whole machine is toast.
Let's say the attack becomes hugely succesful and the worm spreads to thousands of devices. GitHub/NPM could just revoke all compromised tokens (assuming they have a way to query) stopping the worm in its tracks. But because of the Dead Mans Switch, they'd know that in doing so, they'd be bricking thousands of their user's devices. So it effectively moves the responsibility to revoke compromised tokens from a central authority that could do it en-masse, to each individual who got compromised, greatly improving the worm's chances of survival.
Even after the owner has realized the attack and revoked the token, there’s next steps (alerting the community, pulling from NPM) that causing havoc delays even by just a bit.
Only if the goal is to actually spread fear in a civilian population. It's not clear what the motivation is here besides "the worm spreads itself lol".
The dead man's switch reminds me of worms and viruses from my childhood, whose primary purpose was apparently just to wreak havoc rather than direct financial gain. It's a childish gimmick.
If an infected computer gets disabled after deactivating one stolen credential, it might slow down the victim from deactivating their other stolen credentials.
https://github.com/TanStack/router/issues/7383#issuecomment-...