Matasano
December 2nd, 2007, 17:40
In this much delayed installment I’d like to expand on my last one entitled “Exploring Protocols 1″ ("http://www.matasano.com/log/885/exploring-protocols-part-1/"). This is going to be a long one, folks. I guess the big delay in getting this out resulted in a backlog of all the things I wanted to cover. The discussion veers into tools and samples some simple code for dissecting unfamiliar PDUs. There’s more to the “protocol tool” category than just dissecting, of course. But it’s usually the first step and this post will try to focus mostly on it.
The protocol exploration and tools journey often starts out something like this:
1. Got an unknown or little known protocol we’d like to learn more about and maybe mess with.
2. Think: “Hey, self… Wireshark ("http://www.wireshark.org/") has lots of decodes. Lets check it out.” Then one of two things often happens:
But I’ve not had much luck using Wireshark’s framework to add new dissectors or make use of existing ones in other programs. The dissectors Wireshark supports are written in C ("http://anonsvn.wireshark.org/wireshark/trunk/doc/README.developer") and compiled in at build time [** see note] Sure it uses pcap and there’s numerous pcap based tools for packet mangling/manipulation. That might warrant the effort, but WireShark is first and foremost a sniffer, and we need to do a lot more than sniff protocols. Its dissectors aren’t yet as easy as on might like to make available in other programs. Every time I’ve looked into it I end up deciding to just end up writing my own tools from scratch. The reasons will probably become evident as I go on.
** Note: this may be in the process of changing. The Wireshark folks are beginning to implement a LUA interpreter ("http://wiki.wireshark.org/Lua") right into the sniffer. LUA ("http://en.wikipedia.org/wiki/Lua_%28programming_language%29") is an embedded programming language. It’s cool stuff, but so far it’s still pretty new in Wireshark and it’s still just intended as a tool for developing C dissectors.
But anyway… back to my numbers:
3. What’s needed a more flexible framework. “This is not the wheel I am looking for. Reinvent!!!”
Ok so bear with me. I’m going to jump ahead to the tools and talk some about the techniques I’ve used to attack the problem above in the real world. I’ll digress a bit and yammer seemingly pointlessly about a few iSCSI details too.
Yes, we’ll need a protocol to talk about. For simplicity (… ok well, “reference” anyway) we’re going to stick with iSCSI from the first installment. Wireshark actually dissects iSCSI quite completely. This may defeat the point of the discussion about exploring unknown protocols for some, but for now it’s still a good thing since we can actually compare what Wireshark can do with what we build with our own toolchain.
Let’s start with a simple iSCSI PDU hexdump for reference:
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_hexdump.jpg
Our initial goal was to figure out a bit about the format. I talked about that in the last post. Check out the last “Exploring Protocols 1 ("http://www.matasano.com/log/885/exploring-protocols-part-1/")“. Now we’ll try to dissect iSCSI PDU’s in a manner similar to Wireshark.
In the not too distant past, I would have probably used C/C++ for this. This is mostly because C/C++ has ’structs’ and pointers. The ’struct’ lets you describe binary data to your program by defining fields as elements a structure. Using the structure as the type for a pointer variable lets you apply the structure to a buffer in memory like an overlay. This is pretty obvious stuff to anybody who does any C coding at all, but not everybody does. This simple feature is really powerful and efficient. I still get a few goosebumps when my structures “lay over” properly.
Here is an example of a trivial iSCSI_dissector in C ("http://www.matasano.com/log/973/exploring-protocols-2-writing-some-tools/iscsi_dissectc/"). This sample program is not too robust, but serves as a good starting point. I used a structure borrowed and adapted from linux-iscsi-3.6.3 ("http://linux-iscsi.sourceforge.net/"). You should be able to compile this program with “gcc -o iscsi_dissect iscsi_dissect.c” on any *ix and maybe windows. First lets just look at the structure defined for the header:
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_c_struct.jpg
The structure for the header defines the fields and sizes based on what the iSCSI RFC calls for. The size of the datatype (uint*_t) defines the width of the field.
There are some funky field alignment issues that the linux-iscsi header structure doesn’t try to fully address in the BHS structure definition, though.
This is just nitpicking (bitpicking?) and may distract a little from protocol dissection, but lets take a quick look again at the first four bytes from the RFC 3720 syntax description. This time, the structure elements from linux-iscsi are lined up with each field from the RFC description.
http://www.matasano.com/log/wp-content/uploads/2007/10/BHS_with_vars.jpg
Neither the ‘opcode’ nor ‘flags’ elements in the structure are supposed to take up an entire byte in the BHS if you read the RFC “literally”.
The Basic Header Segment as defined in the RFC has a null bit, followed by an ‘I’ bit, a 6-bit opcode, and a single ‘F’ (final) bit followed by 7 bits allocated as “opcode specific”, or as linux-iscsi called it, “reserved”.
So the first two bits should always be “0 0″ or “0 1″. Why the first bit is not used is unclear, but in obvservation of iSCSI it seems like it’s always set to ‘0′.
So what about that 6-bit opcode after ‘F’? Well if you look closely in the spec, you wont find any op-code higher than the number ‘63′ (or 0×3f in hex). Why? Because at least 7 bits are needed to store for the number 64 (or 0×40 hex) and higher. So there can never be more than 63 types of opcode represented in the “Opcode” field alone. Like so:
There’s another similar (but different) situation right after this one:
The basic header segment is just a template for all the types of header segments. They’re all defined in the RFC too. If you read up on them, it turns in several cases the remaining 7 bits in the the ‘[F][rsvd1]’ byte for are used for other flags. In some cases it’s really “reserved”. In other cases it’s used for codes that are significant to the specific segment type. Sometimes the meaning of the ‘F’ bit even gets changed.
It’s a common practice not to define every single bit in a field separately and just combine them in one byte. When using the structure, you’d just use bitwise operations against various values to set, check and clear individual bits.
Protocols often try to squeeze a use out of every single bit. This can give rise to occasional situations where a weird alignment issue like the ‘rsvd1′ or ‘opcode’ ones can result in unexpected behaviors. Depending on the implementation and what assumptions the developer makes, assigning values to anything after the ‘I’ or ‘F’ might inadvertently get set or cleared. This type of thing can might have dangerous side effects.
Ok… don’t know and can’t think of any even remotely dangerous iSCSI opcode or rsvd1 side effects. I and F seem pretty benign to me just from reading the RFC and theres probably no case short of a grotesquely bad implementation where they’d get clobbered by their neighboring values. The spooky music is… um… just to get in the Halloween spirit. Yea! Happy Halloween everybody!
So, here’s what the output from iscsi_dissect.c looks like (cleaned up slightly for display):
The struct -> buffer overlay used in the C program is simple and kind-of elegant. Structures are also nice since they can serve as a short-hand for describing the format of messages we’re trying to figure out.
This version also resembles the way most actual iSCSI implementations probably work. For grey/black-box security testing, this can be an advantage. You may gain insights that will help you find where implementation flaws lurk in the real product. Using the same language that as actual implementation can arguably let you get closer to the same thought processes the developers used. If there was a point to that random ranting about partial use of bit-fields within bytes, that was it. The rant should also serve as a case study in following useless random rabbit-holes too early in the exploration phase. Which is another good lesson on exploring protocols and would make a good blog-post by itself. I’m sure most people have already dropped out of this overly long post by now. Too bad for them, they’ll totally miss out on the best part.
Ok… for some, the problem with C is that, well, it can be too rigid. I personally think that higher level interpreted languages are better for doing exploratory work like this. As you’re examining unfamiliar and possibly undocumented protocols or formats, you’re constantly refining your idea of what your structures should look like and what you want to do with them. You don’t want to have to stop and recompile for every change. You *really* dont want to find yourself having to redesign your tools several times over.
One of the frustrating things about writing quick/dirty tools from scratch for fault testing or fuzzing is first getting rid of faults in your own testing tools. Usually the quicker and dirtier your C is, the harder it becomes to work with. There are lots of programmers out there that this is may not be a problem for. They probably stopped reading a while ago too. But even they end up relying on abstraction to some extent.
My experience has been that using higher level languages gives you more freedom to experiment and you get a lot of relatively stable free abstraction already without having to build it yourself. To put it bluntly, you can get away with more, for longer, usually with less code. On the other hand, all that abstraction can get in your way sometimes when you need to get closer to the wire, but this isn’t as big of a deal as people make it out to be.
So lets see how we could have written a similar dissector/decoder in an interpreted language. I’m going to use Ruby. Ruby is nice. It has some particularly useful qualities for protocol exploration (besides just being “nice”
:
“But somebody must have done something about this by now!”, you say? Actually several have. One such thing is called BitStruct ("http://redshift.sourceforge.net/bit-struct/"). I’ve been using it a lot. Not only does BitStruct let you map out binary structures in a way similar to C’s ’struct’, but it’s goes further. It is really handy for keeping track of and getting at useful field-related information you’re likely to want. Things like descriptions, sizes, offsets, and even display format are all available as parts of a hash and through free methods. Extending the hash-based design for say “annotations” is as easy as tying new elements to a field’s hash. Bit-struct also has its own free (if somehwat rudimentary) ‘inspect’ and ‘inspect_detailed’ methods for dissecting your structures in human readable format. There’s a ‘describe’ class method that returns a human-readable description of the format itself. BitStruct has some alignment quirks of its own, but like C’s structs you can work around them.
Take a look at this code. It’s a lot more descriptive than the C struct version. The descriptions are actually part of the code, not comments. The formats for fields are specified right in the structure too!
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_bitstruct.jpg
Unlike the C version, the rest of the code is really short. So short I’ll paste it all too:
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_bitstruct_rest.jpg
So here is the iSCSI_dissector in Ruby ("http://www.matasano.com/log/973/exploring-protocols-2-writing-some-tools/iscsi_dissectrbtxt/"). Getting BitStruct ("http://redshift.sourceforge.net/bit-struct/bit-struct-0.10.tgz") is a prerequisite ofcourse. Here’s how we run it and what our output looks like:
In fairness to C, I obviously didn’t do as much work on displaying the data segment but could have. I let ‘inspect’ take care of it to illustrate what it does (and doesn’t do).
It’s interesting to note that the dissector framework in Wireshark uses an similar notion of “adding fields” not unlike BitStruct’s. The sniffer needs easy and generalized access to a bunch of packet and protocol related meta-information used for displaying lots of different protocols, filtering, and so on. Abstracting fields makes a lot of sense for a sniffer and most of the reasons why match up for protocol reversing and prototyping.
So there you have it. In general, I tend to use Ruby over C for this stuff. It used to be Perl. It’s not because I think I have figured out all the typical implementation gotchas or that I don’t have anything to gain by “getting closer to the wire/implementation” either. It’s more because I’m lazy and/or slammed most of the time. It’s also been fun learning and using Ruby more.
If you prefer C/C++, then use it instead.
Python? great!
Perl? go for it!
LUA? Why not! We all may be doing it soon.
.NET? that’s swell!
Java? … really?
KSH? yea! That might even win you a beer ("http://www.securiteam.com/tools/6V0011PEBY.html")!
WSH? um… wow! ok (but definitely no beer).
Whatever… don’t listen to me or anybody else, just use what you know and/or like and/or want to learn more of.
I guess if there’s been a point to the C versus Ruby thing, it’s that the real key is the end result. Language wars are for people with more free time on their hands than I have. If a language feels like it slows you down, then it’s probably not the right one. I say “get it done” first. If it makes you feel better, just call your early forays “prototyping”. You can always rewrite it in something else once you know how the protocol works. I do sometimes. To an extent, I sometimes think of “C vs. Ruby or Perl” that way, but in practice, I tend to use the four letter languages most of the time.
Anyway, back to the general topic of protocol exploration, and in summary:
For this and the last installment I’ve been talking about iSCSI; a protocol with pretty good RFC documentation and some open source code guiding us along the process of understanding and dissecting PDU’s. I’ll be talking about tackling lesser understood and undocumented protocols more in future posts. If iSCSI had been totally undocumented we’d have to figure a lot out on our own. Frankly, iSCSI could take a while to understand if it weren’t so well documented. It’s a pretty complicated protocol as far as they go. I’ve only scratched the surface by talking about the BHS.
I’ve gotten some kind words and gentle nudges to get me back to writing this from one or two of you and I want to say again “Thanks for the feedback!”. It should not have taken so long to get the 2nd installment out.
http://www.matasano.com/log/973/exploring-protocols-2-writing-some-tools/
The protocol exploration and tools journey often starts out something like this:
1. Got an unknown or little known protocol we’d like to learn more about and maybe mess with.
2. Think: “Hey, self… Wireshark ("http://www.wireshark.org/") has lots of decodes. Lets check it out.” Then one of two things often happens:
or…
Turns out it is a protocol wireshark DOES decode. “Nice! But what if we want to actively or passively mess with it? Wireshark is a sniffer…”
Let me be clear before going any further with this: Wireshark is fantastic! I use it ALL the time. I don’t have to tell anyone who’s ever used it how long and impressive it’s list of features and dissectors ("http://www.wireshark.org/docs/dfref/") is. It’s gotten a great reputation and it’s well deserved.
Turns out this is a protocol wireshark doesn’t know about. But it does seem to have a framework for building new ones? Shouldn’t be too hard to just plug in a new decode ("http://www.wireshark.org/docs/wsdg_html/")… should it?
But I’ve not had much luck using Wireshark’s framework to add new dissectors or make use of existing ones in other programs. The dissectors Wireshark supports are written in C ("http://anonsvn.wireshark.org/wireshark/trunk/doc/README.developer") and compiled in at build time [** see note] Sure it uses pcap and there’s numerous pcap based tools for packet mangling/manipulation. That might warrant the effort, but WireShark is first and foremost a sniffer, and we need to do a lot more than sniff protocols. Its dissectors aren’t yet as easy as on might like to make available in other programs. Every time I’ve looked into it I end up deciding to just end up writing my own tools from scratch. The reasons will probably become evident as I go on.
** Note: this may be in the process of changing. The Wireshark folks are beginning to implement a LUA interpreter ("http://wiki.wireshark.org/Lua") right into the sniffer. LUA ("http://en.wikipedia.org/wiki/Lua_%28programming_language%29") is an embedded programming language. It’s cool stuff, but so far it’s still pretty new in Wireshark and it’s still just intended as a tool for developing C dissectors.
But anyway… back to my numbers:
3. What’s needed a more flexible framework. “This is not the wheel I am looking for. Reinvent!!!”
Ok so bear with me. I’m going to jump ahead to the tools and talk some about the techniques I’ve used to attack the problem above in the real world. I’ll digress a bit and yammer seemingly pointlessly about a few iSCSI details too.
Yes, we’ll need a protocol to talk about. For simplicity (… ok well, “reference” anyway) we’re going to stick with iSCSI from the first installment. Wireshark actually dissects iSCSI quite completely. This may defeat the point of the discussion about exploring unknown protocols for some, but for now it’s still a good thing since we can actually compare what Wireshark can do with what we build with our own toolchain.
Let’s start with a simple iSCSI PDU hexdump for reference:
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_hexdump.jpg
Our initial goal was to figure out a bit about the format. I talked about that in the last post. Check out the last “Exploring Protocols 1 ("http://www.matasano.com/log/885/exploring-protocols-part-1/")“. Now we’ll try to dissect iSCSI PDU’s in a manner similar to Wireshark.
In the not too distant past, I would have probably used C/C++ for this. This is mostly because C/C++ has ’structs’ and pointers. The ’struct’ lets you describe binary data to your program by defining fields as elements a structure. Using the structure as the type for a pointer variable lets you apply the structure to a buffer in memory like an overlay. This is pretty obvious stuff to anybody who does any C coding at all, but not everybody does. This simple feature is really powerful and efficient. I still get a few goosebumps when my structures “lay over” properly.
Here is an example of a trivial iSCSI_dissector in C ("http://www.matasano.com/log/973/exploring-protocols-2-writing-some-tools/iscsi_dissectc/"). This sample program is not too robust, but serves as a good starting point. I used a structure borrowed and adapted from linux-iscsi-3.6.3 ("http://linux-iscsi.sourceforge.net/"). You should be able to compile this program with “gcc -o iscsi_dissect iscsi_dissect.c” on any *ix and maybe windows. First lets just look at the structure defined for the header:
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_c_struct.jpg
The structure for the header defines the fields and sizes based on what the iSCSI RFC calls for. The size of the datatype (uint*_t) defines the width of the field.
There are some funky field alignment issues that the linux-iscsi header structure doesn’t try to fully address in the BHS structure definition, though.
This is just nitpicking (bitpicking?) and may distract a little from protocol dissection, but lets take a quick look again at the first four bytes from the RFC 3720 syntax description. This time, the structure elements from linux-iscsi are lined up with each field from the RFC description.
http://www.matasano.com/log/wp-content/uploads/2007/10/BHS_with_vars.jpg
Neither the ‘opcode’ nor ‘flags’ elements in the structure are supposed to take up an entire byte in the BHS if you read the RFC “literally”.
The Basic Header Segment as defined in the RFC has a null bit, followed by an ‘I’ bit, a 6-bit opcode, and a single ‘F’ (final) bit followed by 7 bits allocated as “opcode specific”, or as linux-iscsi called it, “reserved”.
Code:
10.2.1.1 I For request PDUs, the I bit set to 1 is an immediate delivery
marker. 10.2.1.2. Opcode The Opcode indicates the type of iSCSI PDU the header
encapsulates.
...
So what about that 6-bit opcode after ‘F’? Well if you look closely in the spec, you wont find any op-code higher than the number ‘63′ (or 0×3f in hex). Why? Because at least 7 bits are needed to store for the number 64 (or 0×40 hex) and higher. So there can never be more than 63 types of opcode represented in the “Opcode” field alone. Like so:
Code:
63 is "0 0 1 1 1 1 1 1" in bits
Code:
64 is "0 1 0 0 0 0 0 0"
Code:
10.2.1.3. Final (F) bit When set to 1 it indicates the final (or only) PDU of a
sequence. 10.2.1.4. Opcode-specific Fields These fields have different meanings for different opcode
types.
It’s a common practice not to define every single bit in a field separately and just combine them in one byte. When using the structure, you’d just use bitwise operations against various values to set, check and clear individual bits.
Protocols often try to squeeze a use out of every single bit. This can give rise to occasional situations where a weird alignment issue like the ‘rsvd1′ or ‘opcode’ ones can result in unexpected behaviors. Depending on the implementation and what assumptions the developer makes, assigning values to anything after the ‘I’ or ‘F’ might inadvertently get set or cleared. This type of thing can might have dangerous side effects.
Code:
Queue haunted house organ music...
So, here’s what the output from iscsi_dissect.c looks like (cleaned up slightly for display):
Code:
Dissecting iSCSI frame: (Actual PDU Length = 136 bytes)
Format is big endian so the hex order matches wire.
Opcode: = 36 : (0x24)
Flags: = 128 : (0x80)
Op-Specific1 = 0 : (0x00)
Op-Specific2 = 0 : (0x00)
TotalAHSLen: = 0 : (0x00)
DataSegmentLen = 85 : (0x000055)
LUN: hex: = 0000000000000000
InitTaskTag: = 1 : (0x00000001)
Opcode Specific Fields in hex:
ff ff ff ff 00 00 00 02 00 00 00 02 00 00 00 03 00
00 00 00 00 00 00 00 00 00 00 00 Data segment strings: (segment length: 88 bytes):
TargetName=iqn.2009-08.com.splatomatic:storage.lvmx00
TargetAddress=192.168.1.10:3260,1x00
x00
x00
x00
This version also resembles the way most actual iSCSI implementations probably work. For grey/black-box security testing, this can be an advantage. You may gain insights that will help you find where implementation flaws lurk in the real product. Using the same language that as actual implementation can arguably let you get closer to the same thought processes the developers used. If there was a point to that random ranting about partial use of bit-fields within bytes, that was it. The rant should also serve as a case study in following useless random rabbit-holes too early in the exploration phase. Which is another good lesson on exploring protocols and would make a good blog-post by itself. I’m sure most people have already dropped out of this overly long post by now. Too bad for them, they’ll totally miss out on the best part.
Ok… for some, the problem with C is that, well, it can be too rigid. I personally think that higher level interpreted languages are better for doing exploratory work like this. As you’re examining unfamiliar and possibly undocumented protocols or formats, you’re constantly refining your idea of what your structures should look like and what you want to do with them. You don’t want to have to stop and recompile for every change. You *really* dont want to find yourself having to redesign your tools several times over.
One of the frustrating things about writing quick/dirty tools from scratch for fault testing or fuzzing is first getting rid of faults in your own testing tools. Usually the quicker and dirtier your C is, the harder it becomes to work with. There are lots of programmers out there that this is may not be a problem for. They probably stopped reading a while ago too. But even they end up relying on abstraction to some extent.
My experience has been that using higher level languages gives you more freedom to experiment and you get a lot of relatively stable free abstraction already without having to build it yourself. To put it bluntly, you can get away with more, for longer, usually with less code. On the other hand, all that abstraction can get in your way sometimes when you need to get closer to the wire, but this isn’t as big of a deal as people make it out to be.
So lets see how we could have written a similar dissector/decoder in an interpreted language. I’m going to use Ruby. Ruby is nice. It has some particularly useful qualities for protocol exploration (besides just being “nice”

One thing ruby doesn’t really do without add-ons is ’structures’. The way Ruby uses references to objects is similar to pointers. Actually, Ruby’s references definitely harken back to C/C++, the language it’s written in. But the similarities aren’t completely linear. It’s also a moot point because what really helps protocol design is ’structs’.
It’s an interpreted scripting language. We can make modifications and tweaks on the fly much more easily. No recompiling necessary.
Ruby code is very portable. Very few problems getting your code to work on different platforms.
It’s got built in large numbers, a string data-type that doubles as a raw buffer, and lots of other free and generally well designed classes methods for for doing all sorts of commonly useful things. All in all this makes for fewer things to screw up as you’re cobbling something together quickly (as I tend to need to).
Modular design is, I think, actually harder *not* to do with Ruby. Keeping things modular when developing exploratory tools will mean that exploration phase actually yields highly useable code that we can adapt very easily down the road.
Did I mention Ruby is nice?
“But somebody must have done something about this by now!”, you say? Actually several have. One such thing is called BitStruct ("http://redshift.sourceforge.net/bit-struct/"). I’ve been using it a lot. Not only does BitStruct let you map out binary structures in a way similar to C’s ’struct’, but it’s goes further. It is really handy for keeping track of and getting at useful field-related information you’re likely to want. Things like descriptions, sizes, offsets, and even display format are all available as parts of a hash and through free methods. Extending the hash-based design for say “annotations” is as easy as tying new elements to a field’s hash. Bit-struct also has its own free (if somehwat rudimentary) ‘inspect’ and ‘inspect_detailed’ methods for dissecting your structures in human readable format. There’s a ‘describe’ class method that returns a human-readable description of the format itself. BitStruct has some alignment quirks of its own, but like C’s structs you can work around them.
Take a look at this code. It’s a lot more descriptive than the C struct version. The descriptions are actually part of the code, not comments. The formats for fields are specified right in the structure too!
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_bitstruct.jpg
Unlike the C version, the rest of the code is really short. So short I’ll paste it all too:
http://www.matasano.com/log/wp-content/uploads/2007/10/iSCSI_bitstruct_rest.jpg
So here is the iSCSI_dissector in Ruby ("http://www.matasano.com/log/973/exploring-protocols-2-writing-some-tools/iscsi_dissectrbtxt/"). Getting BitStruct ("http://redshift.sourceforge.net/bit-struct/bit-struct-0.10.tgz") is a prerequisite ofcourse. Here’s how we run it and what our output looks like:
Code:
$ ruby ./iscsi_dissect.rb -- Header Dissection --
Type: ISCSI_bhs:
Decode:
I bit = 0
Opcode = 36
F bit = 1
Opcode-specific 1 = 0x00
Opcode-specific 2 = 0x00
Opcode-specific 3 = 0x00
TotalAHSLength = 0
DataSegmentLength = 85
LUN or Op-specific = 0x0000000000000000
Initiator Task Tag = 1
Opcode-specific 4-12 = "377377377377�00�00�00
�02�00�00�00�02�00�00�00�03�00�00�00�00
�00�00�00�00�00�00�00�00"
Data Segment Body = "TargetName=iqn.2009-08.com.splatomatic:storage.lvm�00TargetAddress=192.168.1.10:3260,1�00�00�00�00" -- Data Segment Body --
TargetName=iqn.2009-08.com.splatomatic:storage.lvmTargetAddress=192.168.1.10:3260,1
It’s interesting to note that the dissector framework in Wireshark uses an similar notion of “adding fields” not unlike BitStruct’s. The sniffer needs easy and generalized access to a bunch of packet and protocol related meta-information used for displaying lots of different protocols, filtering, and so on. Abstracting fields makes a lot of sense for a sniffer and most of the reasons why match up for protocol reversing and prototyping.
So there you have it. In general, I tend to use Ruby over C for this stuff. It used to be Perl. It’s not because I think I have figured out all the typical implementation gotchas or that I don’t have anything to gain by “getting closer to the wire/implementation” either. It’s more because I’m lazy and/or slammed most of the time. It’s also been fun learning and using Ruby more.
If you prefer C/C++, then use it instead.
Python? great!
Perl? go for it!
LUA? Why not! We all may be doing it soon.
.NET? that’s swell!
Java? … really?
KSH? yea! That might even win you a beer ("http://www.securiteam.com/tools/6V0011PEBY.html")!
WSH? um… wow! ok (but definitely no beer).
Whatever… don’t listen to me or anybody else, just use what you know and/or like and/or want to learn more of.
I guess if there’s been a point to the C versus Ruby thing, it’s that the real key is the end result. Language wars are for people with more free time on their hands than I have. If a language feels like it slows you down, then it’s probably not the right one. I say “get it done” first. If it makes you feel better, just call your early forays “prototyping”. You can always rewrite it in something else once you know how the protocol works. I do sometimes. To an extent, I sometimes think of “C vs. Ruby or Perl” that way, but in practice, I tend to use the four letter languages most of the time.
Anyway, back to the general topic of protocol exploration, and in summary:
For this and the last installment I’ve been talking about iSCSI; a protocol with pretty good RFC documentation and some open source code guiding us along the process of understanding and dissecting PDU’s. I’ll be talking about tackling lesser understood and undocumented protocols more in future posts. If iSCSI had been totally undocumented we’d have to figure a lot out on our own. Frankly, iSCSI could take a while to understand if it weren’t so well documented. It’s a pretty complicated protocol as far as they go. I’ve only scratched the surface by talking about the BHS.
I’ve gotten some kind words and gentle nudges to get me back to writing this from one or two of you and I want to say again “Thanks for the feedback!”. It should not have taken so long to get the 2nd installment out.
http://www.matasano.com/log/973/exploring-protocols-2-writing-some-tools/