Reverse Portscan

Es gibt Situationen, in denen es hilfreich ist, zu wissesn, welche Ports nach außen hin geöffnet sind.
Ob Schule, Universität oder freies WLAN - oft sind Nicht-Standard-Ports blockiert. Ungünstig nur, wenn es nirgendwo Informationen über funktionierende Ports gibt.

Zur Port-Ermittlung:
Man nehme

  • 1 öffentlich erreichbarer Linux Server mit Root Shell
  • Netcat (Linux) Java
  • nmap / Zenmap GUI (Windows) || Netcat

Wenn man ohnehin schon auf solche Maßnahmen angewiesen ist, ist es ratsam, nur die Standardports zu prüfen, alles andere ist wahrscheinlich sowieso schon zu.

Die Top 1000 Ports scannt nmap schon von Haus aus:

portlist=$(nmap --top-ports 1000 -dd -sT -oG - localhost | grep Ports | grep tcp | awk '{for(i=5;i<=NF;i++) printf "%i,", $i}' | awk 'BEGIN {FS = "/"} {print $1}')


Darauf folgend wird auf dem Server für jeden Port eine Instanz von Netcat gestartet, schließlich muss auf dem Port zuallererst ein Listen stattfinden.
Schon in Benutzung befindliche Ports sind nicht betroffen, hier wird sich Netcat mit Fehlermeldung beenden.

for port in $portlist; do (nc -klp $port < /dev/null &); done

Netcat möchte leider nicht spawnen.

Java ist eher nicht die Ideallösung, aber auf die Schnelle ;)

import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;

import javax.xml.transform.stream.StreamSource;

public class Listener {
    
    public Listener(int pPort) {
        (new Thread(() -> {
            ServerSocket socket = null;
            try {
                socket = new ServerSocket(pPort);
            } catch (IOException e) {
                System.err.println("could not bind to port " + pPort);
                return;
            }
            while (true) {
                try {
                    socket.accept().close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        })).start();
    }
    
    public static void main(String[] args) throws InterruptedException {
        try {
            Stream.of((args[0].split(",")))
                    .forEach(s -> new Listener(Integer.valueOf(s)));
        }
        catch(NumberFormatException e) {
            // don't care
        }
        Thread.sleep(5*60000);
        System.exit(123);
    }

}

Zu den Vorzügen von Java 8 ist ein eigener Post geplant.

Kompilierung & Starten des Listener:

javac Listener.java && java -Djava.net.preferIPv4Stack=true -Xms1M -Xmx1M -Xss230k Listener $portlist &
#-Xms start heap size
#-Xmx max heap size
#-Xss stack size thread


1k Threads, 50 MB RAM, 2,5 GB virtueller RAM (ohne -Xss230k 3,5 GB).
Da soll doch noch jemand behaupten, Java wäre nicht performant. Alles eine Frage der Parametrisierung. 😉


Spätestens jetzt sollten bei jedem die Schmerzen eingetreten sein, zumindest bis zur Notabschaltung in 5 Minuten.
iptables. Hilft.
1k+ Ports aufmachen, darauf listen; ist einfach nicht drin bei einem öffentlichen Server.

Ich setze voraus, dass die INPUT-Chain RELATED,ESTABLISHED zulässt, den Rest droppt. Etwa so:

iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 
iptables -A INPUT -j DROP

(Hier hat es nichtmal Regeln für das loopback-device, sollte keinesfalls als Referenz für irgendwas genutzt werden!)

Am Anfang wird das eigene Quellnetz deklariert, von dem aus der Scan stattfindet.

client_ip=ipv4/32

iptables -N REVERSE_PORTSCAN

for port in $(echo ${portlist::-1} | sed "s/,/ /g"); do # syntax erfordert bash
    iptables -A REVERSE_PORTSCAN -p tcp -m tcp --dport $port -j ACCEPT
done;

iptables -I INPUT -s $client_ip -j REVERSE_PORTSCAN


Aller einkommender Traffic passiert die Regeln in der INPUT Chain.

Zuerst wird eine neue Chain angelegt, in dieser werden die Ports freigegeben, auf die das Java Programm hört.
Als nächstes wird an den Start der INPUT Chain eine Regel eingefügt, die für genau die Source-IP bzw. Range einen Jump in die eben angelegte REVERSE_PORTSCAN Chain macht.
Ergo werden die Ports ausschließlich vom selbst festgelegten Quellnetz zugelassen.
Die Umleitung auf die REVERSE_PORTSCAN Chain betrifft sonst keinen.


Auf dem Client wird der Portscan wie folgt ausgeführt:

Für die Geduldigen:

nmap -sT -oG grep.log targethost


Für die Ungeduldigen:

nmap --max-rtt-timeout ping_to_targethost*2 --max-retries 1 --max-rate 100 --top-ports 1000 -sT -oG grep.log targethost


IPv6 (ip6tables) nicht vergessen, falls die Option bei java oben weggelassen wird. Sonst wird IPv6 genutzt - ungeschützt!

Links:
Man iptables

Weiter mit Iptables:
Linux Server absichern: SSH