강좌
클라우드/리눅스에 관한 강좌입니다.
해킹&보안 분류

DNS서버보안 1편 : Bind DNS 개요

작성자 정보

  • 관리자 작성
  • 작성일

컨텐츠 정보

본문

DNS서버보안 1: Bind DNS 개요

 



DNS는 분산 데이터베이스의 가장 대표적인 사례이면서 인터넷에 접속하기 위해 가장 먼저 사용되는 서비스로서 웹이나 메일 등 모든 서비스가 DNS와 직접적으로 관련되어 있으므로 만약 DNS가 오작동하거나 장애가 발생한다면 그 피해는 걷잡을 수 없이 커질 것이다




그럼에도 불구하고 보안의 사각지대라 불릴 만큼 적지 않은 관리자들이 DNS의 작동원리 및 보안에 대해 무지한 것이 사실이다




또한 일부에서는 다음 세대의 공격 대상 유형으로 라우터와 함께 DNS가 언급되고 있어 DNS 프로토콜의 취약성에 대해 이해하고 이에 대한 보안대책을 수립하는 것이 시급하다고 생각한다.

 

실제로 많은 관리자들이 DNS에 도메인을 설정하는 방법은 알고 있어도 DNS와 관련한 문제가 발생하거나 오작동을 할 때에는 어떻게 대응하여야 하는지 당황하는 경우가 많은 것 같다



만약 DNS 서버와 관련된 장애가 발생할 경우에는 설정되어 있는 도메인 전체에 영향을 주기 때문에 신속한 대처가 매우 중요하며 특히 캐시(cache)라는 개념이 있기 때문에 설사 DNS 서비스가 복구되었다 하더라도 예상외로 장애시간이 길어질 수 있다는 문제가 있다.



 

따라서 이번 장에서는 DNS의 표준이라 할 수 있는 Bind DNS를 중심으로, 잘못 알고 있는 DNS에 대해 알아보고 아울러 복잡한 설정 없이 간단한 설정만으로 DNS 보안을 강화할 수 있는 방안에 대해 알아보도록 하자.






지금부터 살펴보려는 bind DNS는 전체 DNS70% 이상을 차지하고 있으므로 DNS = “bind DNS”라고 할 정도로 bindDNS의 표준이 되어있다 라고 할 수 있다.

 

 

 

 

단순히 표준일 뿐만 아니라 서비스의 안정성이나 성능, 기능 등의 이유로 실제로도 그만큼 많이 사용되고 있기 때문에 bind DNS에 대해 잘 알고 있을 필요가 있다.

 

1. Bind DNS에 대한 소개

 

Bind DNS 홈페이지 : http://www.isc.org/

 

d11d3dd421fcb730d23e5be1c34d389e_1671592711_9274.png
 

[그림] ISC 홈페이지

 

 

현재까지 안전한 Bind DNS 버전은?

 

현재를 기준으로 가장 안정한 bind 버전은 무엇인지 확인하기 위해 아래의 URL에 접속하여 어떤 버전이 어떤 취약성이 있는지 확인하기 바란다.

 

 

 

 

 

 

http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=bind

 

새로운 취약성이 계속적으로 보고되고 있으므로 언제나 최신의 DNS 서버를 운영하는 것이 중요하다.

 

 

 

 

다행스럽게도 최근에는 bind에서 심각한 보안취약성이 보고된 바는 없다.

 

 

 

 

 

 

어떤 Bind 버전을 사용하여야 하나?

 

bind4.x 버전부터 시작하여 8.x 버전을 거쳐 9.x 버전이 배포되면서 현재 전 세계적으로 여러 버전의 bind가 함께 사용되고 있는 추세이다.

 

 

 

 

그러나 bind 4.x 버전은 보안등의 문제로 사용자층이 계속 줄어들어 현재는 거의 없으며 이미 개발도 중단된 상태이다.

 

 

 

 

bind 9.xbind 8.x가 워낙 보안 취약성이 많아 완전히 새롭게 코드를 작성하였고 DNSSEC등 새로운 보안기능이 추가되었다.

 

 

 

 

그러나 초기에는 성능적인 측면에서 기존의 8.x에 비해 부족한 면이 많았지만 이후 성능이나 안정성 모두 만족스러울 정도로 개선되어 최근에는 거의 대부분 bind 9.x를 사용하고 있는 추세이다.

아울러 bind의 대안으로 djbdnsnsd등도 일부 사용되고 있는데, 각각에 대해 간단히 살펴보도록 하자. djbdns(http://cr.yp.to/djbdns.html)qmail의 개발자인 Bernstein 박사가 개발한 것으로 qmailsendmail의 대안으로 개발된 것처럼, djbdnsbind의 대안으로 개발된 것이다.

 

 

 

 

따라서 애초부터 보안을 고려하여 설계되었으나 zone-transfer를 제공하지 않고, TCP 53을 지원하지 않는 등 일부 표준 DNS 프로토콜을 따르지 않는 문제가 있으며 기타 새로운 기능을 제공할 계획이 없다고 한다.

 

 

 

 

또한 nsdName Server Daemon의 약자로 위임 도메인에 대한 Query 응답률이 우수한 것으로 알려진 bind에 비해 훨씬 우월한 성능을 발휘하여 현존하는 DNS중 위임 도메인에 대한 성능이 가장 좋은 것으로 알려져 있다.

 

 

 

 

루트 네임서버 중 K,H,I 에서 실제로 사용 중인 것으로 알려져 있다.

 

 

 

 

 

d11d3dd421fcb730d23e5be1c34d389e_1671592735_6506.png
 

[그림] nsd의 성능 차이

 

하지만 Authoritative-only이기 때문에 recursion등이 제공되지 않아 일반적인 DNS resolving의 용도로는 다소 부적합하다.

 

 

 

 

nsd에 관심 있는 독자는 nsd 홈페이지인 http://www.nlnetlabs.nl/nsd/을 참고하기 바란다.

bind 92000년부터 개발이 진행되었는데, 차후 수년간 멀티스레딩, 멀티프로세서, 대용량 램 등이 지원되는 bind 10 버전에 대한 개발도 착수한다고 한다.

 

 

 

 

 

그리고 전 세계적으로 bind는 약 70%, Microsoft DNS20% 그리고 독일의 powerdns

(http://www.powerdns.com/)가 약 10% 정도 사용 중인 것으로 알려져 있다.

 

 

 

 

Bind 9로 업그레이드 시 주의할 점

 

만약 bind 4.x8.x를 사용하다가 bind 9.x로 업그레이드를 한다면 bind 9.x에서 특히 주의할 점이 몇 가지 있다.

 

 

 

 

 

 

- named.confzone 파일에서의 에러 시

 

bind 8.x에서는 named.confzone 파일에서 에러가 있어도 에러가 나는 부분만 skip할 뿐 서비스에는 지장이 없지만, bind 9.x의 경우 특정한 에러가 있다면 아예 서비스를 시작하지 않는다.

 

 

 

 

아래의 로그를 보면 특정 zone정보를 잘못 정의했을 경우 아예 서비스가 작동하지 않는 것을 확인할 수 있다.

 

 

 

 

 

Oct 18 20:47:01 dns /usr/sbin/named[6501]: zone 'server.zone': missing 'masters' entry

Oct 18 20:47:01 dns /usr/sbin/named[6501]: loading configuration: failure

Oct 18 20:47:04 dns /usr/sbin/named[6501]: exiting (due to fatal error)

 

- $TTL 설정

 

bind 8.2 이상에서는 default TTL 값을 각 zone 파일의 상단에 정의하여야 한다.

“$TTL 1D”와 같이 정의하면 되며 만약 정의하지 않으면 로그 파일에 에러메시지가 출력되며 임시로 SOA에서 정의한 TTL 값을 사용하게 되는데, 그렇다 하더라도 특별히 사용상의 특별한 문제는 없다.

 

 

 

 

아래는 이때 보이는 로그 메시지이다.

Oct 18 21:58:12 dns named[24291]: server.zone:2: no TTL specified; using SOA MINTTL instead

Oct 18 21:58:12 dns named[24291]: zone server.com/IN: loaded serial 200311700

 

zone 파일의 최상단에서 명시한 $TTLpositive cache로 긍정적 캐싱이라 하며 정상적인 응답에 대한 캐싱을 하며 통상적으로 하루(1D)를 사용한다.

 

 

 

 

그렇다면 이 값의 최대값은 얼마일까? 물론 zone 파일에는 10일이든 100일이든 제한 없이 설정할 수 있지만, 그렇다하더라도 해당 zone을 캐싱 하는 DNS서버에서는 최대 7일을 넘지 못한다.

 

 

 

 

, 위임권한을 가진 DNS에서 $TTL7일 이상을 지정하였다 하더라도 Resolving DNS에서는 해당 도메인에 대한 정보를 7일까지만 캐싱 하게 된다는 의미이다.

 

 

 

 

 

반면 SOA에서 정의된 Minimum TTLnegative cache로 부정적 캐싱이라 하며 존재하지 않는 레코드에 대한 응답에 대하여 캐싱을 정의하는데, 최대값은 3시간(3600* 3시간 = 10800)으로 지정되어 있다.

 

 

 

 

따라서 만약 이 값보다 크게 설정한다 하더라도 3시간이 최대값으로 인식된다.

 

 

 

 

이는 "dig @ns.dacom.co.kr non-exist.server.com"을 질의하면 아래와 같이 최대 10800부터 시작되는 것을 보고 알 수 있다.

 

 

 

 

그러나 긍정적캐싱 $TTL3시간보다 적게 설정되었을 경우에는 그 값을 따르게 된다.

 

 

 

 

, $TTL3600(1시간)이면 부정적캐싱도 3시간이 아닌 1시간이 되는 것이다.

 

 

 

 

 

 

;; AUTHORITY SECTION:

server.com. 10800 IN SOA

 

아직도 적지 않은 관리자들이 긍정적 캐싱과 부정적 캐싱의 의미와 차이에 대해 잘못 알고 있는 것 같은데, 이번 기회에 그 차이점을 정확히 이해하기 바란다.

 

- rdnc 지원

bind 8.x에서는 DNS 서버의 작동을 제어하기 위해 ndc라는 명령어를 제공하였지만 bind 9.x에서는 이것이 rndc로 바뀌었다.

 

 

 

 

이 툴을 이용하면 설정파일과 zone을 다시 로딩하고 DNS 서버를 제어하는 등의 여러 작업을 할 수 있다.

 

- 멀티 쓰레드 지원

 

bind 9.x에서는 이전 버전과 달리 멀티 쓰레드를 지원하여 다음과 같이 여러 개의 named 프로세스가 보인다.

 

 

 

 

만약 멀티 쓰레드를 이용하기 원하지 않는다면 configure./configure --disable-threads를 실행하면 된다.

 

 

 

 

 

 

# ps aux|grep named

named 436 0.0 5.5 30896 28420 ? S Apr09 0:00 [named]

named 437 0.0 5.5 30896 28420 ? S Apr09 0:00 [named]

named 438 0.2 5.5 30896 28420 ? S Apr09 803:53 [named]

named 440 0.0 5.5 30896 28420 ? S Apr09 2:30 [named]

named 441 0.0 5.5 30896 28420 ? S Apr09 124:10 [named]

 

Bind 설치

 

bind의 소스는 ftp://ftp.isc.org/isc/에서 제공하고 있으며 rpm등 다른 형식은 제공하고 있지 않다.

 

 

 

 

만약 rpm 형식의 파일을 원하면 아래와 같이 rpmfind.net에서 각자의 버전에 맞는 rpm을 검색 및 다운로드하여 설치하면 된다.

 

http://rpmfind.net/linux/rpm2html/search.php?query=bind

 

설치 시에는 bind-utils도 함께 설치하여야 dig이나 nslookup 등의 관련 명령어(유틸리티)를 이용할 수 있다.

 

 

 

 

 

 

Bind 버전정보 확인

 

현재 설치되어 있는 bind 버전을 확인하는 방법은 여러 가지가 있다.

 

 

 

 

먼저 named가 구동을 시작할 때 /var/log/messages 파일에 남는 정보를 보고 확인가능하다.

 

 

 

 

Feb 17 06:09:13 ns2 named[1755]: starting BIND 9.3.3rc2 -u named

 

또는 다음과 같이 -v 옵션을 주어 실행해도 확인 가능하다.

 

 

 

 

 

# named -v

BIND 9.3.3rc2

 

위의 두 방법은 named가 설치되어 있는 local에서만 확인 가능하지만 아래의 두 방법은 원격지에서도 확인 가능한 방법이다.

 

 

 

 

물론 뒤에서 이러한 버전정보 요청을 차단하는 방법에 대해 알아볼 것이다.

 

 

 

 

첫 번째로 nslookup을 이용한 방법이다.

 

 

 

 

 

# nslookup

 

[root@dns /root]# nslookup

> server dns.server.com

> set class=chaos

> set type=txt

> version.bind

Server: dns.server.com

Address: 192.168.1.5

 

VERSION.BIND text = "9.3.3rc2"

 

또는 아래와 같이 한 번에 질의할 수도 있다.

 

 

 

 

 

[root@dns /root]# nslookup -q=txt -class=chaos version.bind dns.server.com

 

두 번째로 dig(domain information groper)을 이용한 방법인데, 아직 많은 사람들이 nslookup에는 익숙하지만 dig에는 익숙하게 사용하지 못하고 있는데, 점차 nslookup 대신 dig을 사용하는 추세이므로 dig에 대한 사용법을 익힐 것을 권장한다.

 

 

 

 

[root@dns /root]# dig @dns.server.com txt chaos version.bind

 

 

2. DNS 자체의 취약성

앞에서 DNS 프로토콜은 자체적으로 취약성을 가지고 있다고 언급 하였는데, 그렇다면 어떠한 취약성을 가지고 있을까? 이는 크게 DNS Cache Poisoning과 서비스거부(Dos)로 나눌 수 있는데, 서비스거부에 대해서는 각각의 보안 설정에서 따로 언급할 것이므로 여기에서는 꾸준히 제기되고 있는 공격 형태인 DNS Cache Poisoning에 대해 알아보도록 하자.

아래는 대표적인 Cache Poisoning 공격 방식의 예를 보여주고 있다.

 

 

 

 

 

 

d11d3dd421fcb730d23e5be1c34d389e_1671592769_1032.png
 

[그림] Birthday attack

 

공격자(attacker)는 해당 DNS에 특정 도메인(server.com)에 대한 많은 질의를 한다.

공격자는 해당 DNS에 질의한 도메인(server.com)에 대해 질의와 동시에 위조된 응답을 보낸다.

이후 클라이언트가 해당 DNS 서버에 server.com 도메인에 대한 정상적인 질의를 한다.

 

 

 

 

 

DNS 서버는 -번 공격에 의해 잘못된 캐시(cache poisoned) 정보를 제공한다.

 

공격자의 입장에서 핵심적인 과정은 ,번 단계인데, 번 과정에서 동시에 server.com 에 대한 많은 질의를 하게 되면 recursion(재귀, 반복, 순환) 질의가 허용된 Victim DNS 서버는 server.com의 실제 DNS 서버(이를테면 ns1.server.com)에 질의를 한 후 응답을 기다리게 될 것이다.

 

 

 

 

여기에서 중요한 것은 ns1.server.com으로부터 정상적인 응답이 오기 전에 번 과정 즉 위조된 응답이 선행되어야 한다는 것이다.

 

 

 

 

DNS는 같은 질의에 대한 응답이라도 먼저 온 응답만을 수용하고, 실제 응답이라도 다음에 온 응답은 거부하기 때문이다.

 

 

 

 

그렇다면 DNS는 자신이 질의한 응답에 대해 어떤 패킷이 자신이 질의한 응답인지를 구분할까? 기본적으로 응답 패킷의 소스IP, 소스 포트는 질의 패킷의 목적지 IP 및 목적지 포트와 동일해야 할 것이다.

 

 

 

 

 

 

, 소스IP : 100.100.100.1 소스포트 :1500이고,

목적지IP : 100.200.100.2, 목적지 포트 : 53

질의 패킷을 DNS 서버에 전송하였을 경우, DNS 서버로부터 전송되는 응답 패킷은 다음과 같아야 한다는 것이다.

 

소스 IP : 100.200.100.2 소스포트 :53

목적지 IP : 100.100.100.1, 목적지 포트 : 1500

 

그러나 IP와 포트만으로는 인증을 하기에 부족하므로 이를 위해 DNS 질의 메시지와 응답 메시지에는 별도로 1부터 65535번까지 가능한 16비트 번호의 transaction id라는 것을 사용하고 있다.

 

 

 

 

, 질의를 할 때 10000번의 id를 발급하여 질의하였다면 해당 응답 메시지에도 10000번의 id로 응답하여야 한다는 것이다.

 

 

 

 

다시 말하면, DNS 질의에 대한 응답 메시지는 IP와 포트, transaction id 이 세 가지가 모두 동일해야 인증이 가능하다는 것이다.

 

 

 

 

그렇다면, IP와 포트번호는 일반적으로 쉽게 추측이 가능하므로 id만 추측할 수 있다면 DNS cache를 쉽게 오염(poisoning)시킬 수 있을 것이다.

 

 

 

 

 

 

다시 위의 그림을 살펴보면, 제목에 “Birthday(생일) attack”이라고 되어 있는데, 왜 하필 Birthday attack이라고 하였을까? 이는 한 조직이나 모임에 서로 다른 많은 사람들이 있지만 우연히 생일이 같은 경우가 종종 있기 때문에 유래한 것인데, 마찬가지로 2번 과정에서 임의의 transaction id를 생성하여 응답하지만 우연히 DNS 클라이언트가 질의 시 사용한 id와 동일할 가능성이 있기 때문이다.

 

 

 

 

 

공격자의 입장에서 또 한 가지 고려해야 할 것은 앞에서 잠시 언급했듯이 번 과정에서의 위조된 응답이 실제 DNS 서버의 응답보다 먼저 이루어져야 한다는 것이다.

 

 

 

 

이를 위해서는 해당 DNS 서버가 다운되었거나 서비스거부 공격을 당하고 있는 상태라면 응답을 하지 못하거나 응답을 늦게 하게 될 것이다.

 

 

 

 

 

 

현재 bind 4.x 버전과 bind 8.x 버전은 이러한 형태의 공격에 취약한 것으로 알려져 있으며 bind 9.x 버전은 randomid를 생성하므로 그나마 안전한 것으로 알려져 있지만 질의를 할 때 소스 포트가 random하지 않아 일정 정도 추측이 가능하다는 취약점이 있다.

 

 

 

 

반면 Cache poisoning에 가장 안전한 DNSdjbdns(http://cr.yp.to/djbdns.html)인 것으로 알려져 있는데, dbjdns는 질의 시 id 뿐만 아니라 소스 포트도 random하게 생성함으로써 이 문제를 해결하고 있다.

 

 

 

 

참고로 앞서 말했듯이 djbdns는 애초부터 bind의 취약성에 대해, 보안을 고려하여 디자인하였지만 dns 표준을 따르지 않는 등의 몇 가지 문제가 있다.

 

 

transaction id는 어떻게 확인할 수 있을까? 간단히 아래와 같이 tcpdump로 확인할 수도 있다.

 

 

 

 

여기에서 56064transaction id이다.

 

 

 

 

 

# tcpdump port 53

client.47978 > server.domain: [udp sum ok] 56064+ A? sevrer.com. [|domain] (DF) [tos 0x10] (ttl 64, id 0, len 54)

server.domain > client.47978: 56064* q: A? tt.co.kr. 1/1/1 server.com. A server.com ns: server.com. NS[|domain] (DF) (ttl 63, id 0, len 104)

 

또는 아래와 같이 dig으로 질의 시 보이는 메시지에서도 확인할 수 있다.

 

 

 

 

역시 56064transaction id이다.

 

# dig server.com

 

; <<>> DiG 9.3.3rc2 <<>> server.com

;; global options: printcmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56064

 

 

 

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,041 명
  • 현재 강좌수 :  35,855 개
  • 현재 접속자 :  87 명