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.
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.
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.
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.
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.
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.
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í.
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.
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á.
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.
Ú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.
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! :)
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.
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ň.
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-----
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.
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.
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
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ý.