Port Knocking

Network

라온화이트햇 핵심연구팀 최용선

0. 개요


DefCampCTF2020 대회 문제 중 notor 라는 웹/네트워크/포렌식 문제를 풀이하면서 port knoking 에 대한 내용을 알게 되어 이에 대한 포스팅을 하게 되었습니다.

이 글에서는 포트노킹에 대한 기본 개념과 구현, 마지막으로 DefCamp2020의 notor 문제에 대한 풀이를 진행합니다.

1. Port Knocking


포트노킹은 말 그대로 port를 두드리는 행위와 유사합니다. 포트노킹을 사용하면 특정 패턴의 포트를 연속하여 서버에 요청할 경우, 해당 패턴에 알맞는 특정 포트를 개방하거나 폐쇄할 수 있습니다.

예를 들어, 서버 관리자가 특정 서비스를 1234 포트에 올려 사용하고 있다고 가정해봅시다. nmap 등의 포트스캐닝 툴을 이용할 경우, 개방된 포트를 확인할 수 있기 때문에 관리자는 1234 포트를 숨기고 싶어 합니다.

이 때 포트노킹을 사용하면 1234 포트는 평소에 닫아두고, 특정 패턴의 포트 가 순차적으로 요청이 오면 개방하는 방식으로 포트를 숨길 수 있습니다.

/assets/2021-04-01/Port Knocking/Untitled.png

평소에는 위와 같이 1234 포트는 닫아두어 요청 시 정상적인 응답이 돌아오지 않습니다. 따라서 포트스캐닝을 통해 해당 포트의 사용 여부를 확인할 수 없습니다.

/assets/2021-04-01/Port Knocking/Untitled%201.png

하지만 포트노킹을 통해 7000, 8000, 9000의 tcp 요청이 들어올 경우 1234 포트를 개방하도록 설정했을 경우 7000, 8000, 9000, 1234 포트에 순차적으로 요청하면 포트가 개방되어 정상적인 응답이 돌아오게 됩니다.

2. 환경 구성


포트노킹을 위한 환경 구성의 순서는 다음과 같습니다.

  1. knockd 설치
  2. iptables 초기 설정
  3. iptables-persistent 설치 (선택)
  4. knockd 설정

1. knockd 설치

~ apt install knockd
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  knockd
0 upgraded, 1 newly installed, 0 to remove and 23 not upgraded.
Need to get 24.7 kB of archives.
After this operation, 103 kB of additional disk space will be used.
Get:1 http://ap-northeast-2.ec2.archive.ubuntu.com/ubuntu focal-updates/universe amd64 knockd amd64 0.7-1ubuntu3.20.04.1 [24.7 kB]
Fetched 24.7 kB in 0s (59.4 kB/s)
Selecting previously unselected package knockd.
(Reading database ... 124751 files and directories currently installed.)
Preparing to unpack .../knockd_0.7-1ubuntu3.20.04.1_amd64.deb ...
Unpacking knockd (0.7-1ubuntu3.20.04.1) ...
Setting up knockd (0.7-1ubuntu3.20.04.1) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for systemd (245.4-4ubuntu3.4) ...

먼저, apt install 명령어를 통해 knockd를 설치합니다.

2. iptables 초기 설정

~ iptables -A INPUT -p tcp --dport 22 -j DROP
~ iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       tcp  --  anywhere             anywhere             tcp dpt:22

포트노킹을 통해 ssh 서비스를 제한하고자 할 경우 22번 포트를 iptables에서 tcp any<->any deny 정책으로 추가합니다. 이를 통해 모든 IP에서 22번 포트로 접근할 수 없게 됩니다.

3. iptables-persistent 설치 (선택)

~ apt install iptables-persistent
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  netfilter-persistent
The following NEW packages will be installed:
  iptables-persistent netfilter-persistent
0 upgraded, 2 newly installed, 0 to remove and 23 not upgraded.
Need to get 13.7 kB of archives.
After this operation, 87.0 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://ap-northeast-2.ec2.archive.ubuntu.com/ubuntu focal/universe amd64 netfilter-persistent all 1.0.14 [7232 B]
Get:2 http://ap-northeast-2.ec2.archive.ubuntu.com/ubuntu focal/universe amd64 iptables-persistent all 1.0.14 [6496 B]
Fetched 13.7 kB in 0s (627 kB/s)         
Preconfiguring packages ...
Selecting previously unselected package netfilter-persistent.
(Reading database ... 124763 files and directories currently installed.)
Preparing to unpack .../netfilter-persistent_1.0.14_all.deb ...
Unpacking netfilter-persistent (1.0.14) ...
Selecting previously unselected package iptables-persistent.
Preparing to unpack .../iptables-persistent_1.0.14_all.deb ...
Unpacking iptables-persistent (1.0.14) ...
Setting up netfilter-persistent (1.0.14) ...
Created symlink /etc/systemd/system/multi-user.target.wants/netfilter-persistent.service → /lib/systemd/system/netfilter-persistent.service.
Setting up iptables-persistent (1.0.14) ...
update-alternatives: using /lib/systemd/system/netfilter-persistent.service to provide /lib/systemd/system/iptables.service (iptables.service) in auto mode
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for systemd (245.4-4ubuntu3.4) ...

iptables-persistent는 iptables 설정한 뒤 재부팅 시 초기화 되는 문제를 해결하기 위한 패키지입니다. iptables에 등록한 rule을 save 해놓을 경우, 재부팅 시 restore 기능을 통해 해당 내용을 불러와 적용시켜주는 기능을 지원합니다.

4. knockd 설정

~ cat /etc/knockd.conf 
[options]
	UseSyslog

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

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

처음 knockd를 설치했을 당시의 /etc/knockd.conf 파일입니다.

~ nc ctf.choiys.kr 7000; nc ctf.choiys.kr 8000; nc ctf.choiys.kr 9000; ssh root@ctf.choiys.kr
root@ctf.choiys.kr's password:

~ nc ctf.choiys.kr 9000; nc ctf.choiys.kr 8000; nc ctf.choiys.kr 7000

위와 같이 nc를 이용하여 7000, 8000, 9000 포트로 순차적으로 요청할 경우 22번 포트가 개방되어 ssh 서비스를 이용할 수 있게 됩니다.

knockd.conf 의 기본 설정에서는 7000, 8000, 9000 포트를 요청하면 해당 IP에 대해 22번 포트를 개방하고 9000, 8000, 7000 포트를 요청하면 해당 IP에 대해 22번 포트를 폐쇄합니다. 즉, 포트 개방 이후 ssh 연결을 시도한 후 연결을 종료해도 자동으로 22번 포트의 폐쇄가 이루어지지 않습니다.

~ cat /etc/knockd.conf
[options]
	UseSyslog

[openSSH]
	sequence    = 7000,8000,9000
	seq_timeout = 1
	tcpflags    = syn
	start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
	cmd_timeout = 10
	stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

위는 이를 해결하기 위해 기본 설정에서 약간 수정한 knockd.conf 입니다.

기본 설정과 달리, 추가된 옵션은 command 대신 start_commandstop_command , cmd_timeout 입니다.

이렇게 start_commandstop_command 명령을 이용하여 연결이 종료된 이후 자동으로 포트를 닫도록 설정할 수 있습니다.

여기서 발생하는 문제점은 start_command 명령 실행 이후 cmd_timeout 시간이 지날 경우, ssh 서비스 연결 여부와 상관 없이 무조건 stop_command 가 실행된다는 점입니다. 즉, 22번 포트 개방 이후 ssh을 통해 로그인에 성공하더라도 10초가 지난 이후에는 연결이 종료됩니다.

그렇기 때문에 start_commandstop_command 를 이용한 자동 폐쇄는 ssh와 같이 연결이 지속적으로 이루어져야 하는 서비스에는 어울리지 않습니다.

~ watch -n11 "for port in 7000 8000 9000; do nc ctf.choiys.kr \$port; done"

ssh와 같은 연결 지속형 서비스와 자동 폐쇄 기능을 함께 사용하기 위해서는 위와 같이 watch 를 사용하여 일정 시간마다 포트를 개방 해주는 작업이 필요합니다.

3. 장단점


장점

단점

4. DefCamp2020 notor 문제


/assets/2021-04-01/Port Knocking/Untitled%202.png

DefCamp2020의 notor 문제입니다.

pcap 파일을 제공하였으며, 패킷을 분석하여 공격자가 서버에 침투하는데 사용한 방법를 찾아내는 것이 목표인 문제였습니다.

서버는 138.68.93.187:1234 라는 것을 명시해주었습니다.

logs.zip

/assets/2021-04-01/Port Knocking/Untitled%203.png

문제 설명에서 서버의 포트를 알려줬기 때문에 wireshark 에서 위와 같이 필터링을 걸어 패킷을 살펴보았습니다.

그 중에서 shelladsasdadsasd.html.php 라는 파일을 요청한 것을 확인할 수 있었고, feature=pwd 라는 쿼리스트링이 포함된 것으로 보아 webshell이라는 것을 파악할 수 있었습니다.

/assets/2021-04-01/Port Knocking/Untitled%204.png

웹쉘에서 telnet을 이용하여 10.5.0.6 에 요청하는 것으로 보아, 문제에서 언급했던 secure infrastructure10.5.0.6 이라는 것을 짐작할 수 있습니다.

/assets/2021-04-01/Port Knocking/Untitled%205.png

10.5.0.6 IP로 필터링하여 패킷을 살펴보면, 위와 같이 특정 패턴의 포트를 요청하는 것을 확인할 수 있습니다. 위의 양상으로 보아 포트노킹이 적용되어 있다는 것을 짐작할 수 있습니다.

/assets/2021-04-01/Port Knocking/Untitled%206.png

이 중에서 10001, 10002, 10003, 22, 445 포트에 요청한 뒤 5000 포트에 연결을 시도했을 때 연결에 성공한 것을 확인할 수 있었습니다.

/assets/2021-04-01/Port Knocking/Untitled%207.png

문제에서 확인한 서버인 138.68.93.187:1234 에 올라가 있을 shelladsasdadsasd.html.php 에 접근하면 위와 같이 웹쉘을 확인할 수 있었습니다.

여기서 포트노킹의 패턴대로 10001, 10002, 10003, 22, 445 포트에 요청하고, 10.5.0.6 IP의 5000 포트에 HTTP 요청을 보내면 플래그를 얻을 수 있습니다.

5. 마치며


포트노킹은 2000년대 전/후에 주로 사용된 기법이었으며, ssh와 같이 brute force 공격에 노출될 수 있는 서비스 등에 대한 보안 대책으로 사용되거나, 루트킷에 이용되었다고 합니다.

하지만 포트노킹은 장점이 있는 반면, 단점도 명확히 존재하는 기법이기 때문에 실제 시스템에 적용하는 것은 추천하지 않습니다.

요즘은 CTF 문제에 종종 사용되고 있기 때문에 네트워크 관련 문제가 나온다면 한번 쯤 떠올려볼 법 할 것 같습니다.

6. 참조