DHCP DNS 스푸핑의 무기화 - 실무 가이드
서론
이 블로그 시리즈의 첫 번째 파트 에서는 Microsoft DHCP(Dynamic Host Configuration Protocol) 서버를 사용하는 Active Directory 도메인을 대상으로 한 새로운 공격에 대해 소개했습니다. 공격자는 이러한 공격으로 DHCP DNS Dynamic Update 기능을 악용해 ADIDNS(Active Directory Integrated DNS) 영역의 DNS 레코드를 스푸핑할 수 있습니다. Akamai는 이 기능의 작동 방식을 살펴보고 공격자가 민감한 DNS 레코드를 스푸핑하기 위해 악용할 수 있는 잘못된 설정을 집중 조명했습니다.
두 번째 블로그 게시물에서는 이 공격표면을 악용하는 데 필요한 몇 가지 기술적 세부 사항을 자세히 설명하고자 합니다. 공격을 실행하는 데 필요한 모든 정보 수집 방법을 자세히 설명하고, 몇 가지 공격 제한 사항에 대해 알아보고, 흥미로운 DHCP 서버 동작을 악용해 여러 DNS 레코드를 스푸핑하는 방법을 살펴보겠습니다.
마지막으로 여러분의 툴 상자에 추가할 만한 새로운 툴을 소개합니다. Akamai는 모든 학습 내용을 결합해 레드팀과 블루팀이 DHCP DNS 공격을 수행하고 연구할 수 있는 Python 툴인 DDSpoof 를 만들었습니다. 이 블로그 게시물의 뒷부분에서는 여러 공격 시나리오에서 이 툴을 어떻게 활용할 수 있는지 설명하겠습니다.
주의: DDSpoof는 보안팀이 리스크를 식별하는 동시에 공격표면에 대한 인식을 높이는 데 도움이 될 수 있습니다. 그러나 툴 하나만으로는 실제 피해를 주기에 충분치 않으며, DNS 스푸핑 프리미티브를 악용하기 위해서는 네트워크 접속 및 추가적인 악용이 필요합니다.
DHCP 열거
이전 게시물에서는 DHCP DNS 스푸핑의 이론을 공유했습니다. 실제로 앞서 설명한 공격을 효과적으로 실행하려면 몇 가지 정보가 필요합니다. 다행히 공격자 입장에서는 DHCP 서버를 발견하고 설정에 대해 알아내는 기능이 DHCP 프로토콜의 일부이므로 정찰 과정이 간단합니다.
다음 섹션에서는 공격자가 인증되지 않은 맥락에서 이러한 다양한 정보를 수집하기 위해 사용할 수 있는 다양한 방법과 트릭에 대해 설명합니다.
DHCP 서버 식별
DHCP DNS 공격에서 가장 중요한 부분은 표적 DHCP 서버이므로 첫 번째 단계는 서버를 식별하는 것입니다. 네트워크에서 활성 DHCP 서버를 식별하는 방법은 매우 간단합니다. 공격자가 DHCP Discover 브로드캐스트를 전송하고 서버의 Offer 응답을 검사하면 됩니다.
DHCP 메시지를 전송하기 위해 DHCP 서버와의 상호 작용을 허용하는 설정 가능한 DHCP 클라이언트인 dhclient Linux 유틸리티를 실행할 수 있습니다. dhclient 는 /etc/dhcp/dhclient.conf에 있는 설정 파일을 편집해 설정할 수 있습니다.
이 파일을 실행하면 dhclient 가 DHCP 서버에 네트워크 설정을 요청하고 이를 머신에 적용해 현재 IP 주소를 재정의합니다. 이를 방지하기 위해 다음 구문을 사용해 가상 인터페이스 에서 파일을 실행할 수 있습니다.
dhclient <interface_name>:<virtual_interface_name>
이 명령을 실행하면 원래 IP 주소(172.25.14.55)가 변경되지 않은 상태로 가상 인터페이스가 DHCP 서버로부터 새 IP 주소를 받은 것을 확인할 수 있습니다(그림 1).
트래픽을 기록하고 DHCP Offer 메시지를 검사하면 모든 활성 DHCP 서버를 식별할 수 있습니다(그림 2).
DHCP 서버의 도메인 및 DNS 서버 가져오기
네트워크에서 DHCP 서버를 식별한 후에는 각 서버를 통해 어떤 레코드를 스푸핑할 수 있는지 알아야 합니다. DHCP 서버는 연결된 ADI 영역 내에서만 레코드를 만들 수 있으며, ‘aka.test’ 도메인과 연결된 서버는 동일한 접미사 <hostname>.aka.test를 가진 DNS 레코드만 작성할 수 있습니다. 스푸핑 가능한 레코드를 알아내려면 이 접미사를 식별해야 합니다.
또한 새 레코드를 호스팅할 DNS 서버를 알아야 해당 레코드를 쿼리하고 공격의 성공 여부를 확인할 수 있습니다.
공격자가 이 두 가지 매개변수를 찾기 위해 사용할 수 있는 한 가지 트릭은 특정 설정에 대해 DHCP 서버에 쿼리할 수 있는 매개변수 요청 목록 옵션입니다. 여기서는 서버의 관련 도메인 이름 및 도메인 이름 서버 옵션을 쿼리할 수 있습니다.
이제 다시 dhclient를 사용할 수 있습니다. 매개변수 요청 목록 옵션을 검색 메시지에 추가하려면 dhclient의 설정 파일에 다음 줄을 추가합니다.
request domain-name, domain-name-servers;
이전과 마찬가지로 가상 인터페이스에서 dhclient 를 실행하고 Discover 메시지를 검사하면 요청한 필드와 함께 매개변수 요청 목록 옵션이 포함된 것을 확인할 수 있습니다(그림 3).
수신 중인 Microsoft DHCP 서버는 이 Discover 메시지에 요청된 매개변수가 포함된 Offer 응답을 보내야 합니다(그림 4).
이름 보호 상태 추론
이름 보호는특정 덮어쓰기 공격 이 가능한지 여부를 결정하기 때문에 DHCP DNS Dynamic Update를 악용하려 할 때 중요한 또 하나의 설정입니다. 이름 보호 상태를 직접 쿼리할 수는 없지만, 간단한 4단계를 통해 이름 보호 상태를 추론할 수 있습니다.
DHCP DNS Dynamic Update를 사용해 DNS 레코드를 만듭니다
A 레코드가 생성되었는지 확인합니다
DNS 서버에 같은 이름의 DHCID 레코드가 있는지 쿼리합니다
A 레코드와 함께 DHCID 레코드가 있으면 이름 보호가 사용 설정된 것입니다.
dhclient를 사용해 DHCP DNS Dynamic Update를 호출하려면 설정 파일에 다음 줄을 추가합니다.
send fqdn.fqdn = “kali.aka.test”;
send fqdn.server-update on;
send dhcp-server-identifier 172.25.14.123;
처음 두 줄은 서버 플래그와 함께 FQDN 옵션을 추가하는데, 이는 DHCP 서버가 우리를 위해 DNS 레코드를 등록하는 데 필요합니다. 세 번째 줄은 선택 사항으로, 서버 식별자 DHCP 옵션을 추가해 여러 DHCP 서버가 있는 경우 특정 서버를 표적으로 지정할 수 있습니다.
dhclient를 실행한 후 nslookup을 사용해 표적 DNS 서버를 쿼리하고 DHCID 레코드를 찾을 수 있습니다(그림 5).
이 경우, 이름 보호가 활성화되었음을 나타내는 DHCID 레코드가 생성되었음을 알 수 있습니다.
DHCP DNS Dynamic Update 설정 추론
DHCP 서버가 클라이언트의 DNS 레코드를 생성하는 경우를 결정하는 3가지 옵션이 있습니다(그림 6). 어떤 설정이 사용되고 있는지 알면 공격자가 DHCP 요청을 스니핑해 매니지드 레코드생성으로 이어지는 요청을 식별할 수 있습니다. 이렇게 하면 매니지드 레코드 덮어쓰기 (DHCP 서버가 만든 레코드를 스푸핑하는 것)의 잠재적 표적을 식별할 수 있습니다.
가능한 세 가지 설정은 다음과 같습니다.
클라이언트가 요청하는 경우에만 동적으로 업데이트. 이 옵션은 기본 옵션으로, 요청에 FQDN 옵션이 있고 서버 플래그가 설정된 경우에만 DNS 레코드를 만듭니다.
항상 동적으로 업데이트. 서버 플래그 값에 관계없이 FQDN 옵션이 있는 모든 DHCP 요청에 대해 DNS 레코드가 만들어집니다.
업데이트를 요청하지 않는 클라이언트에 대해 동적으로 업데이트. FQDN 옵션이 없는 경우에도 클라이언트에 대한 DNS 레코드를 생성합니다. FQDN은 호스트 이름 DHCP 옵션을 기반으로 합니다. 이는 FQDN 옵션을 사용하지 않는 이전 DHCP 클라이언트를 지원하기 위한 것입니다.
설정의 ‘부작용’을 검사하면 이를 추론할 수 있습니다. 다양한 조건에서 DHCP DNS Dynamic Update를 트리거하고 DNS 서버에 쿼리해 레코드가 생성되었는지 확인합니다. 이 작업은 dhclient 를 사용해 IP 주소를 임대하고 nslookup을 사용해 DNS 서버를 쿼리하는 방식으로 수행할 수 있습니다.
가능한 각 설정을 테스트하는 데 필요한 dhclient 설정은 다음과 같습니다.
업데이트를 요청하지 않는 클라이언트에 대한 레코드 생성
# Only include the hostname option, without the FQDN option
send host-name = “test.aka.test”;
send dhcp-server-identifier 172.25.14.123;
항상 레코드 생성(FQDN 옵션이 있는 경우)
# Include the FQDN option, without the server update flag
send fqdn.fqdn = “test.aka.test”;
send dhcp-server-identifier 172.25.14.123;
클라이언트가 요청한 경우에만 레코드 생성
# Include the FQDN option and the server update flag
send fqdn.fqdn = “test.aka.test”;
send fqdn.server-update on;
send dhcp-server-identifier 172.25.14.123;
스푸핑된 레코드 주소의 제한 사항
공격이 효과적이려면 스푸핑된 DNS 레코드가 제어 대상 머신을 가리켜야 합니다. DHCP DNS 스푸핑을 사용하면 DHCP 서버에 의존해 이러한 DNS 레코드를 생성하게 됩니다. 안타깝게도 임의의 IP 주소를 선택할 수 없습니다. DHCP 서버는 내부 IP 주소의 정의된 범위를 가지고 있으며, 이 범위를 벗어나는 IP 주소에 대해서는 임대를 거부하고 DNS 레코드를 생성하지 않습니다.
이러한 이유로 통신을 리디렉션하는 주소에는 두 가지 제한이 있습니다.
주소는 네트워크 외부에 있을 수 없습니다. DHCP 서버에서 외부 IP 주소를 임대할 수 없으므로 스푸핑 시 사용할 수 없습니다.
주소는 고정 IP 주소를 가진 머신의 주소일 수 없습니다. 머신에 고정 IP 주소가 설정된 경우, 이 주소는 DHCP 서버의 임대 풀에 없을 가능성이 높으므로 스푸핑 시 사용할 수 없습니다.
동적 IP 주소를 사용할 수 있는 내부 머신에 접속할 수 있으므로 스푸핑된 레코드에 DHCP 서버에서 제공하는 모든 주소를 사용할 수 있습니다.
추가 작업을 수행할 때 동일한 주소를 사용하고 있는지 확인하려면 요청된 IP 주소 옵션을 사용하면 됩니다. dhclient의 설정에 다음 줄을 추가하면 이 작업을 수행할 수 있습니다.
send dhcp-requested-address 172.25.14.55;
여러 DNS 레코드 쓰기
DHCP DNS 스푸핑을 수행할 때 가능한 한 많은 피해자의 트래픽을 리디렉션하기 위해 단일 레코드가 아닌 여러 개의 DNS 레코드를 스푸핑할 가능성이 높습니다. 하지만 여러 개의 DNS 레코드를 동일한 대상 IP로 가리키려 하면 문제가 발생합니다.
DHCP 서버가 특정 IP 주소를 호스트에 임대하고 나면 다른 클라이언트에서 해당 주소를 임대할 수 없습니다. 이 동작은 서로 다른 클라이언트 간의 IP 충돌을 방지하기 위한 것입니다. DDSpoof를 수행하기 위해 특정 FQDN이 있는 IP 주소를 임대하면 이 IP 주소는 서버의 주소 풀에서 제거됩니다. 동일한 IP 주소를 다른 FQDN으로 다시 임대하려 하면 서버가 다른 주소를 제공합니다(그림 7).
이전 임대를 해제하면, 방금 해제된 레코드를 삭제하기 위해 DHCP 서버의 DNS Dynamic Update가 트리거되고 이전에 스푸핑된 레코드가 제거되므로 이 문제를 해결할 수 없습니다(그림 8).
다시 말해, 목표는 다음과 같습니다.
IP 주소를 해제, 즉 DHCP 서버에서 해당 임대 항목을 제거해 주소 풀로 반환(새 DNS 레코드를 등록하는 데 사용할 수 있도록)
기존에 스푸핑된 DNS 레코드의 삭제 방지
Akamai는 이를 가능하게 하는 흥미로운 행동 또는 버그를 발견했습니다.
현재 IP 주소를 임대하고 있는 DHCP 서버에 다음 매개변수와 함께 DHCP 요청 패킷을 보냅니다.
서버에 기존 DHCP 임대를 요청하는 데 사용된 클라이언트 MAC 주소
표적 서버와 다른 서버의 서버 식별자
이 브로드캐스트 메시지를 본 표적 DHCP 서버는 다른 서버에서 새 IP 주소를 요청하는 것으로 ‘가정’해 기존(임대) 주소가 더 이상 필요하지 않다고 판단합니다. 그러면 관련 DNS 레코드를 삭제하지 않고IP 임대를 삭제합니다(그림 9). DNS 레코드가 삭제되지 않는 이유는 명확하지 않지만, 논리적 버그일 수 있다고 생각합니다.
실제로 확인해 보겠습니다
동일한 IP를 가리키는 두 개의 DNS 레코드를 만들려고 합니다. 앞서 설명한 것과 같은 방법으로 dhclient 를 사용해 첫 번째 레코드를 만듭니다. 레코드가 생성되고 DHCP 서버 임대 테이블을 보면 임대가 있음을 알 수 있습니다(그림 10).
이제 설정 파일에서 dhcp-server-identifier dhclient 옵션을 다른 IP로 수정하고 dhclient dhclient를 다시 실행하면 임대가 삭제된 것을 확인할 수 있습니다!
이제 동일한 IP 주소를 요청하면서 다른 FQDN으로 dhclient 를 다시 실행해 두 번째 레코드를 만들 수 있습니다(그림 11).
DDSpoof.py 소개
이 블로그 시리즈에서 설명한 모든 기능과 기술을 결합해 DHCP DNS 공격의 성능을 지원하는 툴킷인 DDSpoof를 만들었습니다. 이 Python 툴은 DHCP 서버 열거를 수행하고, 사용자 지정 DHCP DNS 명령을 실행하고, 잠재적인 스푸핑 표적을 식별합니다. DDSpoof의 기능은 이 리포지토리에 문서화되어 있습니다.
다음 섹션에서는 DDSpoof로 수행할 수 있는 몇 가지 공격 시나리오를 살펴보겠습니다.
DDSpoof 설정
Akamai는 도메인 인증정보 없이 표적 네트워크 내부에서 Kali Linux 머신을 실행하고 있습니다. 먼저 DDSpoof를 실행해 네트워크를 스캔하고 잠재적 표적을 식별합니다(패킷 송수신에 사용할 인터페이스 지정, 그림 12).
DDSpoof가 다음을 실행하는 것을 알 수 있습니다.
접속 가능한 모든 DHCP 서버와 그 설정을 식별
이름 보호 상태를 결정
현재 IP 주소를 대상 서버에서 임대할 수 있는지 확인
이 예에서는 대상 서버에서 IP 주소를 임대할 수 없으므로 서버에서 제공하는 주소로 수동으로 수정합니다(그림 13).
이제 스푸핑을 시작할 준비가 되었습니다.
DHCP DNS 스푸핑
첫 번째 DHCP DNS 스푸핑을 실행하기 위해 실패한 이름 확인 시도를 식별하고 해당 시도가 Akamai 머신을 가리키는 DNS 레코드를 생성하고자 합니다. 이를 위해 start-llmnr DDSpoof 명령을 사용합니다. 이 명령은 잠재적인 스푸핑 표적으로 이어질 수 있는 네트워크의 LLMNR 쿼리에 대해 알려주는 LLMNR 스니퍼를 시작합니다(그림 14).
여기서 스니퍼가 files.aka.test라는 이름을 식별할 수 있었음을 알 수 있습니다. 이제 write-record 명령을 사용해 이 DNS 이름의 등록을 시도할 수 있습니다(그림 15).
그림에서 볼 수 있듯이, DDSpoof는 Akamai의 IP 주소를 가리키는 이 DNS 레코드를 성공적으로 생성합니다! nslookup으로 이를 확인할 수 있습니다(그림 16).
이제 네트워크의 호스트가 files.aka.test라는 이름을 확인하려고 시도하면 제어된 머신으로 연결됩니다.
공격이 완료되면 delete-record 명령을 사용해 스푸핑된 레코드를 제거할 수 있습니다(그림 17).
DHCP DNS 덮어쓰기
또 다른 옵션은 DHCP DNS 덮어쓰기입니다. 그림 12를 다시 보면 표적 DHCP 서버가 DNS 서버이기도 하다는 것을 알 수 있습니다. 이는 DNS 서버가 Active Directory 환경의 DC에 설치되는 경우가 많으므로 서버가 DC(Domain Controller)일 수도 있음을 암시합니다. 다음 nmap 명령을 사용해 이를 확인할 수 있습니다.
Nmap -p389 -sV 172.25.14.123
DNS 인증정보가 설정되지 않은 경우 ADI 영역의 모든 레코드를 덮어쓸 수 있습니다. file-server.aka.test라는 이름의 호스트를 식별했다고 가정해 보겠습니다(그림 19).
write-record DDSpoof 명령을 사용해 해당 DNS 레코드에 대한 덮어쓰기를 시도할 수 있습니다. 취약한 DNS 인증정보가 설정되어 있다면 이 방법이 실패할 것입니다. 하지만 이 경우에는 취약한 DNS 인증정보가 설정되지 않았기 때문에 덮어쓰기에 성공했습니다(그림 20).
이름 보호 무시
다른 시나리오에서는 DHCP 트래픽을 스니핑해 DHCP 요청 메시지를 식별하는 start-dhcp DDSpoof 명령을 실행합니다(그림 22).
이 예에서는 FQDN이 포함된 DHCP 요청을 전송한 ubuntu-server.aka.test 라는 머신을 식별합니다. 이로 인해 DHCP 서버가 해당 머신에 대한 DNS 레코드를 생성해 관리되는 레코드를 덮어쓸 기회를 제공할 수 있습니다(관리되는 레코드는 도메인의 일부가 아니어서 DNS 서버와 직접 통신할 수 없기 때문에 Windows 이외의 호스트에 대해 생성된다는 점을 기억하세요).
하지만 문제가 있습니다. 이번에는 대상 DHCP 서버가 이름 보호를 사용하도록 설정했습니다(그림 23).
표적 ubuntu-server.aka.test의 모든 DNS 레코드를 쿼리하면 DHCID 레코드가 실제로 존재한다는 것을 알 수 있습니다(그림 24).
하지만 이미 알고 있듯이이름 보호는 쉽게 우회할 수 있으니 걱정하지 마세요!
원래 레코드 소유자와 일치하는 CID(Client ID)(기본적으로 클라이언트 MAC 주소)가 포함된 DHCP Release를 전송하기만 하면 됩니다. 그러면 DHCP 서버가 해당 레코드를 삭제합니다.
이를 위해 set-cid 명령을 사용할 수 있습니다. 이 명령어에 이전에 획득한 표적 CID를 입력하면 DDSpoof가 원래 DHCP 클라이언트로 가장하게 됩니다. 그런 다음 delete-record 명령을 실행해 표적 레코드를 제거할 수 있습니다(그림 25).
이제 write-record 명령을 사용해 이름을 직접 등록할 수 있습니다(그림 26).
요약
이 게시물에서 살펴본 공격 시나리오는 인증되지 않은 맥락에서 Active Directory 도메인의 다양한 DNS 레코드를 스푸핑할 수 있는 방법을 보여줍니다. 이 기능은 매우 유연하며 공격자가 다음과 같은 다양한 방법으로 악용할 수 있습니다.
Windows 머신을 표적으로 삼고 NTLM 또는 Kerberos 인증을 가로채서 추가 릴레이 또는 무차별 대입 공격을 허용
안전하지 않은 프로토콜을 실행하고 민감한 데이터를 가로채는 애플리케이션을 표적으로 삼음
안티바이러스 또는 SIEM과 같은 내부 보안 서버의 DNS 레코드를 표적으로 삼고 이에 대한 접속을 차단
이는 공격자가 이 기능을 악용하는 방법의 몇 가지 예에 불과하며, 이외에도 다양한 방법이 있습니다.
수신: 보안팀
DHCP DNS Dynamic Update로 인해 노출되는 공격표면은 매우 강력하며 Microsoft가 문제를 해결할 계획이 없기 때문에이 문제는 계속 남아있을 가능성이 높습니다. 보안팀은 공격자가 따라잡기 전에 다음 툴을 사용해 DHCP DNS 스푸핑의 리스크를 식별하고 방어할 것을 권장합니다.
Invoke-DHCPCheckup: Active Directory에서 DHCP 및 DNS 설정을 식별
DDSpoof: DHCP DNS Dynamic Update 공격표면의 리스크를 집중적으로 확인하고 안정성을 테스트