Tag: ssh

  • Automatically add SSH keys to SSH agent with GNOME and macOS

    Automatically add SSH keys to SSH agent with GNOME and macOS

    I am using passwordless login via SSH on every box that I administer.
    Of course, my private SSH key is protected with a password that must be provided when accessing the key.
    Modern operating systems incorporate the usage of ssh-agent to “link” the user account to the SSH key(s), in order to unlock the SSH key as soon as the user is logged in. In this way, they avoid nagging the user asking for the SSH key password every time the key needs to be used.
    In my case, I am running GNU/Linux with GNOME and macOS:

    • GNOME, via its Keyring, supports the automatic unlocking of SSH keys upon user login. Starting from GNOME 3.28, ed25519 keys are supported as well as RSA keys (I do not other use any other type of SSH keys). To add your keys, just invoke ssh-add and supply your key path:
    ssh-add ~/.ssh/[your-private-key]
    

    you will be asked for your SSH key password. It will be put in the GNOME Keyring (remember it if you update your SSH password!).

    • macOS supports associating your SSH key password into the Keychain. You can add your key(s) with:
    ssh-add -K ~/.ssh/[your-private-key]
    

    Starting from Sierra, though, you need to change your ~/.ssh/config to persist the key between reboots and add:

    Host *
      UseKeychain yes
      AddKeysToAgent yes
      IdentityFile ~/.ssh/[your-private-key-rsa]
      IdentityFile ~/.ssh/[your-private-key-ed25519]
    

    Now, if you share the same ~/.ssh/config file between GNU/Linux and macOS you would encounter an error: how ssh on Linux is supposed to know about UseKeychain option (which is compiled only in macOS’ ssh)?
    A special instruction, IgnoreUnkown, comes to the rescue:

    IgnoreUnknown UseKeychain
    UseKeychain yes
    

    Eventually, my ~/.ssh/config looks like:

    Host *
      IgnoreUnknown UseKeychain
      UseKeychain yes
      AddKeysToAgent yes
      IdentityFile ~/.ssh/id_rsa
      IdentityFile ~/.ssh/id_ed25519
      Compression yes
      ControlMaster auto
    [...]
    
  • Secure your SSH server against brute-force attacks with Fail2ban

    The problem: SSH can be brute-forced

    I usually leave an SSH server on a dedicated port on every server I administer and, as you may recall, I even linked two well-written guides to properly configure and harden SSH services.

    Now, Internet is a notoriously bad place: scanners and exploiters have always been there, but brute-forcers are on the rise and SSH is one of the services that is heavily targeted by them. Let’s gather some data:

    quebec:/var/log # ag "Invalid user" auth.log.2 auth.log.3 | wc -l
    4560
    quebec:/var/log # head -n 1 auth.log.3 | cut -d " " -f 1-3
    May  8 07:39:01
    quebec:/var/log # tail -n 1 auth.log.2 | cut -d " " -f 1-3
    May 21 07:39:01
    

    So, even if my SSH is allowing only PubkeyAuthentication, in the timespan of two weeks there has been 4560 brute-force attemps (~325 attempts per day).

    This is annoying and potentially insecure, depending on your configuration. What can we do?

    The solution: using Fail2ban

    I have recently read some posts about this problem, and luckily (for us) there are multiple solutions to this problem: the most popular one is Fail2ban. To cut a long story short, the idea behind Fail2ban is to monitor log files of the monitored services and keep track of which IP addresses are trying to use a brute-force attack to use the service. If the same IP address causes a number of bad events in the specified time frame, Fail2ban bans that IP (using netfilter/iptables) for a configure d time amount.

    So I just need to install Fail2ban and I am ready to go:

    # zypper in fail2ban
    

    NO. NO. NO. You will not be protected against brute-force attacks if you just install it without configuring it.

    You MUST configure it!

    Let’s take a step back. The core of Fail2ban is the configuration:

    # "bantime" is the number of seconds that a host is banned.
    bantime  = 600
    
    # A host is banned if it has generated "maxretry" during the last "findtime"
    # seconds.
    findtime = 600
    maxretry = 5
    

    These are the default values. And brute-forcers know them, so they can time accordingly their attempts not to break these limits (or to begin again their attempts after the bantime). Again, let’s gather some data. I noticed a frequent brute-forcer IP and follow his data:

    quebec:/var/log # ag "Invalid user" auth.log.2 auth.log.3 | ag <IP> | cut -d " " -f 1-3
    
    auth.log.2:8106:May 21 03:34:22
    auth.log.2:8112:May 21 03:43:41
    auth.log.2:8116:May 21 03:53:00
    auth.log.2:8120:May 21 04:02:18
    auth.log.2:8126:May 21 04:11:47
    auth.log.2:8132:May 21 04:21:08
    

    Can you believe it? It was just on the edge of the 600 seconds between every attempt!

    Key concept: outsmarting brute-forcers

    The key concept here is to provision a personalized version of your specific choosing of these values, in order to outsmart the brute-forcers (which is easily done). In order to do so, do not modify Fail2ban’s default config file (/etc/fail2ban/fail2ban.conf) but rather just override the defaults in another config file that you can create with:

    quebec:/etc/jail2ban # awk '{ printf "# "; print; }' /etc/fail2ban/jail.conf | sudo tee /etc/fail2ban/jail.local
    

    Your customizations have to be defined in /etc/fail2ban/jail.local, so your selected bantime, findtime and maxretry must go there.

    Further customization

    Some useful findings:

    • you can selectively whitelist a group of IPs, hosts, subnets, etc. in order to not being banned when accessing services from whitelisted IPs (e.g. ignoreip = <VPN subnet>/8 <another VPN subnet>/16)
    • you can receive an email everytime someone is banned with their whois (with good relief from the system administrator)
    • if you are using WordPress, you can extend Fail2ban to monitor failed WordPress login attempts with a WordPress plugin (did I mention that Fail2ban not only monitors sshd? It also monitors nginx, apache, vsftpd and other services)
    • you can have Fail2ban automatically sends the banned IPs to a shared blacklist (I have never used this)

    Disadvantages

    Everything seems perfect now, but what are the disadvantages of it? Given that Fail2ban reasons in terms of banning single IPs, it cannot protect you against distributed brute-force attacks. In this case Fail2ban is pretty useless and other solutions should be implemented that depends from case to case.

  • sshuttle: creiamo una VPN (via transparent proxy) con SSH

    In passato vi ho spiegato come creare un tunnel SSH per poter “tunnelizzare” il traffico Internet usando da tramite un server che esponeva il demone sshd. La scomodità di questa soluzione risiede nell’ultimo passo: dobbiamo impostare un tunnel SOCKS per ogni programma di cui vogliamo tunnelizzare il traffico. Ok, questo può non essere una scomodità vera e propria, tuttavia: per esempio, vogliamo tunnelizzare solo il traffico del browser [pensiamo di trovarci in una rete pubblica], mentre il traffico SSH [già cifrato] non ha bisogno di essere tunnelizzato.

    Oggi facciamo un passo oltre: vogliamo sfruttare la connessione SSH che abbiamo per tunnelizzare  tutto il traffico attraverso SSH. Questo è equivalente a creare una VPN con il server remoto, ma l’unica differenza importante è che non si creano interfacce di rete aggiuntive!

    Di conseguenza, l’host locale (che chiamiamo client) instaurerà una connessione SSH verso il server che si assumerà la responsabilità di instaurare la connessione verso gli altri host e di fare da “passacarte” verso il client. La configurazione è molto utile nel caso in cui il client si trovi ad utilizzare una rete pubblica non sicura (pensiamo ad esempio a Starbucks) ma allo stesso tempo voglia che tutto il traffico sia cifrato per evitare problemi di sniffing.

    Il software che ci permette di costruire la VPN (vi ricordo che non è a tutti gli effetti una VPN, anche se ne si hanno tutti i benefici) è sshuttle, disponibile per Linux e OSX.

    Una volta installato solo sul client (lo trovate nei repo di Ubuntu e in homebrew), vi consiglio di configurarlo per fare il forward di tutto il traffico (comprese le richieste DNS) nel seguente modo:

    ./sshuttle --dns -vvr username@sshserver 0/0

    [Nota: 0/0 è uno shortcut per 0.0.0.0 – se volete modificarlo per fare selective routing verso il tunnel di una particolare subnet, sapete cosa dovete modificare ;)]

    Per i più curiosi, ecco una piccola spiegazione di cosa c’è under the hood di sshuttle.

  • Come mantenere attiva una sessione SSH (keepalive)

    Quando ci connettiamo tramite ssh ad un server remoto, nella maggior parte dei casi la connessione viene terminata dopo un periodo di inattività (idle), e siamo quindi costretti a riconnetterci al server.

    La disconnessione può essere dovuta ad una serie di ragioni; la più verosimile, nel caso di inattività, è quella che un nodo intermedio abbatta la connessione (trascorso un certo periodo di tempo il cui il traffico scambiato è nullo) per mantenere basso il numero di connessioni (e quindi risparmiare risorse). Questo comportamento è perfettamente legittimo (quasi tutti i dispositivi e i provider implementano questa funzionalità).

    Possiamo però evitare questo comportamento abilitando il keepalive di SSH. facendo in modo che SSH scambi del traffico “fittizio” quando la connessione non sta scambiando dati, in modo che la connessione non venga abbattuta. Nota: questa funzionalità è disabilitata di default da ssh.

    Abilitare questo comportamento è molto semplice, e può essere ottenuto in due modi:

    • Se vogliamo abilitare il keepalive per tutti gli utenti, dovremo avere accesso root alla macchina. Modifichiamo il file /etc/ssh/ssh_config e aggiungiamo queste righe:
      ClientAliveInterval 300
      ClientAliveCountMax 1000
    • Se vogliamo abilitare il keepalive solo per l’utente corrente, modifichiamo il file ~/.ssh/config e aggiungiamo queste righe:
      ClientAliveInterval 300
      ClientAliveCountMax 1000

    In questo modo, il server ssh invierà un messaggio di keep-alive nel caso in cui la connessione ssh non scambi dati per 5 minuti (300 secondi), e ripeterà l’invio per massimo 1000 volte.

  • Creare un tunnel ssh dinamico con openssh (Linux, MacOSX, *BSD, UNIX-based OSes) e relativo use-case per Firefox

    Un po’ di tempo fa vi avevo spiegato come creare un tunnel ssh usando PuTTY, il client ssh per eccellenza su Windows.
    Ora, visto che ci siamo evoluti e siamo passati ad un sistema operativo che si basa su UNIX (come ad esempio Linux, MacOSX, Solaris, *BSD, o comunque una qualsiasi piattaforma che supporti openssh), vi spiegherò come creare un tunnel ssh usando questi sistemi operativi.

    Anche qui dobbiamo prima verificare due requisiti fondamentali:

    • di avere installato sulla macchina client (quella che deve usufruire del tunnel) openssh
    • di avere a disposizione una macchina server che metta a disposizione accesso ssh (openssh-server), che sia raggiungibile sulla porta 22/tcp (o se l’avete cambiata sapete anche su quale porta deve essere raggiungibile) e su cui abbiate utenza.

    Se avete bisogno di un tunnel ssh sono certo che sappiate come mettere in piedi queste due cose, e che sappiate già perché vi serve un tunnel ssh.

    Bene, continuiamo. Apriamo un terminale e digitiamo: ssh -D 31337 -f -C -q -N user@remoteserver

    dove user@remoteserver è il server che mette a disposizione l’accesso ssh e su cui abbiamo utenza con utente user. Vi sarà richiesto di inserire la password per l’utente user, inseritela e il tunnel verrà creato [se avete impostato l’accesso tramite chiavi asimmetriche, non dovrete digitare alcuna password].

    Veniamo alla spiegazione dei vari parametri, in modo che possiate customizzare il comportamento del tunnel:

    • -D 31337: imposta un tunnel che faccia il forward verso un indirizzo dinamico, impostato sulla porta specificata come argomento (in questo caso 31337/tcp)
    • -f: forza ssh ad andare in background dopo che abbiamo effettuato il login correttamente
    • -C: abilita la compressione
    • -q: disabilita gli warning dall’output
    • -N: non eseguire alcun comando remoto (visto che dobbiamo solo creare un tunnel)

    La creazione del tunnel è finita! Il vostro tunnel è attivo su localhost:31337 e se avete impostato tutto con criterio potete iniziare ad utilizzarlo.

    Un use-case interessante è configurare il browser Firefox per la navigazione facendo in modo che tutto il traffico sia routato attraverso il tunnel appena creato. Apriamo Firefox e digitiamo about:config nella barra dell’indirizzo. Digitate proxy nella barra del filtro, e vi comparirà la seguente schermata:

    Le voci a cui siamo interessati sono quelle marchiate da un bollino rosso, e dobbiamo modificarle a:

    • network.proxy.no_proxies_on : localhost, 127.0.0.1
    • network.proxy.socks : 127.0.0.1
    • network.proxy.socks_port : 31337. Questa opzione, come avete capito, specifica la porta su cui è attivo il tunnel
    • network.proxy.socks.remote_dns : true. Questa opzione è la più importante, perché permette di fare il forward delle richieste DNS all’host remoto. Consiglio di abilitarla.
    • network.proxy.socks_version : 5
    • network.proxy.type : 1. Questa opzione specifica se utilizzare le impostazioni appena definite per il tunnel (= 1) oppure no (= 0).

    Ora il test finale: usando Firefox controllate quale sia il vostro indirizzo IP. Se vi compare l’indirizzo del vostro server remoto, allora il tunnel funziona alla perfezione. Viceversa, c’è qualcosa di sbagliato nella vostra configurazione; ripartite dall’inizio e controllate che tutto sia configurato correttamente.

  • Come impostare ssh in modo che non richieda la password di accesso (chiavi asimmetriche per il login)

    Alcuni client ssh permettono di definire “sessioni salvate” di connessioni in modo che username e password vengano salvati e non vengano richiesti ad ogni connessione verso un host. Trovo che permettere all’utente di poter salvare la password sia profondamente sbagliato dal punto di vista della security, soprattutto se l’utente ha privilegi non indifferenti sulla macchina remota [ad esempio è nei sudoers].

    Detto questo, trovo anche che sia abbastanza noioso inserire la propria password ad ogni connessione. Ma non disperate: il meccanismo standard per risparmiarvi preziosi secondi esiste e ve lo spiegherò tra poco. Inoltre, il meccanismo standard è sicuro di per sé e non indebolisce la struttura di ssh perché utilizza un’autenticazione basata sulla crittografia asimmetrica.

    Innanzitutto: queste istruzioni sono per Linux e OSX. In futuro posterò anche le istruzioni per Windows/PuTTY.

    Obiettivo: loggarsi dalla macchina locale (local) alla macchina remota (remote) senza inserire la password

    Sulla macchina locale: generare le chiavi di autenticazione [1/2]

    Le chiavi di autenticazione sono composte da 2 chiavi, una pubblica e una privata. La chiave pubblica rappresenta la nostra identità nel mondo esterno. La chiave privata, invece, rappresenta la nostra chiave segreta, la nostra “password” [anche se è molto più lunga di una password].

    Per generare le chiavi bisogna dare questo comando:
    local$ ssh-keygen -t rsa
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/mbologna/.ssh/id_rsa):

    Accettate il path che vi viene proposto premendo Invio
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:

    Vi consiglio fortemente di inserire una password a questo punto. Nonostante molte persone consiglino (sbagliando) di non inserire una password perché si ripeterebbe il problema di dover inserire una password, vi posso assicurare che impostare un ulteriore livello di sicurezza per poter accedere ad un file così delicato come la vostra chiave privata è più che consigliato [e per sfatare un falso mito: non è vero che bisogna reinserire la password, basta affidarsi a un’implementazione sicura di ssh-agent].

    Ora controllate che effettivamente il comando abbia creato le vostre chiavi:

    local$ ls -la .ssh/
    drwx------  2 mbologna mbologna   4096 2009-09-24 18:43 .
    drwx------ 55 mbologna mbologna   4096 2009-11-13 00:42 ..
    -rwx------  1 mbologna mbologna   1743 2009-08-04 16:52 id_rsa
    -rwx------  1 mbologna mbologna    433 2009-08-04 16:52 id_rsa.pub

    id_rsa contiene la vostra chiave privata, mentre id_rsa.pub contiene la vostra chiave pubblica.

    Sulla macchina remota: autorizzare l’autenticazione tramite chiave pubblica [2/2]

    Loggatevi sulla macchina remota inserendo la vostra password [per l’ultima volta :)]:

    local$ ssh username@remote
    A questo punto seguite i seguenti passi:

    • create una directory .ssh nella vostra home mkdir .ssh
    • impostate i permessi appropriati chmod 700 .ssh
    • spostatevi nella directory .ssh cd .ssh
    • create un file chiamato authorized_keys touch authorized_keys
    • impostate i permessi approppriati chmod 600 authorized keys
    • aprite il file authorized_keys con il vostro editor preferito [ad esempio vi] vi authorized_keys
    • copiate e incollate il contenuto del file ~/.ssh/id_rsa.pub presente su local nel file authorized_keys
    • fate un logout

    Abbiamo finito! Ora potete semplicemente loggarvi sulla macchina remote semplicemente con ssh username@remote

    Nota: se non volete digitare la password ogni volta che accedete alla vostra chiave privata, date un’occhiata a ssh-agent.

  • Come creare un tunnel SSH dinamico con PuTTY

    imageAvete bisogno di un tunnel SSH? Ci sono molteplici ragioni per utilizzarlo; se state cercando di realizzare un tunnel sicuramente ne avrete già in mente (almeno) una.

    Passiamo all’opera. Requisito fondamentale: un server Linux con accesso ssh e che permetta ssh tunneling (Ubuntu e quasi tutte le altre distribuzioni con openssh-server di default lo permettono).

    Apriamo PuTTY e cominciamo:

    1. Inserite l’host del vostro server come in figura
    2. Spostatevi nel tab Connection -> SSH -> Tunnels
    3. Nel campo Destination, impostate Dynamic
    4. Scegliete una porta TCP che sapete essere libera sulla vostra macchina locale (un numero >= 1024 potrebbe andare bene) e inserite il numero nel campo Source portimage
    5. Premete Add
    6. Premete ora su Open, connettetevi al vostro server in ssh specificando username e password e lasciate aperta la sessione

    A questo punto il tunnel è creato su localhost, sulla porta TCP che avete specificato come source port: aprite il programma con cui volete sfruttare il tunnel appena creato e specificate di usare un proxy SOCKS5 con indirizzo localhost e come porta la source port che avete scelto.

    A titolo di esempio, usiamo Firefox per sfruttare il tunnel appena creato:

    1. Aprite Firefox
    2. Controllate su www.whatismyip.com quale sia il vostro indirizzo IP e annotatelo
    3. Andate in Strumenti -> Preferenze
    4. Andate su Avanzate e poi nel tab Rete, poi su Connessioni e infine Impostazioni
    5. Cliccate su “Configurazione manuale dei proxy” e inserite nel campo Host SOCKS: l’indirizzo IP del computer locale (127.0.0.1) e come porta la source port che avete scelto in PuTTY (nel mio caso, la 17222)image
    6. Cliccate su OK e chiudete tutte le opzioni che avete aperto
    7. Aprite di nuovo il sito www.whatismyip.com e controllate l’indirizzo IP: se il tunnel sta funzionando correttamente, l’indirizzo IP mostrato è diverso da quello visualizzato al punto 2.
  • Il miglior client SSH per Windows: PuTTY Tray

    Sono sempre stato alla ricerca di un client SSH per Windows con svariate funzionalità per me necessarie:

    • URL hyperlinking (al passaggio del mouse su un URL, alla pressione del tasto sinistro del mouse voglio visitare tale URL)
    • Riconnessione automatica (in caso di disconnessione)
    • Supporto al login mediante chiavi RSA

    Fino ad ora, PuTTY aveva quel che mi serviva, ma purtroppo non aveva URL hyperlinking… finalmente ho trovato tutto questo in PuTTY Tray!