Ryu's Tech

오픈소스 IDS/IPS 수리카타(Suricata) 설치 및 IPS/inline 모드 실행법

Ryusstory 2017. 9. 26. 23:22

Table of Contents

개요

오픈소스 IDS/IPS 로 사용 가능한 Suricata의 최신 버전 4.0.0 설치 방법을 알아보고 어떻게 쓰는지 알아 보도록 하겠습니다.

suricata는 IPS 라고 불리는 탐지/차단 모드와 IDS 라고 불리는 탐지 모드로 모두 사용가능합니다.

탐지 차단 수준이 상용 장비에 비하면 아무래도 약 50% 정도로 떨어지긴 하지만 오픈소스로 IPS 구현이 가능하다는 점에 의미를 두는 것이 좋겠네요.

정리하면 이 글의 목적은 오픈소스 Suricata 의 IPS 설치방법 및 사용법 조금을 알려드리도록 하겠습니다.

테스트 구성

구성도 설명

테스트 환경은 VMware Workstation 으로 진행하였으며, 구성은 위와 같습니다. 혹시나 위의 구성이 이해가 어렵다면 아래 글을 통을 한번 보시는 것도 괜찮습니다.

Vmware Network Type 에 대해서 알아봅시다.

좌측 테스트 환경은 VMware를 통해 가상 네트워크를 구성한 모양이고, 우측은 가상환경을 직접 표현해 본 것입니다.

좀더 설명 드리면

윈도우를 깔아놓은 가상머신(VM)에는 192.168.101.102 IP로 게이트웨이를 리눅스 가상머신으로 잡아놨습니다.

리눅스를 깔아놓은 가상머신은 Suricata가 설치될 리눅스 가상머신으로 공유기를 통해 바로 연결되도록 Bridge 네트워크와 윈도우PC를 연결하기 위한 네트워크를 동시에 잡아놨습니다.

리눅스 가상머신 IP 설정


[root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens34
TYPE=Ethernet
BOOTPROTO=static
NAME=ens34
DEVICE=ens34
IPADDR=192.168.101.101
PREFIX=24
ONBOOT=yes
[root@localhost ~]# systemctl restart network

ens34는 리눅스 가상머신의 2번째 인터페이스로 윈도우 PC와 연결되는 네트워크입니다.

위와 같이 설정 후 IP를 확인해 보면 아래와 같이 IP가 설정됩니다. 첫번째 인터페이스(ens33)은 공유기로부터 DHCP로 받아온 IP입니다.


[root@localhost ~]# ip a | grep -e "inet "

    inet 127.0.0.1/8 scope host lo

    inet 192.168.0.21/24 brd 192.168.0.255 scope global dynamic ens33

    inet 192.168.101.101/24 brd 192.168.101.255 scope global ens34

[root@localhost ~]# 

리눅스 가상머신 라우팅 설정

테스트 구성이 두 개의 네트워크가 연결되다 보니 라우팅 설정을 해줘야 합니다. 리눅스 가상머신의 경우 라우팅을 확인해 보면 추가로 작업해 줘야 할 것은 없습니다. 

양쪽 네트워크를 모두 알고 있고, 디폴트 라우팅이 공유기쪽으로 잡혀 있기 때문입니다.


[root@localhost ~]# ip route

default via 192.168.0.1 dev ens33  proto static  metric 100 

192.168.0.0/24 dev ens33  proto kernel  scope link  src 192.168.0.21  metric 100 

192.168.101.0/24 dev ens34  proto kernel  scope link  src 192.168.101.101  metric 100 

[root@localhost ~]# 

그래서 리눅스 가상머신에서는 실제 google.com 으로 핑을 날려봐도 정상적으로 응답이 옵니다.


[root@localhost ~]# ping google.com

PING google.com (216.58.221.14) 56(84) bytes of data.

64 bytes from nrt13s38-in-f14.1e100.net (216.58.221.14): icmp_seq=1 ttl=54 time=36.5 ms

64 bytes from nrt13s38-in-f14.1e100.net (216.58.221.14): icmp_seq=2 ttl=54 time=36.6 ms

64 bytes from nrt13s38-in-f14.1e100.net (216.58.221.14): icmp_seq=3 ttl=54 time=35.9 ms

64 bytes from nrt13s38-in-f14.1e100.net (216.58.221.14): icmp_seq=4 ttl=54 time=37.0 ms

64 bytes from nrt13s38-in-f14.1e100.net (216.58.221.14): icmp_seq=5 ttl=54 time=35.9 ms

^C

--- google.com ping statistics ---

5 packets transmitted, 5 received, 0% packet loss, time 4004ms

rtt min/avg/max/mdev = 35.903/36.419/37.085/0.470 ms

[root@localhost ~]# 

윈도우 가상머신 IP & 라우팅 설정

현재 상태 확인

윈도우는 구성도에서 나오는 대로 아래처럼 IP를 설정해 줍니다.

이제 PC에서 ping을 쳐보면 앞의 가상머신 까지는 ping이 가지만 외부(인터넷)으로는 나가지 않는 것을 확인 할 수 있습니다.


이를 처리하기 위해서는 세 가지를 손봐줘야 합니다.

1. 방화벽

2. 라우팅

3. 포워딩

하나씩 정리해 보겠습니다.


리눅스 가상머신 방화벽 비활성화

firewalld와 iptables 두 가지를 처리 해줘야 합니다.

먼저 firewalld



[root@localhost ~]# systemctl disable firewalld

Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.

Removed symlink /etc/systemd/system/basic.target.wants/firewalld.service.

[root@localhost ~]# systemctl stop firewalld

[root@localhost ~]# systemctl status firewalld

● firewalld.service - firewalld - dynamic firewall daemon

   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)

   Active: inactive (dead)

     Docs: man:firewalld(1)


Sep 26 19:59:16 localhost.localdomain systemd[1]: Starting firewalld - dynamic firewall daemon...

Sep 26 19:59:18 localhost.localdomain systemd[1]: Started firewalld - dynamic firewall daemon.

Sep 26 22:20:35 localhost.localdomain systemd[1]: Stopping firewalld - dynamic firewall daemon...

Sep 26 22:20:36 localhost.localdomain systemd[1]: Stopped firewalld - dynamic firewall daemon.

[root@localhost ~]# 

그리고 iptables


[root@localhost ~]# iptables -S

-P INPUT ACCEPT

-P FORWARD ACCEPT

-P OUTPUT ACCEPT

-N FORWARD_IN_ZONES

-N FORWARD_IN_ZONES_SOURCE

-N FORWARD_OUT_ZONES

-N FORWARD_OUT_ZONES_SOURCE

-N FORWARD_direct

-N FWDI_public

-N FWDI_public_allow

-N FWDI_public_deny

-N FWDI_public_log

-N FWDO_public

-N FWDO_public_allow

<생략>

[root@localhost ~]# 

위와 같이 iptables 를 확인해 보면 많은 정책들이 적용되어 있는데 두 줄 만으로 모두 날려버리도록 하겠습니다.


[root@localhost ~]# iptables -F

[root@localhost ~]# iptables -X

[root@localhost ~]# iptables -S

-P INPUT ACCEPT

-P FORWARD ACCEPT

-P OUTPUT ACCEPT

[root@localhost ~]# 

깔끔해졌네요.

공유기 라우팅 설정

공유기의 관점에서

공유기는 192.168.0.0/24 네트워크를 가지고 있지만 리눅스 가상머신에 연결된 네트워크 (192.168.101.0/24)에 대해 알지 못합니다.

이에 해당 네트워크로 가려면 리눅스 가상머신(공유기와 연결된 IP 192.168.0.21)을 통해 가야 한다는 내용을 알려줘야합니다.

이렇게 설정해 주면 192.168.101.0/24 네트워크로 가려면 192.168.0.21 (리눅스 가상머신) 으로 가면 된다. 라는 내용을 공유기가 이제 알게 됩니다.

리눅스 가상머신 포워딩 설정

자 이제 마지막 설정인데 이 설정은 패킷을 받았을 때 앞서 확인한 리눅스의 라우팅 테이블을 통해 패킷을 포워딩 하는 것을 허용해 주는 설정입니다. 


[root@localhost ~]# echo 1 > /proc/sys/net/ipv4/ip_forward

[root@localhost ~]# sysctl -w net.ipv4.ip_forward=1


위와 같이 설정하면 적용됩니다. 위 echo 명령어는 재부팅 시에 적용되는 부분이고, 아래 sysctl 명령어는 즉시 적용되는 부분이기 때문에 둘 다 바로 적용해 줍니다.

참고. 트러블 슈팅

사실 위 내용은 그냥 방법만을 알려드리는 것이긴 하지만 tcpdump 라는 패킷 덤프 유틸을 통해 조금 더 알아보면

PING의 경우 request 패킷을 날리고, reply 패킷을 받아서 그 응답시간을 표현하게 됩니다.  

리눅스 가상머신에서 외부(공유기와 연결된 인터페이스)를 tcpdump 유틸로 icmp 패킷(PING) 만 모니터링 했을 때 상태별 패킷은 아래와 같이 보입니다.


먼저 패킷 포워딩이 비활성화 되어 있으면 패킷이 들어와도 외부로 내보내지 않기 때문에 아무 패킷도 안보입니다.


[root@localhost ~]# tcpdump -i ens33 icmp

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

^C

패킷 포워딩이 활성화 된 상태라면 외부로 나가는 패킷을 보이게 됩니다. (ICMP echo request)

하지만 응답 패킷이 돌아오지 않죠.


[root@localhost ~]# tcpdump -i ens33 icmp

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

21:00:47.991128 IP 192.168.101.102 > kns.kornet.net: ICMP echo request, id 1, seq 20, length 40

21:00:52.781496 IP 192.168.101.102 > kns.kornet.net: ICMP echo request, id 1, seq 21, length 40

^C

그리고 공유기에서 라우팅을 설정해주게 되면 아래와같이 request 와 reply 패킷이 모두 보이게 되며 정상적으로 통신하는 것을 확인 할 수 있습니다.


[root@localhost ~]# tcpdump -i ens33 icmp

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

21:01:57.768801 IP 192.168.101.102 > kns.kornet.net: ICMP echo request, id 1, seq 24, length 40

21:01:57.772922 IP kns.kornet.net > 192.168.101.102: ICMP echo reply, id 1, seq 24, length 40

21:01:58.841720 IP 192.168.101.102 > kns.kornet.net: ICMP echo request, id 1, seq 25, length 40

21:01:58.844033 IP kns.kornet.net > 192.168.101.102: ICMP echo reply, id 1, seq 25, length 40

^C

정상 통신 확인

이제 확인해 보면 외부로 ping도 잘 나가게 되고 윈도우 가상머신에서 인터넷도 잘 동작하게 됩니다.

Suricata 3버전 설치

yum...

이제는 패키지로 지원이 되네요.. 허무하긴 하겠지만

yum install suricata 

를 통해 설치가 가능합니다. 하지만 이렇게 설치하면 3.2.3 버전이 설치 되게 됩니다.

Suricata 4버전 설치

그나마 좀 재미를 찾기 위해 최신 버전 4.0.0 을 설치해 보겠습니다. 버전명부터 따끈따끈하네요.

사전 준비

suricata 설치 가이드에서 추천하는 의존성 패키지(?) 들을 설치해 줍니다.


yum -y install gcc libpcap-devel pcre-devel libyaml-devel \

file-devel zlib-devel jansson-devel nss-devel libcap-ng-devel \

libnet-devel tar make libnetfilter_queue-devel lua-devel 

다운로드&압축해제


[root@localhost ~]# wget https://www.openinfosecfoundation.org/download/suricata-4.0.0.tar.gz

--2017-09-26 21:11:31--  https://www.openinfosecfoundation.org/download/suricata-4.0.0.tar.gz

Resolving www.openinfosecfoundation.org (www.openinfosecfoundation.org)... 96.43.130.5

Connecting to www.openinfosecfoundation.org (www.openinfosecfoundation.org)|96.43.130.5|:443... connected.

HTTP request sent, awaiting response... 200 OK

Length: 12252693 (12M) [application/x-gzip]

Saving to: ‘suricata-4.0.0.tar.gz’


100%[=========================================================================================>] 12,252,693   918KB/s   in 14s    


2017-09-26 21:11:46 (849 KB/s) - ‘suricata-4.0.0.tar.gz’ saved [12252693/12252693]

[root@localhost ~]# 

[root@localhost ~]# tar xzf suricata-4.0.0.tar.gz

이와 같이 그냥 받아서 풀어주기만 하면 됩니다.

이제 configure make make install 3종 세트를 해야 하지만 ./configure의 경우 추가 옵션이 일부 필요합니다.

그냥 해도 되긴 하지만 --enable-nfqueue 옵션이 없으면 IPS 구성이 어렵습니다. 단순 IDS만 확인하려 한다면 단순하게 ./configure만 해도 상관없습니다.


[root@localhost ~]# cd suricata-4.0.0

[root@localhost suricata-4.0.0]# ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-nfqueue --enable-lua

<생략>

[root@localhost suricata-4.0.0]# make

<생략>

[root@localhost suricata-4.0.0]# make install-full

<생략>

libhtp


[root@localhost ~]# suricata

suricata: error while loading shared libraries: libhtp.so.2: cannot open shared object file: No such file or directory

[root@localhost ~]# 

역시 오픈소스는 한번에 성공하면 성취감이 없기 때문에 위와 같이 에러가 발생합니다.

이를 해결하려면 먼저 autoconf와 libtool를 설치해줍니다.


[root@localhost ~]# yum install -y autoconf libtool

<생략>

[root@localhost ~]# curl -O https://github.com/OISF/libhtp/archive/0.5.25.tar.gz

--2017-09-26 22:10:29--  https://github.com/OISF/libhtp/archive/0.5.25.tar.gz

Resolving github.com (github.com)... 192.30.255.113, 192.30.255.112

Connecting to github.com (github.com)|192.30.255.113|:443... connected.

HTTP request sent, awaiting response... 302 Found

Location: https://codeload.github.com/OISF/libhtp/tar.gz/0.5.25 [following]

--2017-09-26 22:10:29--  https://codeload.github.com/OISF/libhtp/tar.gz/0.5.25

Resolving codeload.github.com (codeload.github.com)... 192.30.255.121, 192.30.255.120

Connecting to codeload.github.com (codeload.github.com)|192.30.255.121|:443... connected.

HTTP request sent, awaiting response... 200 OK

Length: unspecified [application/x-gzip]

Saving to: ‘0.5.25.tar.gz’



    [      <=>                                                                                 ] 464,321      401KB/s   in 1.1s   



2017-09-26 22:10:32 (401 KB/s) - ‘0.5.25.tar.gz’ saved [464321]


파일을 다운로드 한 뒤에는 보통 소스는 바로 configure make make install 형태로 진행하면 되지만 이 소스는 configure도 만들어 줘야합니다.

그래서 앞서 autoconf와 libtool을 설치했었는데요 아래와 같이 하시면 정상적으로 libhtp가 설치되는 것을 확인 할 수 있습니다.


[root@localhost ~]# tar xzf 0.5.25.tar.gz 

[root@localhost ~]# cd libhtp-0.5.25/

[root@localhost libhtp-0.5.25]# ./autoconf

<생략>

[root@localhost libhtp-0.5.25]# ./configure --prefix=/usr/ --sysconfdir=/etc/ --localstatedir=/var/  \

> --enable-unix-socket --enable-profiling --enable-geoip \

> --with-libnss-libraries=/usr/lib64 --with-libnss-includes=/usr/include/nss3 \

> --with-libnspr-libraries=/usr/lib64 --with-libnspr-includes=/usr/include/nspr4 

<생략>

[root@localhost libhtp-0.5.25]# make clean && make && make install && ldconfig

<생략>

Suricata 실행전

실제 설정 및 차단 적용

/etc/suricata/suricata.yaml 파일에서 suricata설정을 관리할 수 있습니다. 다른 부분보다는 아래 부분을 통해 HOME_NET을 설정해 주어야 합니다. 

HOME_NET은 사용자망이라고 생각하시면 되는데 모든 정책이 HOME_NET -> !HOME_NET 이나 HOME_NET -> EXTERNAL_NET 형태로 정의되는데 설정을 확인해보면 EXTERNAL_NET = !HOME_NET 형태로 정의되어 있습니다.


vars:

  # more specifc is better for alert accuracy and performance

  address-groups:

    HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"

HOME_NET 을 [192.168.101.0/24]로 변경해 줍니다.

그리고 나서 suricata만 실행해 보시면 아래와 같이 다양한 옵션들을 확인할 수 있는데 저는 IPS (inline) 형태의 구성으로 테스트 하지만 IDS의 경우 매우 간단합니다.

들어오는 인터페이스만 -i <interface> 형태로 지정해 주면 되는데, 일단 좀 더 난이도가 있는 IPS만 알아보도록 하겠습니다.


[root@localhost ~]# suricata
Suricata 4.0.0
USAGE: suricata [OPTIONS] [BPF FILTER]

        -c <path>                            : path to configuration file         -T                                   : test configuration file (use with -c)         -i <dev or ip>                       : run in pcap live mode         -F <bpf filter file>                 : bpf filter file         -r <path>                            : run in pcap file/offline mode         -q <qid>                             : run in inline nfqueue mode         -s <path>                            : path to signature file loaded in addition to suricata.yaml settings (optional)         -S <path>                            : path to signature file loaded exclusively (optional)         -l <dir>                             : default log directory <생략>

이제 실행해 보겠습니다.

실행

실행방법1 : NFQUEUE

NFQUEUE로 실행하기 전에는 한가지 설정이 필요합니다.

외부/내부 인터페이스로 통하는 트래픽을 NFQUEUE로 보내서 suricata가 처리할 수 있도록 해야합니다.


[root@localhost ~]# iptables -I FORWARD -i ens33 -o ens34 -j NFQUEUE

[root@localhost ~]# iptables -I FORWARD -i ens34 -o ens33 -j NFQUEUE

위와 같이 설정해 준 뒤에는 아래와 같이 nfqueue를 통해 실행하면 됩니다. 

앞서 iptables에서 지나가는 패킷을 nfqueue로 jump 시키게 되면서 이를 suricata에서 패킷을 제어할 수 있게 됩니다.


[root@localhost ~]# suricata -c /etc/suricata/suricata.yaml -q 0

26/9/2017 -- 22:17:18 - <Notice> - This is Suricata version 4.0.0 RELEASE

26/9/2017 -- 22:17:29 - <Notice> - all 6 packet processing threads, 4 management threads initialized, engine started.

실행방법2 : AF_PACKET

이번엔 위 방법에 이어서 iptables를 사용하지 않는 패킷 복사 방식을 통해 구성해 보도록하겠습니다.

suricata를 종료한 뒤 iptables -F 를 통해 설정된 FORWARDING 룰을 삭제 합니다.


iptables -F

이렇게 하면 윈도우 가상머신에서 인터넷이 동작하지 않게 됩니다.

이제 아래와 같이 suricata.yaml 설정에서 af-packet 파트를 수정해 줍니다.

전체 적인 내용은 들어오는 패킷을 복사해서 상대편 인터페이스로 보내준다는 것인데 아래 이미지를 보시면 af_packet과 iptables forwarding 패킷을 처리하는 차이를 볼 수 있습니다. 

af-packet은 제로 카피를 기반으로 하므로 use-mmap 설정이 둘다 켜져있어야합니다.

이미지 출처는 이곳

이론은 이정도로 하고 af-packet 설정방법은 아래와 같이 참고해서 설정파일에 넣으시면 됩니다. 기존에 있는 내용이 있으니 유의하여 넣으셔야 합니다.



af-packet:

  - interface: ens33

    cluster-id: 99

    cluster-type: cluster_flow

    defrag: yes

    buffer-size: 32768

    copy-mode: ips

    copy-iface: ens34

    use-mmap: yes

  - interface: ens34

    cluster-id: 98

    cluster-type: cluster_flow

    defrag: yes

    buffer-size: 32768

    copy-mode: ips

    copy-iface: ens33

    use-mmap: yes

약간만 설정을 더 알아보면 copy-mode 를 tap으로 하기되면 suricata는 브릿징만 하게 됩니다. 하지만 ips모드라면 af-packet을 통해 상대 인터페이스로 복사하기 이전에 룰을 검사하여 drop으로 매칭되는 패킷은 복사하지 않게 됩니다.

위와 같이 수정한 뒤 아래와 같이 이번에는 --af-packet 옵션으로 실행합니다.


[root@localhost ~]# suricata -c /etc/suricata/suricata.yaml --af-packet

26/9/2017 -- 23:37:49 - <Notice> - This is Suricata version 4.0.0 RELEASE

26/9/2017 -- 23:37:55 - <Notice> - all 8 packet processing threads, 4 management threads initialized, engine started.

끝으로

사용법이나 룰 관련해서는 역시나 다음글로 넘겨야겠네요. 글이 너무 길어지기도 하고 시간이 부족하네요.

자꾸 시작 글만 싸놓는거 같아 걱정이네요.

설치부터 실행까지 내용을 정리하려고 가능하면 중간중간 설명해야 할 것도 많지만 그냥 넘어가긴 했지만 포스팅 하나로 끝을 내긴 했네요.