Comment by chasil

1 day ago

This article does not mention that environment variables are also visible by process in /proc/*/environ (which has restrictive permissions, but is completely visible to root).

PuTTY has added a -pwfile option for use in ssh. If not exported, this interface is likely the best for non-key batch use. It seems much superior to sshpass.

The old .netrc format can be adapted for storage (which appears popular for curl), but I prefer sqlite databases, with permissions removed for all but the owner.

> This article does not mention that environment variables are also visible by process in /proc/*/environ (which has restrictive permissions, but is completely visible to root).

What isn't visible to root? Maybe if you're willing to go down a really deep rabbit hole you can play that game, but I would generally explicitly exclude root from my threat model.

  • Defense in depth. Malware is software programmed to do a number of things, not all possible things (well at least until the attacker gets a shell, which is rather noisy). Scanning env vars is trivial, scanning the entire file system and traversing mount points is a bit harder, traversing all memory and guessing what’s a secret is a hell lot harder even for an interactive attacker. If you happen to include some malicious library doing dragnet mining and exfilatration of secrets, you’re more likely to dodge a bullet if you don’t have secrets in env vars than if you do.

  • Hardware encryption models are becoming more popular, eg on the ESP32. Once you set the private key it is no longer accessible to software.

As pointed out by evgpbfhnr, I do avoid using environment variables and justify it (though with different reasoning than yours).

Your justification is the kind of thing I mention as out-of-scope (for my purposes!) in my conclusion:

> There are also many bases that I don’t cover and routes through which sufficiently-smart malware could easily still obtain the secrets I’m working with.

/proc/$pid/environ, /proc/$pid/mem and other such vectors (ptrace, bpftrace, equivalents on other platforms) are real, but:

- they're not vectors of _accidental_ leakage like dumping the full process environment to logs or shell history are

- they rely on privileged access existing at the time that I'm handling the secret, while logs or shell history can be obtained _in the future_

- they're not the kind of thing I expect broad-spectrum malware to go rooting for: the memory of all processes is a lot of data to classify/exfiltrate, and if I were a malware author I'd fear that that would be far too resource-intensive and thus conspicuous. Browser cookie storage, password manager databases, keylogging, and the like are much easier and more valuable pickings.

> This article does not mention that environment variables are also visible by process in /proc/*/environ (which has restrictive permissions, but is completely visible to root).

He's explicitly not using export, so they won't show up there. Plain variables are not in the environment.

(it's good to bring up this file as well as getting inherited by child processes though)

  • I believe that unexported shell variables will be visible in /proc/*/mem, so it would be prudent to overwrite then unset them as soon as reasonably possible in their usage.

    • mem, yes, definitely. I'm not sure how you can protect yourself from that (or root user using ptrace or equivalent debugging tool) though...

      Oh, memfd_secret?

             The memory areas backing the file created with memfd_secret(2) are visible only to the processes that  have  ac‐
             cess  to the file descriptor.  The memory region is removed from the kernel page tables and only the page tables
             of the processes holding the file descriptor map the corresponding physical memory.  (Thus, the pages in the re‐
             gion can't be accessed by the kernel itself, so that, for example, pointers to the region  can't  be  passed  to
             system calls.)

      2 replies →

  • I think that once root is the adversary, all bets are off. The simplest being /proc/*/mem or hooking a debugger up to the process and pausing it...