Under Construction

Aixpert Skript zu Einstellungen von SSHD

In dem bisher gezeigten Beispiel kann nur das Attribut PermitRootLogin auf „yes“ gesetzt werden und bei einem Undo zurück auf „no“. Es gibt neben PermitRootLogin eine ganze Reihe weitere sicherheitsrelevante Attribute, wie Ciphers, DisableForwarding oder PermitEmptyPasswords. Anstelle für jedes dieser Attribute ein eigenes Skript in Anlehnung des weiter oben entwickelten Skripts zu schreiben, bietet es sich an, das bisherige Skript anzupassen und beliebige Attribute und Werte zu unterstützen. Dazu müssen Attribut und gewünschter Wert als Argumente übergeben werden können, wie z.B. beim Standard-Skript chusrattr. Das bisher einzige Argument, der Regelname, sollte wie bei chusrattr optional sein. Ist das Argument vorhanden, soll ein Undo-Eintrag erzeugt werden, ist das Argument nicht vorhanden, wird kein Undo-Eintrag erzeugt.

Zunächst ändern wir die Beschreibung des Skripts local_chsshdconf wie folgt ab:

#   Command Line Arguments  : This script expects one or two command line arguments.
#                           The first argument should be of the form
#                           'Attr=value', where 'Attr' is a valid keyword for sshd_config
#                           and 'value' is the value to set or to check for.
#                           The second argument is optional and if provided,
#                           indicates that the undo xml rule has to be
#                           generated.
#                           Syntac - local_chsshdconf Attr=value [rulename]
#
#   OUTPUT                  : None
#
#   Description             : This script changes the attribute 'Attr' to
#                           the value 'value' in /etc/ssh/sshd_config.
#                           It dynamically generates an undo XML rule with
#                           shortname as "Undo$2_<timestamp>" if the second
#                           argument is provided.
#                           This script should be run with superuser privileges.

Als Pfad-Präfix für temporäre Dateien verwenden wir nun /etc/security/aixpert/tmp/local_chsshdconf (Variable TMP):

# Initialize variables AIXPERT_FIFO, LOG, REPORT, SCPTDIR and UNDOXML
. /etc/security/aixpert/bin/initialize_variables

TMP=/etc/security/aixpert/tmp/local_chsshdconf
PID=$$

Die Überprüfung auf die korrekte Anzahl von Argumenten muss ebenfalls abgeändert werden. Das Skript muss mit einem oder zwei Argumenten aufgerufen werden:

if [ $# -lt 1 ] || [ $# -gt 2 ]
then
    echo "Usage : local_chsshdconf Attr=value [rulename]\n"
    exit 1
fi

Das zu setzende oder zu überprüfende Attribut wird zusammen mit dem Wert als ein Argument der Form „Attr=value“ übergeben. Das Argument muss in den Attributnamen und den Wert aufgeteilt werden:

# Determine the user attribute that has to be changed.
sshdattr=`echo $1 | awk -F "=" '{print $1; if(NF != 2) exit 1}'`

if [ $? -ne 0 ] || [ "$sshdattr" = "" ]
then
    dspmsg -s 4 aixpert.cat 1 "Usage : local_chsshdconf Attr=value [Rulename]\n"
exit 1
fi

# Determine the value that is being assigned to the $sshdattr
value=`echo $1 | awk -F "=" '{print $2}'`

Der Attributname wird in der Variablen sshdattr gespeichert und der Wert in der Variablen value.

Für die Überprüfung von Attributen schreiben wir eine kleine Funktion, die wir am Anfang des Skripts plazieren. Die Funktion gibt mittels „sshd -T“ die effektive Konfiguration aus, sucht die Zeile mit dem gewünschten Attribut und liefert den zugehörigen Wert zurück.

function getEffectiveSshdValue
{
    typeset -l keyword="$1" # translate to lower case
    typeset key
    typeset value="invalid"

    sshd -T | grep -w "$keyword" | read key value
    print "$value"
}

Mit Hilfe dieser Funktion lässt sich dann die Überprüfung eines Attributs umschreiben. Den bisherigen Check:

    defvalue=`awk '$1 ~ /^PermitRootLogin$/ { print $2; }' /etc/ssh/sshd_config 2>/dev/null | tail -n 1`
   case "$defvalue" in
    [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]) ret=0 ;;
    esac

schreiben wir dann wie folgt um:

   defvalue=`getEffectiveSshdValue "$sshdattr"`
  [ "$defvalue" = "$value" ] && ret=0

Die Meldungen falls die Überprüfung nicht erfolgreich ist (gesetzter Wert weicht vom Soll-Wert ab), müssen ebenfalls etwas angepasst werden:

   if [ $ret = 1 ]
    then
        if [ "$BrType" = "1" ]
        then
            echo "Base Compliance Report\n";
            printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr
$value $defvalue >>$TMPREPT
        elif [ "$DrType" = "1" ]
        then
            echo "Description Report\n";
            printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr
$value $defvalue >>$TMPREPT
        else
            printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr
$value $defvalue >>$REPORT
            printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr
$value $defvalue >>$AIXPERT_FIFO
        fi
    fi

Um einen Test-Lauf für die geänderte Überprüfung zu starten, muss noch die XML-Datei custom/sshd.xml angepasst werden:

/etc/security/aixpert # cat custom/sshd.xml
<?xml version="1.0" encoding="UTF-8"?>
<AIXPertSecurityHardening>
  <AIXPertEntry name="test_permitrootlogin" function="permitrootlogin">
    <AIXPertRuleType type="TEST"/>
    <AIXPertDescription>Ensure that PermitRootLogin is False.</AIXPertDescription>
    <AIXPertPrereqList>openssh.base.server</AIXPertPrereqList>
    <AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>
    <AIXPertArgs>PermitRootLogin=no test_permitrootlogin</AIXPertArgs>
   <AIXPertGroup>SSHD policy rules</AIXPertGroup>
  </AIXPertEntry>

</AIXPertSecurityHardening>
/etc/security/aixpert #

Der Wert von PermitRootLogin ist aktuell:

# grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
#

Eine Überprüfung sollte damit nicht erfolgreich sein:

# aixpert -c -P custom/sshd.xml
Processedrules=1        Passedrules=0   Failedrules=1   Level=TEST
        Input file=custom/sshd.xml
#

Wie erwartet schlägt die Überprüfung fehl (Failedrules=1). Wir ändern den Wert von PermitRootLogin auf „no“ und starten eine weitere Überprüfung:

# aixpert -c -P custom/sshd.xml
Processedrules=1        Passedrules=1   Failedrules=0   Level=TEST
        Input file=custom/sshd.xml
#

Jetzt ist die Überprüfung erfolgreich. Damit erlaubt das modifizierte Skript schon mal die Überprüfung von beliebigen Attributen des sshd.

Als nächstes implementieren wir das Setzen von beliebigen Attributen in /etc/ssh/sshd_config. Auch hier verwenden wir eine Funktion, die wieder am Anfang des Skripts stehen soll:

function setSshdValue
{
    typeset -l keyToChange="$1"
    typeset newValue="$2"
    typeset -l lowerCaseKey

    changed=false
    while read -r line
    do
       print "$line" | read -r key value rest
       lowerCaseKey="$key"
       case "$lowerCaseKey" in
       $keyToChange)
           print "$key $newValue"
            changed=true
            ;;
       *) print "$line" ;;
        esac
    done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
   ${change} || print "$key $newValue" >>/etc/ssh/sshd_config.new
    cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
    rm -f /etc/ssh/sshd_config.new
}

Mittels einer while-Schleife wird Zeile für Zeile nach dem zu ändernden Attributnamen gesucht. Wird dieser gefunden, werden Name und neuer Wert ausgegeben. Ansonsten werden die Zeilen unverändert ausgegeben. Wurde das Attribut nicht gefunden, wird am Ende Name und neuer Wert ausgegeben. Alle Ausgaben werden in eine Zwischendatei (/etc/ssh/sshd_config.new) umgeleitet.

Die bisherigen Zeilen für das Setzen von PermitRootLogin (im Skript nach der Überprüfung), können dann entfernt und durch den folgenden Aufruf der obigen Funktion ersetzt werden:

setSshdValue "$sshdattr" "$value"

Bevor wir einen Test-Lauf der neuen Skript-Version machen, setzen wir PermitRootLogin auf „yes“ und entfernen alle aktiven Regeln:

/etc/security/aixpert # aixpert -u
/etc/security/aixpert # aixpert -u
There are no security rules to undo in file /etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert # rm check_report.txt core/appliedaixpert.* core/undo.xml log/* tmp/* undo/*
rm: check_report.txt: No such file or directory
rm: cannot remove directory undo/data
/etc/security/aixpert # grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
/etc/security/aixpert #

Wir wenden jetzt die Regel für das Setzen von PermitRootLogin erneut an:

/etc/security/aixpert # aixpert -f custom/sshd.xml
Processedrules=1        Passedrules=1   PrereqFailedrules=0     Failedrules=0   Level=TEST
        Input file=custom/sshd.xml
/etc/security/aixpert #

Laut Ausgabe wurde die Regel erfolgreich abgearbeitet (Passedrules=1). Eine kurze Überprüfung mit „aixpert -c“ und grep zeigt das PermitRootLogin auf „no“ gesetzt wurde:

# aixpert -c
Processedrules=1        Passedrules=1   Failedrules=0   Level=TEST
        Input file=/etc/security/aixpert/core/appliedaixpert.xml
# grep ^PermitRo /etc/ssh/sshd_config
PermitRootLogin no
#

Als letztes muss noch die Undo-Funktionalität angepasst werden. Für einen Undo muss das Skript lediglich mit dem Attributnamen und dem ursprünglichen Wert des Attributs aufgerufen werden. Ein Regelname darf in diesem Falle nicht angegeben werden, da beim Undo kein neuer Undo-Eintrag in /etc/security/aixpert/core/undo.xml gemacht werden soll.

Wir überprüfen ob das Skript mit 2 Argumenten, also mit Regelname, aufgerufen wurde. Ist das der Fall, wird der aktuelle Wert des Attributs ermittelt und in der Variablen defvalue abgespeichert. Außerdem wird dann die Variable undo gesetzt.

# This script generates Undo rule if the number of arguments is 2,
# otherwise it works as undo script.
if [ $# -eq 2 ]
then
    # Determine the current value of $sshdattr from the effective configuration
    defvalue=`getEffectiveSshdValue "$sshdattr"`

    # Generate a dynamic undo rule
    undo=1
fi

Das Skript muss nun kein Undo-Skript mehr erzeugen, da das Skript selbst für den Undo aufgerufen werden kann. Die entsprechenden Zeilen im Skript zum Erzeugen des Undo-Skripts entfallen damit.

Der Undo-Eintrag in der XML-Datei /etc/security/aixpert/core/undo.xml muss aber weiterhin vorgenommen werden. Allerdings wird jetzt als AIXPertCommand das Skript selbst hinterlegt und als Argument (AIXPertArgs) wird der Attributname zusammen mit dem ursprünglichen Wert ($defvalue) angegeben:

   # Add an undo XML rule to the file $UNDOXML
    awk -v rulepart1="\t<AIXPertEntry name=\"$name\">\n\
\t\t<AIXPertRuleType type=\"Undo\"/>\n"\
-v rulepart2="\t\t<AIXPertDescription ${desc_catmsginfo}>$undomsg \"$desc\"</AIXPertDes
cription>\n\
\t\t<AIXPertPrereqList/>\n"\
-v rulepart3="\t\t<AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCo
mmand>\n\
\t\t<AIXPertArgs>$sshdattr=$defvalue</AIXPertArgs>\n\
\t\t<AIXPertGroup>SSHD policy rules</AIXPertGroup>\n\
\t</AIXPertEntry>" '{if(match($0,"^[\t ]*</AIXPertUndo>")==0) print $0;
else print rulepart1 rulepart2 rulepart3 "\n" $0}' $UNDOXML >$TMP$PID

Insgesamt ergibt sich dann die folgende Version des Skripts:

/etc/security/aixpert # cat bin/local_chsshdconf
#! /bin/ksh
#
# Copyright (c) 2022 by PowerCampus 01 GmbH
#
# Anyone is free to copy, publish, use, or distribute this software,
# for any purpose, commercial or non-commercial, and by any means,
# as long as this copyright notice is kept.
# Modification of this software is allowed, as long as this copyright
# notice is kept, and a notice is placed in the software that indicates
# that the software has been modified. It is not allowed to sell this
# software without the written permission of PowerCampus 01.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
#
# Command Line Arguments  : This script expects one or two command line arguments.
#                           The first argument should be of the form
#                           'Attr=value', where 'Attr' is a valid keyword for sshd_config
#                           and 'value' is the value to set or to check for.
#                           The second argument is optional and if provided,
#                           indicates that the undo xml rule has to be
#                           generated.
#                           Syntax - local_chsshdconf Attr=value [rulename]
#
# OUTPUT                  : None
#
# Description             : This script changes the attribute 'Attr' to
#                           the value 'value' in /etc/ssh/sshd_config.
#                           It dynamically generates an undo XML rule with
#                           shortname as "Undo$2_<timestamp>" if the second
#                           argument is provided.
#                           This script should be run with superuser privileges.
#

function getEffectiveSshdValue
{
        typeset -l keyword="$1"
        typeset key
        typeset value="invalid"

        sshd -T | grep -w "$keyword" | read key value
        print "$value"
}

function setSshdValue
{
        typeset -l keyToChange="$1"
        typeset newValue="$2"
        typeset -l lowerCaseKey

        changed=false
        while read -r line
        do
               print "$line" | read -r key value rest
               lowerCaseKey="$key"
               case "$lowerCaseKey" in
               $keyToChange)
                       print "$key $newValue"
                        changed=true
                        ;;
               *) print "$line" ;;
                esac
        done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
       ${change} || print "$key $newValue" >>/etc/ssh/sshd_config.new
        cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
        rm -f /etc/ssh/sshd_config.new
}

export PATH=/usr/bin:/usr/sbin:$PATH

# Initialize variables AIXPERT_FIFO, LOG, REPORT, SCPTDIR and UNDOXML
. /etc/security/aixpert/bin/initialize_variables

TMP=/etc/security/aixpert/tmp/local_chsshdconf
PID=$$

# Log output and errors to /etc/security/aixpert/log/aixpert.log
exec 1>>$LOG
exec 2>&1

# echo all the commands and the current time and date to the AIXpert log
set -x
date
echo $0 $@ AIXPERT_CHECK_REPORT=$AIXPERT_CHECK_REPORT BASE_REPT=$BASE_REPT DETAILED_REPT=$DETAILED_REPT

if [ $# -lt 1 ] || [ $# -gt 2 ]
then
    echo "Usage : local_chsshdconf Attr=value [rulename]\n"
    exit 1
fi

# A value of 0 indicates that Undo rule need not be created.
# This variable will be set later in the script if there is anything to be undone
undo=0

# Check whether AIXPERT_CHECK_REPORT environment variable is set or not.
report=`echo $AIXPERT_CHECK_REPORT`
BrType=`echo $BASE_REPT`
DrType=`echo $DETAILED_REPT`

# Determine the user attribute that has to be changed.
sshdattr=`echo $1 | awk -F "=" '{print $1; if(NF != 2) exit 1}'`

if [ $? -ne 0 ] || [ "$sshdattr" = "" ]
then
        dspmsg -s 4 aixpert.cat 1 "Usage : local_chsshdconf Attr=value [Rulename]\n"
exit 1
fi

# Determine the value that is being assigned to the $sshdattr
value=`echo $1 | awk -F "=" '{print $2}'`

# This script generates Undo rule if the number of arguments is 2,
# otherwise it works as undo script.
if [ $# -eq 2 ]
then
        # Determine the current value of $sshdattr from the effective configuration
        defvalue=`getEffectiveSshdValue "$sshdattr"`
        if [ "$report" = "1" ]
        then
                ret=1

                [ "$defvalue" = "$value" ] && ret=0

                if [ $ret = 1 ]
                then
                        if [ "$BrType" = "1" ]
                        then
                                echo "Base Compliance Report\n";
                                printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr $value $defvalue >>$TMPREPT
                        elif [ "$DrType" = "1" ]
                        then
                                echo "Description Report\n";
                                printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr $value $defvalue >>$TMPREPT
                        else
                                printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr $value $defvalue >>$REPORT
                                printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr $value $defvalue >>$AIXPERT_FIFO
                        fi
                fi

                exit $ret
        fi
        # Generate a dynamic undo rule
        undo=1
fi

setSshdValue "$sshdattr" "$value"

if [ $undo -eq 1 ]
then
        # Check if UNDOXML file has <AIXPertUndo> tag or not
        empty=`grep "^<AIXPertUndo>" $UNDOXML`
        if [ "$empty" = "" ]
        then
                echo "\n<AIXPertUndo>\n</AIXPertUndo>" >> $UNDOXML
        fi

        # Get the rulename and put it in undo rule
        name=`echo $AIXPERT_NAME`
        # Get the rule description & pass it to undo rule
        desc=`echo $AIXPERT_DESC`
        desc_catmsginfo=`echo $AIXPERT_DESC_CATMSGINFO`
        undomsg=`/usr/bin/dspmsg -s 49 aixpert.cat 1 "Undo action for: "`

        # Add an undo XML rule to the file $UNDOXML
        awk -v rulepart1="\t<AIXPertEntry name=\"$name\">\n\
\t\t<AIXPertRuleType type=\"Undo\"/>\n"\
-v rulepart2="\t\t<AIXPertDescription ${desc_catmsginfo}>$undomsg \"$desc\"</AIXPertDescription>\n\
\t\t<AIXPertPrereqList/>\n"\
-v rulepart3="\t\t<AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>\n\
\t\t<AIXPertArgs>$sshdattr=$defvalue</AIXPertArgs>\n\
\t\t<AIXPertGroup>SSHD policy rules</AIXPertGroup>\n\
\t</AIXPertEntry>" '{if(match($0,"^[\t ]*</AIXPertUndo>")==0) print $0;
else print rulepart1 rulepart2 rulepart3 "\n" $0}' $UNDOXML >$TMP$PID
        if [ $? -eq 0 ] ; then
                mv $TMP$PID $UNDOXML
        fi
fi

exit 0

/etc/security/aixpert #

Bevor wir einen erneuten Test-Lauf der finalen Skript-Version machen, setzen wir PermitRootLogin wieder auf „yes“ und entfernen alle aktiven Regeln:

/etc/security/aixpert # aixpert -u
/etc/security/aixpert # aixpert -u
There are no security rules to undo in file /etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert # rm check_report.txt core/appliedaixpert.* core/undo.xml log/* tmp/* undo/*
rm: check_report.txt: No such file or directory
rm: cannot remove directory undo/data
/etc/security/aixpert # grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
/etc/security/aixpert #

Wir wenden die Regel wieder auf unser System an:

/etc/security/aixpert # aixpert -f custom/sshd.xml
Processedrules=1        Passedrules=1   PrereqFailedrules=0     Failedrules=0   Level=TEST
        Input file=custom/sshd.xml
/etc/security/aixpert #

Wir schauen uns den Eintrag in der undo.xml an:

/etc/security/aixpert # cat /etc/security/aixpert/core/undo.xml
<AIXPertUndo>
        <AIXPertEntry name="test_permitrootlogin_DD8096ED">
                <AIXPertRuleType type="Undo"/>
                <AIXPertDescription catalog="" setNum="" msgNum="">Undo action for:  "Ensure that PermitRootLogin is False."</AIXPertDescription>
                <AIXPertPrereqList/>
                <AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>
                <AIXPertArgs>PermitRootLogin=yes</AIXPertArgs>
                <AIXPertGroup>SSHD policy rules</AIXPertGroup>
        </AIXPertEntry>
</AIXPertUndo>

/etc/security/aixpert #

Der Undo-Eintrag ruft das obige Skript auf und verwendet dazu das Argument „PermitRootLogin=yes“, also den ursprünglichen Wert von PermitRootLogin.

Als letztes überprüfen wir ob das Undo korrekt funktioniert:

# aixpert -u
#

Eine kurze Überprüfung zeigt das die Einträge aus appliedaixpert.xml und undo.xml entfernt wurden und der Wert von PermitRootLogin wieder „yes“ ist:

/etc/security/aixpert # cat core/appliedaixpert.xml
<?xml version="1.0"?>
<AIXPertSecurityHardening>
</AIXPertSecurityHardening>
/etc/security/aixpert # cat core/undo.xml
<AIXPertUndo>
</AIXPertUndo>
/etc/security/aixpert # grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
/etc/security/aixpert #