Friday, June 13, 2014

How to Setup Chroot SFTP in Suse 11

Setup a chrooted SSH sftp account. (Tested on Suse 11 and OpenSSH) 
We will create a low privileged sftp directory where lets say the users can upload their stuff without exposing our internal filesystem. First, add a user with a home directory, we don't want this user to access ssh via a shell, only for sftp, that's why we are setting the shell to /bin/false. Chrooted shell is a different chapter, so not discussing it here. And you can confirm the settings of newly added bobuser in /etc/passwd.

test:~ # useradd -d /home/bobuser -s /bin/false -m bobuser
test:~ # cat /etc/passwd | grep bobuser
bobuser:x:1505:100::/home/bobuser:/bin/false

Set the password for bobuser, or else you it will not allow you to login if the password is not set.

passwd bobuser
Changing password for bobuser.
New password:
BAD PASSWORD: it is based on a dictionary word
Retype new password:
Password changed.

Add the following settings in /etc/ssh/sshd_config file.

#Sftp/chroot Settings for bobuser in /etc/ssh/sshd_config
#Change LogLevel to debug and check errors (if any) in /var/log/messages
Subsystem sftp internal-sftp

#Sftp/chroot Settings for bobuser
Match User bobuser
   X11Forwarding no
   AllowTcpForwarding no
   ForceCommand internal-sftp
   ChrootDirectory /home/bobuser

Also add bobuser to the allow users list. This is a good practice to set can use ssh/sftp to login.

AllowUsers alexuser bobuser

Now restart the ssh service. And try connecting.

r00ter127:~ # service sshd restart
Shutting down SSH daemon done
Starting SSH daemon done
r00ter127:~ # sftp bobuser@localhost
Connecting to localhost...
Password:
Read from remote host localhost: Connection reset by peer
Couldn't read packet: Connection reset by peer
Ouch..We need to read the errors in /var/log/messages, we had already set it to debug level. There are some requirements expected by the ssh daemon

Jan 25 11:30:27 r00ter127 sshd[10220]: debug1: PAM: establishing credentials
Jan 25 11:30:27 r00ter127 sshd[10220]: fatal: bad ownership or modes for chroot directory "/home/bobuser"
Set the ownership of the home and parent directories to root. That's a requirement.

test:~ # ls -ld /home/bobuser/
drwxr-xr-x 5 bobuser users 4096 Jun 13 12:21 /home/bobuser/
test:~ # chown root:root /home/bobuser
test:~ # ls -ld /home/bobuser/
drwxr-xr-x 5 root root 4096 Jun 13 12:21 /home/bobuser/
We are set with the permissions now.

r00ter127:~ # sftp bobuser@localhost
Connecting to localhost...
Password:
subsystem request failed on channel 0
Couldn't read packet: Connection reset by peer
If you get the above error, then it means there is some problem invoking the sftp server. And the ssh logs are not very helpful in this regard. Make sure you are using the internal-sftp:

Subsystem sftp internal-sftp
...
   ForceCommand internal-sftp
And then.. you are done.

r00ter127:~ # sftp bobuser@localhost
Connecting to localhost...
Password:
sftp> pwd
Remote working directory: /


Monday, June 9, 2014

PAM module security settings for beginners - Suse 11

Pam modules security settings for beginners(Tested on Suse 11)
Configuring Pluggable Authentication Modules for security could be tricky sometimes. A lot of times people are looking for ways to prevent brute force and password guessing attempts on their ssh. But understanding the working of pam modules, testing them correctly surely takes some time. I am trying to list down here what I have tried and tested. There are 4 modules, cracklib, pwhistory, faildelay and tally. You can explore the man pages for detailed options that are supported, however here is the tricky part: depending on the modules version installed in your Linux, and in some cases depending on the Linux distro as well, the actual behavior may vary and some of the options listed in the man page may not even work. This adds a lot of confusion and frustration on how to get it to work. So define clearly your goals first, and then try out settings as listed in the man pages. Also make a note of where you are adding the rules, and finally a round to testing to ensure, things work as expected.

Few checkpoints, if you face problems when your pam module does not work as intended:

1. Ensure you understand the documented behavior of the module, its purpose, results, limitations etc.
2. Make a note of the PAM rule that you are adding, and the meaning of its parameters
3. Make a note of which file you are adding the rule to (e.g. the rule common-auth, common-password) it may not work if you have added it to the wrong file. :)
4. Well the version you are using, or the distro you are using, may have bugs as well. You need to check and google out any such possibility.
5. Well, if some option is not working in your module, even when it is listed in its man page, probably you are reading the documentation for a newer version
6. Is there any log file that this module writes to, where you can see its behavior?

cracklib is being used for enforcing strong password rules.
faildelay is to make the password prompt delay by a period of time when supplied with a wrong password, which reduces the efficiency of password guessing/brute forcing attacks.
pwhistory is to maintain a history of old passwords, so that users do not reuse their old passwords
pam_tally is to maintain a counter of bad login attempts and to lock the account for a given time, when the counter exceeds the set threshold. The useful feature is to reset the counter when a successful attempt occurs. This again is helpful in reduces the efficiency of password guessing/brute forcing attacks.

(The config files in Suse are in /etc/pam.d/common-auth/account/password):
Using cracklib and pwhistory #Password rules for the creation of strong passwords
- at least one special character (ocredit)
- at least one digit (dcredit)
- at least one lower case letter (lcredit)
- at least one upper case letter (ucredit)
- has a minimum length of 8 characters (minlen)

/etc/pam.d/common-password:

password requisite pam_cracklib.so difok=4 minlen=8 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=3

#Dont allow previously set passwords, This will remember upto 5 previous passwords.
#The old passwords are stored in /etc/security/opasswd
password required pam_pwhistory.so remember=5 retry=3


Testing
Those password rules do not work for root account. However for non-root accounts, you can try changing them. The errors however could be misleading. For e.g. you may get "password is too simple", even when u have a long password but you forgot to include a special character. So read the manual and keep trying.

faildelay: Brute force and password guessing attack protection
This means when you provide a bad password, the next password prompt would come after 5 seconds (or more). Which is a discouraging thing for automated brute forcing programs. This combined with strong password rules, and locking mechanism with pam_tally provide a good level of protection. /etc/pam.d/common-auth:

#Faildelay to delay the appearance of prompt (mitigation of brute force and password guessing attacks)
#delay is in micro seconds
auth required pam_faildelay.so delay=5000000


Testing for faildelay
Provide a bad password and the next password prompt should appear after 5 seconds.

pam_tally: Temporary account locking and automatic unlocking
You can use pam_tally to lock accounts which pass the defined threshold.(set with deny)

#Locking accounts temporarily when bad passwords are supplied (mitigating brute force and password guessing attacks)
#It uses the tally counter
auth required pam_tally.so deny=5 lock_time=1 unlock_time=60


Testing for pam_tally
By default, the pam_tally module will use /var/log/faillog log file. If you want to see the contents, run faillog command :

test:~ # faillog
Login Failures Maximum Latest On
alexuser 0 0 06/09/14 15:37:20 +0000 test.system.com



Try logging in and providing wrong passwords, with every wrong attempt, the pam_tally would increment Failure count. Once it goes beyond the threshold of 5, it will start locking you for 60 seconds for every bad password you provide. Only after 60 seconds it will accept a password. If you provide the correct password, the faillog is cleared.


test:~ # ssh alexuser@localhost
Password:
Password:
Password:
Account locked due to 6 failed logins

Received disconnect from 127.0.0.1: 2: Too many authentication failures for alexuser
test:~ # ssh alexuser@localhost
Password:
Password:
Account locked due to 8 failed logins

Password:
Account locked due to 9 failed logins

Received disconnect from 127.0.0.1: 2: Too many authentication failures for alexuser


Now you wait for 60 seconds and try logging again, this time provide correct password in first try (or else it will again start the lock period of 60 sec) and the system should log you in. Now you can run faillog and it will be empty because it got reset by your successful login.




References:
http://linux.die.net/man/8/pam_cracklib
http://linux.die.net/man/8/pam_tally

Saturday, June 7, 2014

Java code: Simple RSA encryption and decryption code

A simple program to generate 1024 bit RSA key pair, and perform simple encryption and decryption. No a big deal. Two classes: AsymetricKeyHelper and Main. AsymmetricKeyHelper.java:
/*AsymmetricKeyHelper.java*/
package com.work.crypto;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class AsymmetricKeyHelper {

 //Generates an RSA public private key pair
 public KeyPair keyPair() {
  KeyPair kp = null;
  try {
   KeyPairGenerator keyPairGenerator = KeyPairGenerator
     .getInstance("RSA");
   keyPairGenerator.initialize(1024);
   kp = keyPairGenerator.generateKeyPair();

  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
  return kp;
 }

 //does the encryption
 public byte[] encrypt(byte[] clearTest, Key key) {
  try {
   Cipher cipher = Cipher.getInstance(key.getAlgorithm());
   cipher.init(Cipher.ENCRYPT_MODE, key);
   return cipher.doFinal(clearTest);
  } catch (InvalidKeyException e) {
   e.printStackTrace();
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  } catch (NoSuchPaddingException e) {
   e.printStackTrace();
  } catch (IllegalBlockSizeException e) {
   e.printStackTrace();
  } catch (BadPaddingException e) {
   e.printStackTrace();
  }
  return null;
 }

 //does the decryption
 public byte[] decrypt(byte[] cipherText, PrivateKey private1) {
  try {
   Cipher cipher;
   System.out.println(private1.getAlgorithm());
   cipher = Cipher.getInstance(private1.getAlgorithm());
   cipher.init(Cipher.DECRYPT_MODE, private1);
   return cipher.doFinal(cipherText);
  } catch (NoSuchAlgorithmException e1) {
   e1.printStackTrace();
  } catch (NoSuchPaddingException e1) {
   e1.printStackTrace();
  } catch (InvalidKeyException e) {
   e.printStackTrace();
  } catch (IllegalBlockSizeException e) {
   e.printStackTrace();
  } catch (BadPaddingException e) {
   e.printStackTrace();
  }

  return null;
 }

}

Main.java:
/*Main.java*/
package com.work.crypto;

import java.security.KeyPair;

public class Main {

 /**
  * @param args
  */
 public static void main(String[] args) {
  asymmetricEncryptionSimple();
 }

 private static void asymmetricEncryptionSimple() {
  AsymmetricKeyHelper keyHelper = new AsymmetricKeyHelper();
  KeyPair keyPair = keyHelper.keyPair();
  System.out.println(keyPair.getPublic().getAlgorithm());
    
  String plainText = "You little Monkey.I am a cryptographer";
  
  byte[] cipherText = keyHelper.encrypt(plainText.getBytes(), keyPair.getPublic());
  //Print the encrypted text, it is in binary. So it will look ugly.
  System.out.println(new String(cipherText));
  
  byte[] clearDecrypt = keyHelper.decrypt(cipherText, keyPair.getPrivate());
  //Create a string out of the byte array
  System.out.println(new String(clearDecrypt));
 }

}