UNIX sockets: Is it possible to spoof getsockopt() SO_PEERCRED? - c

Is there a (compatible) way to spoof (as root) the unix socket (file system sockets) peer credentials which can be obtained by getsockopt(), option SO_PEERCRED?
Background:
I need to connect to a server application (which I cannot modify) which checks the UID of the process which connects to it via SO_PEERCRED. I'd like to spoof the information in order to be able to connect to the application as root, too.
UPDATE
To clarify the question:
I'm searching for a non-invasive way that the server sees a specific peer UID/GID.
Solutions are discouraged which need to alter the kernel (or take the use of kernel modules) or which changes the server process or its loading/linking process in any way (LD_PRELOAD, system call interceptions etc.).
Basically, the solution should work when running on any linux (or unix in general) server without any special requirements. The server process might already be running.

You're on the right lines. A root process has the privileges to spoof things like this, the problem is just that SO_PEERCRED provides no mechanism or API for a process to specify what identity should be to presented to the peer.
Two things you can do:
Temporarily drop root (setreuid(desired,-1)) when you make the connect call. A unix-domain connection is stamped with the credentials of the peer at the time the process called connect (and listen going the other way). SO_PEERCRED does not tell you the credentials of the peer at the current moment. Then you can resume root.
Better, use another API. The message-passing API lets a process pick what identify to present to a peer. Call sendmsg with a struct cmsg that contains the credentials you want to send. The kernel will ignore the credentials specified by an unprivileged user and always make sure the other side sees the actual identity, but a privileged process can pretend to be anyone else. This is a better match for your needs, because dropping and regaining root is a perilous activity and in this case unnecessary. Google for "SCM_CREDENTIALS" (or "man -K" for it on your system) to get code samples.

No. The reason is that the mechanism that provides the UID and GID of the peer is internal to the kernel, and you can't spoof the kernel! The kernel uses the PID of the peer to deduce the effective credentials of the peer. This happens when one side does a connect on the socket. See the call to copy_peercred() from unix_stream_connect() in net/unix/af_unix.c. There isn't any way that the peer can change the data it sends or the socket that will convince the kernel that the peer's PID isn't what it is. This is different from AF_INET sockets where the kernel has no internal knowledge of the peer's process and can only see the data in the IP packet headers that the peer sends.
The only thing that you can do to get this effect is to set the effective UID of the peer process to root or whatever UID/GID you want, and for that you need either root password or sudo privileges.

Related

Linux Raw Socket Permissions Issue

I'm creating a raw ethernet socket in a C application, e.g.
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
and its returning -1 indicating an error
I'm pretty sure its a permissions issue - You can only open a raw socket if you have a UID of 0 (root) or have the CAP_NET_RAW capability
I don't think running the application as root is reasonable, therefore my question is how can I 'add' the CAP_NET_RAW capability permission to my user account?
From http://manpages.ubuntu.com/manpages/zesty/en/man7/packet.7.html
In order to create a packet socket, a process must have the CAP_NET_RAW
capability in the user namespace that governs its network namespace.
But how does one achieve that end?
You set the capabilities on the executable that needs that capability, not a user account. The syntax is
setcap cap_net_raw,cap_net_admin=eip ./your_exeutable
(Note, you need to run setcap as root, so use e.g. sudo setcap ... Also make sure there are no space characters in cap_net_raw,cap_net_admin=eip
Being able to read all network packets is considered a severe security risk, that is why this needs a privileged account.
You can make the application "suid root" to elevate your own rights when starting this application as a "normal" user. But that is a security risk as well and needs a bit of thorough thinking when designing the application (it should at least give up the higher privilege as soon as it doesn't need it any more - i.e. after having opened the raw socket).
You cannot add the CAP_NET_RAW permission to your account, because capabilities on Linux do not follow users. They follow executables.
To make this work, you need to add the CAP_NET_RAW capability to your compiled executable. See the setcap command in order to see how to do that.

upgrade server executable without losing user's connections

I need to develop a mechanism to upgrade a running daemon in production environment to a new version without losing client's (TCP) connections. Something similar to what nginx does when you upgrade it to a new version. I need this for bug removal or to release minor version changes, which may be once a day. The daemon is developed in C for Linux platform.
The process for the upgrade would be like this:
The new_daemon would be ran from the command line specifying the process id of the old_daemon
The new_daemon would connect via socket to the old daemon to send/receive data and mesages.
The new_daemon would send the old_daemon a message to stop listening on the PORT which is used to receive client's connections. After confirming the detention of the listening service, the new_daemon would start listening on PORT
The new_daemon would send the message to old_daemon to send currently open file descriptors of the user's connections. Using the system call sendmsg() the old_daemon would pass the new_daemon all resources it has allocated with the kernel, not only the connections, but also all open files.
The new_daemon would send the message to old_daemon to pass all global memory variables and the old_daemon would send it over the socket connection between both processes.
This process is very complex, so I would like to ask if someone can suggest a better process or maybe there is some methodology to do this easily? The goal is to have the least downtime during the upgrade process.
TIA
Another alternative is to force the old_daemon to fork()/exec() the new_daemon and immediately stop accepting. The new_daemon would inherit the listening socket, existing connections, and open files (unless they are fcntl'd to FD_CLOEXEC) automagically.
That said, I don't think there is a clean way to hand over incomplete jobs (as I understand steps 4 and 5 try to accomplish). If possible, let the old_daemon complete them.
One alternative is to write most of your demon as a shared library and use dlopen to link the new functions into the running process. This means some parts can't be changed and you might have concurrency issues but it removes the need for IPC.

How to restrict write access to a Linux directory by process attributes?

We've got a situation where it would be advantageous to limit write access to a logging directory to a specific subset of user processes. These particular processes (say, for example, telnet and the like) have been modified by us to generate a logging record whenever a significant user action takes place (like a remote connection, etc). What we do not want is for the user to manually create these records by copying and editing existing logging records.
syslog comes close but still allows the user to generate spurious records, SELinux seems plausible but has a terrible reputation of being an unmanageable beast.
Any insight is appreciated.
Run a local logging daemon as root. Have it listen on an Unix domain socket (typically /var/run/my-logger.socket or similar).
Write a simple logging library, where event messages are sent to the locally running daemon via the Unix domain socket. With each event, also send the process credentials via an ancillary message. See man 7 unix for details.
When the local logging daemon receives a message, it checks for the ancillary message, and if none, discards the message. The uid and gid of the credentials tell exactly who is running the process that has sent the logging request; these are verified by the kernel itself, so they cannot be spoofed (unless you have root privileges).
Here comes the clever bit: the daemon also checks the PID in the credentials, and based on its value, /proc/PID/exe. It is a symlink to the actual process binary being executed by the process that send the message, something the user cannot fake. To be able to fake a message, they'd have to overwrite the actual binaries with their own, and that should require root privileges.
(There is a possible race condition: a user may craft a special program that does the same, and immediately exec()s a binary they know to be allowed. To avoid that race, you may need to have the daemon respond after checking the credentials, and the logging client send another message (with credentials), so the daemon can verify the credentials are still the same, and the /proc/PID/exe symlink has not changed. I would personally use this to check the message veracity (by the logger asking for confirmation for the event, with a random cookie, and have the requester respond with both the checksum and the cookie whether the event checksum is correct. Including the random cookie should make it impossible to stuff the confirmation in the socket queue before exec().)
With the pid you can do also further checks. For example, you can trace the process parentage to see how the human user has connected by tracking parents till you detect a login via ssh or console. It's a bit tedious, since you'll need to parse /proc/PID/stat or /proc/PID/status files, and nonportable. OSX and BSDs have a sysctl call you can use to find out the parent process ID, so you can make it portable by writing a platform-specific parent_process_of(pid_t pid) function.
This approach will make sure your logging daemon knows exactly 1) which executable the logging request came from, and 2) which user (and how connected, if you do the process tracing) ran the command.
As the local logging daemon is running as root, it can log the events to file(s) in a root-only directory, and/or forward the messages to a remote machine.
Obviously, this is not exactly lightweight, but assuming you have less than a dozen events per second, the logging overhead should be completely neglible.
Generally there's two ways of doing this. One, run these processes as root and write protect the directory (mentioned mainly for historical purposes). Then no one but root can write there. The second, and more secure is to run them as another user (not root) and give that user, but no one else, write access to the log directory.
The approach we went with was to use a setuid binary to allow write access to the logging directory, the binary was executable by all users but would only allow a log record to be written if the parent process path as defined by /proc/$PPID/exe matched the subset of modified binary paths we placed on the system.

Bind a web server to port 80 without being root

I've written my own web server in C. How can I bind it to port 80 without being root so that the security is not being compromised (buffer overflows etc.)?
Should I simply forward any traffic from another "stable" server that runs on port 80?
Using a forward proxy is indeed the easiest and most recommended solution. It also has the advantage of filtering horribly invalid requests before they even reach your self-written server.
In case your application uses the user's ip address for something remember to retrieve it from whatever header your webserver uses (X-Client-IP etc.). However, only do so for requests that really come from your webserver, otherwise users can spoof their IP. You can do so by checking if the request came from your IP and only check the header in this case or simply make your application bind to localhost.
Another solution would be granting the program the CAP_NET_BIND_SERVICE capability. This requires root to use setcap cap_net_bind_service=ep /path/to/the/executable - since the flag is stored in a filesystem attribute, it will be lost when copying the file to another system or recompiling the application.
Of course you could also make your program setuid root and then switch to an unprivileged user right after calling bind(). However, depending on how your program works and what it does this might not be a good idea - for example, if it needs to close and reopen the listening socket for some reason it would require a full restart of the process.
An alternative to calling bind() as root, then dropping privileges, is to have a root process that creates the socket and binds it, and then passes the listening socket to the unprivileged process over a UNIX-domain socket connection using a SCM_RIGHTS message.
if you want to bind your server to port 80 you must do that as root and afterwards drop the privileges.
bind(sockfd, addr, addrlen);
/* process is running as root, drop privileges after bind*/
if (setgid(groupid) != 0)
errx(1, "setgid: Unable to drop group privileges: %s", strerror(errno));
if (setuid(userid) != 0)
errx(1, "setuid: Unable to drop user privileges: %S", strerror(errno));
How can I bind it to port 80 without being root so that the security is not being compromised (buffer overflows etc.)
not running as root does not make your system more secure it just adds another layer to exploit.
So instead of thinking about how not to run as root, please ensure that you do not use any known-insecure functions like strcpy(), sprintf(), etc. but instead use strncpy(), snprintf(), etc.
Well as you know all ports under 1024 in Unix require root privileges to open.
On a Unix system you do not want as few applications as possible running with root privileges.
It is and will always be a big safety risk.
An alternative is to use iptables to redirect the port 80 traffic to a more harmless port like 8080. Here is a description on how to set it up.
Iptables is not the easiest tool to setup, but once you have mastered it, it is very useful and powerful (and secure).
I worked on this problem for quite some time and came to the conclusion that systemd + iptables is the solution, and not Capabilities, as elaborated in great detail here.

Detect whether a socket program is connecting to itself

How, in C, can I detect whether a program is connecting to itself.
For example, I've set up a listener on port 1234, then I set up another socket to connect to an arbitrary address on port 1234. I want to detect whether I'm connecting to my own program. Is there any way?
Thanks,
Dave
Linux provides tools that I think can solve this problem. If the connection is to the same machine, you can run
fuser -n tcp <port-number>
and get back a list of processes listening to that port. You can then look in /proc and found out if there is a process with a pid not your own which is running the same binary you are. A bit of chewing gum and baling wire will help keep the whole contraption together.
I don't think you can easily ask questions about a process on another machine.
One of the parameters to the accept() function is a pointer to a struct sockaddr.
When you call accept() on the server side it will fill in the address of the remote machine connecting to your server socket.
If that address matches the address of any of the interfaces on that machine then that indicates that the client is on the same machine as the server.
You could send a sequence of magic packets upon connection, which is calculated in a deterministic way. The trick is how to do this in a way that sender and receiver will always calculate the same packet contents if they are from the same instance of the program. A little more information on what your program is would be helpful here, but most likely you can do some sort of hash on a bunch of program state and come up with something fairly unique to that instance of the program.
I assume you mean not just the same program, but the same instance of it running on the same machine.
Do you care about the case where you're connecting back to yourself via the network (perhaps you have two network cards, or a port-forwarding router, or some unusual routing out on the internet somewhere)?
If not, you could check whether the arbitrary address resolves to loopback (127.0.0.1), or any of the other IP addresses you know are you. I'm not a networking expert, so I may have missed some possibilities.
If you do care about that "indirect loopback" case, do some handshaking including a randomly-generated number which the two endpoints share via memory. I don't know whether there are security concerns in your situation: if so bear in mind that this is almost certainly subject to MITM unless you also secure the connection.

Resources