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?

19
  • 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 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 at 14:48
  • 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 at 7:59
  • 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 at 11:01
  • 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 at 23:20

5 Answers 5

62

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

9
  • Right, but if there are only 2 users (root and user) on the system? System users (nobody, etc.) do not count.
    – NewLinux
    Jan 18 at 10:39
  • 11
    @NewLinux If no one else is on your system, does it matter?
    – MechMK1
    Jan 18 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 at 16:08
  • 9
    Linux has the the hidepid mount option for proc 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/<pid>/environ is only readable by the same user.
    – ilkkachu
    Jan 18 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. Jan 19 at 18:55
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).

8
  • 3
    @NewLinux Only if it’s input by hand, and the same issue applies to passing via the command-line. Jan 18 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 at 16:27
  • 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. Jan 20 at 15:27
  • 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. Jan 20 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. Jan 20 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.

1
  • 1
    In the old days many system daemons ran as root, including sendmail which listened to port 25 making it very interesting to break. Jan 20 at 18:46
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.

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.