18

Yes, the transfer to the script via arguments is visible through ps -ax, /proc/<pid>/cmdline etc., BUT if someone has already gained access to your account from the outside (e.g. by hacking your browser) he will have no trouble looking not only ps -ax, but also periodically intercept /proc/<pid>/fd/0 (once intercepted, second skipped, to be less suspicious).

But this is nothing, because if an intruder got access to your account, it will not be difficult for him to just run keylogger (to listen to x11 server) and intercept keystrokes.

I am currently writing a script that runs through sudo (root) and accepts sensitive data. When sending them directly (as arguments) to a script, I can hard restrict the characters used in the arguments with sudo (user ALL = (root) NOPASSWD: /bin/program [0-9][0-9a-z][0-9a-z]...) so that an attacker cannot use special character combinations to bypass the restriction and thus gain root access.

When getting data through the pipe (stdin), I will also of course filter data:

#!/bin/sh
pass=$(dd if=/dev/stdin bs=1 count=10 2>/dev/null | tr -cd [:alnum:])

, but I consider simple rules of restriction of arguments through sudo safer (also in the script itself there will be additional checking).

So is there a fundamental difference between passing through stdin or arguments?

NewLinux
  • 625
  • 3
  • 8
  • 1
    Maybe you should look at **environment variables** for example. You have more options than the two you've mentioned. Some IPC mechanisms are: sockets, named pipes, anonymous pipes, futex and more... As a bonus, Linux **namespaces** may also provide additional isolation for your processes. – Kate Jan 18 '22 at 13:17
  • 28
    _"if someone has already gained access to your account ..."_ - Right, but what about if an attacker has gained access to _a different user account_ on your machine? How do the various strategies compare then? – marcelm Jan 18 '22 at 14:48
  • 1
    "if someone has already gained access to your account" - Linux has a vulnerability that it also casually shares your command line arguments with all other accounts on the system. – Boann Jan 18 '22 at 20:05
  • 6
    I can break your `pass=$(...)` filter by placing a file named `:` in the CWD directory where `tr` runs. Remember to **always quote args** with meta characters. – Jens Jan 19 '22 at 07:59
  • @Jens, or you know, just a file named `a` would do. – ilkkachu Jan 19 '22 at 10:45
  • @ilkkachu Yes, with any of the symbols "[:alnum:]" – NewLinux Jan 19 '22 at 10:58
  • 3
    @ilkkachu Yes, but that would allow for a password of `aaa`, while the colon would result in an *empty* password (assuming only alphabetics on stdin). Empty passwords in certain contexts mean *no password required*, e.g. for classic Unix `passwd`. – Jens Jan 19 '22 at 11:01
  • @Jens, well, sure. But I don't think any of `a`, `aa`, `aaa` etc. would be much better anyway... I think in some contexts, the empty password might give an error, but a hit and miss between getting and error and going full open isn't really fun either. – ilkkachu Jan 19 '22 at 14:15
  • It seems a lot easier to arrange for one program to output encrypted data and the other to consume it, than to encrypt a command line while maintaining POSIX compliance. – Karl Knechtel Jan 19 '22 at 23:01
  • The bigger risk is that you're running part of this process as root. Why? What, exactly, are you doing that requires root access? Are you changing or setting some system-level parameter? Could you do the same in another way? Maybe if you explained what you're trying to do in more detail we could help you find a secure way to do it. – mikem Jan 20 '22 at 06:03
  • @mikem For example, storing an encrypted database under root (even if the user's account has been compromised, the database should not be accessible) and the user should have an interface for limited access to some data from the database. – NewLinux Jan 20 '22 at 06:50
  • @Kate : `ps axeww`. – Eric Towers Jan 20 '22 at 15:32
  • If the goal is to simply separate the database from the users account, it would be better to have another account own the database. root should not be used for this. granting root access, even with sudo, has inherent risks, whereas using sudo to grant access to another non-privileged account is much less risky. Also, by having the database owned by another "functional/service" account could allow options of access using file permissions and groups without having to elevate privilege at all. Maybe outside of the scope here, but something to consider. Never use root for things like this! – mikem Jan 20 '22 at 16:59
  • There is a vast difference between a hacker having gained access to a system as a normal user (different from you) and as root. In the latter case, the only cure if you want to be sure is rebuilding from scratch. – Thorbjørn Ravn Andersen Jan 20 '22 at 18:44
  • @mikem I prefer to run the script as sudo (as root) for isolation purposes. A trivial example, when creating, for example, a new user in Debian, any user by default has access to another user's home folder. Yes, this is easy to fix by reassigning permissions. But I'm not sure if that's where the overlapping of user rights ends, maybe it happens somewhere at the system level as well. But the user will definitely not get into root. And since the script will be run as root, I make it as simple as possible, small as possible considering the features of the sh shell (variables in quotes, etc.). – NewLinux Jan 20 '22 at 18:59
  • @mikem I did think about creating a separate account specifically for the database (this removes a lot of problems with possible elevation of rights), but I am not entirely sure that the separation of rights at the level of ordinary (not root) users really FULLY shares rights and that my database on some system queries will not be able to compromise. – NewLinux Jan 20 '22 at 19:07
  • 2
    root offers no separation of rights... just the opposite. With root, all separation is removed and all file permissions are (basically) ignored. root is the worst case if separation is your goal. Regular users are separate from each other by their very nature. It's much easier to fix the permissions on a home directory and change the users umask so future files will be locked-down as well than it would be to clean up a mess because the wrong user ran the wrong sudo command with the wrong options as root! :-) You lose no security or functionality by running as a non-root user. – mikem Jan 20 '22 at 23:20
  • 1
    -1 because the question does not seem to match the title, and moreover OP does not even seem interested in asking a question, just setting up for an argument. – R.. GitHub STOP HELPING ICE Jan 21 '22 at 01:56
  • @R..GitHubSTOPHELPINGICE Once again I wish you good luck. https://security.stackexchange.com/questions/258911/is-it-really-safe-to-pass-sensitive-data-to-another-script-via-stdin-compared-t#comment534946_258914 You can add more minuses if it makes you feel better. – NewLinux Jan 21 '22 at 05:01

5 Answers5

61

/proc/<pid>/fd/0 can only be read by the process owner and root. /proc/<pid>/cmdline can be read by all users.

  • Right, but if there are only 2 users (root and user) on the system? System users (nobody, etc.) do not count. – NewLinux Jan 18 '22 at 10:39
  • 11
    @NewLinux If no one else is on your system, does it matter? –  Jan 18 '22 at 14:36
  • 54
    @NewLinux: Why do system users not count? If someone exploits a vulnerability in a daemon that's running as `nobody`, and takes it over, then they can see anything that the `nobody` user can see. – psmears Jan 18 '22 at 16:08
  • 9
    Linux has the the [`hidepid` mount option for `proc`](https://man7.org/linux/man-pages/man5/proc.5.html) which can be used to hide processes from other users. It can be used to prevent accidental leaks (and the associated privacy invasion on a multi-user system). I would still avoid passing anything sensitive on the command line, since `hidepid` won't be enabled on all systems, and in any case, one can usually use the environment instead of the command line anyway. `/proc//environ` is only readable by the same user. – ilkkachu Jan 18 '22 at 19:33
  • 4
    @NewLinux: Even if there are no other users on *your* system (and even if none of the system accounts are compromised) can you guarantee that the same is true of *every* system the software might be used on? Unix (and Linux) is fundamentally designed to be a multi-user OS, after all. Having several users that do not fully trust each other on one system is not some weird edge case, it's a perfectly normal and supported way to run things. – Ilmari Karonen Jan 19 '22 at 18:55
  • Also note that the cmdline is stored for lifetime of the process but fd0 content is disposed as soon as it was processed. – vhu Jan 20 '22 at 05:50
  • /proc/pid/fd/0 can be also a soft link to a file, in this case the permissions of the file determine the read privileges. – peterh Jan 20 '22 at 11:24
  • What if /proc is mounted with option hidepid=2? – NewLinux Jan 27 '22 at 04:57
  • @NewLinux See ilkkachu's comment, but especially keep in mind that you can't rely on that always being the case, so it's better to write programs that are secure even if hidepid=0. – Joseph Sible-Reinstate Monica Jan 27 '22 at 06:46
43

In addition to the different permissions needed for a process' command line vs its pipes, consider:

Command lines often show up in audit logs, shell history, or similar; data passed to stdin does not.

Command lines are visible at any time from when the program starts to when it stops (which can be a very long time) even if nothing logs the command line or holds a reference to the process. Data in stdin (and other pipes) is ephemeral; if you want to intercept it, you need to do so at the right time (after writing and before reading).

CBHacking
  • 40,303
  • 3
  • 74
  • 98
  • That's right, but if an intruder has access to an account (e.g. by exploiting a vulnerability in the browser), he can already record e.g. every keystroke on the keyboard (etc.) and he does not need root privileges. In other words, the input data will be compromised before it even goes down the pipe. – NewLinux Jan 18 '22 at 10:44
  • 3
    @NewLinux Only if it’s input by hand, and the same issue applies to passing via the command-line. – Austin Hemmelgarn Jan 18 '22 at 13:36
  • 18
    @NewLinux You are assuming access to an account, but that's not the only attack vector. For example, users may back up their home directory to github (or something) for easy access to their config files and may fail to exclude `.bash_history`. There might also be an LFI in a webserver they run. That will likely not have full access to the system, but may have access to `.bash_history`. – tim Jan 18 '22 at 16:27
  • @tim Regarding LFI or other file read vulnerabilities: ... may have access to `.bash_history` or, as Joseph's answer points out, to `/proc//cmdline` for arbitrary values – CBHacking Jan 19 '22 at 01:54
  • 1
    @NewLinux: That is not true. If an intruder does not have access to *your account* or root, they cannot access keyboard or any other hardware (unless you explicitly set permissions wrong on some device nodes). It sounds like you really do not understand the access control model. – R.. GitHub STOP HELPING ICE Jan 20 '22 at 15:27
  • @R..GitHubSTOPHELPINGICE That's what my post said: `but if an intruder has access to an account`. That is, if I am under the `user` account, an intruder with access to it can easily read the keyboard – NewLinux Jan 20 '22 at 18:46
  • 2
    @NewLinux: If they have access to **your** account, you are already completely pwned. Regardless of how you pass your data. They can read absolutely anything from any of your files or from memory contents of any of your processes. So talking about securing such data under that assumption is meaningless. You already lost. – R.. GitHub STOP HELPING ICE Jan 20 '22 at 21:17
  • 2
    The actual meaningful situation to talk about, which is what everyone is trying to get you to understand, is the one where you are not pwned but some low-privilege process on the same machine is. – R.. GitHub STOP HELPING ICE Jan 20 '22 at 21:18
19

The important part is not about an attacker compromising exactly your account.

Any account on a typical Linux system can run ps and see what others are running.

Even if your particular machine is personal and has a single (human) user, a typical modern Linux system has ~25 accounts created for internal use (just look in your /etc/passwd).

They exist for a reason - to limit the damage if some subsystem is compromised.

By exposing important information to these accounts, you effectively bypass this mechanism.

luk2302
  • 103
  • 3
fraxinus
  • 3,425
  • 5
  • 20
9

I think the title to your question and the body of your question are contradicting each other a bit and I think that may be leading to some of the confusion with the other correct answers.

Your title says "Is it really safe" but in the body of your request you're comparing passing data via stdin vs command line arguments. When you compare two things the result of the comparison only speaks to the comparison and never allows you to make an absolute claim outside of the comparison itself. For example: The number 10 is more than the number 5. So 10 is "bigger" than 5. But is 10 a "big" number when there are obviously much bigger numbers? I can't justify saying "10 is a big number" just because it's bigger than some other number.

So: "is it safe?" is one question, but your question is really implying: "Is it safer?" with an emphasis on the extra "r" on "safer".

Just like it doesn't make sense to say that 10 is a big number when there are always bigger numbers: Nothing in information security is ever 100% "safe". As you point out there are attack vectors that could allow an attacker to get at data passed via stdin. The point is that there are FAR fewer attack vectors that allow an attacker to get access to data passed via stdin. AND those vectors are more difficult to achieve.

As the other answers point out: Data passed via command line arguments are visible for a long time. They are very often logged into log files as well as history files like .bash_history. These log files and history files can get backed up to the cloud, copied to other folders, disks, etc. This data is also visible to other system accounts which could potentially be compromised. In other words: An attacker has a lot of available attack vectors to gain access to command line argument data. And because of how long this data remains around for viewing, the attacker also has a larger window of time for which he can utilize to execute these attacks and still access the command line data.

With stdin there are not only fewer vectors: But the attacker also has a limited time window to execute a successful attack here. He has to compromise your account specifically, or root. Both of which are more difficult than compromising one of the system accounts. Then assuming he pulls off a successful attack to compromise your account or root: Now he can only see data being passed to stdin in real time. He can't go back and look in bash_history or log files to see data from stdin.

Between the lower number of attack vectors and the timing issue: It's obvious that passing data via stdin is SAFER. And that's what matters: It's not possible for something to be 100% foolproof/safe. Everything in security is about choosing the safest possible option which minimizes the number of attack vectors or exposed "surface area" of points that can potentially be attacked and lead to a system becoming compromised.

So: TL;DR: No, stdin is not 100% safe as nothing is. But it's far SAFER than command line arguments which is why it's preferred over using command line arguments to pass sensitive data like passwords.

irwinr
  • 91
  • 2
4

No. Nothing you do with a computer is 100% safe, and nothing in life is 100% safe. That's the wrong way to look at it. The question you should be asking is, which option offers more safety? When planning how to secure your system, you want to follow a defense in depth model: At every point while designing or configuring your system, you want to ask the question, which choice would improve my security?

Is passing sensitive data via stdin safer than passing it through the command line? Yes, for all the reasons CBHacking mentioned: stdin is ephemeral and requires greater privilege escalation to access.

Can someone who has gained access to the root account (or the account running the script) via privilege escalation intercept the data sent to stdin?

Absolutely. However, the command line arguments are accessible to any user account on your system for as long as the program is running, meaning that an attacker can choose which account they want to target, and has more opportunities to witness the sensitive data on the system.

If you give the attacker a choice, you should assume they will attack the most vulnerable account available, which will probably be one that you never thought to protect.

Using stdin to pass the data is not completely secure, and so that isn't the last step you should take to secure your system, if you're concerned about it. However, it is more safe than passing sensitive data on the command line.

jpaugh
  • 161
  • 1
  • 8