Monday, January 31, 2011

Windows Registry with Mono, pt2 - Node Keys

I have had a bit more time on my hands to work on being able to read the registry without using advapi32.dll. Today I was able to hack up a small (incomplete) class for node keys that builds the framework for breaking apart and manipulating the data.

To start off, from this file, we can get the offsets we need to read to get the right data.


the nk-Record
=============

Offset Size Contents
0x0000 Word ID: ASCII-"nk" = 0x6B6E
0x0002 Word for the root-key: 0x2C, otherwise 0x20
0x0004 Q-Word write-date/time in windows nt notation
0x0010 D-Word Offset of Owner/Parent key
0x0014 D-Word number of sub-Keys
0x001C D-Word Offset of the sub-key lf-Records
0x0024 D-Word number of values
0x0028 D-Word Offset of the Value-List
0x002C D-Word Offset of the sk-Record
0x0030 D-Word Offset of the Class-Name
0x0044 D-Word Unused (data-trash)
0x0048 Word name-length
0x004A Word class-name length
0x004C ???? key-name


It's pretty straight forward. In every fragment, we can go to specific offsets and get the data we want. This ends up looking like this:


public NodeKey (string data)
{
ASCIIEncoding enc = new ASCIIEncoding();

byte[] bs = enc.GetBytes(data);

//the lengths we will be working with.
int word = 2;
int dword = word+word; //double word
int qword = dword+dword; //quad word

for (int i = 0; i < bs.Length;)
{
//making sure it is nk
if (i == (int)0x0000) //header
{
if ((int)bs[0] == 110)
{
if ((int)bs[1] == 107)
{
i += word;
continue;
}
else
{
throw new Exception("This may be a damaged nk block. If so, fix the header and try again.");
}
}
else
{

throw new Exception("Not a nk");
}
}

else if (i == (int)0x0002) //is it a root key?
{
if (bs[i] == (byte)0x2C)
{
//It's a root key!
Console.WriteLine("It's a root key!");

}
else
{
//it's not a root key!
Console.WriteLine("It's not a root key!");
}

i += word; //move up 2 elements
continue;
}

else if (i == (int)0x0004) //timestamp in long smb form blegh
{
byte[] blah = new byte[qword];
for (int k = 0;k<qword;k++)
{
blah[k] = bs[i+k];
}

i+= qword;
}
else if (i == (int)0x0010) //offset to parent
{
i += dword;
}
else if (i == (int)0x0014) //number of subkeys
{
i += dword;
}
else if (i == (int)0x001C) //offset to subkey lf blocks
{
i += dword;
}
else if (i == (int)0x0024) //number of values
{
i += dword;
}
else if (i == (int)0x0028) //offset of value list
{
i += dword;
}
else if (i == (int)0x002C) //offset to the sk block
{
i += dword;
}
else if (i == (int)0x0030) //offset to classname
{
i += dword;
}
else if (i == (int)0x0044) //this is trash supposedly
{
i += dword;
}
else if (i == (int)0x0048) //name length
{
i += word;
}
else if (i == (int)0x004A) //class name length
{
i += word;
}
else if (i == (int)0x004C) //key name
{
int length = bs.Length - i;

char[] blah = new char[length];

for (int k = 0; k < length;k++)
{
blah[k] = (char)bs[i+k];
}

Console.WriteLine(blah);

i += length; //we are done.
}
else i+= word; //debugging purposes
}
}



If you notice, however, my code is not complete. I am starting with the most useful stuff first and moving on that way. A more complete class will keep the key name length in a local variable and use that instead of bs.Length when reading the key name later. With the current implementation, I read in too many bytes and grab some extra key headers :-/. You could create properties that are privately set and publicly get'able and set the properties to their respective values, to make it truly object oriented.

Another thing to point out is i is being incremented by the length read each time. It isn't arbitrary. This way next go around we are at the offset we need to be at.

One thing I look forward to implementing is lazy loading of parents and children. If you would like to test this, class, you can see my previous post on initially reading and deciphering the windows registry in C#. Just use this in your for loop instead:


foreach (Match mx in nk.Matches (d)) {

all++;
NodeKey key = new NodeKey(mx.Value);
}

Wednesday, January 5, 2011

Analyzing the Windows NT registry without advapi32.dll using Mono (PoC)

I have been doing some challenges for a contest and one requires analyzing a set of Windows NT registry hives. Regedit really sucks (though it does run in wine). I decided it would be more fun to write a small library that can read the registry hives without relying on p/invoke and advapi32.dll on Windows. I have some small code that carves out the data I need, though I am running into a problem on the software hive supplied. Maybe someone can point me in the right direction.

A lot of my information came from this text file which I found, and have updated some with information that I found missing.

As far as I can tell, there are 6 data types to be carved out of the hives. regf file headers, hbin blocks, node keys, value keys, and lf/h (lh on XP) blocks. There are also security keys (with a sk header) within node keys. The following regex's should carve out the data from the registry files so you may parse out the information you need.


Regex regf = new Regex (@"^regf.{508}");
Regex nk = new Regex (@"nk[\x2c|\x20]\x00.{7}\x01.{64}");
Regex vk = new Regex (@"vk.{3}\x00\x00[\x00|\x80].{64}");
Regex hbin = new Regex (@"hbin.{4}\x00\x10\x00\x00.{8}");
Regex lf = new Regex (@".{4}l[f|h][0-65535].{8}"); //lf or lh on winxp


But in order to search the hive, we need to read it in. This isn't very efficient, and I am aware of this. It works.


using (FileStream fs = File.OpenRead (path)) {
var data = new byte[checked((int)fs.Length)];
int i = 0;
int read;

using (var ms = new MemoryStream (checked((int)fs.Length))) {

while ((read = fs.Read (data, 0, data.Length)) > 0) {
ms.Write (data, 0, read);
i += read;
}

byte[] hive = ms.ToArray ();
char[] cList = new char[fs.Length];

i = 0;
foreach (byte b in hive)
cList[i++] = (char)b;

string d = new string (cList);


int all = 0;

foreach (Match mx in lf.Matches (d)) { //you can change out the regex you want here.
byte[] bb = new byte[mx.Value.Length];
char[] cb = new char[mx.Value.Length];

for (int k = 0; k < mx.Value.Length; k++) {
bb[k] = (byte)mx.Value[k];
cb[k] = (char)bb[k];

}

all++;

//Console.WriteLine (new string (cb));
}

Console.WriteLine (all.ToString ());
all = 0;
}
}


Basically, we read in the hive into a MemoryStream, convert the stream into a byte array, move that into a char array from which we create a string to search for the regexs in. Yes, we store 4 copies of the registry in memory. I am sure there are better ways to do this.

Then we loop through each match and count them. Of course we are working with binary streams, so if you choose to write the data carved out to the console, it will look like random data (to the untrained eye at least).

Running through all the hives supplied, I get this output:



/home/bperry/SAM
nk[\x2c|\x20]\x00.{7}\x01.{64}
47
.{4}l[f|h][0-65535].{8}
0
vk.{3}\x00\x00[\x00|\x80].{64}
36
hbin.{4}\x00\x10\x00\x00.{8}
6
^regf.{508}
1

/home/bperry/software
nk[\x2c|\x20]\x00.{7}\x01.{64}
43147
.{4}l[f|h][0-65535].{8}
6
vk.{3}\x00\x00[\x00|\x80].{64}
54708
hbin.{4}\x00\x10\x00\x00.{8}
2917
^regf.{508}
0

/home/bperry/system
nk[\x2c|\x20]\x00.{7}\x01.{64}
11189
.{4}l[f|h][0-65535].{8}
4
vk.{3}\x00\x00[\x00|\x80].{64}
21926
hbin.{4}\x00\x10\x00\x00.{8}
1121
^regf.{508}
1

/home/bperry/default
nk[\x2c|\x20]\x00.{7}\x01.{64}
554
.{4}l[f|h][0-65535].{8}
0
vk.{3}\x00\x00[\x00|\x80].{64}
1014
hbin.{4}\x00\x10\x00\x00.{8}
58
^regf.{508}
1

/home/bperry/SECURITY
nk[\x2c|\x20]\x00.{7}\x01.{64}
220
.{4}l[f|h][0-65535].{8}
0
vk.{3}\x00\x00[\x00|\x80].{64}
147
hbin.{4}\x00\x10\x00\x00.{8}
10
^regf.{508}
1



The number printed after the regex is the number of matches found. The data is fully carved out, so the only thing left is to break it apart to get the relevant data. If you will notice however, software reports 0 regf file headers, and I cannot figure out why. Any thoughts?

Friday, December 17, 2010

Odd Math.Round() behaviour in Mono (same as .NET?)

I had read on a forum somewhere that Math.Round() rounded to the closest even number. I mentioned this to the guys in #mosa and one mentioned that seems like it would be a bug, as it should go from 4.5 -> 5, rather than the (supposedly) expected 4.5 -> 4, with 4 being the closest even number. Another example is 9.5 -> 10 because 10 is the closest even number (9 is odd).

I wrote a simple method to test this.



using System;

namespace round_test
{
class MainClass
{
public static void Main (string[] args)
{
double x = 0d;

while (x < 5d)
{
Console.WriteLine("actual: " + x.ToString());
Console.WriteLine("rounded: " + Math.Round(x).ToString());

x += 0.1d;
}
}
}
}


The output using mono wasn't very consistent. For instance, 2.5 -> 3 while the rest of the n.5 -> closest even number to n (4.5 -> 4, 3.5 -> 4). (full output here). Odd behaviour, bug??


EDIT: It seems there are two types of rounding, explained on MSDN. The default is banker's rounding.

Thursday, December 9, 2010

Dark theme extension for Wikipedia

I spend a lot of time on wikipedia. A lot of times, to wind down the day, I will just get lost on wikipedia for an hour or two before bed. This is problematic though, because staring into a light bulb for a few hours (in a dark room) right before bed doesn't play well with trying to sleep. I found a neat script to darken the theme of wikipedia, but it hadn't been updated in a while and didn't quite work with the new theme they are using. I took about an hour today to get it running well enough for me, fixing some things the original author left out (like better link colors) and removing other fluff. The results are shown below:



If you would like to install the script (Greasemonkey, but just works on Chrome), click here.

Tuesday, December 7, 2010

Lost ticket revenue in Arlington, TX

The Court here in Arlington offers a (5671 page) PDF with all the arrest warrants in the city for unpaid tickets. It turns out our city is currently missing $56,594,788.04 in revenue for tickets not paid.

If you download the PDF, you can add up the totals yourself. Convert it to HTML using pdftohtml and run:

k=0;for i in `cat outstanding_warrantss.html | egrep -o '[0-9]{1,6}\.[0-9]{2,}'`; do k=`echo "$k+$i" | bc`; done; echo $k


All in all:

bperry@bperry-desktop:~/Downloads$ k=0;for i in `cat outstanding_warrantss.html | egrep -o '[0-9]{1,6}\.[0-9]{2,}'`; do k=`echo "$k+$i" | bc`; done; echo $k
56594788.04
bperry@bperry-desktop:~/Downloads$ time $(k=0;for i in `cat outstanding_warrantss.html | egrep -o '[0-9]{1,6}\.[0-9]{2,}'`; do k=`echo "$k+$i" | bc`; done; echo $k)
56594788.04: command not found

real 10m45.130s
user 0m8.470s
sys 1m43.170s
bperry@bperry-desktop:~/Downloads$


We need a Dog the Bounty Hunter. That is quite a bit of monies.

Wednesday, November 24, 2010

New appliances for network auto-assessment script available

I have uploaded the beta od-autoassess 10.10 virtual appliances (VirtualBox) and have made them available through torrents (preferred) as well. I am getting close to capping my monthly bandwidth (450gb a month, dang!), so please use one of the torrents if possible. Please test them and report any issues by contacting me (or let me know how awesome it is!).

These appliances are fully configured to run all aspects of the autoassessment script. These are beta releases, though I don't think much will change between these betas and any official release. Credentials are rooty/ytoor and you can `sudo su` from there to get root and run a scan (a proper scan should be in the bash history on each appliance, getting root and running through the history should bring it up). But if you are lazy, here is a full scan command:


sh /opt/od-autoassess/od-autoassess.sh --client="FooBarWidgets" --range=192.168.1.0/24 --start-openvassd \
--openvas-user="rooty" --openvas-pass="ytoor" \
--metasploit-sql-driver="mysql" --metasploit-sql-conn="root:toor@127.0.0.1/metasploit" \
--enable-wapiti --enable-w3af


Also, if you like the appliances, the script, or any of my other projects, maybe a donation is in order! I am working part time at Joe's Crab Shack to pay my server and tuition costs while attending school, and any help will be much appreciated!

Tuesday, November 16, 2010

Maths, pt1 and other news

I recently found a really awesome project, MOSA (Managed Operating System Alliance). I haven't had more fun hacking and breaking code in a long time. It's just really neat being able to write your operating system in C#.

One of my projects is building an operating system that performs floating-point arithmetic and fast fourier transforms as kind of a benchmark for the operating system/Ahead-Of-Time compiler. A few years ago, I ported John Walker's FBENCH to C# and I thought this would be an excellent candidate for the task. He also has a benchmark, FFBENCH (Fast-Fourier Transforms) which I plan on porting in the next few days as well.

The MOSA project, however, is quite young compared to other projects like it. It isn't very complete at all and isn't really useful yet. I plan on helping out with this a bit. For instance, I took the trig functions John Walker uses in FBENCH (he defined all the trig functions in case you didn't want to use math.h) and moved them over to C#. It wasn't terribly difficult, just a bit tedious. If you would like a copy of these methods, you may get them here. If all goes well and according to plan, these methods will go into Korlib, the core library MOSA uses for the OS.

I will be making a post in the next few days regarding the ports of the two math benchmarks to C#, and maybe even an image of my OS that can run in QEMU! A new release had been made of the benchmarks since I ported last, so this morning was spent porting the new FBENCH to C# and it is working quite dandily (is that a word?). FFBENCH should be even easier. There are a few tests I want to run regarding these benchmarks. Speed of Mono vs .NET arithmetically and the speed of using System.Math vs my methods. Hopefully I have some good results to show soon.


Also, in other news, the OpenVAS Build Repo has added a 10.10 repository for Ubuntu. I have been testing it on my network here with virtual machines strewn about the house and everything seems dandy! I highly recommend you check it out if you are interested. As soon as I get a bit more free time, I will be releasing two virtual appliances updated to run the od-autoassess script (x86 and x86_64) on Maverick with all the new features I have implemented in the script.

Adding the repository is easy, and you can follow my guide here (updated yesterday) to get a new VM up and running. If you find any problems, let me know!