The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

SECURITY - Security aspects of the server, clients and workers.

Last update: 2004-08-23

This document deals with topics like how to prevent unauthorized access, denial of service attacks and related topics.

PROTECTION AGAINST EXPLOITS

One class of possible security problem are remote exploits against the server and/or client machines.

Possible exploit types

There are basically two types of remote exploits:

Invalid input executed as code

Certain input to the server process might be given to a shell or a client to be executed. For instance, the data rm -fR * would delete all files in the current directory including subdirectories, if executed by the shell.

Buffer overflows

Some input might not fit into pre-allocated, fixed-size buffers, thus overwriting other memory locations, notable the stack. This results in arbitray code to be executed.

Basic Countermeasures

The server process is basically a Perl script. This provides a very good protection against buffer overflows, since all storage in Perl is dynamically allocated and it is not possible to "overflow" a string, for instance.

The only possible problem with huge inputs would be that they could crash the server due to a "out of memory" problem. However, since the server runs in a loop catching exceptions, this might only affect one connection, not the entire server process.

To protect against malicius input, the server always runs in taint mode, meaning that all user input (as well as any other external data) is automatically tainted, and any data comming into contact with the tainted data is also tainted. Furthermore, tainted data cannot be executed as shell code or send to the shell as parameters, this is checked by Perl itself, not the server's Perl code.

A special filter filters out only good characters (typically 'a'..'z', 'A'..'Z' and '0'..'9'), thus effectively preventing tricks like ;rm -fR * from working.

Furthermore, all input is strictly checked. For instance, if two possible input string could be foo and bar, than we check that the input is really either foo or bar and deny anything else. If there was only a check for foo and treating anything else automatically as bar, we would allow arbitray input to be processed later on, which might cause unintended consequences.

Extended Countermeasures

While a Perl deamon running in tain mode offers a good protection, it is not foolproof. There might be some exploits that still work and execute arbitrary code. For instance, bugs in Perl itself, in third-party code or in our own code might expose holes that allow malicius input from the outside to crash the server (effectively a DOS), or even allow execution of arbitray code on it.

While this is a theoretically problem at the moment, since we are not aware of any exploits, however, pretending it does not exist will not protect us from exploits found in the future.

To counter future exploits and limit the damage they could do, we also do:

run as low-privileged user/group

The server does switch the process to a different user and group after the startup phase. Thus any exploit would only be executed with the premissions and rights of this special user and group, instead of root. This greatly limits the damage that can be done, and makes full exploits much harder (for a full root exploit, the exploit code not only needs to break out of the tainted Perl environment, but it also needs a local-root exploit as well).

chroot() to the server directory

Also, after the startup phase the server is changing the root dir via chroot() to it's own local directory. This means the server process can no longer access any files outside of this directory, since they just don't exist for it at all.

The exploit's damage is thus limited to the actual server directory itself (Or the exploit would also need to carry an additional way of breaking out of the chroot() environment, which might not even possible at all - since the usage of the chroot command under Perl is limited to the root user).

To strengthen the server even further, the normal security patches that randomize heap, stack and libc addresses (like PAX) should also be employed, together with keeping the kernel and software current.

CLIENT SECURITY

Just like the server should not trust the clients, the clients should not trust the server. This means that data from the server needs to be checked, limited, and validated before passed on to the worker. Otherwise somebody might either fake a server or hack the main server and then exploit all client machines by sending them malicius responses.

Additional settings

The client also knows the user, group and chroot settings from either the config file or on the command line.

After starting the client as root, the client will change the process to run under the given user and group. (It will also complain if it is supposed to run as root).

The chroot() functionality for the client does currently not work, due to the problem of auto-loading different libraries afterwards.

Enabling at least the user/group setting or running the client as a non-root user from start is highly recommended, since this limits the damage an potential exploit of the client or worker could do!

The client also limits the lengths of the data given to the worker, thus preventing potential buffer-overflows.

ACCESS CONTROL

The access to the server needs to be restricted so that only authorized machines and persons can administrate the server, view status pages, and that only authorized clients can work on the cluster.

Administration

For submitting changes to the server, the administrator needs to authenticate herself. She does this by filling in a username and password.

Currently username and password are transmitted in cleartext over the network.

Without the proper username and password, the change is denied.

New administrator accounts can be added by choosing the "Add User" form and filling it in. This form also needs an authentication from an administrator, which means it is not possible to enter the first administrator account via the HTTP interface.

To add the first user, follow these steps:

shut down the daemon

If the dicopd daemon is running, stop it.

run adduser.pl

Follow the instructions.

restart the daemon

Status pages

Requesting and reporting work and testcases

WORK INTEGRITY

Reasons for false data

False data can occur due to software bugs, hardware errors (for instance memory corruption or other data corruption due to (intermidiate) hardware failure, or malicius intent.

Especially when running untrusted clients (e.g. software on machine you do not have 100% control over) and displaying public statistics, the chances are high that someone will try to modify the client to send in results faster to get higher up in the stats. Basically this can be done by not doing any real work, just pretending it. Thus more chunks per time unit can be done, which results in better statistics for him, and wrong data for us.

Trusted vs. untrusted clients

An easy way to avoid malicius hampering is running only trusted clients, e.g. machines that are under our control. This is, however, not always possible and still does not guard against bugs or faults.

Guarding against errors and bugs

One step to make sure that a client cannot report results or data for other clients is to authenticate each client.

Hampering with the client

The client is public, and thus hampering with it is very easy. Nothing what the client reports should be trusted.

Currently, some things the client reports are taken with much verification, this needs changing.

Hampering with the worker

Verifying client results

A client may report wrong status codes for a chunk, either by error (software or hardware bugs) or by malicius intend.

There are two possible sources of false client results:

False positives

A false positive is a reported result in one chunk, where there was really no result or solution in that chunk, or the result was in that chunk, but at a different key.

These are easily to generate, a client just needs to send in a result for each chunk.

False positives are non-critical, since they can be verified very easily.

False negatives

A false negative is a chunk where there should have been a solution, but the client did not find it.

Since solutions occur to so seldom, these false negatives are actually hard to produce. If a client would send always a status of DONE, a false negative would only occur when there should have been a solution, which is almost never. However, false negatives are critical when they occur, since they would make us miss the solution, very probably requiring the entire job to be redone.

Verifying client solutions

This is quite easily, each chunk with a reported solution is handed to at least one second client, which are asked to verify the solution. Only if all of them agree on the solution, the result is accepted.

Verifying client non-solutions

The same method to verify SOLVED chunks can be used to verify DONE chunks, each chunk is handed out to multiple clients, which all need to verify the chunk. However, this is not enough.

Imagine that 10% of all clients are faking all chunks, simple returning DONE without doing any work at all.

If we get such a fake chunk (a false negative, e.g. a chunk which contains a result, but is given back as DONE, making us thinking it doesn't contain a result), and hand it to another client, the chances that the second client is also faking it's return result are very high. This means that we would never detect that the chunk was false and thus miss the result entirely.

Introducing chunk CRC

The chunk CRC is calculated by the worker, and should be based on plaintext data that depends on each key that is tried (not the key itself). This means it will be very hard to generate the right CRC (e.g. fake it) without going through all the actual work for each key. This is the entire purpose of the CRC.

With the CRC reported back to the server, we can spot clients that report false DONE chunks, by letting their work being verified by a different client.

If the second client is not also faking the CRC (if it is, the CRC can and will be the same fake value, since the bad clients can either communicate with each other, or just base the CRC on the public data of the chunk, like start and end), the second CRC will not match the first CRC. This way we know that one of the reported chunks was a fake.

We don't know which one, but we can mark both clients as suspicious, and if one of them is involved in another suspicious activity, we can shut it down by denying it further work.

AUTHOR

(c) Bundesamt fuer Sicherheit in der Informationstechnik 1998-2004

DiCoP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.

See the file LICENSE or http://www.bsi.bund.de/ for more information.