Návody - OpenSSH bezpečně

Bezpečné používání přístupového serveru

Bezpečné používání přístupového serveru

O čem je ten dlouhý text?

V následujícím textu si vysvětlíme proč a ukážeme jak bezpečně používat SSH pro přístup na servery bez přímého přístupu. Tedy v situacích kdy se např. na servery v rámci firemního prostředí připojujeme přes zprostředkující, tzv. přístupový server. V textu se zabýváme především vysvětlení co je a jak funguje tzv. "SSH agent forwarding" a jak ho používat správně, na konci pak, jak se přihlašovat na vzdálené servery bezpečnějším způsobem.

Proč to potřebuju vědět?

Při přístupu k počítačovým prostředkům je z hlediska bezpečnosti důležité zajistit důvěrnost autentizačních nástrojů, jako např. privátních klíčů, které by v opačném případě mohly být použity k vystupování pod identitou oběti. Může to být podobný problém, jako když si někdo na váš občanský průkaz v bance zařídí finanční půjčku.

Když nechceme aby někdo uhádl naše heslo, používáme SSH klíče

Poměrně běžným bezpečnostním doporučením je vypnutí možnosti přihlášení na SSH server pomocí hesla a upřednostnění nebo i vynucení autentizace tzv. "ssh klíčem." Ten se skládá z privátní a veřejné části, přičemž privátní klíč by měl být uživatelem náležitě chráněn, tak aby jej mohl použít pouze oprávněný uživatel. Z tohoto důvodu se privátní klíč má běžně nacházet pouze na straně ssh klienta.

Proč někdy potřebujeme přístupový server (jumpserver)

SSH klient (např. opensource klient OpenSSH) je často používán pro bezpečný přístup na vzdálený server. V situaci kdy se tímto způsobem potřebujeme připojit na server, který není přístupný přímo z klientského počítače uživatele můžeme použít tzv. "přístupový server" (taktéž se mu říká "jump server"), ze kterého už spojení s cílovým serverem možné je.

Když nepoužívám jumpserver tak se mě to netýká?

Výše popsaný problém se bohužel často týká i uživatelů, který jumpserver nepoužívají! SSH agent forwarding je totiž často zapnutý aniž by si to uživatelé uvědomovali.

Jak se ale na cílový server přihlásíme, když na přístupovém serveru není privátní klíč?

V situaci kdy potřebujeme pro připojení k cílovému serveru využít přístupového serveru by jsme mohli nabýt dojmu, že potřebujeme mít privátní klíč i na tomto přístupovém serveru. To by však mohlo znamenat zásadní ohrožení tohoto privátního klíče! Pro tento účel se tedy běžně využívá funkce "SSH agent forwarding" (u OpenSSH přepínač "ssh -A"). Při přihlašování z přístupového serveru na server cílový, pak ssh klient spuštěný na přistupovém serveru komunikuje s ssh agentem běžícím na klientské straně a umožňuje tak použití privántího klíče uloženého na klientské straně pro přihlášení na cílový server. Privátní klíč tak není třeba z klientského počítače nikam kopírovat!

Přepínači -A/-a explicitně říkáme, zda serveru kam se hlásíme chceme, či nechceme umožnit komunikaci s ssh agentem prostřednictvím SSH agent forwardingu. Běžně použijeme SSH agent forwarding cca následovně.

Na svém notebooku máme v ssh agentovi nahraný klíč, přihlašujeme se na jumpserver a protože se z něj budeme potřebovat autentizovat na cilovy_server, povolujeme SSH agent forwarding (ssh -A).

[user@user-nb ~]$ ssh-add -l
256 SHA256:WeHvenxLK3gYXORFm2hed4MMee1 user@user-nb (ED25519)
[user@user-nb ~]$ ssh user@jumpserver -A

Po úspěšném přihlášení, zkontrolujeme zda je funkční komunikace s ssh-agentem na našem notebooku (tedy funkční SSH agent forwarding).

[user@jumpserver ~]$ ssh-add -l
256 SHA256:WeHvenxLK3gYXORFm2hed4MMee1 user@user-nb (ED25519)

Z jumpserveru se přihlašujeme na cilovy_server. SSH agent forwarding zajistí, že se autentizujeme ssh klíčem z našeho notebooku. Protože se z cílového serveru už nebudeme přihlašovat nikam dál, explicitně říkáme (ssh -a), že cilovému serveru, už komunikaci s ssh agentem nepovolujeme.

[user@jumpserver ~]$ ssh user@cilovy_server -a
[user@cilovy_server ~]$ ssh-add -l
Could not open a connection to your authentication agent. 

Jak ten "SSH agent forwarding" funguje?

SSH příkaz spouštěný na přístupovém serveru si pro účely komunikace s ssh agentem běžícím na klientské straně vytváří na přístupovém serveru v privátním adresáři uživatele tzv. "socket", což je na operačních systémech UNIXového typu speciální soubor, který lze s použitím dostatečných oprávnění číst a zapisovat do něj a rychlým způsobem tak komunikovat s programy, které tento socket používají.

Jak program ssh při spouštění pozná s kterým socketem si má povídat?

Cesta ke správnému socketu je v rámci prostředí přihlášeného uživatele používajího "SSH agent forwarding" uložená v proměnné prostředí SSH_AUTH_SOCK a socket lze též nalézt přímo na souborovém systému jako jakýkoli jiný soubor. Použití socketu je chráněno stejně jako jakýkoli jiný soubor na disku jemu přiřazenými oprávněními.


Když je socket soubor na disku, nemůže ho použít někdo kdo by neměl?

Za normální situace může socket číst pouze příslušný uživatel, který socket vytvořil. V operačním systému však existují i uživatelé s vyššími oprávněními, jako např. root, případně můžeme uvažovat situaci kdy zvýšené oprávnění na přístupovém serveru získala osoba nepovolaná, či nedůvěryhodná.

Problém 1. - Použití SSH klíče jiného uživatele

Problém 1. - Použití SSH klíče jiného uživatele

Zajímalo Vás někdy jak přesně postupuje takový útočník nebo hacker? Budeme mu teď chvíli koukat přes rameno a uvažovat jako on.

Jedním z potenciálně možných útoků realizovatelných prostřednictvím přístupového SSH serveru je únos identity prostřednictvím komunikace s SSH agentem jiného uživatele.

Podmínky pro provedení únosu identity touto metodou:

  • oběť má aktuálně živou session na přístupovém serveru (jumpserver), zapnutý tzv. agent forwarding (ForwardAgent na straně openssh klienta, AllowAgentForwarding na straně ssh serveru, případně přepínač „ssh -A“) a na přístupový server přeposílá konkrétní SSH klíče.
  • útočník má právo číst socket SSH agenta. Toto právo typicky běžný uživatel nemá. Uživatel s vyššími oprávněními, jako např. root, však ano.

Útočník v tomto případě typicky nezíská privátní klíč oběti, ale získá možnost jej použít pro autentizaci pod identitou oběti.

Jak můžu, coby uživatel s vyšším oprávněním, použít SSH klíč jiného uživatele?

Průběh případného únosu identity použitím ssh-agenta jiného uživatele (přihlášení na ssh server dostupný prostřednictvím přístupového serveru) může vypadat následovně.

Na disku prohledám typická místa kde si ssh agent sockety běžně vytváří.
[root@jumpserver ~]# ls -lad /tmp/ssh-*
drwx------ 2 user    user    60 Mar 19 14:26 /tmp/ssh-301kk4eRiGiG
drwx------ 2 ruzicka ruzicka 60 Apr  2 23:38 /tmp/ssh-v4HEU6uAFS

Vidíme, že aktuálně jsou pravděpodobně přihlášeni dva uživatelé (user a ruzicka) používající SSH agent forwarding. Pro každého byl na přístupovém serveru automaticky vytvořen adresář obsahující příslušný socket.

Mého vlastního ssh agenta změnou hodnoty proměnné prostředí v rámci aktuálního sezení přesvědčím, že má komunikovat přes socket jiného uživatele.

[root@jumpserver ~]# export SSH_AUTH_SOCK=/tmp/ssh-301kk4eRiGiG/agent.1811

Pro správné fungování změním i druhou proměnnou prostředí obsahující číslo procesu ssh agenta jiného uživatele. Toto číslo zjistím buď ve výpisu běžících procesů nebo jej vyčtu z názvu socketu.

[root@jumpserver ~]# SSH_AGENT_PID=1811

Teď už můžeme vypsat seznam klíčů, který má oběť nahrané v ssh agentovi na svém notebooku (klient).

[root@jumpserver ~]# ssh-add -l
256 SHA256:WeHvenxLK3gYXORFm2hed4MMee1 user@user-nb (ED25519)

Tím jsme úspěšně ověřili, že jsme schopni komunikovat s ssh agentem oběti. Privátní klíče běžně takto nezískáme, ale můžeme teď vzdálený cílový server přesvědčit, že k nim přístup máme, i když to není pravda. Ve chvíli kdy se nás vzdálený cílový server pokusí autentizovat přenecháme práci ssh agentovi oběti. V tuto chvíli už nejde o nic složitého. Prostě se připojíme někam, kde oběť klíč, v ssh agentovi přítomný, používá. Např. na zmiňovaný cílový server.

[root@jumpserver ~]# ssh user@cilovy_server
[user@cilovy_server ~]$ exit

A jsme tam! :)

Problém 2. - Kompromitace účtu jiného uživatele

Problém 2. - Kompromitace účtu jiného uživatele

Ještě nemáte dost?

Nebylo to dost drsné? Pojďme tedy sledovat uvažování útočníka, který se s tímto nespokojí a bude hloubat dál.

Může být ještě hůř!

Doteď jsem v textu tvrdil, že útočník se k privátnímu klíči nedostane. Na rovinu, něco jsem vám doteď trochu zamlčel. Ale bylo to především proto, aby vás to nepletlo při chápání psaného textu. Teď, když už pravděpodobně chápete jak funguje výše popsané, můžeme postoupit na další úroveň.

Co jsem vám doteď zamlčel?

Důvěrnost privátního klíče by totiž mohla být narušena (došlo by k vyzrazení privátního klíče útočníkovi) v případě, že by některý z klíčů přeposílaných ssh agentem bylo možné použít k autentizaci na ssh server klienta, tedy tam kde oběť má privátní část klíče uloženu, tedy např. typicky ssh server na notebooku oběti. Tato varianta předpokládá možnost navázání spojení z přístupového serveru (jumpserver) na stroj oběti.

Obdobným postupem může tedy být možná až autentizace na notebook oběti:
[root@jumpserver ~]# ssh user@user-nb
[user@user-nb ~]

Když už jsme na notebooku oběti, tak najít příslušný ssh klíč na souborovém systému je poměrně hračka.

[user@user-nb ~]$ head -n 1 .ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----

V čem je tohle větší problém než to první?

Pořád ještě je vysoká šance, že je tento klíč před otevřením chráněn tzv. passphrází (něco jako heslo), ale když už jsme se, coby útočník, dostali na notebook oběti, můžeme si tento soubor zkopírovat k sobě, kde passphrázi můžeme zkoušet libovolně dlouho uhodnout, případně můžeme oběti napáchat na jeho notebooku spoustu všelijakých lotrovin, včetně získání mnoha dalších informací. Možnosti jsou v této fázi tak široké, že je zde už jen těžko lze všechny popsat.

Řešení

Řešení:

Možnost zneužití lze omezit:

  • • přeposíláním pouze skutečně používaných klíčů přes jumpserver, např. pomocí voleb IdentitiesOnly a IdentityFile v konfiguraci klienta (~/.ssh/config).
  • • Nepoužívat ssh klíč používaný pro autentizaci na servery zároveň i pro autentizaci na klientskou stranu, tedy „na notebook“. Pro autentizaci na zařízení uživatele (notebook, PC, tablet, mobil,..) používat pouze pro tento účel určený ssh klíč.
  • • Omezit přístup na účtům s právy root na přístupovém serveru (jumpserver) pouze na důvěryhodné uživatele.
    • ProxyJump

      Od OpenSSH klienta verze 7.3 lze využít na straně klienta konfigurační volbu ProxyJump pro specifikaci přístupového serveru. Jedná se o vylepšenou formu starší konfigurační volby ProxyCommand (kterou lze použít u starších SSH klientů) využívající tunelovaní pomocí TCP forwardingu.

      Připojení na cílový server si pak lze představit následovně:

      Na přístupovém serveru jumpserver se při využití TCP tunelování nevytváří adresářová struktura pro SSH socket uživatele ruzicka jako je tomu v případě využití agent forwardingu.

      [ruzicka@jumpserver ~]$ ls -lad /tmp/ssh-*            
      drwx------ 2 user user 60 Mar 19 14:26 /tmp/ssh-301kk4eRiGiG
      

      Z jumpserveru tedy není možné výše popsaným způsobem komunikovat s ssh agentem potenciální oběti.

      Doporučovaná konfigurace SSH klienta

      Konfigurace SSH klienta (~/.ssh/config) využívající TCP forwarding:

      ForwardAgent no
      ForwardX11 no
      ForwardX11Trusted no
      
      Host jumpserver
      HostName 10.0.0.22
      User ruzicka
      
      Host *.firma.cz
      User ruzicka
      ProxyJump jumpserver
      

      Aha, to je zajímavé. Jak to teda mám použít?

      Pokud vás zajímá jak detailně vypadá průběh takového připojení, pročtěte si následující výpis. Všimněte si, že při zadávání příkazu nemusím psát nic o připojování na jumpserver (klient to pochopi z konfigurace), ale nejen to! Do SSH příkazu totiž rovnou můžu napsat jméno cílového serveru, i když je to název v internetu neznámý.

      $ ssh cilovy_server.firma.cz -v
      OpenSSH_7.6p1, LibreSSL 2.6.2
      debug1: Reading configuration data /home/ruzicka/.ssh/config
      debug1: /home/ruzicka/.ssh/config line 10: Applying options for *.firma.cz
      debug1: Reading configuration data /etc/ssh/ssh_config
      debug1: /etc/ssh/ssh_config line 48: Applying options for *
      debug1: Setting implicit ProxyCommand from ProxyJump: ssh -v -W '[%h]:%p' jumpserver
      debug1: Executing proxy command: exec ssh -v -W '[cilovy_server.firma.cz]:22' jumpserver
      ...
      debug1: Reading configuration data /home/ruzicka/.ssh/config
      debug1: /home/ruzicka/.ssh/config line 5: Applying options for jumpserver
      debug1: Reading configuration data /etc/ssh/ssh_config
      debug1: /home/ruzicka/.ssh/config line 5: Applying options for jumpserver
      debug1: Reading configuration data /etc/ssh/ssh_config
      debug1: /etc/ssh/ssh_config line 48: Applying options for *
      debug1: Connecting to 10.0.0.22 port 22.
      debug1: Connection established.
      ...
      debug1: Authenticating to 10.0.0.22:22 as 'ruzicka'
      ...
      debug1: Host '10.0.0.22' is known and matches the ECDSA host key.
      debug1: Found key in /home/ruzicka/.ssh/known_hosts:4
      ...
      debug1: Authentications that can continue: publickey
      debug1: Offering public key: RSA SHA256:hqwHk9kn720i+3F/pHIK53dbgZggtYVWgA6MIyVgxCk .ssh/nethemba
      debug1: Server accepts key: pkalg rsa-sha2-512 blen 535
      debug1: Authentication succeeded (publickey).
      Authenticated to 10.0.0.22 ([10.0.2.17]:22).
      debug1: channel_connect_stdio_fwd cilovy_server.firma.cz:22
      ...
      debug1: Authenticating to cilovy_server.firma.cz:22 as 'ruzicka'
      ...
      debug1: Host 'cilovy_server.firma.cz' is known and matches the ECDSA host key.
      debug1: Found key in /home/ruzicka/.ssh/known_hosts:5
      ...
      debug1: Authentications that can continue: publickey,password
      debug1: Offering public key: RSA SHA256:hqwHk9kn720i+3F/pHIK53dbgZggtYVWgA6MIyVgxCk .ssh/nethemba
      debug1: Server accepts key: pkalg ssh-rsa blen 535
      debug1: Authentication succeeded (publickey).
      Authenticated to cilovy_server.firma.cz (via proxy).
      ...
      
      Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-115-generic x86_64)
      
      Last login: Mon Apr  9 04:21:21 2018 from nekde.firma.cz
      
      [ruzicka@cilovy_server.firma.cz ~]$ w -i
       04:38:32 up 48 days, 19:59,  2 users,  load average: 0.00, 0.02, 0.05
      USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
      ruzicka  pts/3    10.0.0.22        04:23    2.00s  0.01s  0.00s w -i
      

      Poznámka na konec:Je dobré si uvědomit, že uživatel s vysokým oprávněním na úrovni uživatele root má samozřejmě mnoho dalších možností zásahů do síťové komunikace, přístupu do paměti, apod., než jenom výše do pozornosti uvedená možnost komunikace přes cizí socket. Téměř vždy je však jejich provedení složitější než postup výše uvedený.