Applies to the practice:
Preventing remote OS detection via tcp/ip stack fingerprinting

Applicable technologies:
Solaris and unix derivatives; tcp/ip tweaking

Abstract

A technique exists to determine a remote operating system by sending obscure tcp packets and analyzing the response. Two utilites known as queso and nmap can determine with enough precision your operating system. For the curious, we have provided a link here to a working os detection tool.

Netcraft also proclaims your operating system type with their web survey, analyzing 
the httpd servers response. It can be found here.

So how can we mask our operating system from these tcp/ip stack fingerprinting tools while still being functional?

We must first look at what is sent to our tcp/ip stack, and how the operating system responds to these sometimes obscure packets. 

Here are the packets that are sent: 

             0 SYN           * THIS IS VALID, used to verify LISTEN
             1 SYN+ACK * Response to our SYN request (but we didn't send one) 
             2 FIN
             3 FIN+ACK 
             4 SYN+FIN   * THIS IS NOT SEEN IN THE WILD
             5 PSH
             6 SYN+XXX+YYY   * XXX & YYY are unused TCP flags

Here is what Solaris 2.x would respond, depending on many factors:

*- Firewalled Solaris 2.x
0 1 1 2398 SA
1 - - - -
2 - - - -
3 - - - -
4 - - - -
5 - - - -

* Solaris 2.x
0 1 1 2398 SA
1 0 0 0 R
2 - - - -

* Solaris 2.x
0 1 1 2238 SA
1 0 0 0 R
2 - - - -

The two first packets are sent. Packet one contains a SYN, to initiate the connection, the response from the target host is SYN-ACK (standard), with a window field of 2238 (depending) in hex. Packet two contains a SYN-ACK which generates a valid RST from the host (no connection was initiated by the host, hence the RST response tearing it down.)

A determining factor seems to be the window field, which happens to be a modifiable parameter in Solaris's TCP/IP stack. 

TCP_MSS_DEF

This parameter determines the default MSS (maximum segment size) for non-local destinations. The MSS is the largest chunk of data that TCP will send to the recieving end. 

Whenever a connection is about to be established, the segment size used will be set to the minimum of the smallest MTU of an outgoing interface, and from the MSS anounced by the peer. Each end annouces its MSS, (the option can only appear in a SYN segment) and if one end does not recieve an MSS option, a default of 536 is assumed. (This allows for a 20-byte IP header and a 20-byte TCP header to fit into a 576 byte IP datagram) 

In general, the larger the MSS, the better, until fragmentation occurs. This value can be set to the MTU of the outgoing interface - 40 bytes, if the value is bigger than 536. Queso expects to see a window of 8760 (2238 in hex) or 9112 (2398 in hex) and uses this information to determine the OS.

The solution under solaris 2.x 

Preventing queso and company from determining our OS. This value can be set higher that 536, without any serious side effects. You can add this to the secureip script from a previous module.

ndd -set /dev/tcp tcp_mss_def 546
echo "setting default MSS to 546"

The solution under Linux 2.0.35 

For linux, the repsonse is different, but the solution the same.

* Linux 2.0.35 to 2.0.9999 :)
0 1 1 7FE0 SA * Valid, but the window value can be tweaked i'm sure.
1 0 0 0 R     * Valid
2 - - - -
3 0 0 0 R
4 1 1 7FE0 SFA * This one can be filtered without any problems..
5 - - - -
6 1 1 7FE0 SA  * unknown options can also be filtered.

One could easily get the ip filter package from coombs.anu.edu.au and
setup the following rule to block packet #4.

block in on le0 proto tcp from any to any flags SF/SF


Masking the operating system (from an application perspective) 

1. If you use sendmail, change this field in sendmail.cf,  O SmtpGreetingMessage and modify the sendmail.hf file to something nifty.

2. Use a statically linked ls for your public ftp server, and then make it execute only and owned by root. Use truss -f chroot ~ftp /bin/ls -l to figure out dependencies
on different libraires. I've heard of ldd, use that if you want. Grab a copy of fileutils here.

3. Under Solaris, modify the /etc/default/telnetd file to read:

@paranoia> more /etc/default/telnetd 
BANNER=""

For unix variants, look for a file called issue or issue.net. You shouldn't even be running telnet; using SSH is for the security conscious. 

4.  Depending on the web server, a few hacks can be made to prevent from knowing the operating system. RFC1945 states:
 

10.14  Server

   The Server response-header field contains information about the
   software used by the origin server to handle the request. The field
   can contain multiple product tokens (Section 3.7) and comments
   identifying the server and any significant subproducts. By
   convention, the product tokens are listed in order of their
   significance for identifying the application.

       Server         = "Server" ":" 1*( product | comment )

   Example:

       Server: CERN/3.0 libwww/2.17

 Note: Revealing the specific software version of the server may
 allow the server machine to become more vulnerable to attacks
 against software that is known to contain security holes. Server
 implementors are encouraged to make this field a configurable
option. 
Here is a hack for the Apache 1.3.4 web server (since mod_headers does not offer this option).

The Header directives are processed just before the response is sent by its handler. These means that some headers that are added just before the response is sent cannot be unset or overridden. This includes headers such as "Date" and "Server". 

Insert this somewhere before using getnull()

int getnull(void) 

return 0;
}

http_protocol.c: @ line 1298, 

 /*  ap_send_header_field(r, "Server", ap_get_server_version()); */
      ap_send_header_field(r, "Server", getnull());

http_protocol.c: @ line 566,

/* ap_table_setn(r->headers_out, "Last-Modified",
              ap_gm_timestr_822(r->pool, mod_time)); /*

ap_table_setn(r->headers_out, "\nLast-Modified",
              ap_gm_timestr_822(r->pool, mod_time));
 

Comments can go to gilbert@pgci.ca

----------------------------------------------------------------------------------

Date: Mon, 22 Feb 1999 15:57:49 -0800
From: route@RESENTMENT.INFONEXUS.COM
To: BUGTRAQ@netspace.org
Subject: Re: Preventing remote OS detection

[Patrick Gilbert wrote]
|
| There are many other ways to determine the operating system as well,
| most of which are described in a fairly recent phrack article (number 54
| if I am correct)

    You are correct.  Phrack 54-09.  http://www.phrack.com

| How can we mask our operating system from these tcp/ip stack
| fingerprinting tools while still being functional?
|
| The answer can be found in the latest security improvement module at:
|
| http://www.pgci.ca/fingerprint.html

    While this article does offer some good advice towards risk mitigation,
    there are a few key points I'd like to bring to the table.

    The proposed Solaris solution (to change the default MSS to a larger value)
    is still easily fingerprintable.  Perhaps experimenting with psuedo-random
    values within a `safe` threshold would be a bit better, but this too can
    be fingerprinted.

    The article does mention a few TCP fingerprint techniques, but not TCP
    options, many of which are very stack specific.

    The article doesn't touch down on the prevention of IP or ICMP related
    fingerprinting.  There's a probably good reason for this.  It's somewhat
    difficult and very implementation specific.

    Filtering fringe packets will work to dissuade certain fingerprint checks,
    others are based off of `normal` packets.  For example, ICMP unreachable
    packets are often filled with stack specific information.  And the Solaris
    stack seems to be one of the only ones out there that does path MTU
    discovery by default (this is easily noticable by the presense of the DF
    bit in the IP header).

    The fact of the matter is that most of these fixes are stopgap measures and
    not very extensible.  The proper fix is standards compliance and ubiquitous
    support.  Of course the question then becomes which standards do we adhere
    to, and what is to be done if there isn't standard defined behavior for
    some instance...?  That's a good one.  I say, close the Internet for
    repairs.


--
I live a world of paradox... My willingness to destroy is your chance for
improvement, my hate is your faith -- my failure is your victory, a victory
that won't last.