Arduino Digital Temperature Sensor

December 30, 2012

For Christmas I got an Arduino open-source electronic prototyping platform. After working through some tutorials, I was able to build this digital thermometer.


Minecraft Tower of Doom

January 15, 2012

Here are some images of a tower I created in Minecraft.

You can download the schematic file here:



Google Music Troubleshooting: Stops Uploading

January 15, 2012

This blog post is based on Music Manager version and Windows 7 64-bit.

I want to share my experiences with Google Music. I started out just trying to upload all of my music without preparing any of it. This turned out to be a big mistake. First, Google Music Manager stopped uploading my songs after about 150-200 songs and would never recover even after a restart of the computer. Second,  I had albums with incorrect cover art and songs with wrong titles. It was a mess. If you are at that point, then don’t worry you can still recover from this!

1. Clean Up Your Music with TagScanner

My first recommendation is to forget about Google Music until after you have fixed the tags in your music. Regardless of what music file type you use (MP3, WMA, etc) your music will have tags describing the artist, album, and other information. I used two tools to fix all of the information in these tags. My first recommendation is TagScanner. Most tag editors can download the tag information for you, but TagScanner does it slightly different by allowing you to search for more than just the album name. The other program I used was MP3Tag. It worked very well and I actually used both programs. I used MP3Tag to put each song into its own folder based on artist name and album name. Then I used TagScanner to download the tag information and the album cover art. I attached the cover art to each file not just to each album folder. With TagScanner I was able to import over 1,000 files and sort them by artist, etc. I removed inaccurate and unnecessary information like comments and encoded by data. I was also able to change the name of the file so it matched the tag information. I learned after uploading the music that you need to change a setting in TagScanner to force it to save to all tag types (APEv2, ID3v2.3, ID3v1.1). TagScanner can read from APE and ID3 tag types, but if you are not careful it will only write to one tag type. In the upper right area of the window, I changed the setting from “Auto” to “Complete” which makes it write to all three tag types. This way Google Music will always read the correct information and not an outdated APE or ID3v1 tag. If you change your tag information Music Manager will see it as a new song!

2. Start the Uploading

After I got a large chunk of my music cleaned up and tagged properly, I started uploading all 1,000+ songs that were ready. Once again, the Music Manager software failed to upload all the songs. After doing some research, I found out that the logs for the software are stored at:


I used Notepad++ and its silent refresh feature to watch the logs as Music Manager attempted to upload songs. By reviewing the logs and reading Google Group posts, I learned that Music Manager has problems with certain WMA files and will not upload them. To help figure this out I upload the songs in artist sized chunks. I would upload all songs from one artist and if a WMA file was in the folder, it would not get uploaded. I plan on converting the offending WMA files to MP3 and attempting to re-upload them.

Update: I was successful in converting the WMA files to MP3 and uploading them that way. I used Free MP3 WMA Converter to do the conversion. It kept some of the tag information, but loses the cover art. I would recommend going back and updating the tag information in TagScanner before uploading. I also choose the “Remove original file after conversion” option to prevent duplicates.

3. Post Upload

After I did all of this work, I figured Google would meet me half way and use the tag information I so painstaking entered. I am now noticing on some of my songs the tag information is being stripped or not used. I have 20 or so songs that after being uploaded have no album or artist information. I finally realized that TagScanner is setup by default to read APE (tag type) format and write to whatever tag type is available. So Google must have an order to how they read in the tag information. It must start with one format and ignore the other tag types. In TagScanner you can read one type of tag and write to another. So I had set TagScanner to read APE, then ID3v2, then ID3v1, but not write to APE. So I was reading one tag and then not writing to it. I updated the previous section to reflect this. Then I uploaded more songs and noticed that my previously uploaded songs were being re-uploaded! By changing the tag information, Music Manager “forgot” that those songs had been uploaded.


Simple Text Converter

July 25, 2011

This is a simple wordlist converter. I wanted to try out argparse and continue learning about python. This is the result. I really liked working with argparse and think this is a good example.

Convert wordlist text files to various formats.

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Increases messages being printed to stdout
  -x, --xml             Convert Wordlist to XML (one layer only)
  -c, --csv             Convert Wordlist to csv
  -i INPUTFILE, --inputfile INPUTFILE
                        Name of file to be imported
  -o OUTPUTFILE, --outputfile OUTPUTFILE
                        Output file name
  --version             show program's version number and exit

##Converter by Brad Poulton July 2011
##python v3.2
import sys,argparse
from xml.dom.minidom import parse, parseString

#Declare commandline options and setup argparse
cmdparser=argparse.ArgumentParser(description='Convert wordlist text files to various formats.', prog='Text Converter')
cmdparser.add_argument('-v','--verbose',action='store_true',dest='verbose',help='Increases messages being printed to stdout')
cmdparser.add_argument('-x','--xml',action='store_true',dest='toxml',help='Convert Wordlist to XML (one layer only)')
cmdparser.add_argument('-c','--csv',action='store_true',dest='tocsv',help='Convert Wordlist to csv')
cmdparser.add_argument('-i','--inputfile',type=argparse.FileType('r'),dest='inputfile',help='Name of file to be imported',required=True)
cmdparser.add_argument('-o','--outputfile',type=argparse.FileType('w'),dest='outputfile',help='Output file name',required=True)
cmdparser.add_argument('--version',action='version',version='%(prog)s v0.1')
#cmdparser.add_argument('-t','--inputtype',type=int,dest='inputtype',help='File type of input. (e.g. 0 - Wordlist, 1 - CSV, 2 - XML')
args = cmdparser.parse_args()

#prepare the file

def main(argv):
	#parse through commandline args
	args.outputfile.dest = 'test.txt'
	if args.verbose: 
		print ('Verbose Selected')
	if args.toxml:
		if args.verbose:
			print ('Convert to XML Selected')
	if args.tocsv:
		if args.verbose:
			print ('Convert to CSV selected')
	if not (args.toxml or args.tocsv):
		cmdparser.error('No action requested, add -x or -c')
	return 1

def converttoxml():
	if args.verbose:
		print ('converting to xml...')
	for row in args.inputfile:
		args.outputfile.write('  \n')
		args.outputfile.write('    %s\n' % row)
		args.outputfile.write('  \n')

def converttocsv():
	if args.verbose:
		print ('converting to csv...')
	lineoutput = ''
	#wordlist to csv
	for line in args.inputfile:
		lineoutput+=(str(line).rstrip() + ", ")
	print('Done converting ' + + ' to ' +

if (__name__ == "__main__"):


Custom pfSense Firewall Log Analyzer

April 18, 2011
Tags: , ,

UPDATE: Just use Splunk!

Preamble: This was setup using a pfSense machine and a Debian based LAMP.

pfSense is an amazing open source firewall capable of protecting a network ranging from a home network to a large corporate network. The one thing I could not get it to do was show me statistics on blocked TCP connections at the firewall. This is an interesting metric to discover IP addresses that are probing/scanning an outward facing IP. After searching high and low, I was unable to find an easy plugin solution to do this, so I wrote my own in python on a LAMP machine. Here are the steps to implement it:

      1. Setup the firewall logs to be sent to another machine via SYSLOG. This is accomplished by changing the pfSense settings in Status -> Settings -> Enable syslogging to a remote server  and inputting the remote syslog server IP address. Then, check the box marked “firewall events” and save. This will forward just the firewall logs to the remote server in addition to showing them in pfSense.
      2. Setup the remote log server to accept the logs. On the remote machine we need to set it up to accept the logs. Start by replacing the default rsyslog with syslog-ng (apt-get install syslog-ng). In the /etc/syslog-ng/syslog-ng.conf file add the following lines:
# Brad's Custom listener 
source s_net { udp (); }; 
#Brad's Custom Destination 
destination df_pfsensefirewall { file("/var/log/pfsense/pfsensefirewall.log"); }; 
#Brad's Custom filter 
filter f_pfsensefirewall { host( "" ); }; 
#Brad's Log 
log { source ( s_net ); filter( f_pfsensefirewall ); destination ( df_pfsensefirewall ); };

You may need to adjust the filter IP address for your network.

      1. Next, setup Logrotate. Logrotate will be used to keep our log files from taking over the hard drive. Add an entry in /etc/logrotate.d/syslog-ng:
/var/log/pfsense/pfsensefirewall.log {
rotate 7
size 100k

The postrotate shell script (/home/user/pfsenseparser/ is what will be parsing the logs. I placed the script in a folder entitled pfsenseparser in my home directory. This Logrotate entry will run daily, keep 7 old logs, and run the script after the logs have been rotated. Restart syslog-ng at this step to see if the logs are being written to /var/log/pfsense/pfsensefirewall.log by running /etc/init.d/syslog-ng restart.

      1. Create the file. is the bash script that is called by logrotate after logrotate has done its business. Here is what mine looks like:
#location of the rotated log file
#get rid of identical lines (to speed things up) and run the python script
grep TCP $FILE | uniq > /home/user/pfsenseparser/grepped.log | python /home/user/pfsenseparser/
#restart syslog-ng
/etc/init.d/syslog-ng restart > /dev/null
exit 0
      1. Create the file. is the actual log parsing portion. It cuts up the logs and stacks them in the MySQL database. You may need to install addition python software, e.g. MySQLdb.  My version is setup to record the latitude and longitude of the IP addresses that were attacking/scanning my firewall. I get this information from If you want this functionality you will have to get your own API key at I use this information to display the location of the IP on a google map. Here is the code:

import re,urllib2,MySQLdb,datetime,os
from urllib import urlopen
from xml.dom.minidom import parse, parseString
from xml.etree import ElementTree as ET

#API key for
apikey = "GET YOUR OWN KEY"
#import the file
input = open('/home/user/pfsenseparser/grepped.log', 'r')
#error log
error_output = open('/home/user/pfsenseparser/error.log', 'a')
#output files
output = open('final.txt', 'a')

# this allows for the IP to Lat/Long conversion
url = ""+apikey+"&ip="

#MySQL Connect
db = MySQLdb.connect("localhost","pfsenseparser","username","password")
cursor = db.cursor()

#what time is it?
now =
error_output.write('<------Started at: ' + now.strftime("%Y-%m-%d %H:%M") + '--->\n')

#number of new entries
num_new_data = 0
num_exist_data = 0

#testing variable no SQL or file write if set to 0
testing = 1

for line in input:

   re1='((?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Sept|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?))'    # Month 1
   re2='.*?'    # Non-greedy match on filler
   re3='((?:(?:[0-2]?\\d{1})|(?:[3][0,1]{1})))(?![\\d])'    # Day 1
   re4='.*?'    # Non-greedy match on filler
   re5='((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)'    # HourMinuteSec 1
   re6='.*?'    # Non-greedy match on filler
   re7='(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?![\\d])'    # Uninteresting: ipaddress
   re8='.*?'    # Non-greedy match on filler
   re9='((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?![\\d])'    # IPv4 IP Address 1
   re10='.*?'    # Non-greedy match on filler
   re11='(\\d+)'    # Integer Number 1
   re12='.*?'    # Non-greedy match on filler
   re13='((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?![\\d])'    # IPv4 IP Address 2
   re14='.*?'    # Non-greedy match on filler
   re15='(\\d+)'    # Integer Number 2

   rg = re.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11+re12+re13+re14+re15,re.IGNORECASE|re.DOTALL)
   m =
   if m:
           #print "("+month1+")"+"("+day1+")"+"("+time1+")"+"("+ipaddress1+")"+"("+int1+")"+"("+ipaddress2+")"+"("+int2+")"+"\n"


       #ipaddress1 is the one we want
       #lets see if it is in the database before we ask ipinfodb
       sqlipcheck = "SELECT * FROM pfsenseparser WHERE Ip_Address = ('%s')" % (ipaddress1)
       data = cursor.fetchall()
       ipcheck = ""
       for row in data:
           daycheck = row[2]
           timecheck = row[3]
           ipcheck = row[4]
       if ipcheck != ipaddress1:
           #This is a new IP Address
           error_output.write(ipaddress1+' = New Data\n')
           url2 = ipaddress1+"&timezone=false"
               url3 = url+url2
               urlobj = urllib2.urlopen(url3)
               data =
               dom = ET.XML(data)
           city = dom.findtext("City")
           country = dom.findtext("CountryName")
           region = dom.findtext("RegionName")
           region = region.replace("'", "")
                lat = dom.findtext("Latitude")
               long = dom.findtext("Longitude")
           if testing == 1:
               cursor.execute("INSERT INTO pfsenseparser (Month,Day,Time,Ip_Address, Port_Num,Lat,Longitude,City,Country_Name,Region,Num_Connect,Type) VALUES (%s, %s, %s,%s, %s, %s, %s, %s, %s, %s, 1, \"firewall\")", (month1,day1,time1,ipaddress1,int2,lat,long,city,country,region))
                   output.write(month1+","+day1+","+time1+","+ipaddress1+","+int1+","+lat+","+long+","+ipaddress2+","+int2+" "+"\n")
                       #output2.write(month1+","+day1+","+int1+c1+int2+","+ipaddress1+","+int1+","+lat+","+long+","+ipaddress2+","+int2+" "+"\n")
           num_new_data = num_new_data+1
       elif timecheck != time1 and daycheck != day1:
           #This is an existing IP Address but not a duplicate
           sql2 = "SELECT Num_Connect FROM pfsenseparser WHERE Ip_Address = ('%s')" % (ipaddress1)
           data = cursor.fetchall()
           for row in data:
               num = row[0]
               num_new = int(num)+1
               sql5 = "UPDATE pfsenseparser SET Num_Connect = ('%d') WHERE Ip_Address = ('%s')" % (num_new,ipaddress1)
               if testing == 1:
           num_exist_data = num_exist_data+1

now2 =
if testing == 1:
#send me a text
   os.system('echo \' just ran with ' + str(num_new_data) + ' new entries and ' + str(num_exist_data) + ' existing entries\' | mailx youremailhere ')
   #write to error.log
   #insert timestamp and new entries into database
   if num_new_data != 0:
       cursor.execute("INSERT INTO pf_meta (Last_Run,New_Data) VALUES (NOW(),'Y')")
       cursor.execute("INSERT INTO pf_meta (Last_Run,New_Data) VALUES (NOW(),'N')")
   error_output.write('Ended at: ' + now2.strftime("%Y-%m-%d %H:%M") + ' with ' + str(num_new_data) + ' new entries and ' + str(num_exist_data) + ' existing entries\n')
    os.system('echo \'Just Testing\' | mailx youremailhere ')

      1. Create a place to stack the logs in the mysql database. The looks at the logs and inserts them into the database if they are new IP addresses. If the IP address is already in the database it will increment the number of times the IP address has attempted a connection. Here are the create statements for MySQL
CREATE TABLE `pfsenseparser` (
  `Log_Id` int(11) NOT NULL auto_increment,
  `Month` varchar(30) default NULL,
  `Day` varchar(30) default NULL,
  `Time` varchar(30) default NULL,
  `Ip_Address` varchar(30) default NULL,
  `Port_Num` varchar(30) default NULL,
  `Lat` varchar(30) default NULL,
  `Longitude` varchar(30) default NULL,
  `notes` varchar(200) default NULL,
  `City` varchar(50) default NULL,
  `Country_Name` varchar(75) default NULL,
  `Region` varchar(75) default NULL,
  `Num_Connect` mediumtext,
  `Type` varchar(50) default NULL,
  PRIMARY KEY  (`Log_Id`)

CREATE TABLE `pf_meta` (
  `Meta_Id` int(11) NOT NULL auto_increment,
  `Last_Run` datetime default NULL,
  `New_Data` varchar(30) default NULL,
  PRIMARY KEY  (`Meta_Id`)
      1. Pull the data from the MySQL Database. The great part about inserting the data into a database is the ability to query that data in a meaningful way. By using PHP we can create statistics to help us analyze the information. Here is a sample PHP file for pulling the data out that you can download PHP index.php. The code grabs the top 10 ports, IPs, and countries. I also have PHP files for the Google maps if requested in the comments.
      2. Obviously, this is a work in progress. Please offer suggestions to help improve this code or leave questions if you have any!

UPDATE: As requested here is the code for the Google map displaying where the firewall blocks are coming from.

WARNING! This has only been tested in Firefox! It will not work in Chrome! This is very custom code. When it does not work for you, leave a comment!


Panorama of Pine Valley Mountain

April 15, 2011


Home or Small Office SIEM with OSSIM

March 30, 2011
Tags: , , ,

For the past couple of weeks, I have been working with OSSIM (Open Source Security Information Management). OSSIM is a collection of tools, which provide a detailed view of the network. These tools include IDS, vulnerability scanner, up-time monitor, and more. I installed the 32-bit version of OSSIM (the 64-bit did not work on my hardware) on an old 2.0 GHz P4 I took out of a Sony Viao PCV-RX752. For my small network (less than 20 hosts) this older hardware has worked great. The first hurdle to overcome when setting up an OSSIM installation is the listening interface. In order for OSSIM to do its job, it needs to be able to listen to all the traffic going in and out of the network. The Mikrotik Routerboard RB250GS is an affordable network switch that is able to mirror traffic from one Ethernet port to another. You can purchase one from Data-Alliance for about $40. The switch includes a web interface that allows you to configure the device. Here is a link to a screen shot of the web interface: MikroTik. By placing the switch behind the firewall but in front of the rest of the network, the switch is able to see all the traffic going into and out of the network. One Ethernet cable goes to the firewall another to the next network switch and a third to the OSSIM listening interface. Here is a great picture. With this basic network setup you are ready to install OSSIM and start listening for events.

The installer for OSSIM is very user-friendly. After OSSIM is installed, run apt-get update, apt-get dist-upgrade, and ossim-reconfig to update the OS software and the OSSIM software.  Once the installation and upgrade are complete you should be able to login to the web interface (default username and password: admin/admin). If things are working properly you will be able to see new events under the Analysis -> SIEM section. The OSSIM guys have cleverly use the Snort BASE web interface for the event manager. Next, start defining hosts in the Assets -> Assets section. Hosts represent the different computers on your network. Be sure to have a list of computer names and IP addresses before you start adding hosts. If you have assets that you want Nagios to monitor for up-time, be sure to check the Nagios box under the advanced section. I also like to add the OS and MAC under the inventory section. Do not attempt to add or remove monitored hosts under the Monitors -> Availability (Nagios) section. OSSIM handles all the hard work for you in the Assets section. After you have created an asset that you want to monitor with Nagios, modify it in OSSIM and select what ports you want monitored. OSSIM can use Nmap to scan the host for you or you can manually choose the ports.

After my OSSIM installation was running for a few days, I notice a large number of false positives in the SIEM. OSSIM handles the reduction of false positives through its Policies. OSSIM uses policies to decide what to do with an event. You can create a new policy that modifies OSSIM’s default event behavior. To reduce false positives that were occurring with the Snort plugin, I created a new policy to suppress specific snort alerts. I created a new Policy with any source, destination, or port. I also created a new plugin group called Snort Suppress that uses the snort plugin and the signature ID (SID) of the offending snort rule. OSSIM makes it very easy to verify that you have the correct SID by clicking on the magnifying glass with a plus sign in it. This will bring up a description of the SID you have entered. Once the plugin group has been created, the policy consequences can be adjusted. The consequences section refers to the actions OSSIM takes when the event is detected. To stop the event from registering in the SIEM click on the “No” next to the SIEM. This will suppress the event. Be sure to leave the Active option to Yes. This indicates if the Policy is active or not. The Actions option allows for you to setup a custom action (send email or execute a Linux command) to occur when the event is detected. I have an action setup that will send me an email. I can attach this action to any policy.

This OSSIM configuration is great for monitoring network traffic, but what about individual hosts? OSSIM comes with the ability to do this. A tool called OSSEC is included with OSSIM. OSSEC is an Open Source Host-based Intrusion Detection System (HIDS). Where Snort is a network-based IDS (NIDS), OSSEC is a host-based IDS. This means it resides on and monitors individual hosts. I have used OSSEC in the past for a basic SSH honeypot exercise. Setting up OSSEC on your host is very simple. First, run the manage_agents script under /var/ossec/bin/ on the OSSIM/OSSEC server. Then install the OSSEC agent on the target host. For Windows 7 be sure to install the OSSEC agent program under an administrator account. When the agent prompts for the client key run the mange_agent script and extract the key. Input this key into the agent along with the IP address of the OSSEC server. On the OSSIM machine run list_agents to see if the agent was able to connect successfully. Once the agent has connected you will see events in the SIEM based on the OSSEC plugin.

With this basic setup guide, an old computer, and a $40 switch anyone can monitor their own traffic and get an idea of the security of their network. I have included some helpful links below:

OSSIM Installation Guide

OSSIM Introduction




Caffinated vs Non-Caffinated Barq’s Root Beer Taste Test

June 12, 2010

Thesis: Caffeinated Barq’s Root Beer tastes better than non-caffeinated Barq’s Root Beer because it has caffeine in it.

Materials: One 20oz non-caffeinated Barq’s Root Beer from Utah, One 20oz caffeinated Barq’s Root Beer from Texas, and a bunch of plastic cups.

Conclusion: After three separate taste tests by both Brad and Tyler, we both concluded that the taste difference is insignificant. In fact, in the first test we both thought the non-caffeinated Barq’s was more sweet. In the other two tests, we were split on which version we preferred. My personal opinion is that the amount of caffeine added to drinks in today’s beverage industry is not to add taste, but to add an addictive substance to help increase sales (see the link for more information about caffeine’s addictive properties). Now more than ever caffeine is being pushed on soda drinkers (see and sold as a way to increase your energy and focus. Unfortunately, the caffeine boost will pass and the withdrawal symptoms will begin.


Mobile Tags

May 24, 2010

I recently discovered mobile tags (yes, I know they have been around for a while). They are the strange bar codes on some packages. I found a web page ( that will allow you to create new tags. I was really interested in the ability to “hide” a message.  Try to discover the hidden text in these images:

QR CodeDataMatrix Code

Both images have the same text.


Honeypot Update

April 21, 2010

On april 19th, the day after my last honeypot post and two days after the honeypot was started, the server was logged into by two new IPs. The two new IPs were from Italy and Romania. The Italian IP did the brute forcing and the Romanian IP logged in after the brute force was finished. My guess is the Romanian IP was the command and control, while the other IP was just a bot.

After receiving the text message alerts from OSSEC, I reviewed my .bash_history file to discover the perpetrator had left some clues! First, it downloaded windows 2000 service pack 3 to test my bandwidth, then it downloaded some other software, which it promptly deleted. It then ran the software. I think I am missing some of the history because my /var/log/auth.log file does not contain the IP address. I think it covered up some of its tracks, but not all. I replayed the steps and downloaded the software to discover it was an IRC bot called EnergyMech, which is an open source IRC bot. To protect myself, I have since pulled the server off the internet and plan on wiping the hard drive.

Overall the experience was excellent! OSSEC was a must have for this exercise.  If I had more time I would have setup something to capture all the commands run by Root through SSH that way I could have seen all the commands run. I have attached this time line to show how fast the SSH server started being brute forced and how quickly the usernames and passwords were guessed.