#!/bin/blog

February 10, 2013

Dear Apple, we need to talk about iOS security.

Filed under: Security — Tags: , , — martin @ 11:01 am

Dear Apple, we need to talk about iOS security.

First of all, you need to understand that many people out here, with me being one of them, really have a good time living in the closed and well-regulated iOS world that you built for us. The devices work as desired, they are highly reliable, we have working backup and restore, and the platform is free from malware. Everything is very fine, most of the time, at least according to me.

Still, security problems do exist. I have programmed, and just like everyone who has programmed, I have built security holes. Every piece of software contains security holes, gets some fixed and breeds new ones, all the time: Linux, Firefox, Windows, MacOS and of course iOS. Thankfully, there are countless security researchers out there, who research not only open-source software, but also closed systems such as the iOS environment.

Most of the time, security researchers are good guys. Nowadays, we have this thing called responsible disclosure and most reasonable software vendors, including you, have learned to listen to security reports. This majority of researchers takes pride in disclosing security issues. But what about the others? Everyone knows they do exist. Some may use their exploits for criminal activities, others may work for governments.

4852847095_466bc90184_oI had an insight a few years ago. While I was on vacation, jailbreakme.com started to trend on Twitter. Right after breakfast, I went to the website, swiped the slider, and, behold, the phone was jailbroken. A bug in the PDF rendering engine of iOS enabled administrative access for exploit code hidden in a PDF received from the website. I was quite negatively surprised to see my iPhone being exploited through a link on some web site. You fixed this fantastically dangerous exploit in a matter of days and I wondered how long it had been discovered already before it emerged in the form of this jailbreak.

Which brings us from white hat hackers, who diligently report what they have found, and black hat hackers, who abuse their findings for dishonorable motives, to those grey hats, who hold back their findings to earn jailbreak fame. And many end users actually do appreciate those jailbreaks. In other words, they profit directly from withheld security issues, while at the same time, all users have to face the risks from those same withheld security issues.

As far as I can tell, this culture, where users profit from withheld security issues, is unique to iOS. Similar situations, on a smaller scale and with a close focus on warez, may exist around gaming consoles, but iOS is the only general-purpose operating system where security issues regularly have a potential benefit for the user.

Please understand that it would be beneficial for all users of iOS if you ended this misguided culture of withheld security exploits. Please offer a way to run user-supplied software on iOS. You don’t want to find a place in history for having established “that OS” where users regularly waited out security exploits just to see if they can profit from them.

Please be nice and reasonable. Thank you!

(Historical screenshot credit: Micky.! on Flickr, licensed under CC-BY 2.0)

January 7, 2012

Securitygewixe reloaded

Filed under: Security, UNIX/Linux/BSD — Tags: , — martin @ 11:13 am

Die WordPress-Referrer haben mir einen alten Beitrag über OpenBSD-Security nach oben gespült, in dem Linus Torvalds in seiner unnachahmlichen Art damit zitiert wird, daß er die OpenBSD-Entwickler für Securitywixer hält. Leider muß ich ihm zwischenzeitlich zustimmen.

Mich persönlich hat OpenBSD vor 2 Jahren beim Übergang von 4.6 zu 4.7 mit einer weitreichenden Änderung an der Firewallkonfiguration abgehängt, bei der Rewrite- und Filterregeln vereinigt wurden. Theoretisch betrachtet eine Vereinfachung. Praktisch leider mit dem Haken, daß es keinen Migrationspfad gab, um Regeln Zug um Zug umzustellen, denn mit Einführung der neuen Regeltypen waren die alten Regeln nicht mehr verfügbar. Die einzige Möglichkeit war, das gewachsene Regelwerk im Blindflug komplett umzustellen.

Die OpenBSD-Community zuckte mit den Schultern und verwies auf mein Testsystem, auf dem ich die Regeln ja testen kann. Was den Blindflug bei der Inbetriebnahme nicht minderte. Schade. Seitdem verzichte ich bei Installationen, die auch ohne Kopfschmerzen mal ein oder zwei Updates überstehen sollen, auf OpenBSD und greife lieber zu Debian Linux.

October 12, 2010

FTPS vs. SFTP, once and for all.

Filed under: Security — Tags: , — martin @ 11:09 am

I had to provide an explanation about the differences between FTPS and SFTP today, which sound so similar, but are in reality extremely different and can easily confused by those who don’t spend lots of quality time with them.

SFTP (“SSH FTP”) is based on SSH (Secure Shell) version 2. It uses the same communication channels and encryption mechanisms as SSH.

FTPS (“FTP over SSL”) is based on the the legacy FTP protocol, with an additional SSL/TLS encryption layer. There are several implementations of FTPS, including those with “implicit SSL” where a distinct service listens for encrypted connections, and “explicit SSL” where the connection runs over the same service and is switched to an encrypted connection by a protocol option. In addition, there are several potential combinations of what parts of an FTPS connection are actually being encrypted, such as “only encrypted login” or “encrypted login and data transfer”.

FTPS uses the same communication channels as legacy unencrypted FTP, including dynamically negiotiated side-band connections. Due to these side-band connections, FTP has always been problematic with firewalls. The encryption layer further exacerbates these issues.

Due to this rather long list of ins-and-outs, FTPS can be considered an exotic protocol, while SFTP has widespread acceptance due to the omnipresence of SSH servers on all Linux or UNIX servers.

The only objective advantage of FTPS is that FTPS uses an SSL certificate that is signed by a trusted third party and can be used in an opportunistic way, similar to HTTPS encryption in web browsers. However, if password authentication is not enough and mutual authentication using X.509 client certificates comes into play, this advantage loses part of its validity, because mutual authentication nearly always requires manual intervention from both sides.

June 8, 2010

Building RPM packages as non-root user

Filed under: Security — Tags: , — martin @ 11:38 am

This came up below the posting about Packaging OpenSSH on CentOS:

For non-root building of RPMs, the user needs a configuration file named .rpmmacros in his home directory:

cat <<EOF > ~/.rpmmacros
%_topdir $HOME/rpm
%_tmppath $HOME/rpm/tmp
EOF

The directory structure for RPM needs to be prepared by hand:
mkdir ~/rpm
mkdir ~/rpm/BUILD
mkdir ~/rpm/RPMS
mkdir ~/rpm/RPMS/`uname -p`
mkdir ~/rpm/RPMS/noarch
mkdir ~/rpm/SOURCES
mkdir ~/rpm/SPECS
mkdir ~/rpm/SRPMS
mkdir ~/rpm/tmp

Now build, for example, OpenSSH:
$ cp openssh-5.5p1/contrib/redhat/openssh.spec ~/rpm/SPECS/
$ cp openssh-5.5p1.tar.gz ~/rpm/SOURCES/
$ cd ~/rpm/SPECS/
$ rpmbuild -bb --define 'skip_x11_askpass 1' --define 'skip_gnome_askpass 1' openssh.spec
$ cd ~/rpm/RPMS/`uname -i`
$ ls -l
total 1108
-rw-r--r-- 1 martin martin 359994 Jun 8 12:33 openssh-5.5p1-1.i386.rpm
-rw-r--r-- 1 martin martin 471360 Jun 8 12:33 openssh-clients-5.5p1-1.i386.rpm
-rw-r--r-- 1 martin martin 284453 Jun 8 12:33 openssh-server-5.5p1-1.i386.rpm

Done.

February 2, 2010

Dealing with lengthy SSL certificate chains

Filed under: Security — Tags: , , , , — martin @ 4:16 pm

Comodo delivers the cheapest widely-recognized certificates (available e.g. via psw.net), second only to the famed StartSSL Free CA, which I haven’t had the guts to try out so far. What I got from Comodo, is my server cert, along with no less than three intermediate certificates:

AddTrustExternalCARoot.crt
issuer= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
subject= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root

UTNAddTrustServerCA.crt
issuer= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
subject= /C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware

PositiveSSLCA.crt
issuer= /C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
subject= /C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=PositiveSSL CA

Server.crt
issuer= /C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=PositiveSSL CA

You can obtain this information by running, e.g.:

for c in $(ls *crt); do echo -e "\n$c"; openssl x509 -issuer -subject -noout -in $c; done

Note how I have ordered them from the root certificate on top to the server certificate on the bottom, each being the issuer of the succeeding one. Did I say root certificate? Good news then: AddTrust is the root certificate, hence it does not need to be deployed, which leaves me with a chain of two.

I will need to deploy the certificates into Postfix and Dovecot, which use an all-in-one file that contains the complete chain, including the server certificate. Other servers, such as the Apache webserver, use a server certificate file and a separate file containing the intermediate certificates. Which is the method I prefer. But you just can’t always get what you want. ;-)

I learned the hard way that certificate order does matter. RFC 5246 states:

The sender’s certificate must come first in the list. Each following
certificate must directly certify the one preceding it. Because
certificate validation requires that root keys be distributed
independently, the self-signed certificate that specifies the root
certificate authority may optionally be omitted from the chain,
under the assumption that the remote end must already possess it
in order to validate it in any case.

Thus, the all-in-one file needs to start with the server certificate, followed by the certificate that issued the server certificate, all the way down to the one that is farthest away from the server certificate: 1) Server, 2) PositiveSSLCA, 3) UTNAddTrustServerCA

For servers that use a separate intermediate file, the order is the same, with the difference that the server certificate resides in its own file.

I recommend to maintain the subject and issuer information of all components of the all-in-one file so it won’t have to be dissected at a later point in order to understand what it contains. My starting point is the server cert, to which I will append the intermediate certs:

1) Locate the issuing certificate of the server cert (-> output above) and append the respective certificate to the server cert.
2) Locate the issuing certificate of the previously appended certificate and append it to the server cert.
3) Repeat until the root CA certificate has been reached.

In my case:
openssl x509 -in server.crt -subject -issuer > server-allinone.crt
openssl x509 -in PositiveSSLCA.crt -subject -issuer >> server-allinone.crt
openssl x509 -in UTNAddTrustServerCA.crt -subject -issuer >> server-allinone.crt

Now I have a handy file ready for deployment:

subject= /OU=Domain Control Validated/OU=PositiveSSL/CN=server
issuer= /C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=PositiveSSL CA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject= /C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=PositiveSSL CA
issuer= /C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject= /C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
issuer= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

The main point is that you must understand how the certificates relate to each other. The issuer and subject fields are the key all the way through the procedure.

April 24, 2009

OpenSSH connection multiplexing

Filed under: Security, UNIX & Linux — Tags: , , — martin @ 6:44 am

The Challenge

I was in touch with a developer the other day who used SSH to programmatically connect to a remote machine where he would start some kind of processing job. Unfortunately, he was in trouble when he wanted to kill the remote process. Killing the local SSH client would leave his job active. He claimed that there used to be some sort of signal forwarding feature in OpenSSH on the machine where he had developed his application in OpenSSH 3.x days, but this feature seems to have been removed by now.

I wasn’t able to confirm anything of this, but this gentleman’s problem got me curious. I started to wonder: Is there some kind of sideband connection that I might use in SSH to interact with a program that is running on a remote machine?

The first thing I thought of were port forwards. These might actually be used to maintain a control channel to a running process on the other side. On the other hand, sockets aren’t trivial to implement for a /bin/ksh type of guy, such as the one I was dealing with. Also, this approach just won’t scale. Coordination of local and remote ports is bound to turn into a bureaucratic nightmare.

I then started to skim the SSH man pages for anything that looked like a “sideband”, “session control” or “signaling” feature. What I found, were the options ControlMaster and ControlPath. These configure connection multiplexing in SSH.

Proof Of Concept

Manual one-shot multiplexing can be demonstrated using the -M and -S options:

1) The first connection to the remote machine is opened in Master mode (-M). A UNIX socket is specified using the -S option. This socket enables the connection to be shared with other SSH clients:

localhost$ ssh -M -S ~/.ssh/controlmaster.test.socket remotehost

2) A second SSH session is attached to the running session. The socket that was opened before is specified with the -S option. The remote shell opens without further authentication:

localhost$ ssh -S ~/.ssh/controlmaster.test.socket remotehost

The interesting thing about this is that we now have two login sessions running on the remote machine, who are children of the same sshd process:

remotehost$ pstree -p $PPID
sshd(4228)─┬─bash(4229)
           └─bash(4252)───pstree(4280)

What About The Original Challenge?

Well, he can start his transaction by connecting to the remote machine in Master mode. For simplicity’s sake, let’s say he starts top in one session and wants to be able to kill it from another session:

localhost$ ssh -t -M -S ~/.ssh/controlmaster.mytopsession.socket remotehost top

Now he can pick up the socket and find out the PIDs of all other processes running behind the same SSH connection:

localhost$ ssh -S ~/.ssh/controlmaster.mytopsession.socket remotehost 'ps --ppid=$PPID | grep -v $$'
  PID TTY          TIME CMD
 4390 pts/0    00:00:00 top

This, of course, leads to:

localhost$ ssh -S ~/.ssh/controlmaster.mytopsession.socket remotehost 'ps --no-headers -o pid --ppid=$PPID | grep -v $$ | xargs kill'

Then again, our shell jockey could just use PID or touch files. I think this is what he’s doing now anyway.

Going Fast And Flexible With Multiplexed Connections

With my new developer friend’s troubles out of the way, what else could be done with multiplexed connections? The SSH docs introduce “opportunistic session sharing”, which I believe might actually be quite useful for me.

It is possible to prime all SSH connections with a socket in ~/.ssh/config. If the socket is available, the actual connection attempt is bypassed and the ssh client hitches a ride on a multiplexed connection. In order for the socket to be unique per multiplexed connection, it should be assigned a unique name through the tokens %r (remote user), %h (remote host) and %p (destination port):

ControlPath ~/.ssh/controlmaster.socket.%r.%h.%p
# Will create socket as e.g.: ~/.ssh/controlmaster.socket.root.remotehost.example.com.22

If there is no socket available, SSH connects directly to the remote host. In this case, it is possible to automatically pull up a socket for subsequent connections using the following option in ~/.ssh/config:

ControlMaster auto

So Where’s The Actual Benefit?

I use a lot of complex proxied SSH connections who take ages to come up. However, connecting through an already established connection goes amazingly fast:

# Without multiplexing:
localhost$ time ssh remotehost /bin/true
real    0m1.376s
...
# With an already established shared connection:
localhost$ time ssh remotehost /bin/true
real    0m0.129s
...

I will definitely give this a try for a while, to see if it is usable for my daily tasks.

Update, 2009/05/04: No, it isn’t. Disconnecting slave sessions upon logout of the master session are too much of a nuisance for me.

February 27, 2009

Packaging OpenSSH on CentOS

Filed under: Security, UNIX & Linux — Tags: , , , , — martin @ 8:29 am

March 30, 2010: It was pointed out to me that Redhat has backported chroot functionality into its OpenSSH 4.3 packages, so these directions may not be neccessary anymore.

My article on chrooted SFTP has turned out to be the most popular article on this blog. What a pity that its “companion article” on building current OpenSSH on CentOS 5 is such a bloody hell of a mess.

Fortunately, reader Simon pointed out a really simple method for building RPMs from current OpenSSH sources in a comment. We had the chance to try this out in a production deployment of chrooted SFTP the other day, and what can I say? It just works(tm)! Thanks a lot, dude! :-)

# yum install gcc
# yum install openssl-devel
# yum install pam-devel
# yum install rpm-build

It certainly doesn’t hurt to make the GPG check a habit:

# wget http://ftp.bit.nl/mirror/openssh/openssh-5.2p1.tar.gz
# wget http://ftp.bit.nl/mirror/openssh/openssh-5.2p1.tar.gz.asc
# wget -O- http://ftp.bit.nl/mirror/openssh/DJM-GPG-KEY.asc | gpg –-import
# gpg openssh-5.2p1.tar.gz.asc
gpg: Signature made Mon 23 Feb 2009 01:18:28 AM CET using DSA key ID 86FF9C48
gpg: Good signature from "Damien Miller (Personal Key) "
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 3981 992A 1523 ABA0 79DB FC66 CE8E CB03 86FF 9C48

Prepare, build and install the RPM. Disable the building of GUI components in the spec file. We don’t need these on a server:

# tar zxvf openssh-5.2p1.tar.gz
# cp openssh-5.2p1/contrib/redhat/openssh.spec /usr/src/redhat/SPECS/
# cp openssh-5.2p1.tar.gz /usr/src/redhat/SOURCES/
# cd /usr/src/redhat/SPECS
# perl -i.bak -pe 's/^(%define no_(gnome|x11)_askpass)\s+0$/$1 1/' openssh.spec
# rpmbuild -bb openssh.spec
# cd /usr/src/redhat/RPMS/`uname -i`
# ls -l
-rw-r--r-- 1 root root 275808 Feb 27 08:08 openssh-5.2p1-1.x86_64.rpm
-rw-r--r-- 1 root root 439875 Feb 27 08:08 openssh-clients-5.2p1-1.x86_64.rpm
-rw-r--r-- 1 root root 277714 Feb 27 08:08 openssh-server-5.2p1-1.x86_64.rpm
# rpm -Uvh openssh*rpm
Preparing... ########################################### [100%]
1:openssh ########################################### [ 33%]
2:openssh-clients ########################################### [ 67%]
3:openssh-server ########################################### [100%]
# service sshd restart

The RPM should install cleanly on CentOS 4. On CentOS 5, after installation, service ssh restart throws a warning that initlog is obsolete. I work around this by keeping a copy of the old /etc/init.d/sshd and restoring it after RPM installation.

February 14, 2009

Re-Layering LVM encryption

Filed under: Security, UNIX & Linux — Tags: , , — martin @ 11:48 pm

In an earlier article, I had promised live migration of LVM data to encrypted storage. I was able to acquire an external SATA disk for my backup server today, so here we go. :-)

crypt-lvm1

The backup server is running headless, so I opted to store the key locally for now. Yes, I’m a moron. But hey, at least it’s not on the same medium.

# dd if=/dev/urandom of=/etc/luks.key count=256 ; chmod 600 /etc/luks.key

As long as the disk isn’t the only one, I can’t predict the device name it will come up as. Thus, it is referenced by its udev ID when formatting it with LUKS:

# cryptsetup luksFormat /dev/disk/by-id/scsi-SATA_WD_My_Book_WD-WCAU123-part1 /etc/luks.key

Open the new LUKS device:

# cryptsetup luksOpen -d /etc/luks.key /dev/disk/by-id/scsi-SATA_WD_My_Book_WD-WCAU123-part1 pv_crypt_1

The entry in /etc/crypttab makes the encrypted device come up on boot:

/etc/crypttab:

pv_crypt_1 /dev/disk/by-id/scsi-SATA_WD_My_Book_WD-WCAU123-part1 /etc/luks.key luks

Create a new Physical Volume on the crypted device:

# pvcreate /dev/mapper/pv_crypt_1

Now the Volume Group can be extended with the new PV:

# vgextend datavg /dev/mapper/pv_crypt_1

I rebooted at this point, in order to see if everything would come up as expected.

The new PV is now visible:

# pvs
  PV         VG     Fmt  Attr PSize   PFree
  /dev/dm-0  datavg lvm2 a-   931.51G 931.51G
  /dev/sdb1  datavg lvm2 a-   465.76G      0

The next step is to migrate the VG content to the new PV. Migration will take a very long time if the disk is full, so you may want to use a screen session for this.

# pvmove -v  /dev/sdb1

This is a classical LVM operation that may be cancelled at any time and picked up later. In fact, my Promise SATA driver crashed hard in the middle of the operation, and everything went along fine after a kernel upgrade.

When pvmove is done, throw out the original PV from the volume group:

# vgreduce datavg /dev/sdb1

The Volume Group is now on encrypted storage.

January 18, 2009

Managing encrypted logical volumes

Filed under: Security, UNIX & Linux — Tags: , , — martin @ 1:32 pm

Worked on this with G. the other day.

Create the underlying logical volume:
lvcreate -n datalv_crypted -L 1G vg00

Initialize a LUKS crypto device on the logical volume:
cryptsetup luksFormat /dev/vg00/datalv_crypted

If you have lost your mind and want to keep the passphrase in a file (which is what G.’s weirdo client had asked for):
dd if=/dev/urandom of=/etc/i_am_dumb count=256
cryptsetup luksFormat /dev/vg00/datalv_crypted /etc/i_am_dumb

Bring up the crypto device from the encrypted logical volume:
cryptsetup luksOpen /dev/vg00/datalv_crypted data # optionally -d /etc/i_am_dumb

Create a file system on the crypto device, /dev/mapper/data, which has now sprung to life:
mkfs.ext3 /dev/mapper/data

Enter the crypto device in /etc/fstab:
/dev/mapper/data /data ext3 defaults 0 0

Don’t forget to create the mount point:
mkdir /data

Enter the encrypted logical volume in /etc/crypttab. Substitute “none” with /etc/i_am_dumb if you are keeping the passphrase on the system.
data /dev/vg00/datalv_crypted none luks

Reboot. You will be prompted for the passphrase on bootup, unless you’re keeping it in a file. The new file system will be mounted on /data.

The usual process for resizing file systems now has to be extended by an additional step:

lvresize -L +1G /dev/vg00/datalv_crypted
cryptsetup resize /dev/mapper/data
resize2fs /dev/mapper/data

That’s all there is to it. In another installment, I will hopefully write about encrypted physical volumes, allowing live migration of an entire volume group to encrypted storage during full operation. :-)

With the technical details out of the way, some additional words about keeping the passphrase on-disk:

If you work for someone who wants this, he’s not neccessarily an idiot, but maybe just a bit naive. It is your duty as the expert to explain why keeping the passphrase in-band with the encrypted data is nothing more than just a waste of CPU cycles. Seriously. This, G., means you. ;-)

October 20, 2008

OpenSSH: Going flexible with forced commands

Filed under: Security, UNIX & Linux — Tags: , — martin @ 9:32 am

As we all know, it is possible to use SSH not only for obtaining an interactive login session on a remote machine, but also for executing commands remotely. For instance, the following command will log on to myserver.example.com, execute “uname -a” and return to the local shell:

ssh myserver.example.com uname -a

(The local SSH client returns the exit code from the remote command, if you’re into this kind of detail.)

You might have some users (or scheduled automatisms) that you don’t want to be able to log on to that machine at all, but who should be permitted to execute only a given command. In order to achieve this, you can configure key-based authentication. Once this has been done, the key can be prefixed with a number of configuration options. Using one of these options, it is possible to enforce execution of a given command when this key is used for authentication.

In this example from ~/.ssh/authorized_keys, the user wants to look at the process list, so we set the command to “ps -ef”.

command="/bin/ps -ef"

Using this, when the user tries to log in, or tries to execute an arbitrary command, “/bin/ps -ef” is executed instead and the SSH session terminates.

In addition to enforcing a command, it is advisable to disable a number of advanced SSH features, such as TCP and X11 forwarding. Assignment of a pseudo terminal to the user’s SSH session may also be suppressed, by adding a number of additional configuration options next to the forced command:

no-port-forwarding,no-X11-forwarding,no-pty

Here’s what a full entry from ~/.ssh/authorized_keys might look like:

command="/bin/ps -ef",no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAp0KMipajKK468mfihpZHqmrMk8w+PmzTnJrZUFYZZNmLkRk+icn+m71DdEHmza2cSf9WdiK7TGibGjZTE/Ez0IEhYRj5RM3dKkfYqitKTKlxVhXNda7az6VqAJ/jtaBXAMTjHeD82xlFoghLZOMkScTdWmu47FyVkv/IM1GjgX/I8s4307ds1M+sICyDUmgxUQyNF3UnAduPn1m8ux3V8/xAqPF+bRuFlB0fbiAEsSu4+AkvfX7ggriBONBR6eFexOvRTBWtriHsCybvd6tOpJHN8JYZLxCRYHOGX+sY+YGE4iIePKVf2H54kS5UlpC/fnWgaHbmu/XsGYjYrAFnVw== Test key

This is quite nice: We have successfully limited this user to requesting a process list.

This is called an SSH forced command.

So much for the introduction. :-D

Here’s what I’m really getting at today – What, if we want the user to not only execute a single command, but a number of commands, such as:

- Show process list (ps)
– Show virtual memory statistics (vmstat)
– Stop and start the print server (/etc/init.d/cupsys stop/start)

Following the approach described above, this would give us four key pairs, four entries in ~/.ssh/authorized_keys, and four entirely different invocations of SSH on the client side, each of them using a dedicated private key. In other words: An administrative nightmare.

This is where the environment variable $SSH_ORIGINAL_COMMAND comes in. (This nice facility was pointed out to me last week by G., who had read about it somewhere but wondered what it might be useful for.)

Until now, all we know is that with a forced command in place, the SSH server ignores the command requested by the user. This is not entirely true, though. The SSH server does in fact remember the command that was requested, stores it in $SSH_ORIGINAL_COMMAND and thus makes it available within the environment of the forced command.

With this in mind, it is possible to allow more flexibility inside forced commands, without the need to go crazy with countless key pairs. Instead, it is possible to just create a wrapper script that is called as the forced command from within ~/.ssh/authorized_keys and decides what to do, based on the content of $SSH_ORIGINAL_COMMAND:

#!/bin/sh
# Script: /usr/local/bin/wrapper.sh 

case "$SSH_ORIGINAL_COMMAND" in
	"ps")
		ps -ef
		;;
	"vmstat")
		vmstat 1 100
		;;
	"cups stop")
		/etc/init.d/cupsys stop
		;;
	"cups start")
		/etc/init.d/cupsys start
		;;
	*)
		echo "Sorry. Only these commands are available to you:"
		echo "ps, vmstat, cupsys stop, cupsys start"
		exit 1
		;;
esac

It is important to be aware of potential security issues here, such as the user escaping to a shell prompt from within one of the listed commands. Setting the “no-pty” option already makes this kind of attack somewhat difficult. In addition, some programs, such as “top”, for example, have special options to run them in a “secure” read-only mode. It is advisable to closely examine all programs that are called as SSH forced commands for well-meant “backdoors” and to find out about securing them.

It’s up to you to decide based on your own situation, whether you want to run this wrapper as the root user or if you prefer to use password-less “sudo” commands to raise privileges where needed.

If you encounter problems while debugging $SSH_ORIGINAL_COMMAND, please make absolutely sure that you are authenticating with the correct key. I found it helpful to unset SSH_AUTH_SOCK in the window where I do my testing, in order to prevent intervention from identies stored in the SSH agent.

Older Posts »

The Shocking Blue Green Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.