RDP 연결을 direct로 하지 않고 ssh 터널을 통해 연결하는 방법에 대한 내용이다.
문서에 후반부에 ssh key 방식 도입을 가이드하고 있으며, rdp 해킹(Inbound 접근)이 거의 불가능하게 막는 방법을 설명하고 있다.

아래 포스팅 글은 원리까지 설명하고 있어서 내용이 많고 좀 복잡하다.

RDP Connecting via SSH Tunnel [2] – mapoo's blog  : 바로 적용을 원한다면. 이 글을 추천한다.

목적

  • 보안 강화
    1) ssh 터널 통과로 인한 패킷 암호화
    2) rdp 포트 미노출
    3) administrator와 같은 관리자 계정 미노출
    ** 아래 내용 중 optional 부분을 적용하면 보안성이 강화됨

Server and Client 정보

  • RDP Server : Windows 2016 Server
  • RDP Client : Windows 10
    ** RDP 서버 클라이언트는 RDP가 지원되면 어떤 Windows 버전이든 상관 없음

 

연결 구성

연결도

RDP Port 번호 변경

where: rdp 서버에서

기존 3389에서 다른 포트 번호로 변경하기 (optional)
[참고] 원격 데스크톱 포트(3389) 변경하기

1. 레지스트리 수정

  • 윈도우 시작 - 실행 - regedit
    HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal ServerWdsrdpwdTdstcp

    -> 3389에서 3355로 변경

2. 서비스 관리자에서 Remote Desktop Services (재시작)

  • cmd 창에서 아래 명령으로 확인시 3355로 변경되었을을 확인할 수 있다.
    > netstat -an | findstr 3355

3. 방화벽 설정

  • 절차 :
    설정 - 방화벽 - 고급설정 - 인바운드 규칙 - 새 규칙 - 포트 - TCP/특정로컬포트: 3355 - 연결 허용 - 도메인/개인/공용 모두체크 - 이름: rdp - 마침
  • 본인은 3355 포트로 변경하였다.

OpenSSH 설치

where: rdp 서버에서

  • Windows 2016 Server는 sshd를 별도로 설치해 줘야한다.
  • Windows 10(2019년 이후 패치버전), Windows 2019 Server 의 경우에는 자체 내장된 sshd를 기능 추가해서 사용하면 된다.

1. 다운로드
OpenSSH for Windows 다운로드

2. 설치하기
OpenSSH Install on Win2016

3. 포트 변경하기

  • 기본포트 22에서 다른 포트로 변경한다 (Optional)
    > C:Program Files\OpenSSH-Win64\sshd_config_default
    --> 위 파일을 편집기로 열고 아래 열을 찾아서 주석을 제거 후 원하는 번호로 변경한다.
    Port 22
  • 본인은 8855 포트로 변경하였다.
  • 보안을 더 강화하기 위한 방법으로 Administrator 외에 계정을 만들고 해당 계정으로만 SSH가 접속되게 허용을 한다. (Optional)

4. 방화벽 설정

  • 절차 :
    Windows 방화벽 - 고급설정 - 인바운드 규칙 - 새 규칙 - 포트 TCP/특정로컬포트: 8855 - 연결 허용 - 도메인/개인/공용 모두체크 - 이름: sshd - 마침

5. 포트포워드
where: 공유기에서

  • 보통 Server 앞단에 물리적인 방화벽이 존재한다. 본인의 경우 앞단에 공유기가 있다.
  • 공유기에서 Windows 2016 Server의 NAT IP에 외부포트:TCP(7001~7100), 내부포트:TCP(8855) 포트포워드 룰을 적용 시킨다.
    -> 외부포트를 8855로 내부포트와 매칭해서 사용해도 상관 없다.
    -> 외부에서 공유기 Wan IP의 7001~7100 사이 포트로 접속하면 Windows 2016 Server의 OpenSSH Port 8855로 연결이 된다.
    ** rdp 포트는 포트포워드를 하지않기 때문에 rdp 포트가 외부에 노출되지 않는다.

ssh client 설치

where: rdp 클라이언트에서

1. 아래 사이트에서 purry msi 파일을 다운받아 설치
Putty for Windows 다운로드

2. ssh 접속 테스트

  • putty와 같은 ssh client 프로그램으로 공유기 Wan IP / 7001~7100 Port 로 연결을 시도해 보자.
  • ssh 연결이 잘되면 ssh 터널을 위한 준비된 것이다.

ssh 터널을 통한 rdp 연결

where: rdp 클라이언트에서

1. ssh 터널을 통한 rdp 접속확인

  • cmd 창을 열고 ssh 명령을 통해 아래와 같이 터널링을 만든다.
  • (사전에 Windows client에 ssh가 설치되어 있어야 한다. Windows 10에 ssh 서비스 설치)
    C:UsersUSER>ssh -p7001 myuser@example.com -L 2525:localhost:3355
    -> myuser의 비번을 입력하고 접속한다.

    -> 여기서 myuser는 Windows 2016 Server의 계정, 2525는 Windows Client에서 Listen할 임의의 포트임.
    -> 다른 LISTEN 포트와 겹치지만 않게 아무 포트나 사용 가능.

  • cmd 창 또는 mstsc를 띄워 rdp 연결 시도
    > mstsc /v localhost:2525

    -> localhost는 자기 자신인데?? 이게 좀 핵갈릴 수 있다.
    -> 위의 ssh 명령을 수행하면 클라이언트는 2525 포트를 localhost(127.0.0.1)에 LISTENING 하게된다.
    -> 클라이언트 측 터널의 종단 포트(2525)를 통해 서버 측 터널의 종단 포트인 3355 포트로 연결되는 것이다.
    -> 핵갈리지 않게 일치 실켜도 무관하다. 즉, 3355:localhost:3355 와 같이..

  • 만들어진 터널의 locahost로 연결 접속되는것이 확인된다.
    C:UsersUSER>netstat -an | findstr 2525
    TCP    127.0.0.1:2525         0.0.0.0:0              LISTENING
    TCP    [::1]:2525             [::]:0                 LISTENING
    TCP    [::1]:2525             [::1]:56562            ESTABLISHED
    TCP    [::1]:56562            [::1]:2525             ESTABLISHED

     

스크립트 생성

where: rdp 클라이언트에서

  • batch, visual basic script를 미리 생성해 두고 편리하게 접속을 하기 위함이다.

1. 디렉토리 생성

  • c: 드라이브에 Bat-files라는 디렉토리를 하나 만든다.

2. ssh 연결 batch 파일 작성

  • 아래 내용으로 ssh-con.bat 이라는 이름으로 batch 파일을 하나 만든다.
@echo off
title Reverse SSH Tunnel
color 3F
mode con cols=70 lines=20

taskkill /im plink.exe /f

setlocal
endlocal

set /a result=(%random% *1 %result%) + 1
set /a result=(%random% * 100 / 32768) + 7001

echo ##### Connected Port : %result% #####
echo y | "C:Program FilesPuTTYplink.exe" myuser@example.com -pw PASSWORD -P %result% -2 -4 -T -N -L 2525:localhost:4455

-> putty에 포함된 plink라는 프로그램이 ssh 터널링을 생성해 준다.
-> PASSWORD 는 Windows RDP Server의 myuser 계정에 대한 PASSWORD임.
-> %result%는 공유기에서 설정한 외부 포트 7001~7100 사이에서 랜덤하게 하나가 할당됨. 할당된 포트가 Windows SSH Server의 8585 포트로 포워딩 된다.

3. rdp 연결 batch 파일 작성

  • 아래 내용으로 myuser-m_rdp.bat 이라는 이름으로 batch 파일을 하나 만든다.
    @echo off
    title myrdp
    color 5F
    mode con cols=25 lines=1
    mstsc /v localhost:2525 /multimon
    exit

4. batch 파일을 실행할 vbs 파일 작성

  • 아래 내용으로 myuser-m.vbs 이라는 이름으로 visual basic script 파일을 하나 만든다.
    Set WshShell = CreateObject("WScript.Shell")
    WshShell.Run chr(34) & "C:Bat-filesssh-con.bat" & Chr(34), 0
    WshShell.Run chr(34) & "C:Bat-filesmyuser-m_rdp.bat" & Chr(34), 0
    Set WshShell = Nothing

    -> 이렇게 실행하는 이유는 2개의 batch 파일을 순차적으로 백그라운드 실행하기 위함

 

plink 방식에 문제점이 발견되어 보완된 내용을 추가함. 아래 '2023.01.15에 추가한 내용' 부분을 참조

 

참고하면 좋은 문서

rdp with reverse connection on the ssh server

guacamole-0.9.13 with CentOS 7.4

rdp multimon 옵션으로 연결 시 창 위치

 

2023.01.15에 추가한 내용

 

위와 같이 plink 방식의 rdp 연결 시 아래와 같은 ssh client 에러 메시지가 발생하면서 연결이 해제되어 버리는 심각한 문제가 있다.

에러 확인
plink 실행 라인에 -sshlog 옵션을 넣어서 디버그 로깅 후 로그파일의 맨 마지막 부분 확인

Event Log: Forwarded port closed due to local error: Network error: Software caused connection abort
Outgoing packet #0x562e, type 97 / 0x61 (SSH2_MSG_CHANNEL_CLOSE)
00000000 00 00 00 00 ....
Event Log: Opening connection to localhost:3389 for forwarding from [::1]:61183
Outgoing packet #0x562f, type 90 / 0x5a (SSH2_MSG_CHANNEL_OPEN)
00000000 00 00 00 0c 64 69 72 65 63 74 2d 74 63 70 69 70 ....direct-tcpip
00000010 00 00 01 01 00 00 40 00 00 00 40 00 00 00 00 09 ......@...@.....
00000020 6c 6f 63 61 6c 68 6f 73 74 00 00 0d 3d 00 00 00 localhost...=...
00000030 07 30 2e 30 2e 30 2e 30 00 00 00 00 .0.0.0.0....
Event Log: Network error: Software caused connection abort

 

원인

원인은 아래 사이트에 설명되어 있다.
https://devanswers.co/ubuntu-ssh-keeps-disconnecting-idle/
-> 패킷이 일정 시간 흐르지 않으면 방화벽에서 abort 처리되면서 ssh 터널링 세션이 끊기며 rdp 연결도 함께 끊긴다.
따라서 client 측에서 ssh keepalive 설정이 필요하다.

 

조치

그런데 plink 명령에는 keepalive 옵션이 없다. 그래서 plink가 아닌 putty를 통해 ssh 연결을 하는 것으로 변경하였고 그 이후로 연결 끊김이 없다.

plink에는 password를 지정하는 옵션이 있지만, putty에는 그 옵션이 없기 때문에 key 방식으로 연결하는 방법을 사용한다.

그리고 putty는 portable 버전을 사용하였다. portable 버전을 사용한 이유는 putty 세팅을 하고 세팅값을 PuTTYPortable.exe 파일이 위치한 하위 폴더에 넣어서 배포할 수 있기 때문이다.
(설치형 putty의 session 세팅 값은 Windows 레지스트리에 저장됨)

PuTTYPortable_0.78_English.paf.exe 파일을 이용하였다. 0.78 버전을 기준으로 구/최신 버전을 사용해도 무관하다.

 

아래 과정을 거쳐 'ssh tunnel & rdp' 자동 연결 클라이언트 배포 툴을 만들 수 있다.

  1. portable putty 프로그램 설치
    where: rdp 클라이언트에서

    1. PuTTYPortable_0.78_English.paf.exe 설치
      아무 디렉토리에나 놓구서 실행하면 해당 디렉토리에 단순히 압축이 풀리는 형태로 설치된다.
    2. PuTTYPortable 폴더 이름 변경
      (여기서는 mapoo-rdp로 변경함. 본인이 원하는 이름으로 폴더명 변경)
      (폴더명 변경을 안해도 무관하지만 해당 폴더를 mapoo-rdp.zip 으로 압축할 예정이므로 변경함.)
  2. putty 프로그램 실행 / 설정
    where: rdp 클라이언트에서

    1. PuTTYPortable.exe을 실행 

    2. -> Host Name / Port / Saved Sessions 설정
      -> 여기서 3022 포트는 공유기(NAT방화벽)에서 포트포워딩을 외부(3022) -> 내부(22)로 하였기 때문에 3022를 사용. sshd 기본 포트 22번 포트를 사용하였다면 22를 기입
    3. -> 빨간색 박스 부분 대로 변경
      -> 네트워크 환경 / sshd_config 설정에 따라 값을 변경

    4. -> 빨간 박스에 puttygen.exe 프로그램을 실행 후 생성 한 mapoo-pri.ppk 파일의 경로를 넣어준다.
           (Browse.. 버튼을 눌러서 지정하면 Full 경로가 들어가므로 그렇게 지정하면 다른 PC에서는 키 파일을 못 읽을 수 있다. 빨간 박스 안에 위와 같이 적어 넣어야 함.)
      -> puttygen.exe로 생성한 ssh-private (mapoo-pri.ppk) 키 파일을 mapoo-rdp\Data\settings 폴더에 넣어둔다.
           그리고 ssh-public (mapoo-pub) 키 파일도 같은 폴더 넣어둔다.
          (사실 이 키(ssh-public)는 서버측에서만 필요한 키이기 때문에 여기에 안 넣어도 동작되는데는 문제가 없지만 보관 차원에서 여기 둔다.)

      -> puttygen 으로 키 생성하는 방법은 대략 아래와 같다.
          (puttygen.exe는 putty.exe와 같은 폴더에 위치)
           프로그램 실행 후 마우스 커서를 흔들어 주면 키가 생성됨.
         
      -> 파란색 버튼을 눌러 각각 mapoo-pub, mapoo-pri 이름으로 저장한다.
      -> 빨간색 부분을 복사해서 메모장에 붙여둔다. (mapoo-pub 파일의 내용과 동일)

    5. -> 빨간 박스 안에 위와 같이 기입 후 Add 버튼을 누르면 파란박스와 같이 추가가 된다.
           ( 2526 포트는 3389 포트와 터널링 연결을 위한 포트로 임의의 숫자의 포트를 사용하면 된다.)
      -> 만약 다른 rdp 연결을 동시에 할 필요가 있다고 한다면 포트가 겹치지 않게 2526이 아닌 2527 과 같이 한다.
           (본인의 경우 opc-m.vbs 를 통해 동시 2개 rdp 연결을 하기 때문에 opc-m은 2527 설정하여 연결함)
    6. 설정 저장
      putty 첫 화면(Session 탭)에서 위 mapoo-ssh session 설정을 선택한 상태에서 Save
  3. sshd 서버 설치/실행/설정
    where: rdp 서버에서

    1. openssh 서버 설치
      Windows 10 이상부터는 자체 sshd 기능이 있다. 하지만 설치는 안되어 있으므로 설치 필요.
      Windows 설정 - 검색에서 '선택적 기능 추가' 를 검색 후 메뉴에서 openssh 서버를 설치
    2. 서비스 실행
      Windows 버튼 우측 마우스 - 컴퓨터 관리 - 서비스 및 응용 프로그램 - 서비스 - OpenSSH SSH Server - 시작 유형 '자동' 선택 - 시작 버튼 클릭
    3. 접속 및 mapoo-pub 키 내용 저장
      위 2번 단계의 ssh(rdp) client windows pc에서 putty로 접속한다.
      rdp windows 계정으로 로긴하고 아래와 같이 수행

      myuser@mygroup C:\Users\myuser> mkdir .ssh
      
      myuser@mygroup C:\Users\myuser> cd .ssh
      
      myuser@mygroup C:\Users\myuser> copy con authorized_keys

      --> copy con 명령 실행 후 메모장에 복사해 둔 내용을 붙여넣고, Ctrl - Z 키를 누른다. 그러면 파일에 내용이 저장됨.

    4. 저장된 키 파일 내용 확인
      myuser@mygroup C:\Users\myuser> type authorized_keys

      --> 저장된 파일 내용이 확인된다.

    5. sshd_config 설정
      위치 : C:\ProgramData\ssh\sshd_config
      notepad++ 와 같은 에디터로 파일을 열어 몇 군데를 수정한다.

      1. 아래 2줄 주석 처리 (C:\Users\myuser\.ssh 디렉토리의 authorized_keys 파일을 읽을 수 있게 하기 위함)
        #Match Group administrators
        # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
      2.  패스워드 방식으로 로그인 금지 (ssh key 방식으로만 접근 가능. 보안 강화)
         PasswordAuthentication no
      3. alive 체크 설정 (주석 제거 후 아래 값으로 설정. 300초 * 3회 동안 ssh 패킷이 발생되지 않아도 세션 유지됨)
        TCPKeepAlive yes
        ClientAliveInterval 300
        ClientAliveCountMax 3
      4. Tunnel Device 허용
        PermitTunnel yes
    6. sshd 서비스 재시작
      Windows 버튼 우측 마우스 - 컴퓨터 관리 - 서비스 및 응용 프로그램 - 서비스 - OpenSSH SSH Server - 중지 버튼 클릭 - 중지 후 - 시작 버튼 클릭
  4. 접속하기
    where: rdp 클라이언트에서

    1. PuTTYPortable.exe을 실행 - mapoo-ssh 세션으로 접속 (비번 묻지 않고 자동 로긴됨)
    2. Windows - cmd - mstsc /v localhost:2526 (또는 mstsc /v 127.0.0.1:2526)
  5. 자동 접속 파일 만들기
    where: rdp 클라이언트에서

    -> mapoo-m.vbs 파일을 실행하면, 'ssh 터널링 후 해당 터널을 통해 mapoo rdp 연결' 이 한번에 된다.
    -> 파일명에 s 가 붙는 파일은 single 모니터 옵션 파일임. 옵션만 조금 다를 뿐 m 이 붙는 파일과 동일한 내용임.

    1. mapoo-m.vbs 내용
      Set WshShell = CreateObject("WScript.Shell")
      WshShell.Run chr(34) & "mapoo-ssh_con" & Chr(34), 0
      WshShell.Run chr(34) & "mapoo-m_rdp" & Chr(34), 0
      Set WshShell = Nothing
    2. mapoo-m_rdp.bat 내용
      @echo off
      title mapoo
      color 5F
      mode con cols=25 lines=1
      timeout 1 > nul
      mstsc /v localhost:2526 /multimon
      exit
    3. mapoo-ssh_con.bat 내용
      @echo off
      title mapoo
      color 5F
      mode con cols=25 lines=1
      netstat -na | find "127.0.0.1:2526" | findstr "LISTENING" >nul && (
      echo "Already Connecting SSH"
      ) || (
      PuTTYPortable -load "mapoo-ssh"
      )
      exit
  6. 배포하기
    where: rdp 클라이언트에서

    1. 압축하기
      mapoo-rdp 폴더를 mapoo-rdp.zip 이름으로 압축한다.
    2. 다른 PC에서 사용
      다른 PC에서 mapoo-rdp.zip 파일을 받아 적당한 곳에 위치.
      mapoo-rdp.zip 을 압축 해제 후 mapoo-rdp 폴더 내의 mapoo-m.vbs 파일을 바로가기 하여 바탕화면에 위치해서 사용
  7.  Windows 방화벽 설정 (옵션)
    where: rdp 클라이언트에서
    Windows OS 방화벽에서 rdp 접근을 localhost(127.0.0.1)만 허용

    외부(Internet) 또는 내부(local network)에서 3389(rdp)로 접근이 차단됨.
    즉, ssh 터널링을 통해 localhost로만 접근 허용되므로 보안적으로 매우 뛰어남.
    (*주의 - ssh 터널링을 통한 rdp 접속이 확실히 되는 것을 확인 후 이 설정을 넣을 것.)

마무리

  • 장점
    • 뛰어난 보안
      이렇게 적용 시 외부에서 ssh private key 없이는 inbound rdp 접근은 거의 불가능하다.

      • 널리 알려진 rdp port는 외부에 노출되지 않고 접속 불가하게 방화벽에서 막기 - Brute Force 공격 불가
      • Windows OS 방화벽에서 외부/로컬 네트워크 rdp 포트 접근을 막을 수 있음 - rdp 포트 노출/접근 제거
      • sshd에서 password 로그인 방식은 막고 ssh-key 방식으로만 ssh 접근을 허용 - 키 없이 ssh 연결 불가, Brute Force 공격 불가
      • 최소 권한의 ssh 연결 전용 계정(rdp 권한은 뺌)을 windows rdp 서버측에서 별도로 만들어 운영 - ssh 키가 노출되어 ssh가 뚫려도 fully 컨트롤 및 rdp 권한 탈취 힘듬 (rdp 비번까지 탈취해야 rdp 접근 가능)
        (이 문서에서는 다루지 않았지만 구성하기 어렵지 않다.)
    • 제 2의 리모트 컨트롤
      • 가끔 rdp 데몬 프로세스가 먹통이 될 때 ssh 연결을 통해 cli로 windows os 제어 가능
  • 단점
    • 초기 설정이 복잡함
  • 참고
    • PuTTYTray (또는 HPutty[한글PuTTY]) 을 이용하여 구성
      • session 세팅 값을 별도 파일로 저장 가능
      • putty.exe 단일 파일로 구성 - putty.exe 파일 하나에 keygen(puttygen) 기능까지 포함
      • putty 창을 tray icon으로 보낼 수 있음 (PuTTYPortable에 없는 기능)
        (putty - windows - behaviour 메뉴의 Show tray icon 'Normal' 설정 시 tray icon으로 창을 줄일 수 있음)
RDP connecting via ssh tunnel

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다