.

2008-07-12 07:08 -0400

I recently finished reading Crypto by Steven Levy, and was inspired to set up a public/private key pair for the purposes of encrypting some files on my computer. Having a key pair also allows me to digitally sign emails as well as receive encrypted messages.

I am using GnuPG to handle encryption,decryption, key management, etc. In addition to encrypting single files, I wanted to be able to encrypt whole folders. After researching this, I decided the simplest way to do this would be to tar up the folder and encrypt that. This, however, makes encryption and decryption a two step process. So, I wrote a simple script to handle these steps.

The script attempts to act intelligently based on its arguments. When it encounters directories, it tars then encrypts them. When it encounters an encrypted file, it decrypts it and untars it if necessary. Plain files are simply encrypted. To use the script you must install GnuPG and set up a public/private key pair. I will not cover those steps; there are plenty of resources out there that do (see GnuPG HowTos ). The script is simply called with the files or folders to encrypt or decrypt as arguments. Encrypted files and folders are replaced with files of the same name with a .gpg extension.

#!/bin/bash

# Set this!
recipient=

usage() {
    echo "Usage: $(basename $0) <file | dir>" >&2
} 

error() {
    printf "Error calling \`%s\', exiting...\n" $1 >&2
    exit 1
}

# Check usage.
if [[ $# < 1 ]]; then
    usage
    exit 1
fi

# Process arguments.
until [ -z "$1" ]; do

    # Tar then encrypt directories.
    if [ -d "$1" ]; then
        dir="${1%%/}"
        tar czf "${dir}.tar.gz" "${dir}" || error tar
        gpg --output "${dir}.gpg" --encrypt -r "$recipient" "${dir}.tar.gz" || 
error gpg
        rm -f "${dir}.tar.gz" && \
        rm -rf "$dir"

    # Unencrypt *.gpg files; untar them if necessary.
    elif [[ "$1" == *.gpg ]]; then
        result="${1%.gpg}"
        gpg --output "$result" --decrypt "$1" || error gpg
        if tar -tf "$result" &>/dev/null; then
            mv "$result" "${result}.tar.gz"
            tar -xzf "${result}.tar.gz" || error tar
            rm -f "${result}.tar.gz"
        fi
        rm -f "$1"

    # Must be a plain file, so encrypt it.
    elif [ -f "$1" ]; then
        gpg --output "${1}.gpg" --encrypt -r "$recipient" "$1" || error gpg
        rm -rf "$1"

    # Should never get here.
    else
        echo "Error, I don't know how to handle $1."
        exit 1
    fi

    shift
done
2008-06-23 11:33 -0400

Introduction

Ever since I began using ArchLinux, I have wanted a utility similar to debian's apt-file that allows you to discover which package provides a particular file. Arch's package manager, pacman, has always allowed you to do this for a file you already have installed, via pacman -Qo /path/to/file but this doesn't help if the file isn't already present on your system.

Recently, ArchLinux's developers have decided to provide filelists containing the contents of each package in a repository on the repo mirrors (see discussion). I've written a utility pac-file that downloads and uncompresses the filelists for each repository enabled in /etc/pacman.conf and allows regex searching of them. This allows the user to discover which package contains a file, even if that package is not installed on the user's system.

pac-file is loosely based on a similar script developed by Abhishek Dasgupta and available here.

Example

Suppose you are compiling a program and get an error about a missing library libImath.so To know which package to install to provide this dependency you could:

$ pac-file libImath.so
extra/openexr-1.4.0a-2 usr/lib/libImath.so.4
extra/openexr-1.4.0a-2 usr/lib/libImath.so.4.0.0
extra/openexr-1.4.0a-2 usr/lib/libImath.so

The output indicates that you should install openexr from the extra repo. pac-file searches via grep's extended regex engine, so searches like lib[Ii]math.so or lib*math work as expected.

Usage

pac-file is designed to be similar to pacman. You must first syncronize (via -S or --sync) the filelists. This must be done as root because the filelists are stored in /var/lib/pacman/filelists (although this can be changed in the script). See pac-file -h for more information.

Download

You can download pac-file here. Let me know if you like it or run into any bugs.

Tags: linux, scripting.
2008-06-10 15:49 -0400

It is always fun writing scripts to solve problems. Here, I have a pretty extensive mutt alias file, consisting of records such as:

alias john_doe      john.doe@example.com
alias kate          kate_doe@example.com

The name is either the first name or first_last followed by the email address. I wanted to add a long name so that when I composed an email the To: header would read:

To: <long name> <email address>

This is certainly not a big deal, but I wrote a simple perl script to achieve this. It generates the long name from the alias by replacing underscores with spaces. The long name is appended to each line in parenthesis. It takes the alias file on the command line and writes to stdout. It is specialized for my circumstances but may be of use to others.

#!/usr/bin/perl
use strict;
use warnings;

#----------------------------------------------
# Usage add_names <alias file>
#   Appends the person's name to the end
#   of the line of a mutt mail alias file.
#   The name appended is based on the alias.
#   Writes results to stdout.
#----------------------------------------------

while (my $line = <>) {
    chomp $line;
    my @fields = split /\s+/, $line;
    my $name = $fields[1];
    $name =~ s/_/ /g;
    my $result = sprintf '%-5s %-20s %-35s (%s)', $fields[0], $fields[1], 
        $fields[2], $name;
    print "$result\n";
}

When run on the sample alias file above, it gives the following output:

alias john_doe             john.doe@example.com                (john doe)
alias kate                 kate_doe@example.com                (kate)

Again, this is not a task of any great importance; it is just an example where a simple script allowed me to complete a task that I wouldn't have been willing to do manually.

Tags: linux, scripting.
2008-06-04 08:32 -0400

I found an interesting study of the passwords and methods used in brute force ssh attacks when researching these attacks for my article on the subject (part 1, part 2).

Researchers at Clarkson University set up three SSH honeypots in different environments: small business, residential, and university. The honeypots all ran OpenSSH on port 22. The server daemon was modified to collect all passwords attempted on the system. These machines were active from late July 2007 through February 2008.

Usernames
The results found that attacks often target common usernames, with root being the most common, giving credence to the recommendation of not allowing root to login remotely. The other common usernames attempted include admin, test, guest, user , and several databases such as oracle, postgres, and mysql .

Passwords
By far the most common password used by the attackers was simply the username, e.g. root/root, or user/user. Other common passwords attempted include 123456 and password . The researchers found a high degree of commonality among different attacks and surmised that there are at least five common username/password attack dictionaries in use among attackers.

The research performed allows a current look into brute force attacks on ssh servers on the internet. For more, read the original paper (pdf).

Tags: security.
2008-05-27 11:13 -0400

In part 1 I discussed basic options for securing your ssh server. In this part, I will discuss specific strategies for reducing the number of attacks the server faces.

Reducing the Number of Brute Force Attacks

The strategies discussed in part 1 work to secure the ssh server against attacks, but do nothing to reduce the number of attempts. The following will do just that. Remember that as the administrator, you must evaluate each of these in the context of your environment. For example, if many people connect to a server, running on a non-standard port may not be feasible.

Run sshd on a Non-Standard Port
sshd listens on port 22 by default, making it the main port attackers attempt to brute force. While having the daemon listen on a different port has no impact on the vulnerability of your ssh daemon, it will dramatically reduce the number of brute force attempts. To change the port, edit /etc/ssh/sshd_config:

Port 4321

where 4321 is some random unused port. This change will require a change in the configuration of all clients contacting the server and may necessitate a change in the server's firewall configuration.

Fail2Ban
Fail2Ban is a tool that parses log files and bans IP addresses with too many authentication failures. We will look at using it to defend against ssh brute force attacks although it has additional uses. It can block addresses with iptables or with TCP Wrappers (/etc/hosts.deny). I will detail configuration with the default, iptables, which must be up and running first.

Configuration is done via the /etc/fail2ban.conf file. You will need to set at least the following:

[DEFAULT]
maxfailures = 5     # Number of failures before an IP is banned.
bantime     = 600   # Seconds an IP will be banned.  A negative value will 
                    # permanently ban the IP.
ignoreip    =       # Whitespace delimited list of ip addresses to ignore.  
                    # You can use a mask to specify a range.
                    # e.g. 192.168.1.0/24

[SSH]
enabled     = true
logfile     = /var/log/auth.log
port        = 22

Check the [SSH] section and set the path to the logfile and port on which the daemon runs.

DenyHosts
DenyHosts is similar to Fail2Ban in that it scans log files and bans IP addresses with too many failed connection attempts. However, DenyHosts works only with ssh and blocks IP addresses by adding them to the /etc/hosts.deny file. This prevents that IP address from using any TCP Wrapper aware services on the server whereas Fail2Ban only prevents the attacker from using SSH. Additionally, DenyHosts has an optional synchronization mode that allows DenyHosts users to share attack data, proactively protecting against known attackers.

Configuration is done via the /etc/denyhosts/denyhosts.cfg file. Set the following to match your preferences and system:

SECURE_LOG =                # Path to the log file where sshd writes.
HOSTS_DENY =                # Path to the host access control file.
PURGE_DENY =                # Time denied addresses should remain in
                            # HOSTS_DENY. Leave blank to never purge.
BLOCK_SERVICE =             # Services to block for the offending host.
DENY_THRESHOLD_INVALID =    # Block host after number of failed, invalid
                            # user login attempts.
DENY_THRESHOLD_VALID =      # Block host after number of failed, valid
                            # user login attempts (except root).
DENY_THRESHOLD_ROOT =       # Block host after number of failed login
                            # attempts as root.

pam_abl
pam_abl is a pam module that automatically blacklists hosts and accounts that exceed a specified number of failed authentication attempts. The hosts / users are blacklisted for a configurable amount of time. Rules are written using the following syntax:

host_rule=<host>:<number of failures>/<time>,<number of failures>/<time>

For example, the following rule would ban all hosts (asterisk) with three or more authentication failures in one hour or 30 failed attempts in one day:

host_rule=*:3/1h,30/1d

Rules can be account based instead of host based by using the user_rule directive. The syntax is identical to that of the host_rule. Additional instructions and examples can be found at Linux.com.

iptables
The limit and recent iptables modules can be used to defend against ssh brute force attacks. See EnterpriseLinux and Diary of a Geek for more information and sample rulesets.

Conclusion

Brute force attacks on servers allowing remote ssh access are very common. In these two articles I have provided an overview of some of the steps and technologies available to system administrators for protecting their servers against these attacks. These steps range from restricting access to specific users / networks to programs that block computers that repeatedly fail to log in. Unfortunately, none of these solutions provides a magic bullet that will definitely protect your server. You must evaluate each one and use those that are most appropriate for your system and organization.

Tags: linux, security.
2008-05-21 21:17 -0400

In this article, I will give some background on the SSH protocols as well as discuss some general, best-practice security settings. As with most things, everything I discuss must be evaluated with regard to your particular situation. In part 2, I will discuss some methods for reducing the number of brute force attacks against your ssh server.

Introduction

SSH is a client/server protocol that provides a secure communication channel between two computers by transparently (to the end user) encrypting the transferred data. It provides:

  • Confidentiality: all data passing between the client and server is encrypted.
  • Integrity: the SSH protocol detects if data is altered in transit, guaranteeing that transmitted data is unaltered by a third party.
  • Authentication: the SSH protocol requires proof of identity to access the server. That proof can come in several forms (local or LDAP/Keberos password, public/private key pairs, etc) depending on the configuration.

SSH-1 was developed in 1995 by Tatu Ylönen as an ad-hoc solution for secure remote access. Interest in it grew and Ylönen released the source code. However, as a result of its ad-hoc nature, there were problems and limitations without workarounds. As a result, SSH-2, an incompatible new protocol based on SSH-1 was released in 1996. OpenSSH has become the dominant implementation of the SSH protocol and is available for many platforms, including BSD, Linux, and Solaris [1].

Since an SSH server is typically available over the internet, special attention must be paid to securing it from attack. The following instructions assume you are using OpenSSH, but should be applicable to other ssh implementations.

Security

Brute force attacks are a major security concern when running an ssh server. These automated attacks repeatedly attempt to login to ssh servers using common user names and passwords. These attacks became common in 2005 and continue today [2]. According to the SANS Top-20 Security Risks 2007:

Brute-force attacks against remote services such as SSH, FTP, and telnet are still the most common form of attack to compromise servers facing the Internet. Over the last couple of years a concerted effort has been made by attackers to recover passwords used by these applications via brute-force attacks. Increasingly worms and bots have brute-force password engines built into them. Systems with weak passwords for user accounts are actively and routinely compromised; often privilege escalations are used to gain further privileges, and rootkits installed to hide the compromise. It is important to remember that brute forcing passwords can be a used as a technique to compromise even a fully patched system.

If you are currently running an ssh server, check your access logs and you will likely see entries like:

May 20 14:46:24 xxx sshd[2700]: Invalid user user from ::ffff:xx.x.xx.xxx
May 20 14:46:24 xxx sshd[2700]: error: Could not get shadow information 
for NOUSER
May 20 14:46:24 xxx sshd[2700]: Failed password for invalid user user from 
::ffff:xx.x.xx.xxx port 41247 ssh2

There are many steps that an administrator can take to reduce both the number of these attacks and the likelihood that one will succeed. Here we will look at security measures that reduce the odds of a successful attack.

Strong Passwords Strong passwords typically contain:

  • A mix of UPPER and lower case letters.
  • Numbers.
  • Special characters such as !@&

Additionally, passwords should not be too short, or based on dictionary words and personal information such as birthdate, and children's or pet's names. One effective password generation method is to select the first letter from a easily remembered phrase, substituting some special characters and numbers where appropriate. For example, Picasso's quote:

"Computers are useless. They can only give you answers"

could become caU.7c0gYA.

Public Key Authentication
Strong passwords are a good start, but rely on the user to choose a good password. Even a mechanism to reject "bad" passwords can not guarantee that a user will not choose something easily guessable, write it down on a sticky note under their keyboard, or give it out via a social engineering attack.

Authentication can be done via a public/private key pair instead of an interactive password. Basically, you generate a pair of keys and place the public key on each server you want to log into. The private key must remain secure on every computer from which you will access the remote server. Authentication occurs as follows (note that the private key never leaves the client computer) [3]:

  • The client and server contact each other and exchange a symmetric session key used for encrypting data during the session.
  • The server issues a challenge that is encrypted with the user's public key.
    The challenge message itself is encrypted with the session key.
  • The client decrypts the message with the session key and the challenge with the private key.
  • The challenge is then encrypted with the session key and returned to the server where it is decrypted.
  • If the challenge matches what the server sent, then the client must have the private key that matches the public key stored on the server for that user, thus, authenticating the user.

Below are details of how to generate the public/private key pair and configure the ssh server to use them for authentication. If you are doing this on a Debian or Debian-based system (Ubuntu, MEPIS, Xandros, etc) make sure you have an up to date version of OpenSSL due to a vulnerability in Debian's package. Any keys generated with a vulnerable OpenSSL should be revoked and regenerated.

Generate the key pair:

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX user@host

Note: It is strongly recommended that you enter a passphrase for your key. You can use ssh-agent and keychain to allow pseudo-passwordless ssh access.

Copy the public key to the server:

user@host:~$ scp ~/.ssh/id_rsa.pub user@remotehost:~/

Add the public key to the server's authorized_keys file:

$ ssh user@remotehost
user@remotehost's password:
$ cat id_rsa.pub >> ~/.ssh/authorized_keys
$ rm id_rsa.pub

Configure the server to use public key authentication

On the server, edit /etc/ssh/sshd_config ensuring that the following lines are present:

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

Additionally, you may choose to disable password authentication by setting:

PasswordAuthentication no

Without this change, you allow both password and key based authentication.

Note: When changing the server configuration the service must be restarted to see the changes.

Secure Password-less Logins via ssh-agent and keychain
If you grow tired of entering your passphrase for every ssh connection, you may run ssh-agent, which caches your passphrase for the session. Unfortunately, ssh-agent alone will not allow ssh connections via cron jobs as those run as a separate session. For that you need to configure keychain, a bash script that allows the use of a single ssh-agent per system. While this does open up a security hole - what if someone was able to get into your account - use of the --clean option in a login script essentially treats each login as a security breach until otherwise proven. It does so by clearing the cache at login and requiring the passphrase again. This provides a measure of security, while still allowing cron jobs access to the cache, since the cache is cleared only at login.

Miscellaneous SSH Server Settings
Due to its insecure nature, unless you have good reason not to, you should disable the SSH-1 protocol on the server. Additionally, you should not allow root to log in. This removes a known username often used by brute force attackers. You can simply su to root once logged in as a user. Make the following changes in the /etc/ssh/sshd_config file:

Protocol 2
PermitRootLogin no

User Based Access Control You can limit ssh access to certain users on your system via the AllowUsers directive in /etc/ssh/sshd_config. For example:

AllowUsers pete
AllowUsers meg

would allow ssh connections only from pete and meg; no other accounts would be have access. You can also restrict access via DenyUsers.

Similarly, you can allow or deny access via groups. You could create a group sshusers and place all users that need ssh access into this group. You can then use the AllowGroups directive to specifically allow that group. There is an equivalent DenyGroups directive to deny access to particular groups.

Host Based Access Control
SSH access can be limited to hosts on a particular network or with a particular IP address via /etc/hosts.allow. For example, to restrict access to machines on your local network, you could place the following in /etc/hosts.allow:

sshd:192.168.1.

This can also be done with iptables:

iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -m state --state NEW
-j ACCEPT

The difference is that the iptables rule drops the connection at the firewall, attempt before it reaches the sshd daemon, while the daemon itself rejects the connection with the /etc/hosts.allow method.

References

[1] Barrett, D, Silverman, R, & Byrnes, R (2005). SSH, the Secure Shell. Sebastopol, CA: O'Reilly Media Inc.

[2] Wichmann, R (2008, 04 28). Samhain Labs. Defending against brute force ssh attacks Web site: http://www.la-samhna.de/library/brutessh.html

[3] (2008, 01 07). SSH, version 2. UVA Information Technology and Communication Web site: http://www.itc.virginia.edu/desktop/security/ssh.html#protection

Tags: linux, security.
2008-05-17 07:04 -0400

It appears that Verizon has begun redirecting failed dns queries to its own "Advanced Web Search" page, where they of course make money from ads. This is similar to VeriSign's infamous SiteFinder service, but on a smaller scale. A trial of this "feature" began in the Midwest in June 2007. I can confirm that it has spread to Virginia since then. From Verizon's announcement:

On June 11, 2007, Verizon Online will begin the trial of a new Advanced Web Search service designed to reduce the amount of dead-end, "no file exists" or similar error messages you see and to help you quickly find the destination web site you were seeking. If you type a nonexistent or unavailable URL (e.g., www.verizon.cmo), or enter a search term, into your browser address bar, Verizon may present you with an Advanced Web Search page containing suggested links based upon the query you entered.

Verizon Web Search

Several other companies are doing this, including OpenDNS , and I find it a questionable practice. With this "feature" enabled (as it is by default), you will never receive an "unknown host" error; this makes diagnosing network connectivity problems difficult.

Fortunately, Verizon provided a simple method for opting out of the service. Essentially, you need only to change the last octet in your dns servers from 12 to 14. You will need to make this change in your router if it acts as a dns server for your lan or if it provides the dns servers to the client computers via dhcp.

Tags: networking.
2008-05-15 20:15 -0400

I've set this site up with chronicle, a Perl based blog compiler. It converts content written in html, markdown, or textile into static html. In combination with templates, it generates archives, tag collections, and RSS feeds. Chronicle also provides a mechanism for moderated comments, which I may set up in the future.

It also includes pre- and post-compile hooks for executing scripts. For example, I use the following as a pre-compile hook to fill in the date field in a blog entry:

#!/bin/bash

#---------------------------------------------------
# Fills in the current date wherever "^Date: *$" is
# found in *.mdwn.  Useful with chronicle blog
# entries as a mercurial precommit hook.
#---------------------------------------------------

DIR=${1:-.}
DATE=$(date "+%Y-%m-%d %R %z")

cd "$DIR" || exit 1
for file in *.mdwn; do
    base=$(basename "$file") 
    sed "s/^Date: *$/Date:  $DATE/" "$file" > "/tmp/$base" || exit 1
    mv -f "/tmp/$base" "$file" || exit 1
    rm -f "/tmp/$base"
done

This script scans all .mdwn files in the specified directory (defaults to pwd) for lines consisting of "Date:" and fills in today's date and time. Reading every markdown file in a directory may prove inefficient as the number of entries grows, so I may have to revisit this in the future.

I also maintain the site in the mercurial RCS. This gives me a history and the ability to revert to previous versions of the site, if desired. Unfortunately, my host does not provide any sort of RCS, so I can't use mercurial to keep my local files synced with those on the webserver. Rsync would work, but that's not available either.

Fortunately, I came across lftp, a command line ftp client with the capability to mirror directories. I have it set to run after all mercurial commits, syncing the local files with the remote ones.

I'd like to thank my wife Meg for the awesome theme. There will probably be some subtle changes over the next few weeks, but overall, I'm really happy with the look.

Tags: meta, scripting.