Fundacja Rozwoju Regionu Gołdapedukacja techniczno informatyczna
Access:

» Custom IPTables extensions

Related categories: Linux | FreeBSD | Unix | Networks | Security | Security tools | Linux | Firewalls

Jaros³aw Sajko
Viewed: 8978 | Article date: 2006-08-01 13:35:03

We will show you how to implement the required functionality yourself by writing an extension module when the firewall is based on IPTables. What's more, you'll be surprised just how easy it is.

Applying system security policy to firewall rules can be a difficult task, especially if it requires functionality that the basic firewall product does not provide. Fortunately, if the firewall is based on IPTables, you can implement the required functionality yourself by writing an extension module. What’s more, you’ll be surprised just how easy it is.

About the author

Jaros³aw Sajko is a member of the Poznañ Supercomputer and Network Centre Security Team. His tasks cover a variety of information security issues, ongoing Centre operations, and penetration tests and audits conducted by the Security Team. You can find more information at the Security Team’s website at http://security.psnc.pl.

Anyone even vaguely familiar with the Internet and computers must have heard of firewalls, and anyone who’s ever dealt with IT security must have configured a software firewall at some stage. There’s much variety among available firewall systems, but of course from a technical point of view the crucial factor is the functionality they offer. Commercial firewall vendors will frequently do their best to convince you that their software offers unique and highly advanced features that the competition can only dream of, provides near-infinite filtering capabilities and comes with an inexhaustible supply of helpful and cheerful round-the-clock support.

You will learn...

  • how to write custom IPTables extensions.

You should know...

  • how the IP protocol works,

  • how operating systems work,

  • how to program in C.

The problem is that support does indeed tend to be necessary, even though a working product would be much preferable to delightful e-mail exchanges with the support staff. More often than not we would also like to see and understand why something is not working, as it soon turns out that a chosen product’s capabilities are not only finite, but frequently insufficient. The good news is that if you need unique and advanced functionality, you can develop it yourself using open source software such as IPTables, a bit of spare time and (hopefully) this article. (Which of course is not to say that commercial packages are useless).

You can download the IPTables package at www.netfilter.org, and it is supplied as standard with Linux distributions with kernel 2.4 and later. The website also provides a brief overview of the project’s history - it’s been around long enough to be considered a mature and reliable product. In my opinion, one of the package’s most powerful features is its support for custom extensions.

The Netfilter package on which IPTables is based is actually a development framework for filtering and modifying network packets. From a programmer’s point of view, its key features are:

  • hooks - specific locations in the system’s network protocol stack from which Netfilter code is called for each packet that traverses the stack,

  • functions assigned to particular hooks and called by Netfilter for each packet that traverses the protocol stack,

  • the ip_queue driver for queuing packets into user space for asynchronous processing.

The source code is extensively commented - a non-functional, but equally useful feature.

IPTables is essentially a set of modules that use Netfilter functionality to define rule tables, pattern-based packet matching criteria and actions to be taken for matching packets. All this allows Netfilter functionality to be accessed at a higher level of abstraction for clearer and more convenient use. The name IPTables originates from the fact that rule lists are represented as tables, and each named table is stored in memory.

IPTables can generally be divided into two functional components: one for port and network address translation services (PNAT) and the other for filtering services. Both components are extensible. Apart from extension modules, the package also includes user space tools that allow rules to be entered more conveniently.

Extension modules

An IPTables extension module is a typical kernel module that has to use a number of standard structures and implement several module functions. The module code also has to be re-entrant, as it is possible for its execution to be interrupted during processing by a request to process another packet. In SMP systems with large numbers of processors, the chances of interruption are much larger. Here’s a list of the basic functions that a module has to implement:

  • init_module() - module entry point, which has the basic task of registering the module within the framework, returning 0 if successful or a negative integer in case of failure,

  • cleanup_module() - module exit point; the function code should unregister the module from the Netfilter framework,

  • ipt_register_match() - used to register match extensions; takes a struct ipt_match structure as a parameter,

  • ipt_register_target() - used to register target extensions; takes a struct ipt_target structure as a parameter,

  • ipt_unregister_match() - unregisters a match extension,

  • ipt_unregister_target() - unregisters a target extension.

A module is usually used either as a target module or as a matching module, so you need to select the four relevant functions from the collection above. In fact, in actual implementations the function names are a little different, and we can also make use of standard macros. The structures passed to ipt_register_match() and ipt_register_target() are described in the Inset Extension registration structures.

Apart from the functions listed above, we also need to implement extension-specific functions, whose pointers were passed in the module registration structure. Once that’s done, we have a working module. Let’s see how all this works in practice.

Extension registration structures

Depending on the extension type (match or target), registration is done by calling one of ipt_register_match() or ipt_register_target(). Each function takes a suitable parameter structure (though the two structure types are similar). The structure fields to be filled in are:

  • name - extension module name, preferably included in the module file name (extension module files usually follow the naming convention ipt_NAME.o),

  • me - a field that should be filled with the THIS_MODULE literal to indicate the current module; the field is used by the module reference counter and therefore also the cleanup_module() function,

  • checkentry - pointer to a function that is called whenever a rule is added for the current module; the function should check the validity of the new rule,

  • destroy - optional pointer to a function that should be called when removing an entry of the current extension type,

  • match or target (depending on extension type) - the most important piece of information: a pointer to a function that matches packets or performs specific operations on matched packets.

The match structure is called struct ipt_match and the target structure is struct ipt_target.

Implementing a sample extension

Getting back to commercial products for a while, many of them provide filtering functions that are grouped into packages and accessible through a few clicks within the GUI. A certain commercial solution provides a set of simple operations collectively called Fingerprint Scrambling, which are supposed to hinder operating system fingerprinting. We will implement similar functionality using the ipt_TTL, ipt_IPID and ipt_ISN extensions. The first modifies the TTL field of an IP datagram and is available in the standard package. We will go through creating the second extension below, and developing the third one will be left as homework for the Reader.

Operating system fingerprinting

Any attack has to preceded by reconnaissance to gather information about the target. For attacks in the computer world, vital information includes the operating system type and version, and target application versions. Even without local access to the target host, we can gather information through the analysis of network packets received from the target system - a process commonly known as OS fingerprinting.

Fingerprinting can be divided into passive and active methods. Passive fingerprinting is limited to listening for packets sent by the target system, while active fingerprinting additionally involves provoking the target to respond by sending it various queries, attempting to start a TCP session etc.

Once received, the packets are analysed to see how both obligatory and optional protocol functionality is implemented by the sender system, and the correlated information is used to determine the most likely system type and version.

The name of the ipt_IPID extension is less than obvious, so let’s discuss its purpose first. One of the factors that aid remote OS fingerprinting is the ability to identify the algorithm used to calculate the value of the ID field in IP datagrams sent by the remote system (you can find more information in the Inset ID field in IP datagrams). Our job will be to modify the ID field in outgoing datagrams so as to hinder such identification.

ID field in IP datagrams

Each IP datagram header has an ID field, which is used when reassembling fragmented datagrams. Fragments that are part of the same datagram have the same unique ID - a 16-bit word, theoretically allowing up to 65536 packets fragments to be supported by the same node at any one time. If no fragmentation takes place, the ID field is basically unused, but operating systems still have to calculate its value for each packet and use a variety of algorithms for doing so. Some implementations increment the value by a constant for each datagram, others increment it by a random value from a limited range, and still others simply pick a random number for each datagram.

Other system-dependent subtleties also influence the ID value. A characteristic feature of some older operating systems is that the ID is always 0 for datagrams with the DF (Don’t Fragment) bit set, while recent Linux kernel versions always set the ID to 0 for TCP SYN/ACK packets. And these are just a few of the many implementation-specific features.

Implementation differences make the ID field very useful for fingerprinting, and it is analysed both by active scanners (such as nmap) and passive scanners (such as p0f). To determine the algorithm used by the target system, simply run nmap with the -v and -O options. If subsequent IP datagrams for a target system have predictable ID values, the system can be exploited to scan other networks (including ones inaccessible from the outside - the technique is called an idlescan and can also be performed using nmap (using the -sI options).

A d v e r t i s e m e n t

Page: 1 2 3
Buy article Buy subscription
Buy now add to cart
add to cart
Standard price: 2€/$3 Standard price: 25€/$30
Buy article for as little as (2€/$3) each allow access to individual articles. Buy a full access to our Hakin9 archive portal. You will be able to read the articles from all archive issues from year 2005 and 2006. For just 25€/$30 you get unrestricted access to the entire website for the whole year.
SDJhakin9

.SDJ Users:


.:Login
.:Password

[Register]
[Forgotten your password?]

...hakin9 StarterKit IT Practical Solutions for Newbies

...Shopping Cart

sum: 0 €
Choose currency:

...SUBSCRIBE TO
hakin9 Print Edition


...Advertisement



...Conferences

...Topics

...Advertisement

 

 

Subscribe | Contact Us | Newsletter | See all issues | About Hakin9
Copyright C 2006 by Software Developer's Journal. All rights reserved.