네트워크보안

DNS Server Set up과 DNS Scanning

JustSangRok 2026. 5. 29. 17:38

 사람은 누구나 한 번 쯤은 DNS 서버를 구축하고 DNS Scanning로 정보를 털어버리고 싶다는 생각을 한다.

DNS 서버 구축과 DNS Scanning

오늘은 DNS 서버를 구축한 뒤, 그 서버를 대상으로 DNS Scanning을 해보겠다. nmap이 어떤 포트가 열려있는지를 캐낸다면, DNS Scanning은 이 도메인 밑에 어떤 호스트(서브도메인)들이 숨어있는지를 캐내는 작업이다.

사용하는 환경.

Rocky Linux 9.7 — DNS 서버 (스캔 대상)

Kali Linux — 공격자 (스캐닝 수행)


1. DNS Server 에 대해..

DNS(Domain Name System)는 한마디로 인터넷의 전화번호부 같은 것이다.

사람은 pse.co.kr 같은 이름을 외우지만, 컴퓨터는 192.168.10.50 같은 IP로 통신한다.

이 둘을 이어주는 게 DNS다.

              forward  →  도메인 이름으로 IP 알아내기
도메인 이름  ←——— DNS ———→  IP 주소
              reverse  →  IP로 도메인 이름 알아내기

DNS의 계층 구조

DNS는 거대한 Tree Structure로 되어 있다. 제일 위에 Root가 있고, 그 아래로 내려간다.

                    . (Root)
                   /        \
            gTLD              ccTLD
        (.com .org .net)    (.kr .jp .us)
              |                  |
          domain.com         pse.co.kr

Root — 트리의 최상위. 전 세계에 논리적으로 13개의 root 네임서버 그룹이 존재한다.

gTLD (generic Top-Level Domain) — 일반 최상위 도메인. .com, .org, .net 등.

ccTLD (country code Top-Level Domain) — 국가코드 최상위 도메인. .kr, .jp 등.

그리고 각 TLD마다 그 구역을 책임지는 권한 네임서버(authoritative name server) 가 따로 있다.

root가 모든 도메인의 IP를 직접 들고 있는 게 아니라, DNS Query가 오면 예를 들어 .kr DNS 서버한테 가봐 라는 식으로 길만 알려주는 식이다.

DNS Query(질의)는 어떻게 일어나는가

내가 브라우저에 pse.co.kr을 입력하면, 컴퓨터는 IP를 알아내기 위해 아래 순서로 찾아본다. (Windows 기준)

1) DNS Cache   →  2) hosts 파일   →  3) DNS Server
  1. DNS Cache — 예전에 한 번 접속했던 곳이면 캐시에 IP가 남아있다. 컴퓨터를 끄기 전까지는 캐시가 유지되므로 자체적으로 처리한다.
  2. hosts 파일 — 캐시에 없으면 hosts 파일을 본다. Windows에서는 C:\Windows\System32\drivers\etc\hosts, 리눅스에서는 /etc/hosts이다.
  3. DNS Server — hosts에도 없으면 resolv.conf(또는 네트워크 설정)에 적힌 DNS 서버로 질의를 보낸다.

참고로 찾아보니 Windows는 hosts 파일의 내용을 DNS 클라이언트 캐시에 미리 로드해두는 구조라, 엄밀히는 캐시 안에 hosts 내용이 들어있다고 보는 게 정확하다고 한다. 리눅스는 /etc/nsswitch.conf의 hosts: 줄(보통 files dns)이 순서를 정하는데, files(=hosts)가 dns보다 앞이라 hosts 파일이 먼저 적용된다.

여기서 DNS 서버로 넘어간 다음이 중요한데 만약 resolv.conf에 8.8.8.8(구글 공용 DNS)이 적혀 있다고 하자. 8.8.8.8에게 "pse.co.kr 주소 알아?"라고 물어보는데, 이때 두 종류의 질의가 등장한다.

재귀 질의(Recursive Query) — 클라이언트가 로컬 DNS 서버(리졸버)에게 완성된 답을 가져다 달라고 통째로 맡기는 것. 

(알아서 찾아서 IP 가져다 달라고 하는 것)

반복 질의(Iterative Query) — 답을 받은 리졸버가 root -> TLD -> 권한 서버 순으로 왔다갔다 하는 것.

각 서버는 자기는 모르지 하고 다음 DNS 서버로 가는 길만 알려준다.

 

[반복 질의 과정]
Resolver → Root server :  "pse.co.kr 어디?"  ->  ".kr server한테 물어봐러"
Resolver → .kr server  :  "pse.co.kr 어디?"  ->  "co.kr / pse.co.kr 서버한테 물어봐라"
Resolver → pse.co.kr 권한서버 : "Give me that shit"  ->  "192.168.10.50"
Resolver → 클라이언트 : "192.168.10.50 이야"   <- Established

물론 pse.co.kr은 내가 만든 사설 실습 도메인이라 8.8.8.8 같은 공용 DNS에는 존재하지 않는다.

그래서 이번에는 클라이언트가 내가 구축한 DNS 서버(192.168.10.50) 를 보게 만들 것이다.

Windows에서 현재 DNS chche를 확인하려면 ipconfig /displaydns 명령을 쓰면 된다.

 


2. Rocky Linux에 간단하게 DNS 서버 구축하기

이제 Rocky Linux에 BIND(리눅스 표준 DNS 서버 소프트웨어)를 올려보겠다.

설치

dnf -y install bind* --skip-broken

--skip-broken: 의존성이 깨져서 설치할 수 없는 패키지는 건너뛰기.
 설치 가능한 나머지만 진행하게 하는 옵션.

 named.conf(주 환경설정 파일) 수정

vi /etc/named.conf

아래 두 줄을 수정한다. (줄 번호는 버전에 따라 다를 수 잇음)

listen-on port 53 { any; };     # 11행 : 기본값 127.0.0.1 → any 로 변경
allow-query     { any; };       # 19행 : 기본값 localhost → any 로 변경

● listen-on — 어떤 IP로 들어오는 요청을 받을지. 기본값은 자기 자신(127.0.0.1)뿐이라, 외부에서 못 쓴다. any로 열어준다.

● allow-query — 누구의 질의를 허용할지. 기본 localhost에서 any로 바꿔 다른 장비도 질의할 수 있게 한다.

실무에서는 any로 활짝 여는 건 위험하다.

아무나 질의할 수 있는 Open Resolver가 되면 DNS 증폭 DDoS의 도구로 악용될 수 있기 때문이다.

 named.rfc1912.zones에 zone 등록하기

vi /etc/named.rfc1912.zones

아래 블록을 추가한다.

zone "pse.co.kr" IN {
        type master;
        file "pse.co.kr.zone";
        allow-update { none; };
};

나는 밑에 2개(pse.co.kr, test.co.kr)을 추가함

● type master — 이 서버가 해당 도메인의 주인 이라는 뜻.

● file — 실제 레코드가 담긴 파일 이름. 기준 경로는 /var/named/이다.

 /var/named/pse.co.kr.zone에서 레코드 파일 작성하기

vi /var/named/pse.co.kr.zone
$TTL    86400
@       IN      SOA     pse.co.kr.      admin.pse.co.kr. (
                        20260527        ; Serial  (변경할 때마다 올려야 함)
                        1D              ; Refresh (Slave가 갱신 확인하는 주기)
                        1H              ; Retry   (failse 시 retry 간격)
                        1W              ; Expire  (Master response 없을 때 포기 시점)
                        1W )            ; Minimum (negative chche TTL)

        IN      NS      pse.co.kr.
        IN      A       192.168.10.50
www     IN      A       192.168.10.50
blog    IN      A       192.168.10.51
chat    IN      A       192.168.10.52
ftp     IN      A       192.168.10.53

리눅스마스터랑 네트워크관리사 공부한 사람들이라면 익숙할 것 같은 레코드 파일이다.

 

 

SOA 레코드 — 그 도메인의 기본 정보 카드다. 괄호 안 5개 값은 순서대로 Serial / Refresh / Retry / Expire / Minimum이다. 특히 Serial은 레코드를 수정할 때마다 숫자를 올려줘야 Slave 서버가 변경을 인식한다고 한다. (보통 YYYYMMDDnn 형식으로 날짜+일련번호를 쓴다)

admin.pse.co.kr. 은 관리자 이메일 admin@pse.co.kr을 뜻함. zone 파일에서는 @ 대신 .을 쓴다.

줄 맨 앞이 비어있는(들여쓰기 된) 레코드 — IN NS, IN A 줄처럼 이름 칸을 비우면 "바로 위 레코드와 같은 이름(여기서는 @ = pse.co.kr)을 그대로 사용한다" 는 의미다. 반대로 www, blog처럼 맨 앞 칸에 이름을 쓰면 그게 새 호스트 이름이 된다.

중요: named.rfc1912.zones나 zone 파일 안에서 철자가 틀리면 named 재시작 때 오류가 나서 서비스가 안 뜬다. 반드시 정확히 입력해야 한다. 그리고 간격을 띄울 때 Tap키를 쓰면 편하다. 원래는 Tap키 안쓰면 오류나는 줄 알았는데 찾아보니  BIND zone 파일은 공백과 탭 둘 다 필드 구분자로 인정하므로 공백으로도 정상 동작한다고 한다. 그래도 Tap키가 가독성이 좋고 편리해서 그냥 Tap키 쓰면 된다.

named 재시작 & 클라이언트 설정

systemctl restart named

이제 클라이언트/서버가 이 DNS 서버를 보도록 resolv.conf를 수정한다.

vi /etc/resolv.conf
nameserver 192.168.10.50

 

찾아보니  Rocky 계열은 NetworkManager가 resolv.conf를 재부팅 때 덮어쓸 수 있다고 한다. 설정이 자꾸 초기화되면 NetworkManager 쪽에 DNS를 고정해줘야 한다.

도메인을 하나 더 만들고 싶다면

기존 것을 복사해서 이름만 바꾸면 된다.

# 1) zone 등록 추가 (블록 복사 후 도메인명만 변경)
vi /etc/named.rfc1912.zones

# 2) 레코드 파일 복사 후 내용 수정
cd /var/named
cp pse.co.kr.zone test.co.kr.zone
vi test.co.kr.zone        # 호스트/도메인 정보만 바꾸기

간단한 호스트(DNS 서버) 구축 끝.


3. DNS Spoofing 

DNS Spoofing은 DNS의 우선순위를 악용하는 것이다.

앞에서 IP를 찾는 순서가 cache -> hosts -> DNS Server 라고 했다. 

hosts 파일이 DNS 서버보다 우선한다는 점이 함정이다. Attacker가 Victim의 hosts 파일을 변조할 수 있다면, 정상 DNS 서버가 뭐라고 답하든 공격자가 지정한 IP(ex: 가짜 사이트)로 데려갈 수 있다.

Windows의 hosts 파일에 이렇게 적어두면:

1.1.1.1   google.com

브라우저에 google.com을 쳐도 1.1.1.1로 접속된다. 리눅스도 마찬가지다.

vi /etc/hosts
8.8.8.8   domain.co.kr

이 상태에서 ping domain.co.kr을 하면 8.8.8.8로 간다.

실제로 위조 사이트를 띄워보려면, 공격자 서버의 웹 루트에 가짜 페이지를 하나 만들어두고:

cd /var/www/html
vi index.html        <- 가까 페이지

피해자의 DNS 서버를 공격자 서버(192.168.10.50)로 바꾸거나 hosts를 변조하면, 피해자가 pse.co.kr을 입력했을 때 공격자가 만든 페이지가 그대로 뜬다.

이게 바로 피싱(phishing) 의 기본 원리다. 예를 들면 똑같이 생긴 가짜 로그인 페이지로 유도해 계정 정보를 탈취하는 것이다. hosts 파일 변조는 악성코드가 자주 노리는 지점이라고 한다.

DNS 서버는 안정성을 위해 Master / Slave(Primary / Secondary) 구조로 이중화하기도 한다. Master가 죽어도 Slave가 같은 레코드로 응답을 이어가는 구조다.


4. DNS Scanner로 Subdomain 보기

이제 Kali Linux에서 스캐닝을 해보겠다.

목표는 pse.co.kr 아래에 어떤 호스트들(www, blog, chat, ftp...)이 있는지 알아내는 것이다.

먼저 대상 서버(Rocky)에서 방화벽과 SELinux를 잠시 내려 실습 환경을 정리한다.

systemctl stop firewalld
setenforce 0                 # SELinux를 일시적으로 permissive 모드로

systemctl restart named
systemctl restart httpd

setenforce 0은 SELinux를 일시적으로 permissive 상태로 바꿈. 

그리고 Kali에서 DNS서버를 192.168.10.50으로 바꾸고 스캔 속도를 위해 아래 한줄을 주석 처리 해준다.

vi /etc/resolv.conf


# Genarated by NetworkManager
# search localdomain  ← 이 줄을 주석 처리
nameserver 192.168.10.50

search 도메인이 설정돼 있으면, 스캐너가 후보 이름마다 그 도메인을 덧붙여 불필요한 추가 Query를 날린다. 주석 처리하면 필요없는 질의가 줄어 더 빠르다.

① 첫 번째 사용 도구 - dnsmap 

dnsmap은 사전 파일(wordlist)에 있는 단어들을 도메인 앞에 하나씩 붙여가며 실제로 존재하는 서브도메인을 찾아내는 도구다.

dnsmap pse.co.kr
결과
dnsmap 0.36 - DNS Network Mapper

[+] searching (sub)domains for pse.co.kr using built-in wordlist
[+] using maximum random delay of 10 millisecond(s) between requests

blog.pse.co.kr
IP address #1: 192.168.10.51
[+] warning: internal IP address disclosed

chat.pse.co.kr
IP address #1: 192.168.10.52
[+] warning: internal IP address disclosed
...

여기서 [+] warning: internal IP address disclosed 이게 뭔지 궁금해서 찾아봤는데 서브도메인이 192.168.x.x 같은 사설 IP로 응답하고 있다는 경고라고 한다. 외부에서 DNS 질의만으로 내부망 구조가 새어나가고 있다는 뜻이고, 공격자에게는 내부 정찰의 단서가 된다.

결과 저장하기

dnsmap pse.co.kr > dns.txt          # 표준 출력을 파일로 (리다이렉션)
dnsmap pse.co.kr -r dns2.txt        # 화면 출력 + 파일 저장 (옵션 사용, 더 깔끔)

주요 옵션 (공식 man page 기준)

● -w <wordlist> — 내장 대신 외부 사전 파일 사용

● -r <파일/경로> — 결과를 일반 텍스트(plain text) 파일로 저장

● -c <파일> — 결과를 CSV 형식으로 저장

● -d <밀리초> — 요청 사이의 최대 랜덤 지연시간 설정 (기본 10ms, 트래픽이 과해 인터넷이 느려질 때 사용)

● -i <IP,IP> — 결과에서 제외할 IP 지정 

 

 

외부 사전 파일 사용

dnsmap pse.co.kr -w /usr/share/wordlists/dnsmap.txt

칼리의 /usr/share/wordlists/dnsmap.txt는 약 17,576개의 후보를 담고 있어, 이걸 다 대입하느라 시간이 오래 걸린다. 게다가 사전에 없는 단어는 못 찾는다.

그래서 모의해킹 시에는 필요한 후보만 적어놓은 사전을 쓰는 게 효율적이다.

간단하게 사전 만들기

mkdir pse && cd pse
vi dnsword.txt
www
ftp
blog
chat

여기서 dnsword.txt에 www와 ftp만 저장하고 스캔을 돌린다면 나머지는 나오지 않는것을 볼 수 있다.

dnsmap pse.co.kr -w dnsword.txt
# 절대경로도 가능
dnsmap pse.co.kr -w /root/pse/dnsword.txt

CSV로 저장

dnsmap pse.co.kr -w dnsword.txt -c dns.txt
cat dns.txt
결과
blog.pse.co.kr,192.168.10.51
chat.pse.co.kr,192.168.10.52
ftp.pse.co.kr,192.168.10.53

 

② 두 번째 사용 도구 - dmitry

dmitry(Deepmagic Information Gathering Tool)는 수동적 정보 수집과 능동적 스캔을 섞어서 쓰는 종합 도구다. whois 조회, 호스트 정보, 서브도메인, 이메일 주소 검색에 더해 TCP 포트 스캔까지 온갖거 다 한다.

dmitry pse.co.kr

 

dmitry 에서 스캔을 돌려보면 이상한게 nmap으로 포트 스캔 하면 443 포트를 찾아내지만 dmitry는 443을 놓친다.

이유는 dmitry의 기본 포트 스캔 범위가 약 1~150번 포트로 좁기 때문이다. 443은 그 범위 밖이라 보이지 않는 것이다. 

 

주요 옵션 (공식 사용법 기준)

● -w -  도메인에 대한 whois 조회

● -i -  호스트 IP에 대한 whois 조회

● -s -  서브도메인 검색

● -e -  이메일 주소 검색

● -p -  TCP 포트 스캔 수행

● -o - 결과를 파일로 저장

dmitry는 옵션을 지정하면 그 작업만 수행한다.

그래서 dmitry -w google.com처럼 -w만 주면 whois만 하고 포트 스캔은 하지 않는다. 

저장

dmitry pse.co.kr -o dmitry.txt      # -o 옵션으로 저장
dmitry pse.co.kr > dmitry.txt       # 표준 출력 리다이렉션도 가능

③ 세 번째 사용 도구 - dnsrecon 

dnsrecon은 표준 DNS enumeration과 함께, (허용되 있다면) zone transfer(AXFR) 까지 시도해 zone 파일 안의 레코드를 거의 그대로 보여준다.

dnsrecon -d pse.co.kr

 

여러 형식으로 저장

dnsrecon -d pse.co.kr -c dnsrecon.txt        # CSV 형식
dnsrecon -d pse.co.kr --db dnsrecon.sql      # SQLite DB 파일
dnsrecon -d pse.co.kr --xml dnsrecon.xml     # XML 형식

XML로 저장한 건 firefox 주소창에 file:///root/pse/dnsrecon.xml을 입력하면 브라우저에서 열어볼 수 있다.

④ 네번째 도구 - fierce

fierce도 zone(레코드) 정보를 거의 그대로 보여주는 도구다.

내가 볼 때는 dnsrecon보다 이게 더 보기는 편한 것 같다.

fierce --domain pse.co.kr