Kismet soll auf dem Pi nicht zum „war-drive“ zum Einsatz kommen, sondern ein wenig Überblick über die gewünschten und ggfls. auch unerwünschten Besucher im heimischen Umfeld geben.
Ein paar Pakete und dev-Pakete sind für's kompilieren und für den „Betrieb“ notwendig. Außerdem gibt es ein paar Tools, die einem den Umgang mit dem System erleichtern.
# Voraussetzungen apt-get install build-essential wireshark libncurses5-dev libcap-dev \ libpcre3-dev libnl-3-dev libnl-genl-3-dev # Tools apt-get install vim rcconf
wget http://www.kismetwireless.net/code/kismet-2013-03-R1b.tar.gz tar xvf kismet-2013-03-R1b.tar.gz cd kismet-2013-03-R1b/ ./configure --with-suidgroup=pi --prefix=/usr/local/kismet --sysconfdir=/etc/kismet ########################## OUTPUT # ... Configuration complete: Compiling for: linux-gnueabihf (armv6l) C++ Library: stdc++ Installing as group: root Man pages owned by: man Installing into: /usr/local/kismet Setuid group: pi Terminal Control: ncurses Linux WEXT capture : yes OSX/Darwin capture : n/a (only OSX/Darwin) PCRE Regex Filters : yes pcap capture: yes airpcap control: n/a (only Cygwin/Win32) PPI log format: yes LibCapability (enhanced privilege dropping): no Linux Netlink: yes (mac80211 VAP creation) - libnl-3.0 libnl-genl-3.0 # ... ########################################################### make make suidinstall
# vi /etc/kismet/kismet.conf # ... logprefix=/var/log/kismet # ... ncsource=wlan0:type=rt73,forcevap=false,validatefcs=true # ... #ouifile=/etc/manuf ouifile=/etc/kismet/manuf # ... gps=false # ...
Eine aktuelle Manufacture (manuf) Datei holen:
cd /etc/kismet/ wget http://anonsvn.wireshark.org/wireshark/trunk/manuf
# vi /etc/default/ifplugd # ... #INTERFACES="auto" INTERFACES="eth0" #HOTPLUG_INTERFACES="all" HOTPLUG_INTERFACES="" # ...
Aus dem Skeleton-Skript (/etc/init.d/skeleton) lässt sich „auf die Schnelle“ ein Startskript bauen, damit der kismet_server automatisch startet. Mit Hilfe von „rcconf“ lässt sich dies dann auch in die entsprechende Systemkonfiguration einfügen.
#! /bin/sh ### BEGIN INIT INFO # Provides: skeleton # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Example initscript # Description: This file should be used to construct scripts to be # placed in /etc/init.d. ### END INIT INFO # Author: Foo Bar <foobar@baz.org> # # Please remove the "Author" lines above and replace them # with your own name if you copy and modify this script. # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/kismet/bin DESC="Kismet Server" NAME=kismet_server DAEMON=/usr/local/kismet/bin/kismet_server DAEMON_ARGS="--daemonize" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.2-14) to ensure that this file is present # and status_of_proc is working. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave 'force-reload' as an alias for 'restart'. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac
Die Plugins werden im Source-Code mitgeliefert, müssen aber noch kompiliert werden. Man kann alle Plugins „auf ein Mal“ kompilieren:
cd /install/kismet-2013-03-R1b make plugins make plugins-install
Benötigt werden für dieses „Projekt“ aber nur das 'plugin-syslog' und das 'plugin-btscan'.
Explizites Kompilieren des plugin-syslog
cd /install/kismet-2013-03-R1b/plugin-syslog export KIS_SRC_DIR=/install/kismet-2013-03-R1b # Pfad zu den Kismet-Sourcen mitgeben export KIS_DEST_DIR=/usr/local/kismet/plugins # Installations-Ziel # funktioniert so nicht. # Plugins werden nach /usr/local/kismet/lib/kismet installiert make make install
In der kismet.conf
# vi /etc/kismet/kismet.conf # ... # servername=Kismet Server servername=kismet # => hiermit wird der Syslog-Tag gefüllt. Wenn nichts angegeben wird, # wird der Hostname genommen, der eh schon im Syslog steht. # ... # JB NEW -> # Syslog log types can be: # all All messages from Kismet are logged # none No messages from Kismet are logged # info INFO-class messages # error ERROR-class messages # fatal FATAL-class messages # alert ALERT-class messages syslogtype=all # <- JB NEW # ... #logtypes=pcapdump,gpsxml,netxml,nettxt,alert logtypes=alerts # wenn das plugin-syslog benutzt wird, kann auf die meissten logs verzichtet werden.
Bluetooth-Erkennung
apt-get install bluetooth libbluetooth-dev cd /install/kismet-2013-03-R1b/plugin-btscan export KIS_SRC_DIR=/install/kismet-2013-03-R1b # Pfad zu den Kismet-Sourcen mitgeben make make install
Zur Weiterverarbeitung sollen die Syslog-Meldungen in eine MySQL-DB geschrieben werden. Wir nutzen dazu das rsyslog-MySQL Modul und lassen den rsyslog direkt passend filtern.
apt-get install rsyslog-mysql # ... # dbconfig-common # Konfigurieren der Datenbank für rsyslog-mysql mit dbconfig-common? <Nein>
Die automatische Konfiguration wird abgelehnt, da eine DB auf einem anderen System genutzt werden soll und weil zusätzliche Tabellen benötigt werden.
Die vom MySQL-Modul mitgebrachte /etc/rsyslog.d/mysql.conf kann gelöscht werden.
# vi /etc/rsyslog.d/kismet.conf # MySQL Modul $ModLoad ommysql # 1 Tabelle - alles vom Kismet if $syslogtag startswith 'kismet:' then :ommysql:192.168.11.11,kismet,kismet,password # zweite Tabelle - nur Netzwerke und clients $template SystemEventsKismet,"insert into Incoming (FromHost, Facility, Priority, Message, DeviceReportedTime, ReceivedAt, InfoUnitID, SyslogTag ) values ('%HOSTNAME%', ' %syslogfacility%', '%syslogpriority%', '%msg%', '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')",SQL #if $syslogtag startswith 'kismet:' then :ommysql:192.168.11.11,kismet,kismet,password;SystemEventsKismet :msg,contains,"new managed network" :ommysql:192.168.11.11,kismet,kismet,password;SystemEventsKismet :msg,contains,"new probe network" :ommysql:192.168.11.11,kismet,kismet,password;SystemEventsKismet :msg,contains,"new data network" :ommysql:192.168.11.11,kismet,kismet,password;SystemEventsKismet :msg,contains,"new ad-hoc network" :ommysql:192.168.11.11,kismet,kismet,password;SystemEventsKismet
Für die Datenbank brauchen wir, falls noch nicht vorhanden, einen MySQL-Server und sinnvollerweise PHPMyAdmin für die Verwaltung.
apt-get install mysql-server apt-get install phpmyadmin
Die entsprechende Datenbank kann dann über den Reiter „SQL“ im PHPMyAdmin angelegt werden. Bitte vorher „mypassword“ durch etwas sinnvolles ersetzen.
-- -- Anlegen der DB und eines entsprechenden Users -- CREATE USER 'kismet'@'%' IDENTIFIED BY 'mypassword'; GRANT USAGE ON * . * TO 'kismet'@'%' IDENTIFIED BY 'mypassword' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ; CREATE DATABASE IF NOT EXISTS `kismet` ; GRANT ALL PRIVILEGES ON `kismet` . * TO 'kismet'@'%'; -- -------------------------------------------------------- -- -- Tabellenstruktur für Tabelle `Incoming` -- CREATE TABLE IF NOT EXISTS `Incoming` ( `ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `CustomerID` BIGINT(20) DEFAULT NULL, `ReceivedAt` datetime DEFAULT NULL, `DeviceReportedTime` datetime DEFAULT NULL, `Facility` SMALLINT(6) DEFAULT NULL, `Priority` SMALLINT(6) DEFAULT NULL, `FromHost` VARCHAR(60) DEFAULT NULL, `Message` text, `NTSeverity` INT(11) DEFAULT NULL, `Importance` INT(11) DEFAULT NULL, `EventSource` VARCHAR(60) DEFAULT NULL, `EventUser` VARCHAR(60) DEFAULT NULL, `EventCategory` INT(11) DEFAULT NULL, `EventID` INT(11) DEFAULT NULL, `EventBinaryData` text, `MaxAvailable` INT(11) DEFAULT NULL, `CurrUsage` INT(11) DEFAULT NULL, `MinUsage` INT(11) DEFAULT NULL, `MaxUsage` INT(11) DEFAULT NULL, `InfoUnitID` INT(11) DEFAULT NULL, `SysLogTag` VARCHAR(60) DEFAULT NULL, `EventLogType` VARCHAR(60) DEFAULT NULL, `GenericFileName` VARCHAR(60) DEFAULT NULL, `SystemID` INT(11) DEFAULT NULL, `processid` VARCHAR(60) NOT NULL DEFAULT '', `checksum` INT(11) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`ID`), KEY `FromHost` (`FromHost`), KEY `checksum` (`checksum`), KEY `DeviceReportedTime` (`DeviceReportedTime`), KEY `EventID` (`EventID`), KEY `InfoUnitID` (`InfoUnitID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=33 ; -- -------------------------------------------------------- -- -- Tabellenstruktur für Tabelle `Manufacturer` -- CREATE TABLE IF NOT EXISTS `Manufacturer` ( `MAC` VARCHAR(20) NOT NULL, `ShortDescription` VARCHAR(20) NOT NULL, `Description` text NOT NULL, PRIMARY KEY (`MAC`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -------------------------------------------------------- -- -- Tabellenstruktur für Tabelle `Seen` -- CREATE TABLE IF NOT EXISTS `Seen` ( `ID` INT(11) NOT NULL AUTO_INCREMENT, `SyslogID` INT(11) NOT NULL, `MAC` VARCHAR(20) NOT NULL, `Time` datetime NOT NULL, `Name` VARCHAR(50) NOT NULL, `Type` VARCHAR(20) NOT NULL, `Encryption` VARCHAR(10) NOT NULL, `Channel` INT(3) NOT NULL, `BitRate` INT(8) NOT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; -- -------------------------------------------------------- -- -- Tabellenstruktur für Tabelle `SystemEvents` -- CREATE TABLE IF NOT EXISTS `SystemEvents` ( `ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `CustomerID` BIGINT(20) DEFAULT NULL, `ReceivedAt` datetime DEFAULT NULL, `DeviceReportedTime` datetime DEFAULT NULL, `Facility` SMALLINT(6) DEFAULT NULL, `Priority` SMALLINT(6) DEFAULT NULL, `FromHost` VARCHAR(60) DEFAULT NULL, `Message` text, `NTSeverity` INT(11) DEFAULT NULL, `Importance` INT(11) DEFAULT NULL, `EventSource` VARCHAR(60) DEFAULT NULL, `EventUser` VARCHAR(60) DEFAULT NULL, `EventCategory` INT(11) DEFAULT NULL, `EventID` INT(11) DEFAULT NULL, `EventBinaryData` text, `MaxAvailable` INT(11) DEFAULT NULL, `CurrUsage` INT(11) DEFAULT NULL, `MinUsage` INT(11) DEFAULT NULL, `MaxUsage` INT(11) DEFAULT NULL, `InfoUnitID` INT(11) DEFAULT NULL, `SysLogTag` VARCHAR(60) DEFAULT NULL, `EventLogType` VARCHAR(60) DEFAULT NULL, `GenericFileName` VARCHAR(60) DEFAULT NULL, `SystemID` INT(11) DEFAULT NULL, `processid` VARCHAR(60) NOT NULL DEFAULT '', `checksum` INT(11) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`ID`), KEY `FromHost` (`FromHost`), KEY `checksum` (`checksum`), KEY `DeviceReportedTime` (`DeviceReportedTime`), KEY `EventID` (`EventID`), KEY `InfoUnitID` (`InfoUnitID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=288 ; -- -------------------------------------------------------- -- -- Tabellenstruktur für Tabelle `WellKnown` -- CREATE TABLE IF NOT EXISTS `WellKnown` ( `MAC` VARCHAR(20) NOT NULL, `Comment` text NOT NULL, PRIMARY KEY (`MAC`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
apt-get install apache2 php5 php5-mysql
Ein einfaches Webfront-End lässt sich schnell mit PHP erstellen. Natürlich braucht der Apache dafür noch eine entsprechende Config.
# vi /etc/apache2/conf.d/whoiswho.conf Alias /whoiswho "/usr/local/whoiswho" <Directory "/usr/local/whoiswho"> Options +FollowSymLinks AllowOverride None # AuthName "WhoIsWho Access" # AuthType Basic # AuthUserFile /usr/local/whoiswho/etc/htpasswd.users # Require valid-user </Directory>
Unter /usr/local/whoiswho wird die eigentliche Webseite angelegt.
mkdir /usr/local/whoiswho mkdir /usr/local/whoiswho/cron mkdir /usr/local/whoiswho/etc mkdir /usr/local/whoiswho/include #mkdir /usr/local/whoiswho/images # noch nicht benötigt
<!-- vi /usr/local/whoiswho/index.php --> <?php # SESSION_NAME("WHOISWHO"); # SESSION_START(); require_once("etc/whoiswho.conf.php"); require_once("include/mysql.inc.php"); require_once("include/tools.inc.php"); if (isset($_GET['col']) && is_numeric($_GET['col']) ) { //isset prüft, ob eine Variable gesetzt ist if ($_GET['col'] >= 0 && $_GET['col'] < 5) { //Validitätsprüfung, nur Spalten 0..4 erlaubt $sort_column = $_GET['col']; } else { echo "<H1>HANDS OFF MY URL!!!</H1>"; $sort_column = 0; } } else { $sort_column = 0; }; if (isset($_GET['group'])) { $group = $_GET['group']; } else { $group = "no"; }; #error_log("INDEX.PHP GROUP: $group"); $title = "Who are my 'wireless' visitors"; $db = dbconnect(); $table = SEENTABLE; switch($sort_column) { case '0': $sql = "SELECT * FROM $table ORDER BY ID DESC"; $title = $title." (sort by ID)"; break; case '1': $sql = "SELECT * FROM $table ORDER BY TIME DESC"; $title = $title." (sort by Time)"; break; case '2': if ($group == "yes") { $sql = "SELECT * FROM $table GROUP BY MAC ASC"; $title = $title." (grouped by MAC)"; } else { $sql = "SELECT * FROM $table ORDER BY MAC ASC"; $title = $title." (sort by MAC)"; }; break; case '3': if ($group == "yes") { $sql = "SELECT * FROM $table GROUP BY Name DESC"; $title = $title." (grouped by Network name)"; } else { $sql = "SELECT * FROM $table ORDER BY Name DESC"; $title = $title." (sort by Network name)"; }; break; case '4': $sql = "SELECT * FROM $table ORDER BY Type DESC"; $title = $title." (sort by Network type)"; break; default: $sql = "SELECT * FROM $table ORDER BY Time DESC;"; $title = $title." (sort by Time)"; } ?> <html> <head> <title>'WhoIsWho'</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="whoiswho.css"> <meta http-equiv="refresh" content="60"> </head> <body> <table width=1000><caption><?=$title;?></caption> <thead> <th style='width:50px'><a href="index.php?col=0">ID</a></th> <th style='width:150px'><a href="index.php?col=1">Time</a></th> <th style='width:150px'><a href="index.php?col=2">MAC</a> <a href="index.php?col=2&group=yes">(group)</a></th> <th style='width:200px'><a href="index.php?col=3">Network name</a> <a href="index.php?col=3&group=yes">(group)</a></th> <th style='width:100px'><a href="index.php?col=4">Network type</a></th> <th style='width:400px'>Comment</th> </thead> <tbody> <?php $sth = $db->query($sql); while ($row = $sth->fetch()) { $comment = lookup_mac($row['MAC']); ?> <tr> <td><?=$row['ID'];?></td> <td><?=$row['Time'];?></td> <td><a href="#" onclick='window.open("macinfo.php?mac=<?=$row['MAC'];?>&comment=<?=$comment;?>","WhoIsWho MAC-Info","directories=0,titlebar=0,toolbar=0,location=0,status=0,menubar=0,scrollbars=yes,resizable=no,width=650,height=350"); return false;'><?=$row['MAC'];?></a></td> <td><a href="#" onclick='window.open("netinfo.php?net=<?=$row['Name'];?>","WhoIsWho Network-Info","directories=0,titlebar=0,toolbar=0,location=0,status=0,menubar=0,scrollbars=yes,resizable=no,width=950,height=350"); return false;'><?=$row['Name'];?></a></td> <td><?=$row['Type'];?></td> <td><?=$comment;?></td> </tr> <?php } ?> </tbody> </thead> </body> </html>
<!-- vi /usr/local/whoiswho/whoiswho.css --> table { margin:0; padding:0; font-family: arial, verdana, serif; color: black; font-size: 11px; } table, tr, th, td { border-collapse: collapse; } caption { margin:0; padding:0; background: #f0f0f0; height: 25px; line-height: 25px; text-indent: 5px; font-family: arial, verdana, serif; font-weight: bold; color: black; font-size: 13px; text-align: left; /*letter-spacing: 3px;*/ border: solid 1px #c0c0c0; } thead th { height: 22px; line-height: 20px; text-align: left; color: black; font-size: 13px; background: #A2A2A2; } tbody tr { background: white; padding: 3px; } tbody tr:hover { background: #d0d0d0; /*text-decoration: underline;*/ } table a { /*color: #2c3763;*/ color: black; text-decoration: none; font-size: 11px; font-weight: bold; border-bottom: solid 1px black; } table a:hover { /*color: #2c3763;*/ color: black; font-weight: bold; text-decoration: underline; border-bottom: none; } table a:visited { /*color: #2c3763;*/ color: black; font-weight: bold; }
<!-- vi /usr/local/whoiswho/macinfo.php --> <?php require_once("etc/whoiswho.conf.php"); require_once("include/mysql.inc.php"); require_once("include/tools.inc.php"); if (isset($_GET['mac'])) { $mac = $_GET['mac']; // Prüfen ob MAC-Aufbau // preg_grep('/([a-fA-F0-9]{2}[:|\-]?){6}/', $msg) } else { $mac = "unkown"; }; if (isset($_GET['comment'])) { $comment = $_GET['comment']; } else { $comment = "unkown"; }; $db = dbconnect(); $table = SEENTABLE; $title = "MAC Info for $mac - $comment"; ?> <html> <head> <title>'WhoIsWho - MAC Info'</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="whoiswho.css"> <!-- <meta http-equiv="refresh" content="60"> --> </head> <body> <table width=620><caption><?=$title;?></caption> <thead> <th style='width:120px'>Time</th> <th style='width:100px'>Network name</th> <th style='width:100px'>Network type</th> <th style='width:100px'>Encryption</th> <th style='width:100px'>Channel</th> <th style='width:100px'>BitRate</th> </thead> <tbody> <?php $sql = "SELECT * FROM $table WHERE MAC='$mac' ORDER BY Time DESC;"; $sth = $db->query($sql); $sql_rc = $db->errorCode(); error_log("$sql_rc\n"); while ($row = $sth->fetch()) { ?> <tr> <td><?=$row['Time'];?></td> <td><a href="#" onclick='window.open("netinfo.php?net=<?=$row['Name'];?>","WhoIsWho Network-Info","directories=0,titlebar=0,toolbar=0,location=0,status=0,menubar=0,scrollbars=yes,resizable=no,width=950,height=350"); return false;'><?=$row['Name'];?></a></td> <td><?=$row['Type'];?></td> <td><?=$row['Encryption'];?></td> <td><?=$row['Channel'];?></td> <td><?=$row['BitRate'];?></td> <?php } ?> </tbody> </thead> </body> </html>
<!-- vi /usr/local/whoiswho/netinfo.php --> <?php require_once("etc/whoiswho.conf.php"); require_once("include/mysql.inc.php"); require_once("include/tools.inc.php"); if (isset($_GET['net'])) { $net = $_GET['net']; } else { $net = "unkown"; }; $db = dbconnect(); $table = SEENTABLE; $title = "More Info for $net"; ?> <html> <head> <title>'WhoIsWho - Network Info'</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="whoiswho.css"> <!-- <meta http-equiv="refresh" content="60"> --> </head> <body> <table width=920><caption><?=$title;?></caption> <thead> <th style='width:120px'>Time</th> <th style='width:100px'>MAC</th> <th style='width:100px'>Network type</th> <th style='width:100px'>Encryption</th> <th style='width:100px'>Channel</th> <th style='width:100px'>BitRate</th> <th style='width:300px'>Comment</th> </thead> <tbody> <?php $sql = "SELECT * FROM $table WHERE Name='$net' ORDER BY Time DESC;"; $sth = $db->query($sql); $sql_rc = $db->errorCode(); error_log("$sql_rc\n"); while ($row = $sth->fetch()) { $comment = lookup_mac($row['MAC']); ?> <tr> <td><?=$row['Time'];?></td> <td><a href="#" onclick='window.open("macinfo.php?mac=<?=$row['MAC'];?>&comment=<?=$comment;?>","WhoIsWho MAC-Info","directories=0,titlebar=0,toolbar=0,location=0,status=0,menubar=0,scrollbars=yes,resizable=no,width=650,height=350"); return false;'><?=$row['MAC'];?></a></td> <td><?=$row['Type'];?></td> <td><?=$row['Encryption'];?></td> <td><?=$row['Channel'];?></td> <td><?=$row['BitRate'];?></td> <td><?=$comment;?></td> <?php } ?> </tbody> </thead> </body> </html>
Auf dem Pi ist der I/O nicht wirklich schnell, weshalb es zu empfehlen ist, die „manuf“-Datei in eine entsprechende Tabelle der Datenbank zu importieren.
Eine aktuelle „manuf“-Datei gibts unter https://code.wireshark.org/review/gitweb?p=wireshark.git;a=blob_plain;f=manuf;hb=HEAD … abgelegt wird diese unter /usr/local/whoiswho/etc/.
<!-- vi /usr/local/whoiswho/import-manuf.php> <?php require_once("etc/whoiswho.conf.php"); require_once("include/mysql.inc.php"); $manuf = file("/usr/local/whoiswho/etc/manuf"); $i = 0; $db = dbconnect(); $table = MANUFTABLE; # clear table before start $truncsql = "truncate $table;"; $truncsth = $db->query($truncsql); $sql_rc = $db->errorCode(); print "$truncsql ..."; print "$sql_rc\n"; print "starting import...\n"; foreach ($manuf AS $manuf_row) { #if (preg_match("/([a-fA-F0-9]{2}[:|\-]?){3}/",$manuf_row)) if (preg_match("/([a-fA-F0-9]{2}[:]?){3}/",$manuf_row)) { $i++; $mac = substr($manuf_row,0,8); # eliminate multiple blanks #$text = preg_replace('/\s{2,}/',' ',$manuf_row); $manuf_row = preg_replace('/\040{1,}/',' ',$manuf_row); # eliminate tabs $manuf_row = str_replace("\t", " ", $manuf_row); # elimate Carriage Return and Line Feed $manuf_row = rtrim($manuf_row); $row_presplit = explode("#", $manuf_row); $row_split = explode(" ", $row_presplit[0]); $shortdescr = $row_split[1]; if (isset($row_presplit[1])) { $descr = ltrim($row_presplit[1]); } else { $descr = "none"; }; print "$mac;$shortdescr;$descr \n"; $sql = "INSERT INTO $table (MAC,ShortDescription,Description) values ('$mac','$shortdescr','$descr');"; print $sql; $sth = $db->query($sql); $sql_rc = $db->errorCode(); print "$sql_rc\n"; } } print "$i rows imported!!\n"; ?>
Die eingehenden Meldungen werden über PHP-Skript in die „SEEN“-Tabelle übernommen. Das PHP-Skript wird über CRON gesteuert.
<?php require_once("../etc/whoiswho.conf.php"); require_once("../include/mysql.inc.php"); $i = 0; $db = dbconnect(); $table = INCOMINGTABLE; $sql = "SELECT * FROM $table;"; $sth = $db->query($sql); while ($row = $sth->fetch()) { $i++; print "Processing Message: Time: ".$row['DeviceReportedTime']." Message: ".$row['Message']."\n"; # ID $id = $row['ID']; # Time $time = $row['DeviceReportedTime']; # WLAN name $msg = explode(",", $row['Message']); $msgpart = ltrim($msg[0]); preg_match('/"[^"]*"/', $msgpart, $netnamemsg); $netnamemsg = str_replace(['"','<','>'], '', $netnamemsg); $netname = $netnamemsg[0]; # getting MAC $macmsg = explode(" ", ltrim($msg[1])); $mac = implode(preg_grep('/([a-fA-F0-9]{2}[:|\-]?){6}/', $macmsg)); $mac = str_replace(",", "", $mac); $mac = str_replace("-", ":", $mac); $mac = strtoupper($mac); # network type switch (true) { case (preg_grep('/new managed network/', $msg)): $type="access point"; break; case (preg_grep('/new probe network/', $msg)): $type="client"; break; case (preg_grep('/new ad-hoc network/', $msg)): $type="ad-hoc"; break; case (preg_grep('/new data network/', $msg)): $type="data"; break; default: $type="unknown"; } # encryption $encmsg = explode(" ", $msg[2]); $enc = $encmsg[2]; # channel $channelmsg = explode(" ", $msg[3]); $channel = $channelmsg[2]; # bit rate $bitratemsg = explode(" ", $msg[4]); $bitrate = $bitratemsg[1]; # insert into SEEN Table $inserttable = SEENTABLE; $insertsql = "INSERT INTO $inserttable (SyslogID,MAC,Time,Name,Type,Encryption,Channel,BitRate) values('$id','$mac','$time','$netname','$type','$enc','$channel','$bitrate');"; $insertsth = $db->query($insertsql); $sql_rc = $db->errorCode(); #print "$insertsql ..."; #print "$sql_rc\n"; # delete from INCOMING $delsql = "DELETE FROM $table WHERE ID ='$id';"; $delsth = $db->query($delsql); } print "$i messages processed.\n"; ?>
# vi /etc/cron.hourly/whoiswho #!/bin/bash # cd /usr/local/whoiswho/cron/ /usr/bin/php process_incoming.php cd -
<!-- vi /usr/local/whoiswho/etc/whoiswho.conf.php --> <?php # database connection define('DBDRIVER', 'mysql'); define('DBHOST', '192.168.11.11'); define('DBNAME', 'kismet'); define('DBUSER', 'kismet'); define('DBPASS', 'password'); define('WELLKNOWNTABLE', 'WellKnown'); define('INCOMINGTABLE', 'Incoming'); define('SEENTABLE', 'Seen'); define('MANUFTABLE', 'Manufacturer');
<!-- vi /usr/local/whoiswho/include/mysql.inc.php --> <?php function dbconnect() { /*$opt = array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'", PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION );*/ $opt = array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'" ); $dsn = sprintf('%s:host=%s;dbname=%s', DBDRIVER, DBHOST, DBNAME); #error_log("Connect with " . $dsn); $db = new PDO($dsn, DBUSER, DBPASS, $opt); return $db; }
<!-- vi /usr/local/whoiswho/include/tools.inc.php --> <?php function lookup_manuf_file($mac) { $manuf = file("/usr/local/whoiswho/etc/manuf"); foreach ($manuf AS $manuf_row) { if (substr($mac,0,8) == substr($manuf_row,0,8)) { # eliminate multiple blanks #$text = preg_replace('/\s{2,}/',' ',$manuf_row); $manuf_row = preg_replace('/\040{1,}/',' ',$manuf_row); # eliminate tabs $manuf_row = str_replace("\t", " ", $manuf_row); $row_presplit = explode("#", $manuf_row); $row_split = explode(" ", $row_presplit[0]); $shortdescr = $row_split[1]; if (isset($row_presplit[1])) { $descr = ltrim($row_presplit[1]); } else { $descr = "none"; }; } } if (isset($shortdescr) && isset($descr)) return array($shortdescr,$descr); } function lookup_manuf_db($mac) { $db = dbconnect(); $table = MANUFTABLE; $searchmac = substr($mac,0,8); $sql = "SELECT * FROM $table WHERE MAC='$searchmac' LIMIT 1;"; #error_log("LOOKUP_MANUF_DB: ".$sql); $sth = $db->query($sql); while ($row = $sth->fetch(PDO::FETCH_ASSOC)){ (isset($row['ShortDescription'])) ? $shortdescr = $row['ShortDescription'] : $shortdesc = "none"; (isset($row['Description'])) ? $descr = $row['Description'] : $descr = "none"; } if (isset($shortdescr) && isset($descr)) return array($shortdescr,$descr); } function lookup_mac($mac) { $db = dbconnect(); $table = WELLKNOWNTABLE; $sql = "SELECT * from $table WHERE MAC='$mac';"; $sth = $db->query($sql); while ($row = $sth->fetch(PDO::FETCH_ASSOC)) { $comment = "<B>".$row['Comment']."</B>"; } if (!isset($comment)) { #list($shortdescr,$descr) = lookup_manuf_file($mac); list($shortdescr,$descr) = lookup_manuf_db($mac); if (isset($shortdescr)) { if ($descr == "none") { $comment = $shortdescr; } else { $comment = $shortdescr." (".$descr.")"; } } else $comment = "<i>unknown</i>"; } return $comment; } ?>