Thursday, December 19, 2013

This post will go over digitally signing a file.  Combined with data encrypted with a secure symmetric cipher, this will provide reasonable assurance that an encrypted file was sent from the source that claims to have sent the file, and that the file was not modified during transit, as long as the private key used to sign the file has been kept safe.  As before, GnuPG will be used for both encryption and digital signatures.

Step 1:
Generate a GnuPG key pair.

gpg --gen-keys

There are a number of options that can be specified when generating a key pair.  For this example, the following values will be used:

Type of key: RSA and RSA (default)
Keysize: 4096
Valid for: Never expires
Real name: Test User
Email address: test@user.com
Comment: A test user.

Verify the key pair has been generated with:

gpg --list-keys

Step 2:
Send your public key, or make your public key available, to the party you want to send you digitally signed file to.  It is a good idea to also send the fingerprint of the public key through another means of communication, for example, over the phone.

To export the public key, execute:

gpg --armor --export "Test User"
 
To get the fingerprint of the public key, execute:

gpg --fingerprint "Test User"

Step 3:
Import the public key.  Once the public key has been sent and verified, the receiver needs to import the public key.

gpg --import publickey.key 

Step 4:
Encrypt and sign the file.

gpg --sign --symmetric --cipher-algo AES256 secret.txt

Step 5:
Decrypt the file.  Decrypting the file will automatically verify the digital signature.

gpg -d secret.txt.gpg
...gpg: Good signature from "Test User (A test user.) "...

Tuesday, December 17, 2013

This post will go over how to encrypt and decrypt files using GnuPG with a symmetric cipher.  GnuPG stands for "Gnu Privacy Guard", and is an open implementation of the PGP standard.  Note that the method described below does not provide message integrity (this will be described in another post).

Step 1:
Install GnuPG.  GnuPG should be installed by default during a CentOS installation, but if necessary, execute:

yum install gnupg

Step 2:
Encrypt a file.  Upon first execution (or by using gpg --version), the application will print out a list of available ciphers, hashes, and key algorithms.

Supported algorithms:
Pubkey: RSA, ELG, DSA
Cipher: 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, 
        CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

The default symmetric cipher used on this version of gpg was 3DES.  AES256 will be used instead.

gpg --cipher-algo AES256 -c secret.txt 

This will prompt for a password and produce the encrypted file "secret.txt.gpg".  Checking the file type should yield AES256:

file secret.txt.gpg 
secret.txt.gpg: GPG symmetrically encrypted data (AES256 cipher)

Step 3:
Decrypt a file.  Output goes into secret.txt.

gpg -o secret.txt -d secret.txt.gpg

Thursday, December 12, 2013

This post will go over how to install and use fail2ban, an extremely useful and versatile tool that can ban certain ip addresses that are showing malicious behaviour.  This post will go over how to monitor an ssh server for too many failed login attempts, and block the offending source ip address.

Step 1:
Install fail2ban.  If you have not already done so, install the epel repository.

wget http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
rpm -ivh epel-release-6-8.noarch.rpm

And install the application.

yum install fail2ban

Step 2:
Copy the configuration file.

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Step 3:
Set up the policy of the application.  There are a number of options that you can set in the newly created jail.local configuration file.  For the purposes of this post, only a few options will be modified:

#any ip that crosses the threshold will be banned for 24 hours, or 86400 seconds.
#bantime=600
bantime=86400

#an ip has 5 chances to log in successfully within the "findtime", defined below, before being banned for 24 hours.
#maxretry=3
maxretry=5

#an ip has 5 chances within one hour to log in successfully to a system before being banned for 24 hours.
#Note that after one hour, the threshold resets and the ip has another five attempts.
#findtime=600
findtime=3600
 
Modify the iptables rules to send mail to whatever address you want.  More importantly, ensure the "logpath" option specifies the log file to check for failed login attempts.

enabled  = true
filter   = sshd
action   = iptables[name=SSH, port=ssh, protocol=tcp]
           sendmail-whois[name=SSH, dest=youraddress@yourdomain.com, sender=fail2ban@example.com]
logpath  = /var/log/secure
maxretry = 5

Step 4:
Enable fail2ban.

service fail2ban start
chkconfig fail2ban on

Verify the iptables chain is now active.  Execute "iptables -L".  The INPUT chain should have the line

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
fail2ban-SSH  tcp  --  anywhere             anywhere            tcp dpt:ssh

And the chain fail2ban should be available, although empty right now.
Chain fail2ban-SSH (1 references)
 target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere

Step 5:
Verify operation.  Attempting to log in from 192.168.1.15 to the server that now has fail2ban active (192.168.1.16) and failing five times results in the source ip being added to the fail2ban chain.

REJECT     all  --  192.168.1.15         anywhere            reject-with icmp-port-unreachable

And the source machine can not even make an attempt for the next 24 hours.

ssh root@192.168.1.16
ssh: connect to host 192.168.1.16 port 22: Connection refused


Tuesday, December 10, 2013

This post will go over a quick and dirty way to check file integrity on a *nix system.  This may be useful to check for things such as bit rot or malicious tampering, although, in this example, only backups are being checked for bit rot.  There are other tools that can do this better, and some of them will be the topic of future posts.

Step 1:
Specify the hashing algorithm you want to use.  While there are pros and cons for different hashing algorithms, in this example, md5 will be used for one main reason, it is faster than sha256.

Step 2:
Specify the files you want to ensure are still readable.  For example, the folder "Documents" and "Images", as well as all sub-folders are the current subject of scrutiny.  These files are respectively 1.7GB and 178MB.

Step 3:
Calculate the hashes of the files and store in a file.  This can be done with the find and xargs command.

find $DIR/Images -type f -print0 | xargs -0 md5sum > images.md5
find $DIR/Documents -type f -print0 | xargs -0 md5sum > docs.md5

Step 4:
Force the system to re-read the file from disk and calculate the hashes again.  This will notify you if a file has been tampered with, or is suffering from bit-rot.  In this example, the files have already been cached in main memory, and the checksums are being calculated shortly thereafter, thus not hitting the disk.  The whole point of this is to verify the on disk data is still good.

md5sum -c images.md5 | grep FAIL
real    0m0.542s
md5sum -c documents.md5 | grep FAIL
real    0m5.346s

To force the system to clear the cached files, first write any data buffered in memory to disk:

sync

Then, clear the cache:

echo 3 > /proc/sys/vm/drop_caches

Re-check the hashes.

md5sum -c images.md5 | grep FAIL
real    0m19.415s
md5sum -c documents.md5 | grep FAIL
real    1m6.774s

Thursday, December 5, 2013

This post will go over how to log in to a remote system over ssh using expect.  While it would be a better option to use key-based authentication for non-interactive logins, this is not always an option.

Step 1:
Automatically accept the host fingerprint to known_hosts.  Here is an expect script that will accept the remote host's fingerprint to the known_hosts file, otherwise, you will need to accept the key manually.

#!/usr/bin/expect
set timeout 5
set ip [lindex $argv 0]
spawn ssh user@$ip

expect "(yes/no)?"
send "yes\n"

Step 2:
Create a script to log in and do whatever task needs to be automated.  For example, this script logs in to a host, grabs the uptime, and stores the session in the file log.txt.

#!/usr/bin/expect

set timeout 5
set ip [lindex $argv 0]
set password [lindex $argv 1]
set output [open "log.txt" "a+"]

spawn ssh user@$ip

expect "Password:"
send "$password\n"

expect "#"
send "uptime\n"

expect "#"
send "exit\n"

expect eof


Tuesday, December 3, 2013

This post will go over how to use keys to log in to a remote system over ssh.  Note that once this system is in place, it becomes critical to keep your private key safe and secure, and not give it out to anyone.  In this example, 10.0.0.3 is the client, and 10.0.0.2 is the server.

Step 1:
On the client, generate an ssh key pair.  This example is using rsa keys.

ssh-keygen -t rsa -b 4096

This will create a public key, id_rsa.pub, and a private key, id_rsa, in the users home folder in the .ssh directory.  During this command, you have the option to encrypt the private key with a password.  Although you can unlock the private key once and login to remote machines without a password afterwards (shown in step 4), you can also leave the private key in an unencrypted format.  It depends on the convenience/security trade-off you are willing to make.

Step 2:
Copy the public key to the server(s) you want to log in to.  You can use the ssh-copy-id command for convenience.  In this case, the local machine at 10.0.0.3 wants to log in to the remote server at 10.0.0.2.

ssh-copy-id -i ~/.ssh/id_rsa.pub <user>@10.0.0.2

The -i specifies the public key you want to transfer over.  The <user> is the account you want to log in to the server with.  Once this command completes, the public key of the client machine, 10.0.0.3, will have their public key added to the authorized_keys file of the server, 10.0.0.2.  Logging in to the console of the server at 10.0.0.2 as the user and cating the file ~/.ssh/authorized_keys reveals a new public key.

Step 3:
Modify the ssh server config file to only support key based logins.  Although not necessary for key based authentication, the server is still vulnerable to brute force attacks using username/password combinations.  There are tools to limit the number of login attempts and/or block repeated failures, but if possible, it would be best to just disable the option altogether.  In /etc/ssh/sshd_config, change "PasswordAuthentication yes" to "PasswordAuthentication no", and restart the service.

Step 4 (optional):
Unencrypt an encrypted private key once for use multiple times.  If you encrypted your private key, you can use an ssh-agent to unencrypt and load it into memory.

Run the "ssh-agent" command.

ssh-agent

This command will output some environment variables that the program needs.  Add these variables manually to your shell session, or execute the modified version of the command.

eval $(ssh-agent)

Once this is done, add your private key(s).

ssh-add