You need to have a quite current version of openssl installed. Then, just
$ make
for Linux, and
$ make -f Makefile.bsd
for BSD etc. For embedded systems please see at the end of this document. crash was successfully tested on Linux (openSUSE 10.3, 11.1, 12.3, 13.1), FreeBSD 7.2, OpenSolaris and OSX 10.8. It probably runs on a lot of other Linux and BSD's but I was not able to test it there yet.
To generate server and authentication keys:
$ make keys
or see further instructions in this document. If you want to use ephemeral keying (aka PFS), invoke
$ ./newdh
before make
in order to generate DH parameters before the build.
crash does not need any config or option files to run. Its easy and straight forward to use. Anything can be enabled/disabled by runtime switches:
stealth@linux ~> ./crashd -h
./crashd: invalid option -- h
Usage: ./crashd [-U] [-q] [-a] [-6] [-w] [-H host] [-p port] [-A authorized keys]
[-k server key-file] [-c server X509 certificate]
[-t trigger-file] [-m trigger message] [-e] [-g good IPs]
-a -- always login (if authenticated), even with a /bin/false default shell
-U -- run as user (e.g. turn off setuid() calls) if invoked as such
-e -- extract key and certfile from the binary itself (no -k/-c needed)
-q -- quiet mode, turns off logging and utmp entries
-6 -- use IPv6 rather than IPv4
-w -- wrap around PID's so crashd appears in system PID space
-H -- host/IP to connect to; if omitted it uses passive connect (default)
-p -- port to connect/listen to; default is 2222
-P -- local port used in active connects (default is no bind)
-g -- file containing list of good IP/IP6's in D/DoS case (default off)
-A -- authorized-key files for users if starts with '/'; subdir in users ~
containing authorized_keys file otherwise; 'self' means to use
blob-extraction (see -e); default is .crash
-k -- servers key file; default is ./serverkey.pem
-c -- X509 certificate-file that belongs to serverkey (-k); default is ./pubkey.x509
-t -- watch a triggerfile for certain message (-m) before connect/listen
-m -- wait with connect/listen until message in file (-t) is seen
Most of it is pretty self-explaining. crashd can run as user. -U
makes
it skipping apropriate setuid() calls, effectively being able to run as user.
It only accepts logins to that user then by checking login name's UID against
current EUID.
Both, crashc and crashd can use active and passive connect. Whenever
a host-argument -H
is given, it uses active connect to this host
and the belonging port -p
. If -H
is given, it also accepts
-P
which specifies the local port it has to bind to before
doing active connect.
If -w
is used it forks itself as [nfsd] and tries to wrap around its
PID to be somewhere around the system daemons. This can take a while!
The easiest way is to just
$ make keys
But you can also do it by hand. To generate a X509 certificate containing the server key:
$ umask 066
$ openssl genrsa -out serverkey.pem 4096
$ openssl req -new -x509 -nodes -sha1 -key serverkey.pem -out pubkey.x509
To extract the public key in a form crashc can use it as a hostkey for comparison:
$ openssl x509 -in pubkey.x509 -pubkey -noout > HK_127.0.0.1
So you have HK_127.0.0.1
as the known-hosts keyfile for this host.
As an alternative, you can use crashc with -v
upon connect to
extract the pubkey. But note that this might already be a key presented to
you during an attack. So only do that if you know that the connection is
not tampered with (e.g. single user on localhost).
The values you enter for Country-Name, Email, CN etc. do not matter since crashc is not validating the X509. Rather it compares the public key it obtained from the server with the key it has in its local key-store belonging to that server (similar to SSH). That way, crashc cannot fall into the common X509 traps like a lot of web browsers do. The server key is not encrypted since crashd is usually started via init scripts. Rather, the key file must have proper permissions so only apropriate users can read it (mode 0600). You can, if you like, also encrypt the server key but then you have to enter a passphrase whenever crashd is started.
To generate a public/private RSA keypair for your authentication:
$ openssl genrsa -out privkey.pem -aes256 4096
$ openssl rsa -in privkey.pem -pubout -out pubkey.pem
Copy pubkey.pem
to ~/.crash/authorized_keys
on the remote box, and
use privkey.pem
for the crashc -i
argument.
Auth-Key sizes larger than 7500 bit must not be used; the tokens do not fit into the auth handshake otherwise.
crashc is using the .crash/
subdir by default to check for
already seen server keys. If you connect to a host via -H $host -p $port
then a keyfile of form .crash/HK_$host:$port
is looked up unless
you specify a path to a known keyfile.
crashd automatically detects whether it has been invoked as a CGI by
a webserver by checking $QUERY_STRING environment variable. It parses
and converts the query-string into arguments it understands. It
does not translate %2F etc characters! They should not be needed,
since spaces, '(' and other weird characters do not make sense when
calling crashd. Arguments that dont have a parameter such as -U
have to be given =1
argument to enable it, such as in:
http://127.0.0.1/cgi-bin/crashd?-K=/path/to/serverkey.pem& \
-C=/path/to/pubkey.x509&-p=1234&-A=/tmp/.crash/authorized_keys&-U=1&-a=1
which invokes crashd on the host 127.0.0.1 as user (probably "wwwrun" or whatever
the webserver is running as).
For pentesting or embedded/emergency systems, crashd has the -e
option.
If -e
is used, it extracts the server key-file and the X509 certificate
from the ELF binary file, which have to be appended first:
$ cat serverkey.pem>>crashd
$ cat pubkey.x509>>crashd
If you give -A self
instead of a valid authentication directory or file,
it also extracts the user-key used for authentication from its binary.
It has to be appended in the same manner as above. This is useful in pentests
where you cannot upload arbitrary amount of files or do not know the
exact pathname of the upload storage:
$ curl 'http://127.0.0.1/cgi-bin/crashd?-A=self&-U=1&-e=1&-a=1'
-a
is needed since most likely the wwwrun user has a /bin/false shell,
which -a
ignores.
crashd is using mkstemp() to store the key files temporarily, with
mode 0444 (world readable!) since it needs to access authentication
files as user. So be warned that, if you have users, they may read
the private key used during SSL handshake. After all, its just an
emergency mode!!! Stripping the crashd binary is not possible after
appending the keys, or they will get lost.
Back-connect etc. also work in CGI mode as well.
If using that, client should use -K
switch to tell client which key to use
to authenticate the server.
In Germany, these devices are quite common and support open build
environment/SDK since the firmware is based on Linux and available
in source. Download/unpack the SDK/tarball and the MIPS toolchain. I assume you
are familar with building router images for these devices. The openssl
package for the speedport W-500V I tested has version 0.9.7 and I had
to build it by hand before, so the references to the libssl.a
inside crash Makefile are valid. On the system I tested (500V)
I had to make it static, since dynamic openssl library requires libdl
which was not on the device. Building a firmware image often
calls strip on the user binaries, so take care it doesnt
strip off the embedded keys if using -e
.
Then, inside userapps/opensource/
directory, unpack the crash tarball,
edit the Makefile
to match "true" at the first ifeq() and then you are able
to just "make crashd" to build crashd for the DSL router.
You can now put it into the firmware image, make it loaded at boot and you are able to admin your DSL box from remote via full protected crypto shell and without stupid web interface.
Here's how I connect to a 500V DSL modem running crashd inside:
stealth@linux ~> ./crashc -l root -H 192.168.2.1 -K .crash/HK_127.0.0.1\:2222 -v \
-i privkey.pem -c '/bin/sh -i'
crash: starting crypted administration shell
crash: connecting to 192.168.2.1:2222 ...
Enter PEM pass phrase:
crash:{
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4PKEDfrj1v1RlK307j1o
JX9aUuadp3KjGqs2gpoxYTuYf8oBh+1qhwbsH5wC1oQ4HerlIAfLFfUL0+yjy1BO
jNW/4sCo3QSxByRC9DORmfADrxJYkWjyC+cgdXCRaudYBLsz4oIDbg6B8Gtzma8c
ifFPUuSfEoLMRlQOSBIr15WzjS9/wIJfU+D0maJAFRySvVhcRQEbQZ5uuhLnmf4R
zEEiVV+HU79AfhuaKjs1gnTCZwj/dUmsD2zNjHuU6bZpjiQlQdkXLKe2wTvvYFQL
pbmx/XEapoW+tes9pbGgkFIs0jQLz/xYB07luUy46teVAVyB70R7l/WDyFpocPwW
seLNINDUKTvN6vo4UJD9tg1xhClim+P8Jnkyh5X5MqSdXwYC4N/FQsGs223jtxY2
XvQNPBR06d8HJu66GCDSTy7jKKARQ3c3Odq87JDOquUntR1pg26Dj3lOHWVQpuof
7jZ6vLyivpnh4JcdBgGTkzC+Ua0VE1tlokl58+FjhkIbeijD6FK+xcUNaylRo9YM
TrHjBnCi9FIb85WfBo1pj+basKAM85+BkFX3sLC+HR62CL1qJKue7qDBMJbK4INx
ZvoDpdJyBRZXLx+lGisasT3zgNDjJAjSWYn5bY1FfTMBZbvhZyN2/5Uxe85VicUV
8NS0w2TCghjgA0B+hiln1mMCAwEAAQ==
-----END PUBLIC KEY-----
crash:}
Using fallback suid method
Using fallback suid method
BusyBox v1.00 (2008.06.03-09:17+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.
# ps aux
[...]
206 root 1712 S httpd
210 root 232 S smdog
520 root 1160 S /bin/crashd -A /var/pubkey.pem
546 root 1464 S /bin/crashd -A /var/pubkey.pem
561 root 352 S /bin/sh -c /bin/sh -i
562 root 396 S /bin/sh -i
715 root 340 R ps aux
#
Keep in mind that on embedded systems, UNIX98 pty's are often not available and there are only a limited number of BSD pty's (2 or so) so you cant login a hundred times simultaneously.
crashd includes some sort of D/DoS protection. Only one connection per second is allowed per IP, except if the IP is listed (or the network it belongs to) in a good-IP file given with -g at startup. Per default no good IPs are assigned. Network-address-goodness only works with IPv4 yet. A simple good-IP file may look like this:
# sample good-IP file
192.168.3.1
192.168.2.0
10.0.0.0
fe80:216::1234
# end of file
Together with the interval timer for hanging un-authenticated connections this allows to have no more than 12 'hanging' crashd's at the same time, still allowing you to login if you are listed in good-IPs and your underlying TCP/IP stack is not already trashed.