본문으로 바로가기

안녕하세요, SATAz입니다.

이번 포스팅은 IPTables에 대해서 소개드리는 열 번째 내용입니다.



지난 포스팅에서는 hashlimit를 이용한 Flooding 공격 방어에 대해서 다루었는데요,

이번 포스팅은 IPTables의 limit 매치를 이용하여 Flooding 공격을 방어하는 방법에 대해서 알려드리고자 합니다.


limit 매치는 connlimit, recent, limit 매치와는 다르게, DROP정책이 아닌 ACCEPT 정책을 통해서 트래픽을 제한합니다.

상당히 특이한 매치입니다...



▣주의!!! : 이 블로그에 작성된 IPTables 포스팅들은 교육용으로 작성된 내용입니다. 

 서비스 중인 서버에 아래의 내용만 갖고 바로 적용하지 마시고, 서버에 적용 전에 반드시 테스트를 거치시기 바랍니다.  IPTables도 방화벽인지라, 무턱대고 서버에 적용했다가는 서비스 중단되는 사태가 발생할 수 있습니다. 필히 주의하셔야합니다!!!


#IPTables 설정를 위한 환경


- 테스트 머신 : VMware WorkStation 12 Player

- 운영체제 : CentOS/RHEL 7 - 64bit ( Minimal 설치 )

- 메모리 : 2GB

- IPTables Version : iptables v1.4.21

- 서버 아이피 : 192.168.0.18


# 공격을 위한 서버 설정 환경

- 공격자 테스트 머신 : VMware WorkStation 12 Player

- 공격자 운영체제 : CentOS/RHEL 6 - 64bit ( Minimal 설치 )

- 공격자 메모리 : 2GB

- 공격자 서버 아이피 : 192.168.0.19



1. limit를 이용해서, 비정상적으로 많은 접근이 발생하는 것을 차단하자

 IPTables에는 limit라는 매치가 있습니다. limit 1초/1분/1시간 단위로 패킷이 들어오는 횟수를 선허용하고, 그 다음 패킷을 후차단하는 설정입니다.


※ limit 매치는 DROP 정책이 아니라, ACCEPT 정책을 사용합니다!!!


# limit를 이용한 패킷 차단 명령어

iptables -D INPUT -s 0.0.0.0/0 -d 192.168.0.18/32 -p tcp --dport 80 -j ACCEPT

iptables -I INPUT -m limit -p tcp -d 192.168.0.18 --dport 80 --limit 10/m --limit-burst 10  -j ACCEPT


위의 명령어는 다음과 같이 해석이 가능합니다.

첫 번째 줄 : 192.168.0.18 아이피의 80/tcp로 들어오는 패킷 허용 정책을 삭제한다.

두 번째 줄 : 처음 10번째 패킷을 허용하고, 11번째 패킷부터는 차단한다. 6초마다 패킷을 1개씩 허용한다. 


역시나 80포트의 속도제한을 위해서 ACCEPT를 걸다보니, 기존에 전체 허용되어있던 룰을 삭제해주셔야합니다.

안그러면 80포트 전체허용되는 룰에 걸려서, 속도제한이 먹히지가 않습니다.


어느정도 패킷이 허용되었는지를 확인하기 위해서, 로그도 함께 남겨놓도록 설정하겠습니다.


# 명령어의 적용

[root@localhost ~]# iptables -D INPUT -s 0.0.0.0/0 -d 192.168.0.18/32 -p tcp --dport 80 -j ACCEPT

[root@localhost ~]# iptables -I INPUT -m limit -p tcp -d 192.168.0.18 --dport 80 --limit 10/m --limit-burst 10  -j ACCEPT

[root@localhost ~]# iptables -I INPUT -m limit -p tcp -d 192.168.0.18 --dport 80 --limit 10/m --limit-burst 10  -j LOG --log-prefix "[Im Accepted]:"

[root@localhost ~]# iptables -nL

Chain INPUT (policy ACCEPT)

target     prot opt source               destination         

LOG        tcp  --  0.0.0.0/0            192.168.0.18         limit: avg 10/min burst 10 tcp dpt:80 LOG flags 0 level 4 prefix "[Im Accepted]:"

ACCEPT     tcp  --  0.0.0.0/0            192.168.0.18         limit: avg 10/min burst 10 tcp dpt:80

ACCEPT     all  --  0.0.0.0/0            192.168.0.18         state RELATED,ESTABLISHED

ACCEPT     tcp  --  192.168.0.2          192.168.0.18         tcp dpt:22

ACCEPT     all  --  192.168.0.1          192.168.0.18        

ACCEPT     all  --  8.8.8.8              192.168.0.18        

DROP       all  --  0.0.0.0/0            192.168.0.18        


Chain FORWARD (policy ACCEPT)

target     prot opt source               destination         


Chain OUTPUT (policy ACCEPT)

target     prot opt source               destination  


로그가 딱 5개만 찍혔습니다. 

그 이유는, 패킷 개수는 접속 횟수를 의미하는 것이 아니기 때문입니다.

통신 과정에서 발생하는 모든 패킷을 의미합니다. 따라서 3way handshake 에 의해서 연결이 성립이 되면, 

최소 한번 접속할 때에는 두개 정도의 패킷이 들어오는 것입니다. 


# 로그 상태 - DOS 공격 (Flooding)

[root@localhost ~]# tail -f /var/log/iptables_log

Aug  6 11:23:22 localhost kernel: [Im Accepted]:IN=ens33 OUT= MAC=00:0c:29:a9:76:18:00:0c:29:c8:f6:8a:08:00 SRC=192.168.0.19 DST=192.168.0.18 LEN=58 TOS=0x00 PREC=0x00 TTL=128 ID=16595 DF PROTO=TCP SPT=56774 DPT=80 WINDOW=16425 RES=0x00 ACK PSH URGP=0 

Aug  6 11:23:28 localhost kernel: [Im Accepted]:IN=ens33 OUT= MAC=00:0c:29:a9:76:18:00:0c:29:c8:f6:8a:08:00 SRC=192.168.0.19 DST=192.168.0.18 LEN=58 TOS=0x00 PREC=0x00 TTL=128 ID=16597 DF PROTO=TCP SPT=56735 DPT=80 WINDOW=16425 RES=0x00 ACK PSH URGP=0 

Aug  6 11:23:50 localhost kernel: [Im Accepted]:IN=ens33 OUT= MAC=00:0c:29:a9:76:18:00:0c:29:c8:f6:8a:08:00 SRC=192.168.0.19 DST=192.168.0.18 LEN=52 TOS=0x00 PREC=0x00 TTL=128 ID=16641 DF PROTO=TCP SPT=56775 DPT=80 WINDOW=8192 RES=0x00 SYN URGP=0 

Aug  6 11:23:50 localhost kernel: [Im Accepted]:IN=ens33 OUT= MAC=00:0c:29:a9:76:18:00:0c:29:c8:f6:8a:08:00 SRC=192.168.0.19 DST=192.168.0.18 LEN=52 TOS=0x00 PREC=0x00 TTL=128 ID=16642 DF PROTO=TCP SPT=56776 DPT=80 WINDOW=8192 RES=0x00 SYN URGP=0 

....



2. limit 매치의 방식을 더욱 쉽게 이해해보자.

가) --limit 10/m 은 일종의 타이머라고 보시면 됩니다. --limit-burst 10 은 카운트(count)라고 보시면 됩니다. 그리고 여러분은 20개의 패킷을 동시에 서버로 보낸다고 가정합시다.

나) --limit-burst 설정에 의해서 첫 10개의 패킷은 그냥 통과가 가능합니다. 패킷이 1개 들어올 때 마다 count가 -1이 되기 때문에, 10개가 통과하면 count는 0이 됩니다.

다) count는 0이 되었기 때문에 11번째 패킷부터는 차단이되고, 클라이언트는 재요청을 하거나 응답을 기다립니다.


라) 10/m은 다음과 같이 계산이 되어, 6초마다 count가 +1이 됩니다. [60초 / 10개 = 6초 / 1개]

마) 30초가 지나면 count는 5, 60초가 지나면 count는 10이 되어있겠죠.

바) 만약 30초 후에 다시 20개 패킷이 동시에 발생하게 되면, count가 5이기 때문에 5개의 패킷만 통과가 되고 그 이후 패킷은 차단이 됩니다.

사) 마찬가지로 60초 후에 다시 20개 패킷이 동시 발생하게 되면, count는 10이기 때문에 10개의 패킷만 통과되고 그 이후 패킷은 차단됩니다.


아) 만약에 600초가 지났다 하더라도 --limit-burst의 값이 10이기 때문에, count는 10까지만 유지하고 그 이상 넘어가지 않습니다.



3. 방화벽 설정을 걸기 전에! hashlimit의 한계를 알고, 실 서비스에 적용하자

다른 것과 마찬가지로, 아이피를 변조하거나 DDOS 공격을 받게되면 차단할 수가 없습니다.

1. 특정 아이피에 대해서 패킷을 제한하는 것이기 때문에, 아이피를 변조하거나 DDOS 공격이 들어오면 차단할 수가 없다.

2. iptables를 재시작하지 않는 이상, 차단된 아이피를 풀어줄 수가 없다. 방화벽에서 추가적으로 허용을 해줘야한다. (이번 한번만 풀어주겠다... 뭐 이런 것이 안된다는 의미입니다,)


사실 limit 또한 특정 시간이 지나면 추가적인 연결이 가능한 특징을 갖고있습니다. 

다만, 이것도 DDOS처럼 전혀 다른 아이피들이 1번씩만 접근을 시도하는 공격은 차단할 수가 없습니다.


마찬가지로, 아이피 변조 및 DDOS 공격의 경우에는 PREROUTING을 이용해서 방어가 가능합니다.




4. 혹시 limit 매치에 ACCEPT가 아닌 DROP을 시킨다면?

소제목과 같이 ACCEPT가 아닌 DROP을 시킬 경우에는 반대가 될 것입니다. 그러면 해석은 아래와 같이 바뀌게 되겠죠.


# limit를 이용한 패킷 차단 명령어

iptables -I INPUT -m limit -p tcp -d 192.168.0.18 --dport 80 --limit 10/m --limit-burst 10  -j DROP


처음 10번째 패킷을 차단하고, 11번째 패킷부터는 허용한다. 6초마다 패킷을 1개씩 차단한다. 


뭐... 단순하게 생각하면 DDOS도 막을 수 있는거 아닌가? 라고 생각을 하시겠지만...

정상적으로 서비스를 이용하는 사람들의 패킷도 위와 같이 차단되기 때문에 사용하시는 것을 비추합니다.



5. limit vs hashlimit vs recent 매치는 어떤 차이가 있을까?

가) hashlimit & recent은 DROP 정책을 사용해서 패킷을 제한하지만, limit은 ACCEPT로 패킷을 제한한다.

나) recent는 차단된 아이피를 풀어주는 명령어가 있으나, hashlimit & limit 은 그러한 기능이 없다.



항상 상황에 맞는 매치를 사용하는 것이 중요합니다. 하지만 limit 함수는... 다른 좋은 매치가 있어서 굳이 이 것을 어느 상황에 사용해야하는지는 잘 모르겠습니다.


근데 다른 블로그에서 limit 매치를 잘못 소개하는 곳이 많아서 제가 한번 포스팅해보았습니다.



다음 시간에는 DDOS를 방어하는 방법에 대해서 포스팅하려고 합니다.

글이 길어지는 것은 아니지만 셋팅하는데 좀 애먹을 것 같아서 시간이 좀 걸릴 것 같네요 ^^


긴 글 읽어주셔서 감사합니다 ^^

반응형