ผูก: blackhole สำหรับการค้นหาแบบเรียกซ้ำที่ไม่ถูกต้อง?


13

ฉันมีเซิร์ฟเวอร์ชื่อที่สาธารณชนสามารถเข้าถึงได้เพราะมันเป็นชื่อเซิร์ฟเวอร์สิทธิ์สำหรับคู่ของโดเมน

ขณะนี้เซิร์ฟเวอร์เต็มไปด้วยANYคำขอประเภทปลอมสำหรับ isc.org, ripe.net และสิ่งที่คล้ายกัน (นั่นคือการโจมตี DoS แบบกระจาย )

เซิร์ฟเวอร์รัน BIND และallow-recursionตั้งค่าเป็น LAN ของฉันเพื่อให้คำขอเหล่านี้ถูกปฏิเสธ ในกรณีเช่นนี้เซิร์ฟเวอร์จะตอบสนองด้วยauthorityและในadditionalส่วนที่อ้างอิงถึงเซิร์ฟเวอร์ราก

ฉันสามารถกำหนดค่า 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 ทุกประเภท
Udo 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 ได้
Udo G

@UdoG: คุณลองเพิ่มallow-query "none";การกำหนดค่าแล้วzone "."หรือยัง?
Freiheit

ดูเหมือนว่านี่จะเป็นการประหยัดแบนด์วิดท์อัปสตรีมเท่านั้น ด้วยการแก้ไขของคุณผู้โจมตีได้ใช้แบนด์วิธดาวน์สตรีมและพลังการประมวลผลของเซิร์ฟเวอร์ของคุณแล้ว
TheLQ

@TheLQ: คำถามนี้หมายถึงการโจมตี DDoS การโจมตี DDoS ที่ใช้ DNS ทั่วไปคือการส่งการสืบค้น DNS ที่มี IP ปลอมแปลงของเป้าหมาย เนื่องจากแพ็กเก็ตตอบกลับ DNS มีขนาดใหญ่กว่าแบบสอบถามจึงมีตัวคูณ หากเซิร์ฟเวอร์ของคุณไม่ตอบสนองด้วยแพ็คเก็ตที่มีขนาดใหญ่กว่าอย่างเห็นได้ชัดคุณได้ตัดเหตุผลที่พวกเขากำลังใช้เซิร์ฟเวอร์ของคุณในการโจมตี
Freiheit

@UdoG: แพ็คเก็ตที่ล้มเหลวของเซิร์ฟเวอร์มีเพียง 31 ถึง 32 ในขณะที่การอ้างอิงไปยังเซิร์ฟเวอร์รากอาจเป็นหลายร้อยไบต์ หากการตอบกลับของเซิร์ฟเวอร์ของคุณมีขนาดเท่ากับแบบสอบถามหรือใหญ่กว่านิดหน่อยเซิร์ฟเวอร์ของคุณไม่มีประโยชน์ในการโจมตี DNS DDoS เนื่องจากผู้โจมตีจะใช้แบนด์วิดท์เท่าที่พวกเขาให้คุณส่งไปยังเป้าหมาย ฉันทดสอบกับเซิร์ฟเวอร์ชื่อที่เชื่อถือได้ซึ่งมีการกำหนดค่าจำนวนมาก (เช่นของ Google) และพวกเขาตอบกลับด้วย "ร้องขอการสอบถามซ้ำ แต่ไม่สามารถใช้งานได้"
Freiheit

1

โดยทั่วไปฉันจะแนะนำ:

เปิดบันทึกการผูกและบันทึก ips ที่รับคำตอบถูกปฏิเสธ ติดตั้งโปรแกรม fail2ban เพิ่มการกระทำของ blackhole: http://pastebin.com/k4BxrAeG (ใส่กฎในไฟล์ใน /etc/fail2ban/actions.d)

สร้างไฟล์ตัวกรอง bind ใน /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

หวังว่านี่จะช่วยได้!


สิ่งที่ต้องทำ: ตัวอย่างไฟล์บันทึกผูก
Andrei Mikhaltsov

1

แนวคิดพื้นฐานให้ผูกจัดประเภทการตอบสนอง DNS เป็น Refused จากนั้นใช้ iptables เพื่อแปลง Refused เป็นละเว้นโดยไม่ต้องพูด

ปฏิเสธเป็นส่วนที่ง่ายในส่วนของ options.conf:

allow-recursion { none;};

หรือแน่นอน ACL ที่คุณชื่นชอบสำหรับข้อยกเว้นในท้องถิ่น ...

ถัดไป iptables บ้าสุดวิเศษปรับหรือลบ "-o eth0" ตามต้องการ คำสั่งนี้ถือว่าส่วนหัวเลเยอร์ IPv4 เลเยอร์ 20 ไบต์มาตรฐานก่อน UDP

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 หรือการใช้งานคุกกี้ DNS ของ Eastlake


0

คุณพยายามบล็อก string isc.org หรือบล็อค string hex สำหรับมันหรือไม่?

สิ่งนี้ใช้ได้กับฉัน:

iptables -A อินพุต -p udp -m string --hex-string "| 03697363036f726700 |" --algo bm -j DROP


จะเป็นการดีกว่าหรือถ้าจะระบุสตริงฐานสิบหกสำหรับโดเมนทั้งหมดที่เซิร์ฟเวอร์ควรตอบสนองทำตามข้างบนเพื่ออนุญาตให้ใช้และปล่อย udp / 53 trafic อื่นทั้งหมดหรือไม่
Freiheit

ขณะนี้ฉันกำลังบล็อกการตอบสนอง UDP ที่อ้างอิงถึงเซิร์ฟเวอร์ราก: iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROPแต่ฉันต้องการโซลูชันที่ใช้การกำหนดค่า BIND จริงๆถ้าเป็นไปได้
Udo G

มันอ่อนแอ คุณสามารถสร้างสิ่งที่คุณต้องการเป็นโดเมน เรากำลังเผชิญกับปัญหานั้นในตอนนี้และมันไม่ได้เป็นวิธีการบล็อกมันผ่านชื่อคงที่'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x

0

การโจมตีนี้เรียกว่า Amplified Denial of Service คุณควรกำหนดค่าการผูกอย่างถูกต้อง แต่การรับส่งข้อมูลนั้นไม่ควรไปถึงการผูกในครั้งแรก บล็อกมันบนอุปกรณ์เครือข่ายแรกที่สามารถทำได้ในเครือข่ายของคุณ ฉันมีปัญหาเดียวกันและจัดการกับกฎ snort deafult:

แจ้งเตือน udp $ EXTERNAL_NET ใด ๆ -> $ HOME_NET 53 (msg: "ข้อความค้นหามากเกินไปของ PROTOCOL-DNS ประเภท ANY - potential DoS"; byte_test: 1,! &, 0xF8,2; เนื้อหา: "| 00 00 FF 00 01 |"; detection_filter: track by_src, นับ 30, วินาที 30; ข้อมูลเมตา: service dns, การอ้างอิง: url, foxpa.ws / 2010/07/21 / thwarting-the-isc-org-dns-ddos /; classtype: พยายาม-dos; sid : 21817; rev: 4;)


0

ก่อนอื่นฉันรู้ว่านี่เป็นคำถามเก่า แต่ ...

ฉันใช้เซิร์ฟเวอร์ DNS ที่เชื่อถือได้และไม่ต้องทำซ้ำมานานหลายทศวรรษ แต่ไม่เคยตกเป็นเหยื่อของการโจมตี DDoS ที่ใช้ DNS เลยจนกระทั่งตอนนี้เมื่อฉันเปลี่ยนไปใช้ ISP ใหม่ การสืบค้น DNS ปลอมแปลงหลายพันรายการทำให้บันทึกของฉันท่วมท้นและฉันรำคาญมาก - ไม่มากเกี่ยวกับผลกระทบต่อเซิร์ฟเวอร์ของฉัน แต่ความจริงแล้วมันรกแฟ้มบันทึกของฉัน ดูเหมือนว่าผู้โจมตีพยายามที่จะใช้ DNS ของฉันในการ " โจมตีเซิร์ฟเวอร์ชื่อที่มีสิทธิ์ "

ดังนั้นฉันจึงคิดว่าแม้ว่าฉันจะ จำกัด เคียวรีแบบเรียกซ้ำภายในเครือข่ายของฉัน (ปฏิเสธทั้งหมด) ฉันก็ใช้วงจรของ CPU ในการจับคู่สตริงใน iptables มากกว่าส่งการตอบกลับเชิงลบไปยังที่อยู่ IP ที่ปลอมแปลง (ถ่วงน้อยลงในบันทึกของฉัน ปริมาณการใช้เครือข่ายและระดับความพึงพอใจที่สูงขึ้นของฉัน)

ฉันเริ่มต้นด้วยการทำเหมือนคนอื่น ๆ ทำค้นหาชื่อโดเมนที่มีการสอบถามและสร้างสตริงที่ตรงกับโดเมนที่มีเป้าหมาย DROP แต่ในไม่ช้าฉันก็รู้ว่าฉันจะจบลงด้วยกฎจำนวนมากแต่ละอันใช้เวลาในการประมวลผลของ CPU ดังนั้นจะทำอย่างไร? เนื่องจากฉันไม่ได้เรียกใช้เซิร์ฟเวอร์ชื่อซ้ำฉันคิดว่าฉันอาจทำการจับคู่ในโซนจริงฉันมีสิทธิ์และวางทุกอย่างอื่น

นโยบายเริ่มต้นของฉันใน iptables คือยอมรับหากนโยบายของคุณเป็น 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;
};

หมายเหตุความคิดเห็น“ // ส่วนตัว” ในสองโซนแรกของฉันฉันใช้สิ่งนี้ในสคริปต์ต่อไปนี้เพื่อแยกพวกเขาออกจากรายการของโซนที่ถูกต้อง

#!/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 ที่ไม่ถูกต้องทั้งหมด

run / sbin / iptables -L DNSvalidate -nvx เพื่อดูเคาน์เตอร์แพ็คเก็ต (และไบต์) ในแต่ละกฎในเชนใหม่ (คุณอาจต้องการย้ายโซนด้วยแพ็กเก็ตส่วนใหญ่ไปด้านบนของรายการเพื่อให้มีประสิทธิภาพมากขึ้น)

ด้วยความหวังว่าบางคนอาจพบว่ามีประโยชน์นี้ :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.