- SSH는 원격 접속을 넘어 포트 포워딩, 점프 호스트, 설정 파일, 키 관리까지 묶어 다루는 도구이며, 웹 서버 예시는 RDP·SQL 같은 다른 서비스에도 그대로 응용 가능함
- 로컬·원격·동적 포트 포워딩은 각각
-L, -R, -D로 구성되며, 포트가 어느 쪽에 열리고 트래픽이 어디로 흐르는지가 핵심 차이임
- 직접 접근이 막힌 네트워크에서는
-J 점프 호스트와 ProxyJump로 여러 SSH 경유지를 연결해 목적지까지 들어갈 수 있음
ssh-agent와 -A 에이전트 포워딩은 원격 호스트에서도 로컬 키를 쓰게 해 편리하지만, 에이전트 오용에 따른 보안 위험을 먼저 확인해야 함
~/.ssh/config, ssh-copy-id, ssh-keygen, SSH 콘솔 ~?·~C를 함께 쓰면 반복 옵션 입력을 줄이고 세션 중 포워딩 추가, 공개키 배포, 키 생성·검사가 쉬워짐
SSH 포트 포워딩을 이해하기 위한 전제
- SSH 포트 포워딩은 다이어그램만으로는 흐름을 잡기 어려워, 실제 명령과 네트워크 시나리오를 함께 봐야 이해하기 쉬움
- 예시는 웹 서버 접근을 기준으로 하지만, 같은 방식은 RDP, SQL 등 거의 모든 서비스에 적용 가능함
- 반복해서 쓰는 옵션은 다음 의미를 가짐
-N: 원격 서버에서 명령을 실행하지 않고 셸도 열지 않음
-f: SSH를 백그라운드로 보냄
root@host: 터널을 만들 사용자와 호스트로 로그인함
로컬 포트 포워딩 -L
- 로컬 포트 포워딩은 로컬 머신의 포트를 원격 서버의 포트로 전달함
- 예시 상황
internal-web.int가 루프백 인터페이스에서만 접근 가능한 웹 페이지를 호스팅함
campfire.int에서 internal-web.int로 SSH 접근이 가능함
campfire.int의 로컬 포트를 통해 internal-web.int의 웹 서버에 접근하려 함
- 사용 명령
ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int
- 옵션 해석
-L: 로컬 포워딩을 지정함
1337:127.0.0.1:80: 로컬 포트 1337을 원격의 127.0.0.1:80에 바인딩함
- 터널 생성 후에는
campfire.int에서 로컬 포트 1337로 요청을 보내 internal-web.int의 포트 80과 상호작용할 수 있음
- 기억할 점은
-L에서는 로컬 포트가 주소의 왼쪽에 온다는 것임
원격 포트 포워딩 -R
- 원격 포트 포워딩은 로컬에서 접근 가능한 포트를 원격 서버의 포트로 노출함
- 예시 상황
internal-web.int는 루프백에서만 접근 가능한 웹 페이지를 호스팅함
campfire.int는 방화벽 때문에 internal-web.int에 직접 접근할 수 없음
vuln-server.int는 campfire.int와 internal-web.int 양쪽에서 접근 가능함
- 사용 명령
ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int
- 옵션 해석
-R: 원격 포워딩을 지정함
3000:127.0.0.1:80: vuln-server.int의 포트 3000을 로컬의 127.0.0.1:80에 바인딩함
- 이후
vuln-server.int:3000으로 curl 요청을 보내면 internal-web.int의 포트 80에서 동작하는 내부 웹 페이지에 접근할 수 있음
- 기억할 점은
-R에서는 로컬 포트가 주소의 오른쪽에 온다는 것임
동적 포트 포워딩 -D와 SOCKS 프록시
- 동적 포트 포워딩은
-D 옵션으로 SOCKS 프록시를 만들고 트래픽을 SSH 경유지로 보냄
- 예시 상황
internal-web.int는 내부 네트워크에서만 접근 가능한 웹 애플리케이션을 호스팅함
vuln-server.int는 같은 내부 네트워크에 있고 internal-web.int에 접근 가능함
campfire.int에서 vuln-server.int를 통해 트래픽을 프록시하려 함
/etc/proxychains.conf 설정은 SSH 명령의 포트와 맞아야 함
socks5: proxychains가 SOCKS5를 사용하게 함
127.0.0.1: 로컬호스트를 사용함
8080: SSH -D에 지정한 포트와 일치해야 함
- 사용 명령
ssh -N -f -D 8080 root@vuln-server.int
- 포워딩 생성 후
socks5 127.0.0.1 8080을 설정하면 proxychains curl 192.168.1.185로 내부 웹 페이지에 접근할 수 있음
- SOCKS를 통한 DNS는 환경에 따라 잘 되지 않을 수 있어 예시에서는 호스트명 대신 IP 주소를 사용함
- Firefox에서도 수동 프록시 설정으로 SOCKS 프록시를 사용할 수 있음
- 경로: Settings → Privacy & Security → Network Settings
- Manual proxy configuration 선택
- “Proxy DNS when using SOCKS V5” 체크
- SOCKS host를
127.0.0.1, port를 8080으로 설정함
점프 호스트 -J
- 점프 호스트는 현재 호스트에서 직접 접근할 수 없는 목적지에 여러 SSH 경유지를 거쳐 접속하게 함
- 예시 체인은
campfire.int → vuln-server.int → internal-web.int → dns.int임
- 사용 명령
ssh -J root@vuln-server.int,root@internal-web.int root@dns.int
- 여러 점프 대상은 쉼표로 구분함
에이전트 포워딩 -A
ssh-agent는 로컬 머신에서 ssh-add <private_key_file>로 개인 키나 ID를 추가할 수 있게 함
- 추가된 키는
ssh-add -l로 확인 가능함
ssh-agent에 키를 추가하면 비밀번호를 다시 입력하지 않고 해당 키로 SSH 접속할 수 있어 사람과 서비스 계정 모두에 유용함
-A 에이전트 포워딩은 접속한 원격 머신에서도 로컬 에이전트의 키를 사용할 수 있게 함
- 사용 전 보안 위험을 확인하려면 Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement를 참고해야 함
- 예시 명령
ssh -A -J root@vuln-server.int root@internal-web.int
- 이 명령은
vuln-server.int를 거쳐 internal-web.int에 접속하면서 로컬 campfire.int의 SSH 에이전트에 있는 키를 사용할 수 있게 함
- 이후
internal-web.int에서 ssh root@dns.int를 실행할 때 개인 키 지정이나 자격 증명 입력 없이 접속할 수 있음
TTY 명령 할당 -t
-t 옵션은 원격 서버에서 상호작용이 필요한 명령을 빠르게 실행할 때 유용함
- 예시는
Vim이나 top처럼 TTY가 필요한 명령임
- 사용 명령
ssh root@internal-web.int -t top
- 실행하면 원격 서버에서
top 명령을 포함한 TTY를 받게 됨
외부 호스트도 로컬 포워딩 포트에 붙게 하는 -g
-g 옵션은 원격 호스트가 로컬 포워딩된 포트에 접속할 수 있게 함
- 로컬 포트 포워딩
-L과 비슷하지만, 외부 머신에서도 해당 “로컬” 포트를 사용할 수 있게 하는 차이가 있음
- 예시 상황
vuln-server.int에 셸 접근이 있음
vuln-server.int의 포트 2222로 들어오는 연결을 internal-web.int의 포트 22로 프록시하려 함
- 사용 명령
ssh -N -f -g -L 2222:localhost:22 root@internal-web.int
- 옵션 해석
-g: 원격 호스트가 로컬 포워딩 포트에 연결할 수 있게 함
-L: 로컬 포워딩을 지정함
vuln-server.int의 포트 2222로 SSH 접속했더라도 실제 셸은 internal-web.int에 있게 됨
SSH 콘솔 ~?와 세션 중 포워딩
- SSH 콘솔은 원격 시스템과 직접 상호작용하지 않고 SSH 자체를 제어할 수 있는 숨겨진 기능임
- 셸이 깨졌거나 SSH 세션 자체를 제어해야 할 때 유용함
- 도움말 콘솔은
~?로 열 수 있음
- 유용한 옵션
~.: 현재 SSH 세션을 종료함
~C: SSH 콘솔을 열어 포워딩 옵션을 추가할 수 있음
- 이미 일반
ssh 명령으로 vuln-server.int에 접속한 상태에서도 ~C를 누르고 -D 8080을 입력하면, 해당 세션을 동적 포워딩 세션처럼 사용할 수 있음
campfire.int에서 /etc/proxychains.conf가 포트 8080을 사용하도록 설정되어 있으면, 처음부터 ssh -D로 시작한 것처럼 proxychains를 활용할 수 있음
SSH 설정 파일 ~/.ssh/config
- SSH 설정 파일은
~/.ssh/config에 있으며, 반복해서 입력하는 SSH 옵션을 저장해 시간을 줄여줌
- SSH 접속 시 이 파일을 파싱하고, 접속 대상에 맞는
host 설정이 있으면 해당 옵션을 사용함
- 명령줄 인자가 설정 파일보다 우선함
- 예를 들어 설정 파일에서
internal-web.int 사용자를 root로 지정했더라도 ssh graham@internal-web.int를 실행하면 graham으로 로그인 시도함
- 기본 설정 예시
# You can put comments with a `#` at the beginning of the line only.
host internal-web.int
User root
IdentityFile /home/smores/ssh_agent/internal-web-no-pw
Port 2222
ssh internal-web.int 실행 시 처리 흐름
- 명령줄의
internal-web.int와 ~/.ssh/config의 host internal-web.int를 매칭함
- 매칭되면 명령줄에서 지정하지 않은 옵션을 설정 파일에서 가져옴
- 매칭되지 않으면 명령줄에서 정의한 옵션만 사용함
자주 쓰는 SSH config 키워드
IdentityFile /path/to/private_key
- 호스트에 사용할 개인 키를 지정함
ssh -i와 같은 역할을 함
ForwardAgent
ProxyJump root@internal-web.int
- 트래픽을 프록시할 서버를 지정함
-J 옵션과 같은 역할을 함
- 예시에서는
vuln-server.int 인증을 먼저 요구해 트래픽이 해당 호스트를 거친다는 점을 보여줌
Match
- 조건에 따라 SSH config 키워드를 적용함
- 예시에서는
export | grep PROXYME=TRUE 명령의 종료 코드가 0이면 Match 블록 아래의 ProxyJump를 사용함
PROXYME 환경 변수가 없으면 일반 host internal-web.int 블록만 사용함
export PROXYME=TRUE 설정 후 같은 ssh internal-web.int를 실행하면 vuln-server.int 인증을 거친 뒤 internal-web.int 셸을 받음
scp와 일부 SSH 기반 유틸리티도 보통 SSH config를 사용할 수 있음
- 자동으로 사용하지 않는 환경에서는
-F ~/.ssh/config로 명시할 수 있음
공개키 복사 ssh-copy-id
ssh-copy-id 는 공개키를 서버에 빠르게 업로드하는 작은 유틸리티임
- 사용 명령
ssh-copy-id -i internal-web root@internal-web.int
- 옵션 해석
-i internal-web: 서버 인증에 사용할 개인 키 이름을 지정함
root@internal-web.int: 공개키를 업로드할 서버를 지정함
키 생성과 검사 ssh-keygen
ssh-keygen 은 개인키·공개키 쌍을 생성하는 유틸리티임
-b 옵션으로 더 큰 키 크기를 지정하는 방식이 일반적으로 권장됨
- 기본 키 크기는 예시 환경에서
3072였음
- 기본 알고리듬은 RSA지만,
-t 플래그로 다른 알고리듬을 지정할 수 있음
- 예:
ssh-keygen -t ecdsa -b 521
- 키의 지문과 바이트 크기는 다음 명령으로 확인할 수 있음
ssh-keygen -lf <file-name>