PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : SSH-Befehle gemäss Liste regulärer Ausdrücke erlauben (Restricted Shell im Eigenbau)



testian
29.04.14, 23:51
Wie der Titel schon sagt möchte ich Usern erlauben beliebige shell-Befehle auszuführen, sofern diese vorgegeben regulären Ausdrücken entsprechen. Das ist die Spezifikation.

Die Lösung habe ich bereits geschrieben, aber da ich das Gefühl habe sicherheitstechnisch gesehen etwas heikles zu machen, erhoffe ich mir etwas Feedback. Für den folgenden Fall soll angenommen werden, dass sowohl der öffentliche als auch der private Schlüssel von someuser@somehost öffentlich ist, also dem potenziellen Angreifer bekannt ist.

Zunächst habe ich folgendes gemacht:

Für sshd_config ist von defaults auszugehen (z.B. für AcceptEnv)

Eintrag in ~/.ssh/authorized_keys


command="./restrict test",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa ... someuser@somehost


Dieser Eintrag erzwingt für den Inhaber des "privaten" Schlüssels someuser@somehost den Befehl "./restrict" mit dem Parameter "test". Der Parameter "test" soll der Name einer Art Berechtigungsgruppe oder Rolle sein wie man später sieht. Weitere builtin-Funktionen von SSH (diverse Forwarding-Dienste) sollen abgeschaltet werden.

Die Datei ~/restrict hat folgenden Inhalt und ist ausführbar:


#!/bin/bash
set -e
cd -- "$(dirname -- "$0")"
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <group>" >&2
exit 1
fi
GROUP="$1"
set +e
grep -E -f <(grep -vE '^\s*$' "restrict-groups/$GROUP") <<< "$SSH_ORIGINAL_COMMAND" > /dev/null
EXITCODE=$?
if [[ EXITCODE -ne 0 ]]; then
echo "No permission to execute: $SSH_ORIGINAL_COMMAND" >&2
exit $EXITCODE
fi
bash -c "$SSH_ORIGINAL_COMMAND"


Neben dieser Datei gibt es ein Verzeichnis ~/restrict-groups
Im Verzeichnis ~/restrict-groups gibt es für jede Berechtigsungsgruppe eine Datei mit dem Namen derselben. Diese Datei enthält eine Liste von regulären Ausdrücken.
Entspricht ein SSH mitgegebener Befehl einem der regulären Ausdrücke, dann soll der Befehl ausgeführt werden. Dies wird mit grep -E geprüft. Es kann davon ausgegangen werden, dass die Liste sorgfältig erstellt wurde. Hinweise auf Falltüren sind aber trotzdem willkommen.

Aktuell ist folgendes in der Datei ~/restricted-groups/test zu finden:


^echo fish$
^cat$


Was sagt ihr? Ist das sicher? Gibt es potenzielle Flaws? Erfinde ich das Rad neu?

Meine ersten Sorgen bisher sind, ob das auslesen des EXITCODEs nach "grep -E -f <(grep -vE '^\s*$' "restrict-groups/$GROUP") <<< "$SSH_ORIGINAL_COMMAND" > /dev/null" tatsächlich den Exit-Code des ersten grep erfasst. Ich mag mich erinnern, dass das bei Verwendung der Pipe nicht ganz so einfach ist. Wie ist es in diesem Fall?

Ein weiteres Problem besteht vielleicht dann, wenn die Datei "test" unvollständig kopiert oder während dem Speichervorgang ausgelesen wird und eine Zeile dann dadurch zuviel matcht, weil z.B. kein Match mit dem Zeilenende "$" verlangt wird. Wie sollte ich das auffangen?

Edit: Die entfernte Ausführung gelingt dann nicht interaktiv, sondern einfach so:


ssh exec@remotehost "echo fish"

DrunkenFreak
30.04.14, 11:18
Guck dir mal lshell an. Das sollte ein bisschen einfacher gehen.

testian
01.05.14, 15:44
Kann man lshell nicht-interaktiv verwenden? "bash -r" erweist mir sonst nämlich auch gute Dienste, z.B. wie folgt:



#!/bin/bash
set -e
cd -- "$(dirname -- "$0")"
export PATH="$PWD/bash_restrict_bin"
cd bash_restrict_working
/bin/bash -r -c "$SSH_ORIGINAL_COMMAND"


Habe noch eine kleine Anpassung gemacht: Ich matche immer den ganzen Befehl statt die Expressions mit ^$ zu definieren. Das ist sowieso immer Erfordernis, um beliebige Ausführung zu verhindern. Dafür muss ich leere Zeilen nicht filtern, weil leere Befehle ungefährtlich sind.



#!/bin/bash
set -e
cd -- "$(dirname -- "$0")"
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <group>" >&2
exit 1
fi
GROUP="$1"
set +e
grep -xE -f "restrict-groups/$GROUP" <<< "$SSH_ORIGINAL_COMMAND" > /dev/null
EXITCODE=$?
if [[ EXITCODE -ne 0 ]]; then
echo "No permission to execute: $SSH_ORIGINAL_COMMAND" >&2
exit $EXITCODE
fi
bash -c "$SSH_ORIGINAL_COMMAND"