Linux /tmp read-only nachträglich für Arme – ohne getrenntes Dateisystem

Temporär-Verzeichnisse wie /tmp oder /var/tmp auf Linux Rechnern read-only zu haben, kann einen vor den Folgen des einen oder anderen -meist automatischen- “Skriptkiddie” Angriffs schützen.

Im Rahmen einiger dieser Angriffe werden in einem für jedermann beschreibbaren Verzeichnis -also meist /tmp- ein Skript abgelegt, dass von dort ausgeführt wird, um weiteren Schaden zu verursachen.

Wenn dieses Verzeichnis nun mit der Option “noexec” gemounted ist, ist das Ausführen von Dateien dirkt aus dem Verzeichnis immerhin schwieriger. Unmöglich ist es jedoch nicht: Man könnte immer noch den notwendigen Befehlsinterpreter starten und das Skript als Parameter übergeben. Aber es geht hier einfach nur um eine weiter Hürde, die es für wenig Aufwand gibt und um automatische Angriffe, die ohne viel manuellen Zutun von nicht höchst fachlich fähigen Leuten ausgeführt werden.

Gut, ein Dateisystem kann man mit dem Parameter “-o noexec” mounten. – Was aber, wenn nun kein getrenntes Dateisystem für /tmp (und /var/tmp) bereit steht?

Hier lässt sich die Option “mount –bind” nutzen, um ein Verzeichnis in ein anderes zu mounten.

Vorbereitung. Kopien der Verzeichnisse /tmp und /var/tmp anfertigen. z.B. so:

cp -a /tmp /tmp-real
cp -a /var/temp /var/tmp-real

Dann lassen sich die “tmp-real” Verzeichnisse auf die “tmp” Verzeichnisse mounten:

mount -v --bind /tmp-real /tmp
mount -v -o remount,noexec,nosuid /tmp

Probe aufs Exempel:

$ ls -l /tmp
total 4
-rwxrwxr-x 1 testuser user 28 May 7 22:14 test.sh
$ cat /tmp/test.sh 
#! /bin/sh

echo Jaaaaaaaa

$ /tmp/test.sh
bash: /tmp/test.sh: Permission denied

Auch als root läßt es sich nicht ausführen:

~ # id
uid=0(root) gid=0(root) groups=0(root)
~ # /tmp/test.sh
-su: /tmp/test.sh: Permission denied

Jetzt noch alles zusammen: Ein Skript, um die Verzeichnisse read-only zu mounten:

~/bin # cat mount_tmp_noexec.sh
#!/bin/sh

echo noexec  to /tmp
mount -v --bind /tmp-real /tmp && mount -v -o remount,noexec,nosuid /tmp

echo
echo noexec to /var/tmp
mount -v --bind /var/tmp-real /var/tmp && mount -v -o remount,noexec,nosuid /var/tmp

echo 
echo Now mounted:
mount

…und eines das Ganze wieder rückgängig zu machen:

~/bin # cat mount_tmp_exec.sh 
#!/bin/sh

echo Umounting /tmp from noexec
# mount --bind /tmp-real /tmp && mount -o remount,exec,suid /tmp
umount /tmp

echo
echo Umounting /var/tmp from noexec
# mount --bind /var/tmp-real /var/tmp && mount -o remount,exec,suid /var/tmp
umount /var/tmp

echo 
echo Now mounted:
mount

Für das Einspielen von Paketen ist es zu empfehlen /tmp wieder read-write zu haben, da auch die Pakete vielfach Skripte zur Pre- oder Post-Installation dort ablegen und ausführen.

Beim Umounten kann es zu Problemen kommen, wenn Prozesse noch Dateien in dem Verzeichniss geöffnet lassen. Hier mit “lsof” o.ä. nachforschen.

Shell-Script: Welcher Tag ist der 6. Arbeitstag im Monat?

Letztens wollte ich in einem Shell-Script bestimmen ob der n-te Tag eines Monats ein Arbeitstag (Montag bis Freitag) ist…

Log geht’s mit “cal”:

$ cal -m
     April 2011
Mo Di Mi Do Fr Sa So
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

Die ersten beiden Zeilen müssen weg! Hier hilft uns awk weiter. Alle Records (sprich Zeilen) >2 ausgeben:

$ cal -m | awk 'NR>2'
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

Dann die beiden rechten Spalten, also die Samstage und Sonntage abschneiden. Auch ein job für awk. Nur die ersten 14 Zeichen…

$ cal -m | awk 'NR>2' | awk '{print substr($0,0,14)}'
             1
 4  5  6  7  8
11 12 13 14 15
18 19 20 21 22
25 26 27 28 29

Und jetzt zusammen:

$ cal -m | awk 'NR>2 {print substr($0,0,14)}'
             1
 4  5  6  7  8
11 12 13 14 15
18 19 20 21 22
25 26 27 28 29

Jetzt sind schon mal nur alle Arbeitstage (Mon – Fr) übrig. – Wär’ noch schick das alles in einer Zeile zu haben. Also weg mit den Zeilenumbrüchen. Ein Job für tr (=translate):

$ cal -m | awk 'NR>2' | awk '{print substr($0,0,14)}' | tr "\n" " "
             1  4  5  6  7  8 11 12 13 14 15 18 19 20 21 22 25 26 27 28 29

Jetzt müssen wir nur noch die n-te (also z.B. 6.) Spalte ausgeben. Noch ein job für awk:

$ cal -m | awk 'NR>2' | awk '{print substr($0,0,14)}' | tr "\n" " " | awk '{printf $6}'
8

Also ist der 6. Arbeitstag im April 2011 der 8.4.2011. – Stimmt’s?! 😉

Immer der Stress mit den signierten PGP Keys… – Automagisch neue Signaturen auf PGP Servern veröffentlichen.

Jetzt habe ich soweit alle Leute der letzten PGP Signing Party mit
meinen Signaturen versorgt. – Puh, dank caff aber machbar!

…jetzt bekomme ich aber natürlich auch alle meine PGP IDs (eMail-Adressen…)
unterschrieben von den anderen zugeschickt. Dank caff pro ID eine eMail
von jedem Unterzeichner! – Also z.B. bei meinen 5 IDs und 51 Leuten, die an der
PGP Signing Party teilgenommen haben etwa 250 eMails!!

Jetzt müsste ich um die Signatur in meinen Key zu importieren von jeder
eMail den Anhang entschlüsseln und in eine Datei speichern. – Also
müsste ich den Speichern-Dialog (mit y-Eingabe oder OK-Klicken…) 250
Mal durchlaufen!

Irgendwie habe ich bei den eMail Programmen wie alpine, Evolution und KMail keine
Möglichkeit gefunden von markierten/ ausgewählten eMails die Anhänge in
Dateien zu speichern… :-/ – Wenn jemand weiß, wie das doch geht bitte
ich um Info. 😉

…aber ich habe einen Workaround gebaut:
– Alle “Your signed PGP key…” eMails in einer (MBOX) Datei speichern
(Ich weiß, dass es mit alpine, Evolution, KMail und mutt geht)
– …und einfach das folgende bash-Script “unpack_pgp-sigs.sh” drüber
laufen lassen:
— 8< —

#! /bin/bash

# David Huecking <d.huecking@gmx.net>, 2010-08-31
#
# Quick'n'dirty hack to unpack GPG signatures from eMails stored in mbox
# files.

counter=0
pastepgp=0
pastekey=0

# Loop over mbox file

while read line; do

# If line is
# -----BEGIN PGP MESSAGE-----
# start pasting into a new file
# msg<counter>.pgp
# until and including line
# -----END PGP MESSAGE-----

if [ "$line" == "-----BEGIN PGP MESSAGE-----" ]; then
pastepgp=1
fi

if [ $pastepgp -eq 1 ]; then
echo $line >> msg$counter.pgp
fi

if [ "$line" == "-----END PGP MESSAGE-----" ]; then
pastepgp=0

# Decrypt new msg<counter>.pgp file to
# msg<counter>
gpg msg$counter.pgp

# Extract from msg<counter> the PGP signature
# beginning and including line
# -----BEGIN PGP PUBLIC KEY BLOCK-----
# until and including line
# -----END PGP PUBLIC KEY BLOCK-----
# into new file sig<counter>.asc
while read msgline; do
if [ "$msgline" == "-----BEGIN PGP PUBLIC KEY BLOCK-----" ]; then
pastekey=1
fi

if [ $pastekey -eq 1 ]; then
echo $msgline >> sig$counter.asc
fi

if [ "$msgline" == "-----END PGP PUBLIC KEY BLOCK-----" ]; then
pastekey=0
fi

done < msg$counter

let counter+=1
fi

done < $1

— 8< —

Wenn jetzt noch ein GPG-Agent im Hintergrund läuft, wird man nur einmal
nach seinem GPG-Mantra gefragt und nach ein wenig Rödeln hat man die
PGP-Signaturen in Dateien “sig0.asc” bis “sig<n>.asc” liegen…

Diese kann man dann mit

for f in `ls *.asc`; do gpg --import $f; done

importieren und dann den Key wiederum mit

gpg --send-key

zum PGP-Server hochladen!