I presented the Web Track for the Microsoft Security Summit in Charlotte, NC this Wednesday. I don't believe that any of the attendees left that day without learning something. I was not the only one talking either; the attendees contributed many important points. I want to thank them all for their insights.
I will be presenting at two more summits: St. Louis and Seattle. Go to the official website and register for one of these events. They are free, you get to miss a day of work, and you will receive invaluable information about application security.
Steve Henke (sorry, no blog) and I were sitting in a meeting room one day, trying to design the configuration program for my Windows Service application. This service has 20 or so classes that exist solely to provide structure to the data. Steve and I desperately wanted to avoid hard-coding the configuration program, because of the existing number of data classes. We were also sure that more data classes would be added in the future. The configuration program was beginning to seem like a nightmare.
We came up with a very cool solution. We altered the data classes so that they could descibe themselves. The configuration program would have no knowlege of the classes themselves, it would just know how to query the classes for the information needed to dynamically create configuration screens.
How did we do this?
Custom attributes and Reflection.
We created a custom attribute class that allows the data class developer to specify attributes for each data class property. These attributes provide the configuraiton program with the data it needs to function: the label, description, minimum and maximum length, minimum and maximum values, and a regular expression for validation. Through Reflection, this attribute information is retrieved and provided when needed. Reflection also provides the property name and data type. Because obtaining this information can be a bit involved, we created a base data class that provides the implementation for all of this. Each data class derives from this base class. Because of inheritance, each data class now contains a method that returns configuration information for each of its properties. When the configuration program needs to decide how to handle a data class, it calls the GetConfigurationData method of the specific data class.
Sample Attributes
[ConfigurationAttribute(
Container=false,
Configurable=true,
Label="File Mask",
Description="The file mask used to specify input files. (Example: '*.xml')",
Minimum="1",
Maximum="50",
ValidationExpression=@"^([\w\?]+[\w\? ]*\*?)|(\*)\.([\w\?]+[\w\? ]*\*?)|(\*)$")]
The actual code is very long, so I won't provide it here. However, here are some snippets to get you started:
Sample Code
// create an array of properties
PropertyInformation = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
// process each property
foreach (PropertyInfo pi in PropertyInformation)
{
// get an array of custom attributes
object[] Attributes = pi.GetCustomAttributes(typeof(ConfigurationAttribute), false);
// do any attributes exist?
if (Attributes.Length == 0)
{
// create a ConfigurationInfo with all default values;
ci = new ConfigurationInfo();
ci.Configurable = false;
ci.Container = false;
ci.Description = pi.Name;
ci.Label = pi.Name;
ci._Name = pi.Name;
ci._Type = pi.PropertyType;
// add the ConfigurationInfo to the list
ReturnValue.Add(ci.Name,ci);
}
else
{
// get the first element of the array (we only care about the first (and only) one.)
ca = (ConfigurationAttribute)Attributes[0];
if (ca == null)
{
// create a ConfigurationInfo with all default values;
ci = new ConfigurationInfo();
ci.Configurable = false;
ci.Container = false;
ci.Description = pi.Name;
ci.Label = pi.Name;
ci._Name = pi.Name;
ci._Type = pi.PropertyType;
// add the ConfigurationInfo to the list
ReturnValue.Add(ci.Name,ci);
}
else
{
// create a ConfigurationInfo with values from the object's attributes
ci = new ConfigurationInfo();
ci._Name = pi.Name;
ci._Type = pi.PropertyType;
ci.Configurable = ca.Configurable;
ci.Container = ca.Container;
ci.Description = ca.Description;
ci.Label = ca.Label;
ci.Maximum = ca.Maximum;
ci.Minimum = ca.Minimum;
ci.ValidationExpression = ca.ValidationExpression;
// add the ConfigurationInfo to the list
ReturnValue.Add(ci.Name,ci);
}
}
}
Update: Dan Fox demostrates the creation of custom attributes in his blog post entitled “
Another topic I came across while trying to read myself to sleep is Alternate Data Streams in NTFS. Apparently, this feature is provided for compatibility with Macintosh Hierarchical File System resource forks. Whatever the reason, they exist and I wanted to tell you about them.
Open a command window and try the following:
Create a file called “names.txt“ that contains my name:
echo Jerry > names.txt
Prove that the file contains my name:
more < names.txt
Add my wife's name to the file, in an alternate data stream:
echo Tammy > names.txt:wife
Retrieve the contents:
more < names.txt
more < names.txt:wife
There are now two separate sets of data in this one file.
You can access the default stream in two ways:
more < names.txt
more < names.txt::$DATA
I do not know how many streams you can have in a single file. I have sucessfully added three streams myself.
As you can imagine, this poses a bit of a security threat. A malicious user can “hide” data, such as script, in your files. Most people would never think to look into a file's alternate data streams. A quick scan of the net shows that many anti-virus programs don't either.
I came across the concept of dotless ip addresses recently while enjoying some “light” bedtime reading. After doing some surfing on the net, I discovered some information that I would like to share. I am going to show you many different ways to tell your browser to navigate to Yahoo's web site. (NOTE: all of the following methods work in some browser, but not all methods work in every browser.)
“Normal” Addresses
DNS: http://www.yahoo.com
IP: http://216.109.117.109
Dotless Addresses
1). Convert each decimal octet to hex:
216 = D8
109 = 6D
117 = 75
109 = 6D
2). Make one hex number out of them:
D86D756D
3). Convert back to decimal:
3631052141
So, you can get to Yahoo via http://3631052141
You can also calculate this with the formula:
dotless ip =
(octet1 * 16777216) +
(octet2 * 65536) +
(octet3 * 256) +
(octet4)
Weird Alternatives:
Octal: http://0330.0155.0165.0155
Hex: http://0xD8.0x6D.0x75.0x6D
Hex: http://0xD86D756D
and finally, to really confuse things, mix the methods together:
http://0330.0x6D.117.0x6D
Why do we do this to ourselves?