Saturday, 22 May 2010

Fun with bash: crc16, hashes and plugins

Today I released simple plugin architecture for bash scripts.

To do what it does, it uses three interesting features of bash:


  • The source command to read in the plugins

  • Bash arrays turned into hashes using a crc16 function written in bash

  • Bash functions within functions to limit the scope of plugin commands



This post describes those three interesting features.

Bash Plugin Architecture

The project page is at: http://code.google.com/p/b-p-a/

It allows you to create plugins like:


user@host:~/bpa$ cat plugins/security/nmap.shp
#!/bin/bash

registerPlugin "NMap" "nmap" "The mighty portscanner"

registerCommand 'SynScan' 'syn' 'TCP Syn scan of hosts'
registerCommand 'Ping' 'ping' 'Ping scan of hosts'

# Name of the plugin
NMap()
{
# Name of the command.
# Each command goes inside the Plugin() function
SynScan()
{
# Code for this command
hosts=$@
nmap -sS -P0 $hosts
}

Ping()
{
hosts=$@
nmap -v -sP $hosts
}
}


which can be used like


$ sudo security.sh --nmap --syn -- 192.168.0.1


For this to work, security.sh just needs to source the BPA.sh script and run a few commands (see the project page for details).

Sourcing plugins

This feature is probably the simplest, and part of the code of BPA.sh is below:


#
# Registers a new application.
#
# This must be the first thing called inside the application script.
#
# @param name
# Name of the application.
#
# @param debug
# (optional) If set to '1' debugging is enabled for the application. Defaults
# to '0'.
#
# @param plugins
# (optional) Sets the plugins directory for the application. Defaults to
# './plugins' inside the directory of the application script.
#
# @return
# Does not return a value
#
# Example:
# @code
# new 'MyApp' 1 '/var/lib/plugins/myapp'
#
new() {
sAppName="$1"
bDebug=${2:-"0"}
sAppPluginsDir=${3:-"./plugins"}

doDebug=$bDebug

debug "New application $sAppName"
for plugin in $(ls ${sAppPluginsDir}/*.shp); do
debug "Sourcing $plugin"
source "$plugin"
done
}


Basically, when the application script security.sh sources the main script BPA.sh and calls the new function, looks inside a plugins directory for all files ending in .shp (shell plugin). For each file it finds it calls the source command.

Now, when you source a plugin, you run it's registerPlugin function and all of it's registerCommand functions which in turn uses the hash functions as described next.

Bash hashes

The registerPlugin function looks something like:


#
# Registers a plugin for the application.
#
# This should the first thing a plugin (.shp) script does.
#
# @param name
# The name of the plugin.
#
# @param switch
# The command-line switch used to access the plugin, using --switch.
#
# @param description
# A description of the plugin. This is displayed when the --help switch
# is used.
#
# @return
# Does not return a value
#
# Example
# @code
# registerPlugin 'MyPlugin' 'my' 'An example plugin'
#
registerPlugin()
{
sPluginName=$1
sPluginSwitch=$2
sPluginDescription=$3

debug "Registering $sPluginName"

hash_set $sPluginName name "$sPluginName"
hash_set $sPluginName description "$sPluginDescription"

hash_set hPlugins "$sPluginSwitch" "$sPluginName"
}


The interesting thing in that function is the use of hash_set, which is:


#
# Creates hash with given name and sets key/value pair.
#
# @param name
# Name of the hash.
#
# @param key
# Hash key value.
#
# @param value
# Hash value for key.
#
# @return
# Does not return a value.
#
hash_set()
{
name=$1
key=$2
value=$3
lookup="${name}_keys"

id=$(crc16 $key)
eval $name\[\$id\]=\"\$value\"
array_push $lookup $key
}


This function takes a name for the hash as its first argument, then a key followed by the value for that key. It then uses the crc16 function (shown below) to generate a numeric index for the actual bash array. It then uses the bash eval command to create a real array from the hash name that was supplied. Finally, it uses a simple array_push function to keep track of the keys in case we want to iterate over them.

Quite simple, and definitely overkill ;) It would be possible to just create two parallel arrays to track the key/value pairs, but this is more fun.

The crc16 function looks like this:


#
# Generates a crc16 value for the given string.
#
# @param string
# String to be crc16'd.
#
# @return
# Decimal crc16 value of string
#
crc16()
{
# This could probably be more efficient...
string=$1
aString=($(echo $string | fold -w 1))
cnt=${#aString[@]}
crcPolyNom=0x8408
crcPreset=0xFFFF
crc=$crcPreset

for ((x=0;x<$cnt;x++)); do
char=${aString[$x]}
byte=$(printf "%d" \'$char)
for ((i=0;i<8;i++)); do
(( charLsb = $byte & 0x0001 ))
(( crcLsb = $crc & 0x0001 ))
(( doAdd = $charLsb ^ $crcLsb ))

(( byte = $byte >> 1 ))
(( crc = $crc >> 1))

if [ "$doAdd" -eq "1" ]; then
(( crc = $crc ^ $crcPolyNom ))
fi
done
done
echo $crc
}


To get a value from the array, we just have to generate the crc16 for the key:


#
# Gets the value for key from the given hash.
#
# @param name
# Name of the hash.
#
# @param key
# The key value.
#
# @return
# The value associated with the key
#
hash_get()
{
name=$1
key=$2

id=$(crc16 $key)
eval echo \$\{$name\[\$id\]\}
}


So yeah, this is pretty slow... but also pretty cool.

Functions within functions

You can declare a function within a function. For example:


NMap()
{
# Name of the command.
# Each command goes inside the Plugin() function
SynScan()
{
# Code for this command
hosts=$@
nmap -sS -P0 $hosts
}
}


In order to run the SynScan function, you must first run the NMap function. At first this might not seem very useful. But for a plugin system it is, as it allows multiple plugins to have the same commands, without any clashing.

BPA.sh calls the plugin function and command in the run function:


#
# Runs the actual application.
#
# @return
# Does not return a value.
#
# Example:
# @code
# run
#
run() {
debug "Running $sAppName"
parse $aAppArgs
debug "Plugin: $sSelectedPlugin"
debug "Command: $sSelectedCommand"
$sSelectedPlugin
$sSelectedCommand $aCmdArgs
}


So we could happily have another plugin, perhaps like:


OtherCoolPortScanner()
{
# Name of the command.
# Each command goes inside the Plugin() function
SynScan()
{
# Code for this command
hosts=$@
othercoolportscanner -s $hosts
}
}


...without worrying about mixups.

Monday, 17 May 2010

sp@m witt no spalling mistokes

Just received the following email:


from Adobe
reply-to newsletter@download-adobe-pdf.com
to me@gmail.com
date 17 May 2010 16:40
subject Download New Adobe PDF Reader For Windows
mailed-by mmmail.co.uk

hide details 16:40 (1 hour ago)


PDF Reader for Windows - Compatible with All Windows Platforms

Get the new and improved 2010 version.
The ultimate PDF software pack to open, read and share PDF files online.

Download New PDF reader here:

http://www.download-adobe-pdf.com/

New Features in PDF Reader:

- Search, open & share PDF files online
- 50% faster startup then previous versions
- Search & save online Internet content
- NEW! Improved user interface

Also receive the award winning OfficeSuite absolutely free.

New version available :

http://www.download-adobe-pdf.com/

Since the 90's, PDF has become the standard file format for document exchange. - Adobe

Thank you,

Adobe Reader Support



Click here to unsubscribe


Not only did this get through the usual spam filters Google so wonderfully provides, but it actually looks quite professional =/

A quick look at the whois output...


Domain name: DOWNLOAD-ADOBE-PDF.COM
Name Server: ns1.download-adobe-pdf.com 67.225.133.235
Name Server: ns2.download-adobe-pdf.com 67.225.133.235
Creation Date: 2010.05.17

Status: DELEGATED

Registrant ID: UALWS2Z-RU
Registrant Name: Tommy Anderson
Registrant Organization: Tommy Anderson
Registrant Street1: 273 Parkway
Registrant City: Miami
Registrant State: FL
Registrant Postal Code: 33402
Registrant Country: US

Administrative, Technical Contact
Contact ID: UALWS2Z-RU
Contact Name: Tommy Anderson
Contact Organization: Tommy Anderson
Contact Street1: 273 Parkway
Contact City: Miami
Contact State: FL
Contact Postal Code: 33402
Contact Country: US
Contact Phone: +1 504 3442930
Contact E-mail: tommy3849@hotmail.com

Registrar: Regional Network Information Center, JSC dba RU-CENTER

Last updated on 2010.05.17 20:38:33 MSK/MSD


and suddenly it doesn't look so professional.

I haven't actually tried visiting the site yet, I don't have any systems I can happily pwn.

The unsubscribe link goes to:


http://www.mailingm.co.uk/3/unsubscribe.php?M=2723658&N=2435&=4&C=fbe0b28cf0f58710c5b4dea8a6e2ca68


A quick Google search:


Mailingm.co.uk - Online Marketing Services Provider | Visit ...
This company specializes on marketing services through e-mail giving their clients the possibility of reaching a wider and international audience.
www.killerstartups.com › Site Reviews - Cached - Similar


In conclusion, this might just be some dodgy marketing for an Adobe reseller, but I don't think I'll take my chances.