Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Mar 2014 20:00:20 -0700
From:      Julian Elischer <julian@freebsd.org>
To:        Brett Glass <brett@lariat.org>, Fabian Wenk <fabian@wenks.ch>, freebsd-security@freebsd.org
Subject:   Re: NTP security hole CVE-2013-5211?
Message-ID:  <5323C244.8050101@freebsd.org>
In-Reply-To: <201403141700.LAA21140@mail.lariat.net>
References:  <B0F3AA0A-2D23-424B-8A79-817CD2EBB277@FreeBSD.org> <52CEAD69.6090000@grosbein.net> <81785015-5083-451C-AC0B-4333CE766618@FreeBSD.org> <52CF82C0.9040708@delphij.net> <CAO82ECEsS-rKq7A-9w7VuxKpe_c_f=tvZQoRKgHEfi-yPdNeGQ@mail.gmail.com> <86d2jud85v.fsf@nine.des.no> <52D7A944.70604@wenks.ch> <201403141700.LAA21140@mail.lariat.net>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------010709070803080609010703
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

On 3/14/14, 8:38 AM, Brett Glass wrote:
> Everyone:
>
> Two months after this vulnerability was announced, we're still 
> seeing attempts to use the NTP "monitor" query to execute and 
> amplify DDoS attacks. Unfortunately, FreeBSD, in its default 
> configuration, will amplify the attacks if not patched and will 
> still relay them (by sending "rejection" packets), obfuscating the 
> source of the attack, if the system is patched using freebsd-update 
> but the default ntp.conf file is not changed.
>
> To avoid this, it's necessary to change /etc/ntp.conf to include the 
> following lines:
>
> # Stop amplification attacks via NTP servers
> disable monitor
> restrict default kod nomodify notrap nopeer noquery
> restrict 127.0.0.1
> restrict 127.127.1.0
> # Note: Comment out these lines on machines without IPv6
> restrict -6 default kod nomodify notrap nopeer noquery
> restrict -6 ::1
>
> We've tested this configuration on our servers and it successfully 
> prevents the latest patches of FreeBSD 9.x and 10.0 from 
> participating in a DDoS attack, either as a relay or as an amplifier.

the best solution is to add a firewall stateful rule so that the ONLY 
port 123 udp packet that gets in is one that is a response to one you 
sent out first.
  I include for fun my ipfw script. (slightly anonimised..  hope I 
didn't break it doing so,
  last i checked the average packet only hit about 6 rules in this 
set. and interface and local address are only checked once.
it's about as efficient as one can get on an ipfw firewall. beware the 
script puts the rules in out of order..


>
> Some of our own systems which were probed prior to the time we 
> secured them are still receiving a large stream of attack packets, 
> apparently from a botnet.

yeah me too.. 500 pps up until a few ours ago.. then it stopped
>
> I'd recommend that the lines above be included in the default 
> /etc/ntp.conf in all future releases, and that all systems that use 
> the default ntp.conf without modification be patched automatically 
> via freebsd-update.

it already is.

>
> --Brett Glass
>
> _______________________________________________
> freebsd-security@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-security
> To unsubscribe, send any mail to 
> "freebsd-security-unsubscribe@freebsd.org"
>


--------------010709070803080609010703
Content-Type: text/plain; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
 name="rc.firewall.jre"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="rc.firewall.jre"

#!/bin/sh
IPFW=/sbin/ipfw
SYSCTL=/sbin/sysctl
set -x
#Here is a revised version fo hte firewall rules.
# includes the fib fix and the NAT rules integrated.
# ipfw and sysctl defiend tp "echo" so that the script does nothing.
# run as  "sh firewall3.sh |sort -n -k 4 >/tmp/xx" to see the output as injected.
# rules are not injected in order so for debug output
# the sort is needed to see output in final form.

# Suck in the configuration variables.
if [ -z "${source_rc_confs_defined}" ]; then
        if [ -r /etc/defaults/rc.conf ]; then
                . /etc/defaults/rc.conf
                source_rc_confs
        elif [ -r /etc/rc.conf ]; then
                . /etc/rc.conf
        fi
fi

INCLUDE_COMMENTS="YES"
HAVE_TUNNEL="NO"

# nets of form a.b.c.d/xx from rc.conf
iif=${firewall_simple_iif}
iip=${firewall_simple_inet%%/[0-9]*}
oif=${firewall_simple_oif}
oip=${firewall_simple_onet%%/[0-9]*}

DEFAULT_SET=0
APP_SET=1
APP_BLOCK_SET=2
NAT_SET=3

${IPFW} disable firewall
sleep 1
${IPFW} -q -f flush

# For each interface set up 4 sets of rules
#
#   rules incoming to that interface to us
#   rules incoming to that interface not for us (for routing)
#   rules outgoing on that interface from us
#   rules outgoing on that interface not from us
#
# Allow 200 numbers for each rule set and 1000 for each interface

OUR_INCOMING=0
OUR_OUTGOING=0
OTHER_INCOMING=0
OTHER_OUTGOING=0

NEXTRULE=0
#decide how many number between rules and keep the kernel in sync with this
RULESKIP=2

${SYSCTL} net.inet.ip.fw.autoinc_step=$RULESKIP

# Make sure that pipes and NAT return to processing at the next rule number
${SYSCTL} net.inet.ip.fw.one_pass=0

#################################################################
#################################################################
# special values to set up pre-processing for a NAT'd tunnel
# e.g. from home to office.  not fully set up yet... ignore
#################################################################
#################################################################
TUN_REMOTE=10.0.1.2
VPN_SRC=18.0.0.1
VPN_NET=18.0.0.0/24
TUN=tun0

##############################################################
# N.B. port lists must contain 30 elements or less.
# These are for SESSIONS. stateful behaviour is expected
# to keep these sessions alive.
# We may have to tune dynamic timeouts
##############################################################
# Expected services handled, (inwards):                      #
# == udp ==
  UDP_INPORTS_SYS=53 # We will serve dns so we need this

# === tcp ===
# TCP ports we enable as soon as possible
#-----------------------------------------------------
  TCP_INPORTS_SYS=1234 # admin ssh

   $IPFW table add 2 $SECONDARY1  # dns secondary
   $IPFW table add 2 $SECONDARY2

   ${IPFW} table add 13 10.0.0.0/8
   ${IPFW} table add 13 172.16.0.0/12j
   ${IPFW} table add 13 192.168.0.0/16
   ${IPFW} table add 13 0.0.0.0/8
   ${IPFW} table add 13 169.254.0.0/16
   ${IPFW} table add 13 192.0.2.0/24
   ${IPFW} table add 13 224.0.0.0/4
   ${IPFW} table add 13 240.0.0.0/4

  TCP_DNS_ZONE=53 # DNS ZONES to secondaries

# TCP ports we only enable when we turn on client services
#-----------------------------------------------------
  TCP_INPORTS_APP=25 # Mail inwards
  TCP_INPORTS_APP=$TCP_INPORTS_APP,993
  TCP_INPORTS_APP=$TCP_INPORTS_APP,995
  TCP_INPORTS_APP=$TCP_INPORTS_APP,597
  TCP_INPORTS_APP=$TCP_INPORTS_APP,514
  TCP_INPORTS_APP=$TCP_INPORTS_APP,80
  TCP_INPORTS_APP=$TCP_INPORTS_APP,443

##############################################################
# Known remote services we use are:
# We initiate these sessions..
# ======= udp =======
  UDP_REMPORTS_SYS=53 # DNS 53
  UDP_REMPORTS_SYS=$UDP_REMPORTS_SYS,67 # DHCP 67
  UDP_REMPORTS_SYS=$UDP_REMPORTS_SYS,123 # NTP 123

# ======= tcp =======
  TCP_REMPORTS_SYS=53 # DNS 53 .. actually I probably don't need this

#-------------------------------------------------------
  TCP_REMPORTS_BACKUP=22  # ports used out the internal interface.
                          # Machine does not route. just has 2 interfaces.
# ===== ICMP =======
##############################################################

# add $NEXTRULE set {setnumber} {rule}
writerule () {
  SET=$1
  shift
  ${IPFW} -q add $NEXTRULE set $SET $@
  NEXTRULE=$(($NEXTRULE + $RULESKIP))
}

# skipto {setnumber} {rules-to-skip} rulebody
skipcount () {
  SET=$1
  shift
  SKIPDIST=$(($RULESKIP * $1))
  shift
  ${IPFW} -q add $NEXTRULE set $SET skipto $(($NEXTRULE + $SKIPDIST )) $@
  NEXTRULE=$(($NEXTRULE + $RULESKIP))
}

if [ "$INCLUDE_COMMENTS" = "YES" ]
then
 # set {setnumber} // {commnet}
 writecomment () {
   SET=$1
   shift
   ${IPFW} -q add $NEXTRULE set $SET "//" $@
   NEXTRULE=$(($NEXTRULE + $RULESKIP))
 }
else
 writecomment() {
 }
fi

#  writefilter baserule ifname
# sets up a filter set as:
# YY00 skipto X000 inward
# YY10 skipto X500 outward
#
# and then adds the base filter sections further down.
# you should set up one of these per interface.
#
# [...]
# X000  skipto X200 to us
# [...] # routed packet rules go here
# X200
# [...] # rules for our packets go here
# X500  skipto X700 from us
# [...] # routed packet rules go here
# X700
# [...] # rules for our packets go here
#
# Leaves OUR_INCOMING OUR_OUTGOING OTHER_INCOMING OTHER_OUTGOING
# set up to where more rules should go to

writefilter () {
  # rule number, interface name, interface address
  # Write an interface filter in the filters section
  # splitting into two sectins (in and out)
  local TARGET_RULE=$1
  local IFACE=$2
  local IPADDR=$3
  local INCOMING=${TARGET_RULE}
  local OUTGOING=$(( ${TARGET_RULE} + 500 ))

  if [ ${IFACE} = "lo0" ] # Optimise for lo0
  then
    writecomment ${DEFAULT_SET}  "filter out packets on ${IFACE}"
    writerule ${DEFAULT_SET} skipto ${INCOMING} ip from any to any in recv ${IFACE}
    writerule ${DEFAULT_SET} skipto ${OUTGOING} ip from any to any out xmit ${IFACE}
    #just have two simple sections this is already probably too much
    OUR_INCOMING=${INCOMING}
    OUR_OUTGOING=${OUTGOING}
  else
    NEXTRULE=${NEXTFILTER}
    writecomment ${DEFAULT_SET}  "filter out packets on ${IFACE}"
    writerule ${DEFAULT_SET} skipto ${INCOMING} ip from any to any in recv ${IFACE}
    writerule ${DEFAULT_SET} skipto ${OUTGOING} ip from any to any out xmit ${IFACE}
    NEXTFILTER=${NEXTRULE}

    # then further split those sections into "ours and other"

    NEXTRULE=${INCOMING}
    OUR_INCOMING=$(( ${INCOMING} + 200 ))
    writerule ${DEFAULT_SET} skipto $OUR_INCOMING ip from any to ${IPADDR}
    writecomment ${DEFAULT_SET} "packets not addressed to us coming in on ${IFACE}"
    OTHER_INCOMING=$NEXTRULE

    NEXTRULE=${OUR_INCOMING}
    writecomment ${DEFAULT_SET} "packets addressed to US comin in on ${IFACE}"
    OUR_INCOMING=$NEXTRULE

    NEXTRULE=${OUTGOING}
    OUR_OUTGOING=$(( ${OUTGOING} + 200 ))
    writerule ${DEFAULT_SET} skipto ${OUR_OUTGOING} ip from ${IPADDR} to any
    writecomment ${DEFAULT_SET} "Packets NOT from us, going out on ${IFACE}"
    OTHER_OUTGOING=$NEXTRULE

    NEXTRULE=$OUR_OUTGOING
    writecomment ${DEFAULT_SET} "packets from us, going out ${IFACE}"
    OUR_OUTGOING=$NEXTRULE
  fi
}

if [ ${HAVE_TUNNEL} = "YES" ]
then
  if ${IPFW} nat 123 config if ${iif} log reset same_ports
  then
    NAT_OP="nat 123"
  else
    NAT_OP="count" # for testing when we don't have NAT loaded
    echo "Need to load NAT kernel module"
    echo "adding dummy rules for NAT" 
  fi
fi

##############################################################
##############################################################
# Special initial rules                                      #
# Leave space at front for manually debugging etc.           #
##############################################################
##############################################################
NEXTRULE=400
# should put standard non spoofing rules from rc.firewal here (except better ones)

NEXTFILTER=1000

##############################################################
##############################################################
# loopback                                                   #
# This is optimised a bit. (see above)                       #
##############################################################
##############################################################
# First for efficiency put Loopback spoofing test in right
# after the lo0 filter. Packets to or from 127.0.0.1 die right here
# if they didn't get sent to lo0 procesing
writefilter  2000 "lo0" "127.0.0.1"
NEXTRULE=${NEXTFILTER}
writerule ${DEFAULT_SET} deny all from 127.0.0.1 to any
writerule ${DEFAULT_SET} deny all from any to 127.0.0.1
NEXTFILTER=$NEXTRULE

NEXTRULE=$OUR_INCOMING
writerule ${DEFAULT_SET} allow all from any to any

NEXTRULE=$OUR_OUTGOING
writerule ${DEFAULT_SET} allow all from any to any


##############################################################
##############################################################
# Interface 0                                                #
##############################################################
##############################################################

writefilter  3000 ${oif} ${oip}

##############################################################
#  INCOMING packets ADDRESSED TO US                          #
# We should only accept them if we export a known service    #
# or they are a response to an outgoing packet of our own.   #
##############################################################
NEXTRULE=$OUR_INCOMING
# we will only have dynamic rules for locally connected sessions
# that do not do rate control or NAT, so we can skip these expensive
# operations by utilising this fact.
writerule ${DEFAULT_SET} check-state
writerule ${DEFAULT_SET} reject ip from table\(13\) to any
writerule ${DEFAULT_SET} reject ip from any to table\(13\)

if [ ${HAVE_TUNNEL} = "YES" ]
then
  # check incoming packets against known NAT sessions
  writecomment ${NAT_SET} "check incoming packets against known NAT sessions and dispatch them."
  writerule ${NAT_SET} ${NAT_OP} ip from any to ${VPN_SRC}
  # A NAT'd packet will now look like this:  accept it. We're done.
  writerule ${NAT_SET} accept ip from any to ${TUN_REMOTE}
  # Because we set one_pass to 0, packets that are NOT NAT'd
  # will be left untouched and will be for us.
  # We need to handle these when they return to us
  # along with any that were not sent for NATing.
fi

#================================================================
# set keep-state for these to skip future NAT and pipe calls.
writerule ${DEFAULT_SET} allow tcp from any to any ${TCP_INPORTS_SYS} setup keep-state
writerule ${DEFAULT_SET} allow udp from any to any ${UDP_INPORTS_SYS} keep-state
writerule ${DEFAULT_SET} allow tcp from table\(2\) to any ${TCP_DNS_ZONE} keep_state
writerule ${APP_SET} allow tcp from any to any ${TCP_INPORTS_APP} setup keep-state
writerule ${APP_SET} allow udp from any to any ${UDP_INPORTS_APP} keep-state

# IP fragments for UDP NFS # check the safety of this
writerule ${DEFAULT_SET} allow udp from any to any frag

# ICMP
# there are some one might want to stop
writerule ${DEFAULT_SET} allow icmp from any to any keep-state
# an alternative... (thought we probably want more)
# writerule ${DEFAULT_SET} allow icmp from any to any icmptype 0,8 keep-state

writerule ${DEFAULT_SET} drop ip from any to any

#################################################################
# Incoming packets not for us.                                  #
# There is just no excuse for any incoming packet not for us.   #
# Throw it away.     hmm only exception.. dhcp broadcast?       # 
#################################################################
NEXTRULE=$OTHER_INCOMING
writerule ${DEFAULT_SET} drop ip from any to any

#################################################################
# OUTGOING packets FROM US                                      #
# these should either be reponses to incoming service requests  #
# or our own service requests going out. Either way, we should  #
# let them go and make a rule for the return packet.            #
#################################################################
NEXTRULE=$OUR_OUTGOING
writecomment ${DEFAULT_SET} "outgoing packets from sesions we have already aproved are ok"
writerule ${DEFAULT_SET} check-state

# writecomment ${DEFAULT_SET}  "remember any outgoing session we initiate"
# writerule ${DEFAULT_SET} allow tcp from any to any setup keep-state
# This is redundant if we allow the above rule.
writecomment ${DEFAULT_SET}  "remeber any outgoing session we allow"
writerule ${DEFAULT_SET} allow tcp from any to any ${TCP_REMPORTS_SYS} setup keep-state
writerule ${DEFAULT_SET} allow udp from any to any ${UDP_REMPORTS_SYS} keep-state
# when we turn on, allow already running sessiosn to continue if we know about them (and send a packet).
writerule ${DEFAULT_SET} allow tcp from any to any established keep-state

writerule ${DEFAULT_SET} allow icmp from any to any keep-state

writerule ${DEFAULT_SET} drop ip from any to any

#################################################################
# Outgoing packets not from us.                                 #
# If it's not from us it must be from the tunnel in which case  #
# it is a NAT candidate. If not then throw it away.             #
#################################################################
NEXTRULE=$OTHER_OUTGOING
if [ ${HAVE_TUNNEL} = "YES" ]
then
  # only NAT packets we need to. Why waste time with others?
  writerule ${NAT_SET} ${NAT_OP} all from ${TUN_REMOTE} to any recv ${TUN}
  # successfully NAT'd packets will look like this.
  writerule ${NAT_SET} accept all from ${VPN_SRC} to any
fi
writerule ${DEFAULT_SET} drop ip from any to any


if [ "$iif" != "$oif" ]
then
  ##############################################################
  ##############################################################
  # Interface 1  In INLINE mode this goes to the cloud         #
  ##############################################################
  ##############################################################
  writefilter  4000 ${iif} ${iip}

  NEXTRULE=$OUR_INCOMING
  writerule ${DEFAULT_SET} check-state   # Only allow incoming packets on sessions we initiated.
  writerule ${DEFAULT_SET} allow icmp from any to any icmptype 0,3,8 keep-state
  writerule ${DEFAULT_SET} deny log ip from any to any

  # Packets coming in here that are not for us? drop them.
  NEXTRULE=$OTHER_INCOMING
  writerule ${DEFAULT_SET} deny log ip from any to any

  # packets FROM US going out this interface
  NEXTRULE=$OUR_OUTGOING
  writerule ${DEFAULT_SET} check-state   #  may be redundant due to the "keep-state" in the next rule
  writerule ${DEFAULT_SET} allow tcp from any to any ${TCP_REMPORTS_BACKUP} setup keep-state
  writerule ${DEFAULT_SET} deny ip from any to any

  # packets NOT FROM US going out this interface,.. there shoudn't be any.
  NEXTRULE=$OTHER_OUTGOING
  writerule ${DEFAULT_SET} deny log ip from any to any
fi

##############################################################
##############################################################
# Tunnel interface                                           #
##############################################################
##############################################################
if [ ${HAVE_TUNNEL} = "YES" ]
then
  writefilter  5000 tun0 me  # punt on addr.. we have no idea

  NEXTRULE=$OUR_INCOMING
  writerule ${DEFAULT_SET} allow ip from any to any

  NEXTRULE=$OTHER_INCOMING
  writerule ${DEFAULT_SET} allow ip from any to any

  NEXTRULE=$OUR_OUTGOING
  writerule ${DEFAULT_SET} allow ip from any to any

  NEXTRULE=$OTHER_OUTGOING
  writerule ${DEFAULT_SET} allow ip from any to any
fi

##############################################################
##############################################################
# Any other interfaces not mentioned                         #
##############################################################
##############################################################
NEXTRULE=${NEXTFILTER}
writecomment ${DEFAULT_SET}  "handle other intefaces"
writerule ${DEFAULT_SET} deny ip from any to any


# post rule stuff
${IPFW} set enable $DEFAULT_SET
${IPFW} set disable $APP_SET
${IPFW} set disable $APP_BLOCK_SET  # not written yet
${IPFW} set disable $NAT_SET        # nat rules disabled if written. not ready..
${IPFW} enable firewall
# ---- EOF ----

--------------010709070803080609010703--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5323C244.8050101>