Benutzer-Werkzeuge

Webseiten-Werkzeuge


kismet_auf_dem_pi

Kismet auf dem Pi

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.

Voraussetzungen

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

Kismet kompilieren

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

Konfigurieren

# 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=""
# ...

Startskript

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.

kismet_server
#! /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

plugins

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'.

plugin-syslog

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

config

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.

plugin-btscan

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

Weiterverarbeitung / WhoIsWho

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.

rsyslog

Die vom MySQL-Modul mitgebrachte /etc/rsyslog.d/mysql.conf kann gelöscht werden.

kismet.conf
# 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

Datenbank

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.

whoiswho.sql

whoiswho.sql
--
-- 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;

Webfrontend

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

index.php

index.php
<!-- 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> &nbsp; <a href="index.php?col=2&group=yes">(group)</a></th>
        <th style='width:200px'><a href="index.php?col=3">Network name</a> &nbsp; <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>

whoiswho.css

whoiswho.css
<!-- 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;
}

macinfo.php

macinfo.php
<!-- 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>

netinfo.php

netinfo.php
<!-- 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>

import-manuf.php

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/.

import-manuf.php
<!-- 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";
?>

process_incoming.php

Die eingehenden Meldungen werden über PHP-Skript in die „SEEN“-Tabelle übernommen. Das PHP-Skript wird über CRON gesteuert.

process_incoming.php
<?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 -

whoiswho.conf.php

whoiswho.conf.php
<!-- 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');

mysql.inc.php

mysql.inc.php
<!-- 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;
}

tools.inc.php

tools.inc.php
<!-- 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;
}
 
?>
kismet_auf_dem_pi.txt · Zuletzt geändert: 2015/06/02 19:57 von admin