Chapter 21. Tool: Validating Configuration

As a system administrator or security practitioner, it is useful to have a tool that allows you to verify the current configuration of a system, such as files that exist, registry values, or user accounts. In addition to verifying a configuration, this technique can be used as a lightweight host intrusion-detection system by recording a baseline configuration and then monitoring for variations from that baseline. You can also use it to look for specific indicators of compromise.

In this chapter, we develop a tool to read in a text file that consists of a series of configurations to validate, such as the existence of a file or user, and verify that the condition exists on the system. This tool is targeted at the Windows operating system but could easily be modified to support Linux.

Implementation

The validateconfig.sh tool validates the following:

  • The existence or nonexistence of a file

  • The SHA-1 hash of a file

  • A Windows Registry value

  • The existence or nonexistence of a user or group

Table 21-1 shows the syntax for the configuration file the script will read.

Table 21-1. Validation file format
Purpose Format

Existence of a file

file <_file path_>

Nonexistence of a file

!file <_file path_>

File hash

hash <_sha1 hash_> <_file path_>

Registry key value

reg "<_key path_>" "<_value_>" "<_expected_>"

Existence of a user

user <_user id_>

Nonexistence of a user

!user <_user id_>

Existence of a group

group <_group id_>

Nonexistence of a group

!group <_group id_>

Example 21-1 shows a sample configuration file.

Example 21-1. validconfig.txt
user jsmith
file "c:windowssystem32calc.exe"
!file "c:windowssystem32ad.exe"

The script in Example 21-2 reads in a previously created configuration file and confirms that the configuration exists on the system.

Example 21-2. validateconfig.sh
#!/bin/bash -
#
# Cybersecurity Ops with bash
# validateconfig.sh
#
# Description:
# Validate a specified configuration exists
#
# Usage:
# validateconfig.sh < configfile
#
# configuration specification looks like:
# [[!]file|hash|reg|[!]user|[!]group] [args]
# examples:
# file /usr/local/bin/sfx 		- file exists
# hash 12384970347 /usr/local/bin/sfx   - file has this hash
# !user bono				- no user "bono" allowed
# group students			- must have a students group
#
# errexit - show correct usage and exit
function errexit ()
{
    echo "invalid syntax at line $ln"
    echo "usage: [!]file|hash|reg|[!]user|[!]group [args]"    1
    exit 2

} # errexit

# vfile - vaildate the [non]existance of filename
#	args: 1: the "not" flag - value:1/0
#             2: filename
#
function vfile ()
{
    local isThere=0
    [[ -e $2 ]] && isThere=1                    2
    (( $1 )) && let isThere=1-$isThere          3

    return $isThere

} # vfile

# verify the user id
function vuser ()
{
    local isUser
    $UCMD $2 &>/dev/null
    isUser=$?
    if (( $1 ))                                 4
    then
        let isUser=1-$isUser
    fi

    return $isUser

} # vuser

# verify the group id
function vgroup ()
{
    local isGroup
    id $2 &>/dev/null
    isGroup=$?
    if (( $1 ))
    then
        let isGroup=1-$isGroup
    fi

    return $isGroup

} # vgroup

# verify the hash on the file
function vhash ()
{
    local res=0
    local X=$(sha1sum $2)                       5
    if [[ ${X%% *} == $1 ]]                     6
    then
        res=1
    fi

    return $res

} # vhash

# a windows system registry check
function vreg ()
{
    local res=0
    local keypath=$1
    local value=$2
    local expected=$3
    local REGVAL=$(query $keypath //v $value)

    if [[ $REGVAL == $expected ]]
    then
        res=1
    fi
    return $res

} # vreg

#
# main
#

# do this once, for use in verifying user ids
UCMD="net user"
type -t net &>/dev/null  || UCMD="id"           7

ln=0
while read cmd args
do
    let ln++

    donot=0
    if [[ ${cmd:0:1} == '!' ]]                  8
    then
        donot=1
	basecmd=${cmd#!}                       9
    fi

    case "$basecmd" in
    file)
        OK=1
        vfile $donot "$args"
        res=$?
        ;;
    hash)
        OK=1
	# split args into 1st word , remainder
        vhash "${args%% *}" "${args#* }"        10
        res=$?
        ;;
    reg)
        # Windows Only!
        OK=1
        vreg $args
        res=$?
        ;;
    user)
        OK=0
        vuser $args
        res=$?
        ;;
    group)
        OK=0
        vgroup $args
        res=$?
        ;;
    *)  errexit					11
        ;;
    esac

    if (( res != OK ))
    then
        echo "FAIL: [$ln] $cmd $args"
    fi
done
1

The errexit function is a handy helper function to have, to give the user some helpful information on the correct use of the script—and then exiting with an error value. The syntax used in the usage message is typical *nix syntax: items separated by a vertical bar are choices; items inside square brackets are optional.

2

This uses the if-less f statement to check on the file’s existence.

3

This is a simple way to toggle a 1 to a 0, or a 0 to a 1, conditional on the first argument being nonzero.

4

This uses the more readable, but bulkier, if statement to do the toggle.

5

Running the sha1sum command, the output will be saved in the X variable. The output consists of two “words”: the hash value and the filename.

6

To check whether the hash values match, we need to remove the filename, the second word, from the output of the sha1sum command. The %% indicates the longest match possible, and the pattern specifies starting with a blank and then any characters (*).

7

The type command will tell us whether the net command exists; if it fails to find it, then we’ll use the id command instead.

8

Reminder: This takes a substring of cmd beginning at position 0 and taking only one character; i.e., it’s the first character of cmd. Is it an exclamation mark (aka bang)? That is often used in programming to mean “not.”

9

We need to take off the bang from the command name.

10

As the comment says, it splits the args in two—taking the first word and then the remainder, as it calls our vhash function.

11

The case statement in bash allows for pattern matching in the separate cases. A common pattern is the asterisk to match any string, placed as the last case, to act as a default. If no other pattern was matched, this one will match and will be executed. Since the input didn’t match any supported choice, it must be bad input, so we call errexit to fail out.

Summary

The validateconfig.sh tool enables you to verify that a specific configuration exists on a system. This is useful for compliance checks and can also be used to identify the existence of malware or an intrusion by looking for specific indicators of compromise.

Tip

YARA is a great source for host-based indicators of compromise. To learn more, visit the YARA website.

In the next chapter, we look at auditing user accounts and credentials to determine whether they have been involved in a known compromise.

Workshop

Try expanding and customizing the features of validateconfig.sh by adding the following functionality:

  1. Check whether a specific file permission exists.

  2. Check whether a particular network port is open or closed.

  3. Check whether a particular process is running.

  4. Support comments in the input stream. If the first character of a line read is a hashtag, discard the line (i.e., nothing to process).

Visit the Cybersecurity Ops website for additional resources and the answers to these questions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset