5

As a part of my system, I have many processes, each of them created through a script. One of the processes can be considered as a "Master Process" in the sense that this process communicates with the Server and gets all configuration and key related information.

Now, I have a requirement to the pass the configuration and key information from the "Master Process" to other processes. Currently, I am trying to write the configuration information to a file (one file for each of the other process) and the other processes read from that file designated for itself.

The problem now arises as I also have a key and I don't want that to be written to the file.

What is the most secure way to pass the key from the "Master Process" to other processes?

I have thought of the below so far:

  • Have a SSL/TLS protected socket communication (TCP) between other processes and master process. The problem with this approach is that, SSL/TLS is heavy and I cannot open a listening socket on the Master Process.
  • Use Pipes. But, I am not clear how I can secure pipes and also ensure that processes which are not intended to connect to Master Process and get the key, don't get it.
  • Shared-Memory - Same problem as above.

Please note that, these processes don't share a Parent-Child Process relationship.

Any pointers will be of great help!

Jay
  • 525
  • 6
  • 15
  • 1
    So... you want to authenticate the processes to the master process? Does the master process launch the slave processes? You could exchange a secret when launching the slave processes (using a secure exchange scheme) and then use that secret as authentication. However, you might be able to provide a pipe to the slave process upon launch such in a way that the OS makes sure that no other process can access that pipe. – mroman Dec 29 '17 at 12:36
  • 1
    Are you asking about mechanisms independent of the OS or are you asking about a specific OS? Do both processes have the same permissions or are they different? Are you really worried about attacks from processes with same or higher permissions since these might have ways to get to the secret inside the application already and thus don't need to attack the sharing? – Steffen Ullrich Dec 29 '17 at 13:11
  • Shared memory can only be shared by the processes that are intending to share it. There is no risk of anything else getting the memory. The secrets are not even buffered in by the kernel (like they are for pipes). But I have two questions. First, what OS is this for? And second, does your threat model include a malicious process impersonating the trusted process, or is authentication out of scope? – forest Dec 30 '17 at 04:09
  • @mroman, The Master Process doesn't launch the Slave Process. Master process invokes a script which in-turn launches the Slave Processes. Also, Master Process will be launching the Slave Process at different points in time depending on some commands from the server. I am curious to know, how can we share a secret to the slave process if the master process were indeed launching the slave process. – Jay Dec 30 '17 at 16:39
  • @SteffenUllrich, My software is supposed to run on Ubuntu, Windows and MacOS. Both the Master and Slave processes share the same permissions. – Jay Dec 30 '17 at 16:41
  • @forest, This is for Ubuntu, Windows and MacOS. To prevent a malicious process from impersonating a trusted process, I am using the said secret. That "secret" is supposed to be used for authentication. But, if the secret itself gets compromised, then the authentication is of no use. – Jay Dec 30 '17 at 16:45

4 Answers4

8

If your threat model includes "malicious processes running as the same user as the legitimate process that needs the key", you need to go back to the drawing board and redesign. It is not possible to protect against that. Processes within a single user session are not, and should not be expected to be, secure from one another.

The concern you express about pipes, for example, extends to any other kind of IPC mechanism. TLS sockets with mutual auth? Any process that can connect to the socket can also be impersonated by another process in the same user context, reading the same key data, and spoofing the legit process. Even if you could securely establish the IPC, that's no guarantee that the data would be secure. For example, some operating systems (Windows notably, but I think also some Unix-likes) allow any process running under a given use to debug any other process under the same user, so the malicious process could just read the secret right out of the legit process' address space.


OK, let's talk about scenarios where you don't assume that another process in the same user context as you is malicious. Maybe that's because you (re)designed the whole thing so that it runs under a special user context used only for the specific purpose of your software. Maybe that's because you're working on an embedded device where you control all the code that runs. Maybe it's just because you accepted that trying to defend against malicious code with the same privileges as you is hopeless and pointless (if the bad guys are executing code in your user context, it's already game over, man).

You didn't specify the OS that your software needs to run on. However, in general, there are a few decent choices here for secret that you don't ever want to commit to persistent storage.

On Unix-like systems:

  • Unix domain (local) sockets. Fast and fairly straightforward. Support bidirectional communication, if that matters. To be secure, you just have to create them in a location that is neither readable nor writable by any other user (something under the user profile is a popular choice). On the other hand, you said you can't host a listening socket on the Master (why not?) so this may not work.
  • A named pipe, also called a FIFO. Fast and straightforward, but unidirectional only (if you want bidirectional, you need to create a pair of pipes). As with the local socket, make sure the FIFO is created where no other user can access.

On Windows:

  • A named pipe. Unlike Unix named pipes, Windows pipes don't go in the standard file system; there's a special "named pipe file system" for them. This means you need to ensure you create the pipe with the right access control list (ACL). Once created, though, using the pipe is fast and simple.
  • A named memory mapping. The CreateFileMapping API can be used to create a memory mapping that is not backed by any normal file, but instead by the system paging file. While the pagefile is backed by persistent data and therefore could lead to the secret being stored on disk, that is a risk with any process; you can't guarantee that the secret won't ever be paged out of working memory unless your platform offers (and you use) some kind of kernel-secured buffer. Meanwhile, an attacker wouldn't know where to look for the secret in the pagefile, so you're probably safe. Named memory mappings, like named pipes, must be secure using an ACL that prevents processes running under other users from opening the mapping. Once both parties have opened the mapping, though, it's very fast.
  • Direct memory access (read, most likely) between processes. The client process simply reads the secret out of the parent's virtual address space. This requires a way to pass the relevant address to the other process, but it's OK if that address is exposed; other users can't access the process' memory even if they know where to look, because processes always have an ACL that prevents other users from reading their memory.
CBHacking
  • 40,303
  • 3
  • 74
  • 98
  • *nix also supports shmem/POSIX shared memory, SysV IPC, regular shared memory, ptrace-based and ptrace-like data sharing (`process_vm_readv`, etc), UNIX domain socket, and more. – forest Dec 30 '17 at 04:11
  • @CBHacking, Thanks for your reply. As I mentioned, the solution is needed for Unix, Windows and MacOS. Direct memory access seems to be a nice mechanism. But, can it be done for Unix and MacOS too? – Jay Dec 30 '17 at 16:51
  • @Jay: As @forest pointed out, Linux has the `process_vm_readv` function, which works like `ReadProcessMemory` on Windows. I'm sure Mac has something equivalent (though you should check the Mac-specific manual; it might not be exactly the same call). Do bear in mind that, with direct memory access, you need some way to get the address of the secret *out* of the parent process. However, since the address itself isn't super-sensitive, you could just write it to a temp file that the other processes read. – CBHacking Dec 31 '17 at 12:50
  • @forest I mentioned Unix/local sockets (which are coming to Win10! But not until the next release) but yes, there's a lot of IPC mechanisms I left out. I didn't know about `shmget` and friends (for shared memory that can be opened by unrelated processes and isn't a mapped file), thanks for the tip! Direct memory access may or may not work, though, for unrelated processes; some OSes don't allow two unrelated processes (even under the same user) to read/trace/debug each other. – CBHacking Dec 31 '17 at 12:54
  • 1
    Direct memory access restrictions are governed by regular ptrace restrictions, so unless the Yama LSM is installed, two users of identical privilege can trace each other and/or read/write memory directly. – forest Dec 31 '17 at 13:04
2

Where are the executables for both processes stored? Because if both are stored on the machine and you don't want to have to manually enter secrets on process launch then anyone that can read the executable would be able to falsify any authentication method. You may as well keep your current system but storing the config file in the same place with the same permissions (/ maybe lock down to only readable by the user running the processes).

If the executables are not stored on the machine then you could just encrypt the config file with a hard coded key inside of the executables (or read from a file also not stored on the machine at launch).

With SLS/TLS how do you know you are talking to the real server and not another process listening on that port? Usually you would use a certificate to authenticate - but as above if its stored on the machine anyone that can read it can impersonate the real server.

And you've already mentioned pipes and shared memory have the same issue.

Hector
  • 10,893
  • 3
  • 41
  • 44
  • Thanks for the reply. I did think about a hard coded key inside the executable, but I am not sure if that is a good idea, as those keys can never be changed and it is also possible for people with access to the executable to get hold of the key. Once the key is compromised, there is no way to update the key without updating the software. – Jay Dec 30 '17 at 16:54
  • @Jay - recompilation replaces the key. As said another alternative is read it in from file on launch from media removed from the machine after boot. Both involve changing a file required at boot so from a practical point of view there isnt a massive amount of difference. As said any authentication method needs to either require something to be input on process start or is going to be impersonated by anyone with access to the executable and able to run a process under the same user - so locking the executable permissions to only be readable by that user offers just as much protection. – Hector Dec 30 '17 at 18:28
2

You miss Un*x sockets:

  • The Master Process simply create one (or more) un*x socket, located in protected directories, with correct 'srw-rw----' attributes (all process are running under different user, but are member of same group).

  • The Master Process stay listenning on this socket (server)

  • All process, running on same host, with sufficient acces right (member of targeted group) could communicate with Master process by using already created socket (client).

  • Of course, Master process who create the socket have to use his own protocol and correctly sanitize sockets inputs!

Nota: Master Process could be member of many groups and open as many socket, one for each group, then consider difference from which socket is used for any request...

From there, as there are no network connection, you only need to correctly organize your users/groups configuration and care abount permissions on socket (and his path).

Using encryption over un*x socket is possible, but seem overkill...

But please, have a look at CBHacking's answer: You may have to go back to the drawing board and redesign...

Anyway, my meaning is:

That's the correct way for communicate between two process... and if this won't work under window, use BSD or Linux!

1

I think you can run "master process" as a debugger, and use it to create other processes as debuggee.Then you can send message between each other with debug event.So you can make sure no other processes steal your secret.

VictorV
  • 111
  • 2