📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 65편
이전 글: 64. SFTP · 다음 글: 66. Telnet과 평문 프로토콜의 위험
SSH(Secure Shell)는 TCP 22번에서 동작하는 암호화된 원격 접속 프로토콜입니다. 서버 구성, 인증 방식, sshd_config 설정, Brute Force 로그 분석은 리눅스 시리즈에서 이미 다뤘습니다.
이 글은 "22번 포트 위에서 무엇이 오가는가"만 봅니다. 핵심은 SSH가 하나의 TCP 연결 안에 여러 용도(셸, 파일 전송, 터널)를 채널로 겹쳐 싣는 프로토콜이라는 점입니다.
| 항목 | 값 |
|---|---|
| 전송 계층 | TCP |
| 기본 포트 | 22 (IANA 등록) |
| 표준 | RFC 4251(구조), 4253(전송), 4252(인증), 4254(연결) |
| 암호화 시작 시점 | 키 교환 완료(NEWKEYS) 이후 |
| 같은 포트를 쓰는 기능 | 원격 셸, 명령 실행, SFTP·SCP, 포트 포워딩 |
SSH 연결은 세 계층 프로토콜이 차례로 올라가는 구조입니다.
클라이언트 192.168.10.10:51544 서버 192.168.10.20:22
│ ── TCP 3-Way Handshake ─────────────────────→ │
│ ←─ "SSH-2.0-OpenSSH_8.7" (평문 식별 문자열) ── │
│ ── "SSH-2.0-OpenSSH_9.6" (평문) ─────────────→ │
│ │
│ ⇄ KEXINIT: 지원 알고리즘 목록 교환 (평문) │ ← 전송 계층
│ ⇄ 키 교환 (예: curve25519) + 서버 호스트 키 전달 │ (RFC 4253)
│ ⇄ NEWKEYS ── 이후 전부 암호화 ──────────────── │
↓ ↓
│ ⇄ 사용자 인증 (password / publickey 등) │ ← 인증 계층 (RFC 4252)
↓ ↓
│ ⇄ 채널 열기: session / direct-tcpip ... │ ← 연결 계층 (RFC 4254)
│ 채널 1: 셸 채널 2: sftp 서브시스템 │
22번 위에 실리는 대표 채널 유형입니다.
| 용도 | 채널·요청 유형 | 클라이언트 예 | 네트워크에서 보이는 모습 |
|---|---|---|---|
| 대화형 셸 | session + shell | ssh user@host | 작은 패킷이 키 입력 간격으로 오감 |
| 명령 실행 | session + exec | ssh host 'uptime' | 짧은 세션 |
| 파일 전송 | session + subsystem sftp | sftp, 최신 scp | 한 방향으로 큰 전송량 |
| 로컬 포워딩 | direct-tcpip | ssh -L | 22번 안에 다른 서비스 트래픽 |
| 원격 포워딩 | tcpip-forward 요청 | ssh -R | 서버 쪽에서 새 포트가 LISTEN |
| 동적 포워딩 | direct-tcpip (SOCKS) | ssh -D | 여러 목적지로 가는 트래픽이 22번 하나로 합쳐짐 |
같은 SSH라도 텔넷·FTP와 비교하면 관제 관점의 차이가 뚜렷합니다.
| 비교 | SSH (22) | Telnet (23) | FTP (21) |
|---|---|---|---|
| 인증 정보 | 암호화 | 평문 | 평문 |
| 명령 내용 | 네트워크에서 안 보임 | 보임 | 보임 |
| 연결 수 | TCP 1개 (채널 다중화) | 1개 | 제어+데이터 분리 |
| 네트워크 식별 근거 | 식별 문자열, KEXINIT | 협상 옵션 | 응답 코드 |
포트를 22가 아닌 번호로 바꿔도 첫 데이터가 SSH-2.0-으로 시작하므로 프로토콜은 그대로 식별됩니다(93. 서비스와 포트 매핑 — 포트 번호만으로 서비스를 단정하면 안 되는 이유 참고).
실습 예시 — 본인 소유 VM 두 대(클라이언트 192.168.10.10, 서버 192.168.10.20), 인터페이스 ens33은 예시입니다.
# 서버: 22번 LISTEN과 프로세스 확인 (Rocky/Ubuntu 공통)
sudo ss -tlnp 'sport = :22'
# 서버: 22번 캡처 (평문 구간 확인용, -A로 ASCII 표시)
sudo tcpdump -nn -i ens33 -A 'tcp port 22' -c 30
# 클라이언트: 식별 문자열만 확인 (nc 패키지: Rocky nmap-ncat / Ubuntu netcat-openbsd)
nc 192.168.10.20 22
# 클라이언트: 협상 과정 상세 출력
ssh -v user@192.168.10.20 exit
ssh -v 출력 형식 예시(값은 환경마다 다름, 일부 생략):
debug1: Connecting to 192.168.10.20 [192.168.10.20] port 22.
debug1: Local version string SSH-2.0-OpenSSH_9.6
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.7
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: Authentications that can continue: publickey,gssapi-with-mic,password
| 줄 | 확인 포인트 |
|---|---|
remote software version | 서버가 평문으로 알린 버전. 스캐너도 같은 정보를 수집 |
kex: algorithm | 키 교환 방식. 이 이후부터 암호화 |
Authentications that can continue | 서버가 허용하는 인증 방식 |
포트를 바꾸는 경우 배포판별 추가 조치가 있습니다.
| 항목 | Rocky Linux | Ubuntu |
|---|---|---|
| 설정 | /etc/ssh/sshd_config의 Port | 같음 |
| 추가 조치 | SELinux에 포트 등록 (semanage port -a -t ssh_port_t -p tcp 2222) | 22.10 이후 버전은 소켓 활성화(ssh.socket) 사용 시 systemctl daemon-reload 후 소켓 재시작 필요 |
| 방화벽 | firewall-cmd로 새 포트 허용 | ufw allow 2222/tcp |
📷 [실습 화면 삽입 위치] tcpdump -A 출력에서
SSH-2.0-OpenSSH_...문자열과 알고리즘 이름 목록이 평문으로 보이고, 이후 패킷은 읽을 수 없는 부분
AllowTcpForwarding no 등으로 제한합니다.-R 포워딩을 열면, 외부에서 내부로 들어오는 통로가 됩니다. Inbound 정책만으로는 보이지 않습니다.| 흔적 위치 | 확인할 수 있는 것 |
|---|---|
| 방화벽 로그 | 출발지·목적지, 세션 시간, 송수신 바이트 |
NSM(Zeek ssh.log 등) | 클라이언트·서버 식별 문자열, 협상 알고리즘, 호스트 키 |
| IDS/IPS | SSH 버전 문자열 기반 규칙, 짧은 연결 반복(대입 시도) 임계치 |
| 서버 인증 로그 | 계정, 인증 방식, 성공·실패 (Rocky /var/log/secure, Ubuntu /var/log/auth.log) |
관제자가 확인할 질문
SSH-2.0- 식별 문자열이 보이는가?오탐 주의: 백업·배포 자동화(rsync, Ansible 등)는 SSH로 긴 세션과 대용량 전송을 만듭니다. 목적지와 시간대가 일정한지, 등록된 관리 서버인지 먼저 확인합니다. 네트워크에서는 내용이 보이지 않으므로 판단은 서버 인증 로그와 연계해야 합니다.
SSH-2.0-...)과 KEXINIT 알고리즘 목록까지는 평문이고, 이후는 모두 암호화됩니다.