PHP E-Mail Benachrichtigung bei Datei Änderungen durch Hacker auf Webserver

WannabeTux

Cadet 4th Year
Registriert
Sep. 2014
Beiträge
114
Hallo zusammen,

mein Ziel ist, dass ich via E-Mail benachrichtigt werde, falls mein Server defaced wird und da fremde Finger ins Spiel kommen.

Man müsste die Pfade auswählen können und am besten eigentlich die Hashes vergleichen, leider ist bei folgendem Script das so eingebaut, dass er nur die Dateigröße abgleicht und Bescheid gibt, sobald sich da was tut.

Bekomme das Script aber gar nicht erst zum laufen, da der SQLite3 nicht erkennt und PuTTY beim Ausführen dann eine Fehlermeldung raus gibt..


Das komplette Script:

PHP:
<?php

define('EMAIL', 'mail@mail.de');
define('DBPATH', '/path/to/db');
define('DBNAME', 'dbname_db.idx');
define('CHECK_PATH', '/home/user/private', '/home/user/myfiles', '/opt/projects');

// true - check subfolders too
define('CHECK_RECURSIVE', true);

define('DBFILE', DBPATH . '/' .DBNAME);
define('CHG_UNCHANGED', 'UNCHANGED');
define('CHG_ADDED', 'ADDED');
define('CHG_CHANGED', 'CHANGED');

function createDb() {
  $db = new SQLite3(DBFILE);
  $db->queryExec("CREATE TABLE tbl_files (f_name TEXT, f_size INTEGER, PRIMARY KEY (f_name))");
}

function sendEmail($changesBody, $time) {

  if (empty($changesBody)) return;

  // set email headers
  $headers  = "MIME-Version: 1.0\r\n";
  $headers .= "Content-type: text/plain; charset=\"us-ascii\"\r\n";
  $headers .= "From: " . EMAIL . "\r\n";
  $headers .= "Reply-To: " . EMAIL . "\r\n";
  $headers .= 'X-Mailer: webcheck';

  $message = $changesBody . "
 Job took from start to finish: " . $time;

  if (EMAIL != '') {
    // send email
    @mail(EMAIL,              // TO email
      'Server Check Alert',  // subject
      $message,               // email text
      $headers);              // headers
  }
}

function isChanged($filename) {
  if (strpos($filename, DBNAME) != FALSE) return '';

  $isChanged = CHG_UNCHANGED;
  $db = new SQLite3(DBFILE);
  $q = $db->query("SELECT f_size FROM tbl_files WHERE f_name = '$filename' ");

  $filesize_old = $q->fetchSingle();
  $filesize_new = filesize($filename);

  // not in db?
  if ($filesize_old === FALSE) {
    $isChanged = CHG_ADDED;
  }
  else if (filesize($filename) != $filesize_old) {
    $isChanged = CHG_CHANGED;
  }
  // update database
  if ($isChanged != CHG_UNCHANGED) {
    if ($isChanged == CHG_ADDED) {
      $db->queryExec("INSERT INTO tbl_files VALUES ('$filename', " . filesize($filename) . " )");
    }
    else if ($isChanged == CHG_CHANGED) {
      $db->queryExec("UPDATE tbl_files SET f_size = " . filesize($filename) . " WHERE f_name = '$filename'");
    }
  }

  if ($isChanged != CHG_UNCHANGED) {
    if (!empty($_GET['web'])) echo "$filename -- $isChanged (was:" . $filesize_old . '/is:' . $filesize_new . ")<br>";
    return "$filename -- $isChanged (was:" . $filesize_old . '/is:' . $filesize_new . ")\n";
  }
  else
    return "";
}

$changesBody = "";

function loopDir($dirname) {
  global $changesBody;

  $dir = opendir($dirname);

  while ($file = readdir($dir)) {
    if ($file != '.' && $file != '..') {
      if (is_dir($dirname.'/'.$file)) {
        if (CHECK_RECURSIVE) {
          loopDir($dirname.'/'.$file);
        }
      } else {
        $changesBody = $changesBody . isChanged($dirname.'/'.$file);
      }
    }
  }
}

if (!file_exists(DBFILE)) {
  createDb();
  sendEmail("Database file not found! Creating.", 0);
}

$stime = microtime(true);
loopDir(CHECK_PATH);
sendEmail($changesBody, microtime(true) - $stime);

echo "\nDONE";
?>

Weiß ja nichtmal ob das Script an sich funktionieren würde..
Hat da vielleicht jemand mehr Erfahrung in PHP und kann mir helfen?


Die Fehlermeldung von PuTTY ist folgende:

Code:
PHP Fatal error:  Class 'SQLite3' not found in /opt/projects/webcheck/webcheck.php on line 17

In dem Fall wird sich SQLite3 wohl nicht auf dem Server befinden.
Gibt's auch Möglichkeiten, dass er in einer lokalen Datei die tables speichert und gar keinen Zugriff erst auf die Datenbank benötigt? Möchte ja nur mit nem cron job das Script arbeiten lassen und die Ordner damit prüfen, nichts in der SQL.
 
Ist die sqlite-Extension in deiner PHP-Installation aktiviert? Führ mal "php -i" aus und schau in der Ausgabe nach, ob du was über sqlite findest.
 
Hab nichts von sqlite gefunden, hab mich jetzt aber auch mal an ein eigenes Script gemacht, da dieses Script von oben nicht 100% dem entspricht was ich brauche.

Ziel:

URLs in sha256 Hash Codes umwandeln und in einer lokalen Datenbank als Datei im gleichen Pfad speichern, die DB dient nur dem Abgleich der Hashes. Für den Fall, dass ein Hacker eine der Dateien verändert, wird man per Mail benachrichtigt.

Nunja, ich bin momentan so weit, dass Hashes für alle Links generiert werden.

Nur wie speichere ich die in eine single file DB die im gleichen Pfad liegt?
 
Nur so eine Überlegung:

Defacement setzt voraus, dass vorher jemand an deinen Server rankommt.
Wo willst du das Script denn speichern, damit es nicht gleich mitgelöscht wird?
 
Wahrscheinlich dann auf einem anderen Server, das Script welches ich zurzeit nutze generiert sha256 hashes aus den URLs

Datenbank lasse ich weg, vielleicht nur ne Art Text Datei oder ein Zwischenspeicher worüber das Script die Hashes abgleichen kann und im Falle einer Änderung über Mail Alarm schlägt und als flag bestätigt, dass Alarm gegeben wurde.

Ich hab nur die Aufgabe so nen Script zu schreiben obwohl ich selbst nicht wirklich einen Plan von php habe oder wie ich nun weiterkomme und das Script kann ich nicht hier posten..

Ich brauche nur eine Art Anlaufstelle wie ich die generierten Hashes abgleichen lasse
 
Du solltest ja sowieso ein Remote-Backup haben.
Dann nimm doch einfach rsync.
Im dry-run listest es dir recht zuverlässig alle geänderten Dateien auf.
 
kannst ja ein git init im root machen und dann per git status auf änderung prüfen :D
 
Das scheint mich nicht weiterzubringen. (muss ein php script sein)
Das Ding ist folgendes, ich soll für jemanden ein Script schreiben welches folgendes macht (ist als eine Art Aufgabe zum testen, soll mich in php was durchlesen und das probieren hinzubekommen, lese mich nun schon seit 2 Tagen durch und komme einfach zu keinem sinnvollen Ergebnis wie ich nun weiterkommen könnte):

Hashes aus den im array angegebenen 3 URLs generieren und diese dann irgendwo speichern, wie oder wo die hashes nun gespeichert werden sollen weiß ich nicht. Kenne dazu nichtmal den Befehl.

Also Hashes in eine Datei schreiben. Danach die Hashes erneut generieren und prüfen, ob die schon in der Datei vorhanden (was ja eigentlich der Fall sein sollte).
Dann sollen die Hashes miteinander verglichen werden, sofern alles übereinstimmt ist der Vorgang beendet und fängt nach 5 Minuten via cron job neu an um eben erneut zu prüfen.
Falls nun ein Hacker da irgendwas an defacement gemacht haben sollte stimmt der hinterlegte Hash ja nichtmehr mit dem neu generierten überein (braucht ja nur ein neuer Zeitstempel der geänderten Datei sein und der Hash verändert sich).

Da nun der Fall eingetreten ist indem das Script Alarm schlagen soll, müsste man das mit einer flag kennzeichnen.
Ob alles mit der Übereinstimmung ok ist könnte man auch mit einer flag kennzeichnen, 0=Nein, 1=Ja und 2=benachrichtigt (über Mail)

Nur hänge ich immer noch beim nächsten Schritt nach dem Generieren der Hashes...
 
kannst dir dann die datenbank ja eigentlich sparen

würde ein array mit den dateinamen als schlüssel und dem hash als value erzeugen
und dann einfach serialisiert weg speichern... und wieder laden halt
hier ein beispiel das du nur noch ausfüllen musst.. praktisch malen nach zahlen
PHP:
<?php

class HashChecker
{
    private static $hashes = [];
    //Datei in die die Hashes gespeichert werden
    private $file = 'path/to/file';
    private $dirs = [
        '/home/user/private',
        '/home/user/myfiles', 
        '/opt/projects'
    ];
    
    private $modified = [];
    
    
    public function run()
    {
        //Wenn hash Datei nicht exestiert dann soll die erstellt und gefüllt werden
        if (!file_exists($this->file)) {
            $this->create();
        }
        //Datei Laden
        $this->load();
        
        //Ordner durchsuchen
        foreach ($this->dirs as $dir) {
            foreach ($this->getFiles($dir) as $file) {
                $this->checkFile($file);
            }
        }
        
        $this->save();
        
        //Wenn Veränderte Dateien dann E-Mail
        if (count($this->modified) > 0) {
            $this->sendMail();
        }
    }
    
    private function checkFile($file)
    {
        $hash = $this->getFileHash($file);
        if (self::hashes[$file] != $hash) {
            $self::modified[] = [
                'file' => $file;
                'old_hash' => self::$hashes[$file],
                'new_hash' => $hash
            ];
            
            //Den neuen Hash Abspeichern
            self::hashes[$files] = $hash;
            
        }
    }
    
    private function getFileHash($file)
    {
        //hash der datei Rausfinden
        return $hash;
    }
    
    private function sendMail()
    {
        //email versenden
    }
    
    private function create()
    {
        foreach ($this->dirs as $dir) {
            foreach ($this->getFiles($dir) as $file) {
                self::hashes[$file] = $this->getFileHash($file);
            }
        }
        
        $this->save();
    }
    
    private function getFiles($dir)
    {
        //alle dateien in des Verzeichnisses im $files Array Speichern
        return $files;
    }
    
    private function load()
    {
        //laden der Hashes aus der Datei
        self::$hashes = unserialize(file_get_contents($this->file));
    }
    
    private function save()
    {
        //speichern der Hashes in der Datei
        file_put_contents($this->file, serialize(self::$hashes));
    }
    
}

(new HashChecker())->run();
 
Dann kann man dir wohl nur das Php Manual ans Herz legen.
Website auslesen: file_get_contents
Hash bilden: md5() (ist glaube ich fixer als sha)
Wert in lokale Datei schreiben: file_put_contents
Mail schicken: Mail


Also ich würde die 3 urls in ein Array packen, das mit foreach durchgehen, mit file_get_contents die Seiten abholen und md5 drüberjagen, anschließend schauen ob es auf dem lokalen Server schpn eine Datei mit Hashes giebt (file_exists), wenn ja auslesen, dann md5 hashes mit file_put_contents reinschreiben, anschließend vergleichen und wenn ungleich mail ausführen mit der Url die nicht gestimmt hat. Kannst dich ja melden wenn du nicht weiterkommst mit deinem Quellcode am Besten.
Ergänzung ()

Btw, wenn jemand deinen Webserver übernimmt wird er einen Teufel tun da irgendwas zu ändern. Dass da was übernommen wurde merkst du 2 Wochen später wenn sich jemand bei dir beschwert, dass dein Server eine Spamschleuder ist oder eine DOS Attacke abgefeuert hat. Diese Defacement Checks machen echt nur Sinn bei Servern, die sinnvolle Ziele für Defacements sind, also Server mit politischen Inhalten oder Inhalten die jemand anderem gehörig auf den Senkel gehen, der das auch Kund tun will. In der Zeit wo du das Script zusammengehackt hast, hättest du auch ein oder zwei Sicherheitsseiten besuchen können und den Server wirklich sicherer machen können. So wartest du nur darauf, das jemand tut was du erwartest.
 
Wenn er die Seite defaced hat er sicher auch Zugang zu den Datenbanken.
Wäre es nicht klüger ein externes Programm die Hashes überwachen zu lassen ?
 
Zurück
Oben