Wednesday, 18 January 2012

Passphrase generator in bash

[EDIT]

The script below has been improved upon and can be found here: http://blog.0x10.co.uk/2013/04/passphrase-generators-part-ii.html

Passwords are dead. Long live passphrases. Or something like that anyway. As perfectly summarized by XKCD here http://xkcd.com/936/, passwords are hard to remember and easy to guess. Passphrases on the other hand are easy to remember and hard to guess.
To help generate passphrases, I've put together a little bash script.
Firstly, download the dictionary containing 10000 most common English words. If you have a 4 word passphrase, thats 10^16 possible combinations.
$ wget http://wortschatz.uni-leipzig.de/Papers/top10000en.txt
Now save the following script:
 
#!/bin/bash

dict=$1
script=$2

chars="a-zA-Z0-9 "
size=$(cat $dict | wc -l)
echo "#!/bin/bash" > $script
( echo -n "dict=( "; i=0; cat $dict | while read word; do echo -n "$word " | tr -c -d "$chars"; if [ "$i" -eq "10" ]; then i=1; echo ""; fi; ((i++)); done; echo ")" ) >> $script

echo "size=$size" >> $script
echo 'count=${1:-10}
words=${2:-4}

for i in $(seq 1 $count); do
    first=1
    for j in $(seq 1 $words); do
        r=$RANDOM
        let "r %= $size"
        word=${dict[$r]}
        if [ "$first" == "0" ]; then
            echo -n " "
                fi
        echo -n "$word"
        first=0
    done
    echo ""
done
' >> $script
chmod +x $script
Using modulo on a random number? tut tut tut. Anyway, I've called this script make.sh.
Now run it, giving it the dictionary file and an output script name:
$ ./make.sh top10000en.txt ppgen.sh
What it basically does is embed an array of words into ppgen.sh plus the code necessary to show passphrases.
It will look something like:
#!/bin/bash
dict=( the of to and a in for is The that on 
said with be was by as are at from 
it has an have will or its he not 
were which this but can more his been would 
...
definite fragile rewards antiabortion respects careers backers seize inefficient 
conceptual densities EPS Me Sparc spirits experimentally shallow )
size=10000
count=${1:-10}
words=${2:-4}

for i in $(seq 1 $count); do
    first=1
    for j in $(seq 1 $words); do
        r=$RANDOM
        let "r %= $size"
        word=${dict[$r]}
        if [ "$first" == "0" ]; then
            echo -n " "
                fi
        echo -n "$word"
        first=0
    done
    echo ""
done
We can now run it:
$ ./ppgen.sh 
Does Brazil quotas message
amount losers sing Oregon
patient misleading rebels smoking
refuse subordinated clerk wrote
have handle Rockwell strong
Committee Insurance consumer else
tariffs Unit mouth loved
V singled graduate kidney
uranium Hungary scientists Mar
fined Hercules Kemp Indian
Or, if we wanted to create just one 5 word phrase:
$ ./ppgen.sh 1 5
Commodity dioxide Boris unit drop

Thursday, 12 January 2012

Visualising rules from Firewall Builder - Part 1

Firewall Builder (available here http://www.fwbuilder.org/) is a GUI that lets you configure a variety of firewall devices, for example iptables on a linux box or Cisco ASAs.

The idea is to take the configuration file from Firewall Builder and generate some sort of rule visualisation. The ruleset I'm using is basically just the built-in template called "fw template 3". I then saved the ruleset as testfw.fwb.

So, lets process the file:

user@host:~/fwbvis$ ./fwbvis.py testfw.fwb ignoreme testfw.dot
user@host:~/fwbvis$ 

Where the arguments are as follows:

  • fwbvis.py - the script (below)
  • testfw.fwb - the firewall config saved by Firewall Builder
  • ignoreme - to be ignored for now. It will become a configuration file for colours etc.
  • testfw.dot - the output file. We just generate a png at the moment, in this case called testfw.dot.png

Here is the result:

It isn't perfect, but it is a pretty good start. The colours are as follows:

  • red - reject
  • orange - deny
  • green - accept
  • blue - anything else

So, here is the script so far. It's pretty ugly btw...

#!/usr/bin/python

import sys
import pydot
from xml.etree.ElementTree import ElementTree

sFWFile = sys.argv[1];
sConfigFile = sys.argv[2];
sOutputFile = sys.argv[3];

try:
    ds = open(sFWFile)
except:
    print "Could not open file", sFWFile
    sys.exit(1)

try:
    tree = ElementTree()
    tree.parse(sFWFile)
except:
    print "Could not parse file", sFWFile
    sys.exit(1)

graph = pydot.Dot(graph_type='digraph')

prefix = ""
rules = []
objects = {}
for element in tree.iter():
    tag = element.tag
    if tag[0] == "{":
        uri,tag = tag[1:].split("}")
        if prefix == "":
            prefix = uri
    oid = element.get('id')
    if oid is None:
        next
    objects[oid] = {'tag': tag }
    for (key,value) in element.items():
        if key != 'id':
            objects[oid][key] = value

for rule in tree.findall('.//{%s}PolicyRule' % prefix):
    oid = rule.get('id')
    action = objects[oid]['action']
    color = "black"
    if action == "Reject":
        color = "red"
    elif action == "Deny":
        color = "orange"
    elif action == "Accept":
        color = "green"
    else:
        color = "blue"

    src = rule.find('.//{%s}Src' % prefix).find('.//{%s}ObjectRef' % prefix).get("ref")
    if src in objects:
        src = objects[src]['name']
    dst = rule.find('.//{%s}Dst' % prefix).find('.//{%s}ObjectRef' % prefix).get("ref")
    if dst in objects:
        dst = objects[dst]['name']
    srv = rule.find('.//{%s}Srv' % prefix).find('.//{%s}ServiceRef' % prefix).get("ref")
    if srv in objects:
        srv = objects[srv]['name']
    else:
        srv = "unknown"
    graph.add_edge(pydot.Edge(src, dst, label=srv, color=color))

#graph.write(sOutputFile)
graph.write_png(sOutputFile+".png")

So, there you have it. More to follow as things improve.

Sunday, 1 January 2012

Some bash array functions

Following on from the previous post, here are some functions for bash arrays. I'll add to this post later with more functions.
Test if a variable is an array:
# is_array - Tests whether variable name is an array
# Parameters:
#   name - name of variable to test
# Returns:
#   0 if an array
#   1 otherwise
is_array()
{
    # Only takes one argument
    if [ "${#}" -ne "1" ]; then
        return 1
    fi

    # Name of the variable to test
    local name="$1"; shift
    # Run the declare command against the variable
    local x=$(declare -p $name 2>/dev/null)
    # If it errored then the name probably isn't even
    # a variable
    if [ "$?" -ne "0" ]; then
        return 1
    else
        # It is at least declared, test if it is an array
        if [ "${x:8:2}" == "-a" ]; then
            return 0
        else
            return 1
        fi
    fi
}
Push values onto an array:
# array_push - Pushes one or more values onto an array
# Parameters:
#   name - name of the destination array
#   ...  - values to push onto array
# Returns:
#   Nothing
array_push()
{
    # Need two or more arguments
    if [ "${#}" -lt "2" ]; then
        return
    fi

    # Name of the destination array
    local name="$1"; shift
    # Number of elements we're going to push
    local numElements=${#}
    # Counter
    local i=0
    # Starting position of destination array is the
    # size of the array
    eval local start=\$\{\#$name\[\@\]\}
    # Iterate over the elements supplied, adding them
    # to the destination array
    while [ "$i" -lt "$numElements" ]; do
        pos=$((start+i))
        eval $name\[$pos\]=\"$1\";
        shift
        ((i++))
    done
}
Pop from an array:
# array_pop - pops a value from the end of the array
# Parameters:
#   name - name of array
#   dest - optional name of variable to put value in
# Returns:
#   Nothing
array_pop()
{
    # Need at least one argument
    if [ "${#}" -eq "0" ]; then
        return
    fi

    # Name of the array
    local name="$1"; shift
    # If we have a second argument, use it to write value
    if [ -n "$1" ]; then
        local dest="$1"; shift
    else
        local dest=""
    fi
    # Size of the array
    eval local numElements=\$\{\#$name\[\@\]\}
    # Index of element is one less than size
    local index=$((numElements-1))
    # Get the value
    eval local value=\"\$\{$name\[$index\]\}\"
    if [ -n "$dest" ]; then
        # Update the specified dest variable
        eval $dest=\"$value\"
    else
        # Simply echo the value
        echo "$value"
    fi
    # Unset from the array
    eval unset $name\[$index\]
}
One thing to note is the clash between variable names. E.g. if you wanted to return the value into the name variable, it would be bad to call that variable 'value'. local doesn't help here, best option would probably to use obscure variable names that are unlikely to clash.
Walk an array:
# array_walk - Walks through an array, calling the
#              callback function for each element
# Parameters:
#   name     - name of array to walk
#   callback - name of callback function
#   ...      - any parameters to be passed to callback
# Returns:
#   Nothing
array_walk()
{
    # Name of array to walk over
    local name="$1"; shift
    # Name of call back function
    local callback="$1"; shift
    # TODO - We should probably check whether callback
    # is actually a function

    # Number of elements in array
    eval local numElements=\$\{\#$name\[\@\]\}
    # Counter
    local i=0
    # Iterate over the elements in the array
    while [ "$i" -lt "$numElements" ]; do
        # Get the value
        eval value=$\{$name\[$i\]\}
        # Check whether it is an array
        is_array $value
        if [ "$?" -eq "0" ]; then
            # If so, recursively walk that array
            array_walk "$value" "$callback" "$@"
        else
            # Just a variable, so call the callback
            # function giving it the args and value
            $callback "$@" "$value"
        fi
        ((i++))
    done
}
Now, a little play with those functions:
declare -a aTest

echo First push
array_push aTest 'Hello' 'there' 'you' ':)'
echo new array is ${aTest[@]}
echo

declare -a aTest2
echo Second push
array_push aTest2 'How' 'are' 'you today?'
echo second array is ${aTest2[@]}
echo

echo Third push to add second array to the first
array_push aTest 'aTest2'
echo first array is ${aTest[@]}
echo

echo Defining destination array
declare -a aMerged
echo defining callback function
merge()
{
    local name="$1"
    local value="$2"
    # Simple push the value onto the destination
    array_push "$name" "$value"
}
echo Doing walk
array_walk aTest merge aMerged
echo merged array is ${aMerged[@]}
echo

echo Popping last element of merged array by reference
array_pop aMerged val
echo Value is $val
echo and again
array_pop aMerged val
echo Value is $val
echo merged array is now ${aMerged[@]}
Running it gives us:
$ ./arrays2.sh 
First push
new array is Hello there you :)

Second push
second array is How are you today?

Third push to add second array to the first
first array is Hello there you :) aTest2

Defining destination array
defining callback function
Doing walk
merged array is Hello there you :) How are you today?

Popping last element of merged array by reference
Value is you today?
and again
Value is are
merged array is now Hello there you :) How
$
So that sort of works. Next I should add an array_indexes() and array_values(). Oh, and happy new year :D
Edit:
Added array_pop function.