본문 바로가기

Port-Knocking

쉽게 이해하기

서버 : 저에게 닫혀 있는 문이 65535개 있고, 사전에 약속된 것과 같이 특정 3개의 문에 노크하면 들어오고 싶은 문을 열도록 하겠습니다.
주인 : 2222 똑똑똑!.... 3333.....4444 똑똑똑! 난 22번 문을 열어줘
서버 : 2222 확인!..... 3333..... 4444 확인! 인가된 사용자입니다. 요청하신 22번 문을 열어드리도록 하겠습니다.

서버 : 나에게 닫혀 있는 문이 65535개 있는데 사전에 약속된 것과 같이 특정 3개의 문에 노크하면 들어오고 싶은 문을 열어줄께
공격자 : 몇 번 문을 몇번째로 두드려야 하는지 모르는데... 일단 아무거나 두드려보자 1 2 3 4 똑똑똑!! 난 22번 문을 열어줘
서버 : 확인 불가! 거부!
공격자 : 그럼 강제로라도 들어가보자 일단 순서대로 해보면 언젠가 되겠지....

..라고 생각하겠지만 결코 쉽지만은 않은 작업입니다. 이는 서로 다른 65535개의 원소에서 중복을 허용하여 (기본) 3개를 뽑는 중복조합의 경우의 수를 갖습니다.


knockd

개념도

4.jpeg

보안 성립 주요점

  1. iptables에 의해 가용한 모든 포트들에 대한 차단을 기본 설정으로 한다.
  2. iptables는 `iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT` 설정에 의해 수립된 커넥션을 유지한다.
  3. iptables에 의해 보호된 서버에 대한 port scanning에 의해 어떠한 정보도 얻을 수 없다.
  4. knockd는 정해진 시퀀스에 의한 신호가 감지되면 iptables 설정을 정해진 시간동안 일시적으로 변경 후 원상 복귀 시킨다. (혹은 또 다른 신호에 의해 수동적으로 변경한다.)



1. 설치하기 (CentOS 5.6 i386 기준)

knock 홈페이지
www.zeroflux.org/projects/knock


 cd /usr/src/redhat/SRPM/
wget http://www.invoca.ch/pub/packages/knock/RPMS/ils-5/SRPMS/knock-0.5-7.el5.src.rpm

rpm -ivh /usr/src/redhat/SRPM/knock-0.5-7.el5.src.rpm
rpmbuild -ba /usr/src/redhat/SPEC/knock.spec
rpm -ivh /usr/src/redhat/RPMS/i386/knock-0.5-7.i386.rpm
rpm -ivh /usr/src/redhat/RPMS/i386/knock-server-0.5-7.i386.rpm
rpm -ivh /usr/src/redhat/RPMS/i386/knock-debuginfo-0.5-7.i386.rpm


소스 컴파일시 "src/knockd.o Error" 가 발생한다면 다음의 제안을 실행해보자

src/list.h 에 다음 내용 추가
#include <limits.h>


엮인 내용

libpcap 의존
selinux 설정
iptables (방화벽)
nmap (port scanning tools)




2. 관련 주요 파일

/etc/sysconfig/knockd
/etc/knockd.conf
/etc/rc.d/init.d/knockd
/usr/sbin/knockd
/usr/sbin/knock


3. knockd 서버 설정하기

knockd 가 iptables 를 조작하는 과정에서 SELInux 차단 설정이 되어있다면 해제하여준다.


iptables 설정을 변경한다.


iptables -F
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT


knockd-iptables 설정 효과를 알아보기 위한 가장 간단한 설정이다. 서버나 운용하는 데스크탑에서의 설정은 상황과 용도에 따라 다양하게 변경하면 된다. (단, 중요한 서버에 잘 수립된 방화벽 설정을 운용 중이라면 충분한 고려가 선행된 후 변경하길 바란다.)

위 설정에 의해 기본적으로 해당 머신으로의 Inbound 통신은 모두 DROP 된다는 것에 유의하라


/etc/sysconfig/knockd


 OPTION='-i eth1'


knockd 실행시 추가로 기능할 수 있는 옵션들에 대한 설정을 넣는다.
위 설정은 eth1에 대한 리슨을 실시하다는 의미이며, 아무런 설정이 없을시 기본적으로 eth0를 리슨한다.


/etc/knockd.conf


case. 1


 [options]
        logfile = /var/log/knockd.log

[opencloseSSH]
        sequence      = 2222:udp,3333:tcp,4444:udp
        seq_timeout   = 15
        tcpflags      = syn
        start_command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --syn --dport 22 -j ACCEPT
        cmd_timeout   = 10
        stop_command  = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --syn --dport 22 -j ACCEPT


2222:udp, 3333:tcp, 4444:udp 포트를 차례대로 두드리면 knockd에 의해 iptables 명령이 실행되며, ssh의 경우 로그인과 같은 특정한 서비스 이용 행위가 10초간 확인되지 않으면 stop_command의 내용을 실행한다.

seq_timeout은 15초간 정해진 2222:udp, 3333:tcp, 4444:udp 에 대한 노킹 시퀀스가 완료되지 않는다면 이 또한 종료된다.


case. 2


 [options]
        logfile = /var/log/knockd.log

[openSSH]
        sequence    = 2222, 3333, 4444
        seq_timeout = 5
        command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn

[closeSSH]
        sequence    = 4444, 3333, 2222
        seq_timeout = 5
        command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn


2222, 3333, 4444 (tcp) 시퀀스에 의한 노킹이 확인될 경우 iptables 설정에 의해 22 포트가 개방된다 단 주의할 점은 start_command, cmd_timeout, stopcommand 에 의한 자동 차단 설정이 되지 않는다는 점이다. 또한 한번 개방된 설정에 의해 관리자가 정상적으로 22번 포트에서의 모든 업무가 종료되어 접속을 종료했음에도 불구하고 자동으로 닫히지 않는다는 점이다.

22 포트에 대한 차단은 4444, 3333, 2222 시퀀스가 확인될 때까지 개방된 상태로 유지될 것이다.


한가지 주의할 점은 방화벽 설정의 개방시와 차단시 사용하는 시퀀스의 1번째 부분이 동일하면 문제가 발생한다는 것이다.


예를들면


[openSSH]

        sequence    = 2222, 3333, 4444


[closeSSH]

        sequence    = 2222, 3333, 2222


위와 같이 시퀀스 자체는 서로 다른 상태이지만 첫 시퀀스의 2222이 동일하다면 knockd 는 해당 knocking이 개방 요청인지 차단 요청인지 구분하지 못하는 것을 발견하였다. 물론 이는 필자의 실험용 컴퓨터에 국한되는 문제일 수도 있다. 일단 두 정책 변경에 대한 첫 시퀀스가 동일하여 knockd가 다음 행위를 결정하지 못한다면 command의 iptables 변경 명령은 실행되지 않는다.



4. 클라이언트에서 서비스 이용 방법

knock client 프로그램을 설치한다. (설치 부분 참조)

case. 1


 shell> (sudo) knock -v 192.168.1.16 2222:udp 2222:tcp 4444:udp
hitting udp 192.168.1.16:2222
hitting tcp 192.168.1.16:2222
hitting udp 192.168.1.16:4444

shell>
shell> (sudo) ssh -l root 192.168.1.16



case. 2


shell> (sudo) knock -v 192.168.1.16 2222 3333 4444
hitting udp 192.168.1.16:2222
hitting udp 192.168.1.16:3333
hitting udp 192.168.1.16:4444

shell>
shell> (sudo) ssh -l root 192.168.1.16
.
ssh 접속 종료 후
.
shell> (sudo) nmap 192.168.1.16
shell> (sudo) knock -v 192.168.1.16 4444 3333 2222







5. knock server-client reaction 자료

iptraf에 의한 확인


0.png

2222 2222 4444 시퀀스에 의한 포트 개방 요청에 따라 knockd는 22번 포트를 개방 해주었다.

1.png
ssh 정상 접속을 확인 후 종료하였으며, 커넥션이 종료되었다.


knockd 서버내 watch 2초 간격 확인 (cmd_timeout의 기능 확인)


2.png

22번 개방 요청 시퀀스에 의해 22번 포트가 열였다. (cmd_timeout=10)


3.png
정상적인 시퀀스가 확인되어 22번 포트가 개방되었으나 해당 포트에 대한 서비스 이용이 10초간 이루어지지 않아 닫혔다. (cmd_timeout=10)




knock squence 가 진행되지 않았을 때


 super@super-desktop:~$ sudo nmap -v 192.168.1.16

Starting Nmap 5.21 ( http://nmap.org ) at 2011-05-13 01:26 KST
Initiating ARP Ping Scan at 01:26
Scanning 192.168.1.16 [1 port]
Completed ARP Ping Scan at 01:26, 0.01s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 01:26
Completed Parallel DNS resolution of 1 host. at 01:26, 0.00s elapsed
Initiating SYN Stealth Scan at 01:26
Scanning 192.168.1.16 [1000 ports]
Completed SYN Stealth Scan at 01:26, 21.06s elapsed (1000 total ports)
Nmap scan report for 192.168.1.16
Host is up (0.00016s latency).
All 1000 scanned ports on 192.168.1.16 are filtered
MAC Address: 00:0F:**:**:**:** (Giga-Byte Technology Co.)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 21.16 seconds
           Raw packets sent: 2001 (88.042KB) | Rcvd: 1 (42B)


위의 nmap 결과와 같이 해당 서버에 대한 어떠한 포트 정보도 알 수 없으므로 공격자의 가장 초기 단계인 포트 스캐닝으로부터 벗어날 수 있으며, 결국 공격 대상이 되는 경우를 줄일 수 있다.


knock sequence 가 진행되어 요청한 포트가 개방되었을 때


 super@super-desktop:~$ sudo knock -v 192.168.1.16 2222 2222 4444
hitting tcp 192.168.1.16:2222
hitting tcp 192.168.1.16:2222
hitting tcp 192.168.1.16:4444
super@super-desktop:~$ sudo nmap -v 192.168.1.16

Starting Nmap 5.21 ( http://nmap.org ) at 2011-05-13 01:28 KST
Initiating ARP Ping Scan at 01:28
Scanning 192.168.1.16 [1 port]
Completed ARP Ping Scan at 01:28, 0.00s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 01:28
Completed Parallel DNS resolution of 1 host. at 01:28, 0.00s elapsed
Initiating SYN Stealth Scan at 01:28
Scanning 192.168.1.16 [1000 ports]
Discovered open port 22/tcp on 192.168.1.16
Completed SYN Stealth Scan at 01:28, 4.74s elapsed (1000 total ports)
Nmap scan report for 192.168.1.16
Host is up (0.00016s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE
22/tcp open  ssh
MAC Address: 00:0F:**:**:**:** (Giga-Byte Technology Co.)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 4.84 seconds
           Raw packets sent: 2002 (88.086KB) | Rcvd: 4 (174B)







특징


 [root@localhost i386]# netstat -nlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name 
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      2230/portmap      
tcp        0      0 0.0.0.0:752                 0.0.0.0:*                   LISTEN      2266/rpc.statd    
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      2508/sshd         
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      2519/cupsd        
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      2555/sendmail: acce
udp        0      0 0.0.0.0:55042               0.0.0.0:*                               2662/avahi-daemon:
udp        0      0 0.0.0.0:68                  0.0.0.0:*                               2071/dhclient     
udp        0      0 0.0.0.0:5353                0.0.0.0:*                               2662/avahi-daemon:
udp        0      0 0.0.0.0:746                 0.0.0.0:*                               2266/rpc.statd    
udp        0      0 0.0.0.0:749                 0.0.0.0:*                               2266/rpc.statd    
udp        0      0 0.0.0.0:111                 0.0.0.0:*                               2230/portmap      
udp        0      0 0.0.0.0:631                 0.0.0.0:*                               2519/cupsd


위의 netstat 결과는 knockd 실험을 위해 테스트한 머신의 네트워크 관련 데몬들이다.
확인되는 바와 같이 knockd는 확인되지 않으며 시퀀스로 설정한 (예 2222, 3333, 4444) 포트들 또한 열려 있다거나 Listen 상태로 있지 않는다는 것에 주목해야 한다.

knockd 는 방화벽의 차단 내역과는 무관하게 65535개의 모든 포트들에 대한 knock를 감지할 수 있다.



만약 knockd-iptables 의 위와 같은 사항을 서버에서 사용하고자 한다면 최악의 경우도 생각해야한는데 바로 knockd의 crash가 발생하였을 경우이다.
`iptables -P INPUT DROP` 에 의해 INPUT 체인에 대한 기본 설정이 DROP 이므로 만약 knockd가 crash된다면 외부에서 접속할 방법을 상실하게 된다. 이를 위해 간단한 스크립트와 crontab을 이용해 최소한의 장애 대비를 하는 것이 좋다.


 shell> vi rescue_port_block.sh

#!/bin/sh

cnt=`ps aux | grep knockd | grep -v grep | wc -l`

if [ $cnt != 1 ]; then
service knockd restart
if [ $? != 0 ]; then
iptables -nL >> /root/iptables_policy.bak
iptables -F
else
echo `date` knockd recovered >> /var/log/knockd.log
fi
fi

sleep 10
exit 0

shell> chmod 700 rescue_port_block.sh


위의 스크립트를 crontab의 적절한 시간대에 등록하여 knockd crash에 대비하는 것도 하나의 방법이다.

예를들면

* * * * * su - root -c 'rescue_port_block.sh'

위와 같이 등록되어있다면 만약 knock 다운의 의한 접속장애는 1분에 국한될 것이다.




활용

가정 등에서 사용하는 유동 IP로 서버를 관리 하는 경우를 생각해 볼 수 있다.
관리자가 할당 받는 IP가 지속적으로 변화 하지만 할당 받는 IP가 정해진 것이 아니기 때문에 서버에서 관리자의 접속을 위해선 모든 IP에 대한 접속 허용을 유지하여야 한다 그러나 이런한 방법은 보안상 매우 큰 허점이 된다.


5.png

관리용 워크스테이션은 기본적으로 모든 포트에 대한 DROP이 기본 설정이다. 그러나 knockd에 의해 관리자가 특정 포트에 knock 시퀀스를 진행하면 knockd는 iptables의 설정을 관리자가 접근할 수 있도록 변경한다. 관리자는 제공된 포트를 통해 관리용 워크스테이션으로 입장한다. 이후 관리자는 목적한 업무를 원활히 수행 할 수 있다.

그렇다면 knockd에 의한 기능을 사용할 수 없을때는 어떨까


6.png

유동 IP 할당 상태에 따라 관리용 워크스테이션의 방화벽 설정을 수시로 바꿔주거나 혹은 IP를 특정할 수 없게된다. 만약 사용의 편의를 위해 모든 IP에 대한 접속 허용을 해둔 상태라면 이는 이미 방화벽으로써의 기능을 상실한 것이나 다름이 없다. 곧 공격자들의 좋은 먹이감이 될 것이다.


참고문서
http://www.portknocking.org/
http://www.zeroflux.org/projects/knock
http://www.linuxjournal.com/magazine/implement-port-knocking-security-knockd?page=0,0