바인딩 : 잘못된 재귀 쿼리에 대한 블랙홀?


13

나는 두 개의 도메인에 대한 권위있는 이름 서버 이기 때문에 공개적으로 액세스 할 수 있는 이름 서버가 있습니다.

현재 서버는 ANYisc.org, ripe.net 및 이와 유사한 것으로 알려진 가짜 유형의 요청으로 넘쳐납니다 (이는 분산 된 DoS 공격입니다 ).

서버가 BIND를 실행 allow-recursion하고 이러한 요청이 거부되도록 LAN으로 설정했습니다. 이러한 경우 서버는 응답 authorityadditional섹션 루트 서버를 참조.

응답을 보내지 않고 이러한 요청을 완전히 무시하도록 BIND를 구성 할 수 있습니까?

답변:


5

같은 문제에 직면하여 모든 재귀 요청을 무시하기로 결정했습니다. 모든 확인자는 내 서버를 신뢰할 수있는 서버로 사용하려고 할 때 비 재귀 쿼리를 보냅니다. 내 경우에는 잘못 구성된 클라이언트와 공격자 만 재귀 쿼리를 사용합니다.

불행히도 나는 BIND가 그렇게 할 수있는 방법을 찾지 못했지만 iptables가 당신에게 충분하다면

iptables -t raw -I PREROUTING -i eth0 -p udp --destination-port 53 \
    -m string --algo kmp --from 30 \
    --hex-string "|01000001000000000000|" -j DROP

아니, 그 규칙은 (적어도 내 컴퓨터에서) 권위있는 유형의 요청도 차단합니다. 분명히 모든 종류의 DNS 요청을 차단합니다.
우도 G

나는 두 번 확인했고 정확히 그 규칙을 사용하고 있습니다. 라이브 서버에서 잘라서 붙여 넣기는 다음과 같습니다. 명령 : iptables -t raw -S PREROUTING. 출력 : -P PREROUTING ACCEPT, 뒤에 -A PREROUTING -i eth0 -p udp -m udp --dport 53 -m string --hex-string "|01000001000000000000|" --algo kmp --from 30 --to 65535 -j DROP. 나는 그것이 올바르게 작동하는지 테스트했습니다 host -ar exampledomain.com dns-server.example.net. 물론 -r옵션을 추가 할 때까지 제대로 작동하지 않았습니다 .
pino42

좋아, -r옵션은 차이가 있습니다. 나는 개인적으로 간단한 host쿼리가 더 이상 작동하지 않는다는 것을 좋아하지 않으며 이는 매우 혼란 스러울 수 있습니다. 그럼에도 불구하고 이것은 아마도 유효한 (지금까지 가장 좋은) 대답 일 것입니다 .OUTPUT을 필터링하여 내 자신의 접근 방식을 계속 사용할지라도 만료 될 예정이므로 현상금을 줄 것입니다.
Udo G

감사! 더 나은 솔루션을 발견하면 게시해야합니다. 나는 당신에게 동의합니다 : 이것은 해킹입니다. 작동하지만 여전히 해킹입니다.
pino42

2

나는 시도 할 것이다 :

zone "." {
  type redirect;
  allow-query "none";
}

클라이언트를 루트 서버로 보내는 응답은 "리디렉션"영역에 의해 제어됩니다. 응답하지 말라고 알려야합니다.

Bind9 문서에서 힌트를 얻었습니다. http://ftp.isc.org/isc/bind9/cur/9.9/doc/arm/Bv9ARM.ch06.html#id2592674

"none"로컬 서브넷 으로 교체 할 수 있습니다 .

zone "."선언 이 이미 있으면 추가 allow-query "none";하십시오.


나는이 zone "." { type hint; file "/etc/bind/db.root"; };db.root 루트 서버를 목록으로 선언. 이 선언을 제거하면 외부 도메인에 대한 응답이 중지되지만 서버는 "서버 장애"로 응답하므로 여전히 DoS에 사용할 수 있습니다.
우도 G

@ UdoG : 구성에 추가 allow-query "none";해 보셨습니까 zone "."?
freiheit

이것은 업스트림 대역폭 만 절약하는 것처럼 보이지만 충분해야합니다. 당신의 수정을 통해 공격자는 이미 서버 다운 스트림 대역폭과 처리 능력까지 사용하고있다
TheLQ

@TheLQ : 질문은 이것이 DDoS 공격임을 나타냅니다. 일반적인 DNS 기반 DDoS 공격은 대상이 위조 된 IP로 DNS 쿼리를 보내는 것입니다. DNS 응답 패킷은 쿼리보다 크기 때문에 승수를 제공합니다. 서버가 훨씬 더 큰 패킷으로 응답하지 않으면 공격에 서버를 사용하는 이유를 제거했습니다.
freiheit

@UdoG : 서버 장애 패킷은 31에서 32까지이지만 루트 서버에 대한 조회는 아마도 수백 바이트 일 것입니다. 서버의 응답이 쿼리와 크기가 같거나 조금 더 크면 DNS DDoS 공격에는 서버가 쓸모가 없습니다. 공격자는 대상에게 전송하는 데 많은 대역폭을 소비하기 때문입니다. 필자는 잘 구성된 여러 정식 이름 서버 (예 : Google)에 대해 테스트했으며 "재귀가 요청되었지만 사용할 수 없음"으로 응답했습니다.
freiheit

1

일반적으로, 나는 제안 할 것이다 :

바인드 로그를 켜고 거부 된 응답을 기록하는 IP를 기록하십시오. fail2ban 프로그램 설치, 블랙홀 작업 추가 : http://pastebin.com/k4BxrAeG(/etc/fail2ban/actions.d의 파일에 규칙을 넣음)

이와 같은 방법으로 /etc/fail2ban/filter.d에 바인드 필터 파일을 만듭니다 (디버깅 필요)!

[Definition]
failregex = ^.* security: info: client #<HOST>: query \(cache\) .* denied

fail2ban.conf를 편집하고 섹션을 추가하십시오.

[bindban]

enabled  = true
filter   = bind
# "bantime" is the number of seconds that a host is banned.
bantime  = 6000
# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 60
# "maxretry" is the number of failures before a host get banned.
maxretry = 150
action   = blackhole
logpath  = /var/log/named.log

이것이 도움이되기를 바랍니다!


TODO : 바인드 로그 파일 예제.
Andrei Mikhaltsov

1

기본 아이디어는 DNS 응답을 Refused로 분류 한 다음 iptables를 사용하여 Refused를 자동 무시 된 것으로 변환합니다.

Refused는 named.conf 옵션 섹션에서 가장 쉬운 부분입니다.

allow-recursion { none;};

또는 로컬 예외에 대해 가장 좋아하는 ACL ...

다음 미친 iptables 마술, 필요에 따라 "-o eth0"를 조정하거나 제거하십시오. 이 명령은 UDP 이전의 표준 20 바이트 IPv4 계층 헤더를 가정합니다.

iptables -A OUTPUT -o eth0 -p udp --sport 53 -m string --from 30 --to 32 --hex-string "|8105|" --algo bm -j DROP

이 비트는 다음 비트 세트가있는 DNS 응답의 플래그 필드에 있습니다.

  • DNS 응답
  • 재귀 쿼리
  • 회신 코드가 거부되었습니다

규칙이 테스트에 대한 일부 피드백을 갖도록 일치 할 때 디버그 "오류 전송 응답 : 호스트에 도달 할 수 없음"에서 바인드를 실행하는 로그 메시지가 발견되었습니다.

이것은 모두 다소 무의미한 운동이라는 것을 인정해야합니다. 증폭이 없으면 공격자는 TCP SYN을 쉽게 반영 할 수 있습니다. 궁극적으로 DNS는 TCP를 사용하거나 Eastlake의 DNS 쿠키를 배포하는 것 외에는 실행 가능한 솔루션이 아닙니다.


0

문자열 isc.org를 차단하거나 16 진 문자열을 차단하려고 했습니까?

이것은 나를 위해 일했다 :

iptables -A 입력 -p udp -m 문자열 --hex-string "| 03697363036f726700 |" --algo bm -j DROP


서버가 응답해야하는 모든 도메인의 16 진 문자열을 식별하고이를 허용하기 위해 위의 작업을 수행하고 다른 모든 udp / 53 트래픽을 제거하는 것이 더 좋지 않습니까?
freiheit

현재 루트 서버를 참조하는 UDP 응답을 이미 차단하고 있습니다. iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROP그러나 가능하다면 BIND 구성을 기반으로하는 솔루션을 선호합니다.
우도 G

이것은 약하다. 도메인으로 원하는 찌르기를 생성 할 수 있습니다. 우리는 지금 그 문제에 직면하고 있으며 정적 이름을 통해 문제를 차단하는 방법이 아닙니다'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x

0

이 공격을 Amplified Denial of Service라고합니다. 바인드를 올바르게 구성해야하지만 트래픽이 처음에는 바인드에 도달하지 않아야합니다. 네트워크에서이를 수행 할 수있는 첫 번째 네트워크 장치에서 차단하십시오. 나는 같은 문제가 있었고 귀머거리 코골이 규칙으로 처리했습니다.

경고 udp $ EXTERNAL_NET any-> $ HOME_NET 53 (msg : "PROTOCOL-DNS 유형의 모든 쿼리-잠재적 DoS"; byte_test : 1,! &, 0xF8,2; content : "| 00 00 FF 00 01 |"; detection_filter : 트랙 by_src, 카운트 30, 초 30; 메타 데이터 : service dns; 참조 : url, foxpa.ws / 2010 / 07 / 21 / thwarting-the-isc-org-dns-ddos /; classtype : attempted-dos; sid : 21817; rev : 4;)


0

첫째, 나는 이것이 오래된 질문이라는 것을 알고 있지만 ...

저는 수십 년 동안 저만의 정식 비 재귀 DNS 서버를 운영해 왔지만 지금까지 새로운 ISP로 전환 할 때까지 DNS 기반 DDoS 공격의 희생자는 없었습니다. 수천 개의 스푸핑 된 DNS 쿼리가 내 로그를 쇄도했고 서버에 미치는 영향이 아니라 내 로그를 어지럽히고 불쾌한 악용을 느꼈다는 사실에 대해 짜증이났습니다. 침입자는 " 권한있는 이름 서버 공격 " 에서 내 DNS를 사용하려고합니다 .

따라서 재귀 쿼리를 내부 네트워크 (다른 모든 거부)로 제한하더라도 스푸핑 된 IP 주소에 부정적인 응답을 다시 보내는 것보다 iptables의 문자열 일치에 CPU주기를 소비한다고 생각했습니다. 네트워크 트래픽 및 내 자신의 높은 만족도).

다른 사람들이하는 것처럼 시작하여 시작한 도메인 이름을 찾아 해당 도메인에서 대상 DROP으로 문자열 일치를 생성했습니다. 그러나 곧 엄청난 양의 규칙이 생겨 각각 CPU 사이클을 소비한다는 것을 깨달았습니다. 그래서 뭐 할까? 재귀 이름 서버를 실행하지 않기 때문에 권한이있는 실제 영역에서 일치시킬 수 있고 다른 모든 항목을 삭제할 수 있다고 생각했습니다.

iptables의 기본 정책은 ACCEPT입니다. 정책이 DROP 인 경우 다음 솔루션을 사용하려면 약간의 조정이 필요할 수 있습니다.

영역 구성을 별도의 파일 (/etc/bind/named.conf.local)에 유지합니다.이를 예로 사용하겠습니다.

zone "1.168.192.in-addr.arpa" { // Private
        type master;
        allow-query { 192.168.1.0/24; 127.0.0.1; };
        allow-transfer { 127.0.0.1; };
        file "/etc/bind/db.192.168.1";
};

zone "home.example.net" { // Private
        type master;
        allow-query { 192.168.1.0/24; 127.0.0.1; };
        allow-transfer { 127.0.0.1; };
        file "/etc/bind/pri/db.home.example.net";
};

zone "example.net" {
        type master;
        file "/etc/bind/pri/db.example.net";
        allow-transfer { 127.0.0.1; 8.8.8.8; };
};

zone "example.com" {
        type slave;
        masters { 8.8.8.8; };
        file "sec.example.com";
        allow-transfer { 127.0.0.1; };
        notify no;
};

zone "subdomain.of.example.nu" {
        type slave;
        masters { 8.8.8.8; };
        file "sec.subdomain.of.example.nu";
        allow-transfer { 127.0.0.1; };
        notify no;
};

첫 두 영역에 대한“// Private”주석에 유의하십시오. 다음 스크립트에서이를 사용하여 유효한 영역 목록에서 해당 영역을 제외시킵니다.

#!/usr/bin/perl
# zone2iptables - Richard Lithvall, april 2014
#
# Since we want to match not only example.net, but also (for example)
# www.example.net we need to set a reasonable maximum value for a domain
# name in our zones - 100 character should be more that enough for most people
# and 255 is the absolute maximum allowed in rfc1034.
# Set it to 0 (zero) if you would like the script to fetch each zone (axfr)
# to get the actual max value.
$maxLengthOfQueryName=255;
$externalInterface="eth1";

print "# first time you run this, you will get error on the 3 first commands.\n";
print "# It's here to make it safe/possible to periodically run this script.\n";
print "/sbin/iptables -D INPUT -i $externalInterface -p udp --dport 53 -j DNSvalidate\n";
print "/sbin/iptables -F DNSvalidate\n";
print "/sbin/iptables -X DNSvalidate\n";
print "#\n";
print "# now, create the chain (again)\n";
print "/sbin/iptables -N DNSvalidate\n";
print "# and populate it with your zones\n";
while(<>){
        if(/^zone\s+"(.+)"\s+\{$/){
                $zone=$1;
                if($maxLengthOfQueryName){
                        $max=$maxLengthOfQueryName;
                } else {
                        open(DIG,"dig -t axfr +nocmd +nostats $zone |");
                        $max=0;
                        while(<DIG>){
                                if(/^(.+?)\.\s/){
                                        $max=(length($1)>$max)?length($1):$max;
                                }
                        }
                        close(DIG);
                }
                printf("iptables -A DNSvalidate -m string --from 40 --to %d --hex-string \"",($max+42));
                foreach $subdomain (split('\.',$zone)){
                        printf("|%02X|%s",length($subdomain),$subdomain);
                }
                print("|00|\" --algo bm -j RETURN -m comment --comment \"$zone\"\n");
        }
}
print "# and end the new chain with a drop\n";
print "/sbin/iptables -A DNSvalidate -j DROP\n";
print "# And, at last, make the new chain active (on UDP/53)\n";
print "/sbin/iptables -A INPUT -i $externalInterface -p udp --dport 53 -j DNSvalidate\n";

영역 구성 파일을 인수로 사용하여 위 스크립트를 실행하십시오.

root:~/tmp/# ./zone2iptables.pl /etc/bind/named.conf.local 
# first time you run this, you will get error on the 3 first commands.
# It's here to make it safe/possible to periodically run this script.
/sbin/iptables -D INPUT -i eth1 -p udp --dport 53 -j DNSvalidate
/sbin/iptables -F DNSvalidate
/sbin/iptables -X DNSvalidate
#
# now, create the chain (again)
/sbin/iptables -N DNSvalidate
# and populate it with your zones
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|07|example|03|net|00|" --algo bm -j RETURN -m comment --comment "example.net"
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|07|example|03|com|00|" --algo bm -j RETURN -m comment --comment "example.com"
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|09|subdomain|02|of|07|example|02|nu|00|" --algo bm -j RETURN -m comment --comment "subdomain.of.example.nu"
# and end the new chain with a drop
/sbin/iptables -A DNSvalidate -j DROP
# And, at last, make the new chain active (on UDP/53)
/sbin/iptables -A INPUT -i eth1 -p udp --dport 53 -j DNSvalidate

출력을 스크립트에 저장하고 셸로 파이프하거나 터미널에 복사하여 붙여 넣어 새 체인을 생성하고 모든 유효하지 않은 DNS 쿼리를 필터링하십시오.

/ sbin / iptables -L DNSvalidate -nvx 를 실행 하여 새 체인의 각 규칙에서 패킷 (및 바이트) 카운터를 봅니다 (대부분의 패킷이있는 영역을 목록의 맨 위로 이동하여 더 효율적으로 만들 수 있음).

누군가가 이것을 유용하게 사용할 수 있기를 바랍니다. :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.