|
Vulnerability fingerprinting Affected most unices Description 'fobic' made following paper: Examining Advanced Remote OS Detection Methods/Concepts using Perl. This paper discusses the theory and practice behind OS detection with a specific focus on the practice related to the PERL programming language. Methods and concepts for remote operating system detection are closely examined and implemented into Perl code. Throughout the years, a host of information has been posted online about the use of various techniques and methods to determine what OS (operating system) a certain host is running. Since these OS detection techniques rely on certain factors that are not constant, the accuracy of these OS predictions can not be guaranteed a full 100 percent. This paper stresses the importance of these factors and gives pointers on how to apply these various OS detection methods in perl. Before we get to Advanced remote OS detection concepts, we wanted to briefly point out some other methods which can be used to detect a remote hosts' OS. These techniques may old, but they get the job done. (1) telnet banner grabbing This is pretty self-explanatory to you. But just in-case, you connect to telnetd on the remote host, and see what the telnet login banner prints. (2) FTP banner grabbing Same basic concept as telnet banner grabbing, just with ftpd instead of telnetd. (3) http head method You can try and determine an OS by checking what web server (httpd) the target is running. i.e. Microsoft-IIS should be WindowsNT/2k. There is a wide variety of techniques to determine a hosts OS. This paper discusses four ways to do so: * telnetd fingerprinting: - relies on telnet session negotiations and telopts. * identd fingerprinting: - relies on identd/auth (113) to be open. * TCP stack fingerprinting: - relies on Window, TTL, ToS, and DF. * Queso fingerprinting: - relies on Window, Seq, Ack_seq - relies on various IP/TCP header flags. * Passive fingerprinting: - closely related to TCP stack fingerprinting. - relies on Window, TTL, ToS, and DF. - relies on network traffic. We'll discuss each of these methods in more detail throughout the next couple of sections. Some terminology: * Window: TCP Packet Window-size - the maximum amount of packets that can be sent out without receiving an acknowledgement. * TTL: Time-To-Live - the maximum number of hops a packet can pass through before being discarded. * ToS: Type of Service * DF: Don't Fragment bit * MSS: Maximum Segment Size These factors can be used in determining what kind of operating system a remote host is running. Depending on the combination of all of these flags, a match can be ran against a database of flags and an operating system guess can be made. The following is a tcpdump snippet of an incoming packet: 00:44:09.194998 eth0 < 203.9.66.52.www > my.ip.com.domain: S 2006693595:2006693595(0) ack 1 win 9112 <mss 536> (DF) (ttl 232, id 25119) When we discard some of the information enclosed in the packet we will get the following: +-> Device +-> Source Address +-> Dont Frag bit | | | eth0 < 203.9.66.52.www > my.ip.com.domain: win 9112 (DF) (ttl 232) | | | +-> Dest Address | +-> TTL value | +-> TCP Window-size Tcpdump has gathered the following information about the packet: +++++++++++++++++++++++++++++++++++++++++++++++++ + Source Address : my.ip.com + + Source Port : domain (53) + + Dest. Address : 203.9.66.52 (www.sun.com.au) + + Dest. Port : www (80) + + Window Size : 9112 (0x2398) + + TTL Value : 232 + + ToS Value : 0 + + DF (Dont Frag) : ON + + MSS Value : 536 + +++++++++++++++++++++++++++++++++++++++++++++++++ The window (9112) could be that of a Solaris box. Also the TTL (232) and the ToS (0) match the profile of a Solaris host, given some leeway. The default TTL for the Solaris Operating System is 255, given the number of hops it hits on it's path to the destination address, the TTL value may decrease to a value such as 232. A little side-note on the window-size. Generally, a high window-size indicates a UNIX machine, whereas lower window sizes often are Windows machines, routers, switches, etc... The following traceroute confirms our expectations of the actual TTL value laying close to 255: 1 my.ip.com (127.0.0.1) 148.010 ms 138.609 ms 118.812 ms 2 ??.kpnbelgium.be (194.119.225.185) 129.111 ms 138.566 ms 118.877 ms 3 ??.kpnbelgium.be (194.119.228.161) 119.008 ms 119.300 ms 128.546 ms ... ... 20 fddi0-0.chw1.sydney.telstra.net (139.130.36.227) 509.930 ms 519.879 ms 509.941 ms 21 sunmi1.lnk.telstra.net (139.130.37.142) 538.911 ms !X 509.879 ms !X 549.903 ms !X Hop 21 is the last hop we can get to from the internet. The !X signals a "communication administratively prohibited": Our TTL : 232 # of hops : 21 + --- Total TTL : 253 We lack two hops to get to the default Solaris TTL value of 255, so we know that there are 2 more hops behind hop 21. The first one being one of the internetworking devices within the internal network. The second one being the target host (203.9.66.52) with the Solaris TTL of 255. Now we can (with some certainty) say 203.9.66.52 is a Solaris box. Remote host path projection is an important issue when dealing with OS fingerprinting. The path a packet follows can significantly determine the differences between OS fingerprint matches. Therefore, it is always of great use to build in a "buffer" which incorporates these differences in TTL. What about remote OS detection methods in Perl? 1. Telnetd Session Negotiation (TSN) and Telnet Ops. ==================================================== This technique involves the remote host running telnetd, allowing you to connect to it. As a socket with the telnetd gets initiated, we execute a sysread() and gather the telnet session negotiation fingerprint. Such a fingerprint would look as follows: Linux <= 2.2.16 : ÿý^Xÿý ÿý#ÿý' In order to determine an OS by use of the telnet daemon, we need to know the order of the TELOPT (Telnet Option) as defined in telnet.h. Each OS has it's own sequence with the exceptions of a couple. Once we gather our ASCII fingerprint, we must first convert that to an ordinal value (1-255), and then seperately match each ordinal value to its corresponding TELOPT value. Ascii Value : ÿý^Xÿý ÿý#ÿý' Ordinal Value : 255 253 24 255 253 32 255 253 35 255 253 39 Telopts Value : IAC DO TELOPT_TTYPE IAC DO TELOPT_LINEMODE IAC DO TELOPT_XDISPLOC IAC DO TELOPT_NEW_ENVIRON Although these TELOPT values can be found in /usr/include/arpa/telnet.h, we have also added them below so you can get used to them if you are planning on doing some telnetd fingerprinting: /* telnet protocol definitions */ 255 IAC /* interpret as command: */ 254 DONT /* you are not to use option */ 253 DO /* please, you use option */ 252 WONT /* I won't use option */ 251 WILL /* I will use option */ 250 SB /* interpret as subnegotiation */ 249 GA /* you may reverse the line */ 248 EL /* erase the current line */ 247 EC /* erase the current character */ 246 AYT /* are you there */ 245 AO /* abort output--but let prog finish */ 244 IP /* interrupt process--permanently */ 243 BREAK /* break */ 242 DM /* data mark--for connect. cleaning */ 241 NOP /* nop */ 240 SE /* end sub negotiation */ 239 EOR /* end of record (transparent mode) */ 238 ABORT /* Abort process */ 237 SUSP /* Suspend process */ 236 xEOF /* End of file: EOF is already used... */ /* telnet options */ 0 TELOPT_BINARY /* 8-bit data path */ 1 TELOPT_ECHO /* echo */ 2 TELOPT_RCP /* prepare to reconnect */ 3 TELOPT_SGA /* suppress go ahead */ 4 TELOPT_NAMS /* approximate message size */ 5 TELOPT_STATUS /* give status */ 6 TELOPT_TM /* timing mark */ 7 TELOPT_RCTE /* remote controlled transmission and echo */ 8 TELOPT_NAOL /* negotiate about output line width */ 9 TELOPT_NAOP /* negotiate about output page size */ 10 TELOPT_NAOCRD /* negotiate about CR disposition */ 11 TELOPT_NAOHTS /* negotiate about horizontal tabstops */ 12 TELOPT_NAOHTD /* negotiate about horizontal tab disposition */ 13 TELOPT_NAOFFD /* negotiate about formfeed disposition */ 14 TELOPT_NAOVTS /* negotiate about vertical tab stops */ 15 TELOPT_NAOVTD /* negotiate about vertical tab disposition */ 16 TELOPT_NAOLFD /* negotiate about output LF disposition */ 17 TELOPT_XASCII /* extended ascii character set */ 18 TELOPT_LOGOUT /* force logout */ 19 TELOPT_BM /* byte macro */ 20 TELOPT_DET /* data entry terminal */ 21 TELOPT_SUPDUP /* supdup protocol */ 22 TELOPT_SUPDUPOUTPUT /* supdup output */ 23 TELOPT_SNDLOC /* send location */ 24 TELOPT_TTYPE /* terminal type */ 25 TELOPT_EOR /* end of record */ 26 TELOPT_TUID /* TACACS user identification */ 27 TELOPT_OUTMRK /* output marking */ 28 TELOPT_TTYLOC /* terminal location number */ 29 TELOPT_3270REGIME /* 3270 regime */ 30 TELOPT_X3PAD /* X.3 PAD */ 31 TELOPT_NAWS /* window size */ 32 TELOPT_TSPEED /* terminal speed */ 33 TELOPT_LFLOW /* remote flow control */ 34 TELOPT_LINEMODE /* Linemode option */ 35 TELOPT_XDISPLOC /* X Display location */ 36 TELOPT_OLD_ENVIRON /* Old - Environmental variables */ 37 TELOPT_AUTHENTICATION /* Authenticate */ 38 TELOPT_ENCRYPT /* Encryption option */ 39 TELOPT_NEW_ENVIRON /* New - Environmental variables */ 255 TELOPT_EXOPL /* extended options list */ When fingerprinting telnetd it's important to remember that these detection methods rely greatly on the default telnetd install on any operating system you're trying to fingerprint. If you're not running in.telnetd on a Linux machine, this method might be confused and think you are running another operating system then you actually are. Here's a snippet of one telnetd fingerprinting file: # daemon, daemon version, os, os version, architecture, fingerprint # 3Com SuperStack_II Switch ,,3Com,,SuperStack_II Switch,ÿý^C, # HP-UX B.10.20 ,,HP-UX,B.10.20,HP 9000,ÿý$, # Linux 2.2.9 ,,Linux,2.2.9,x86,ÿý^Xÿý ÿý#ÿý', # Cobalt Linux 3.0 ,,Cobalt Linux,3.0,mips,ÿý^Xÿý ÿý#ÿý', The problem we might encounter with this type of fingerprinting is that in some cases, several OS's have the same type of fingerprint which makes OS fingerprinting all the harder. Of course, if there's a problem, there's a solution as well. Instead of just doing a sysread() on the telnetd, we can send telnet opts to the target host, gather the reply, and match it against a database of fingerprints. By sending commands such as IAC/DO/DONT/WILL/WONT, we will get a clearer view of how each operating system responds and get a more accurate projection of a possible operating system. Example code to gather a TSN fingerprint: #!/usr/bin/perl # # TSN fingerprint example (by f0bic) # usage: ./tsn <host> (telnetd-port) # It is also possible to check for the DONT's # instead of for the DO's. use Socket; $h=$ARGV[0]; $p="23" unless $ARGV[1]; socket(S, PF_INET, SOCK_STREAM, 6); $iaddr=inet_aton($h);$paddr=sockaddr_in($p,$iaddr); if(connect(S, $paddr)) { sysread(S, $fprint, 200); # gathering telnetd fingerprint print "\n[$h - connected]\n\nfingerprint: $fprint\n"; @ords = split(//, $fprint);print "ordinal: "; foreach $tval (@ords){print ord($tval);print " ";} # ordinal print "\n\n"; } else { print "$host: cant connect!\n\n"; } Once you get a fingerprint with tsn.pl you can run it against a database and see if it pops up with a possible operating system match. Advantages: fast, doesn't require any superuser privileges. Disadvantages: less reliable, easily logged. Telnet Session Negotiation Fingerprinting Tools: 1. Telnetfp http://teso.scene.at/releases/telnetfp_0.1.2.tar.gz 2. Prod-1.0 http://www.low-level.net/f0bic/releases/prod-1.0/ 2. Identd Fingerprinting ======================== This form of fingerprinting requires the remote host to be running identd and for us to be able to connect to it. By establishing a connection with a remote ident daemon, we can gather version information about it and match the identd type, version, and compilation date with a fingerprint file to try and determine an operating system guess. The following is an example in which a connection is made to a remote identd server: ::(ninja)-([f0bic]--[/sys])$ telnet www.chemie.fu-berlin.de 113 Trying 160.45.22.11... Connected to ester.chemie.fu-berlin.de (160.45.22.11). Escape character is '^]'. VERSION 0 , 0 : X-VERSION : pidentd 3.0.7 for IRIX64 6.5 (Sep 15 1999 11:21:21) The syntax for an identd reply according to RFC 1413 is as follows: <port-on-server> , <port-on-client> : <resp-type> : <add-info> In our example we queried for VERSION only, so ports where not displayed so the identd reply sent "0" for both serverport aswell as clientport. The response type (resp-type) is X-VERSION, and the additional information is pidentd 3.0.7 for IRIX64 6.5 (Sep 15 1999 11:21:21). This tells us the remote daemon is "pidentd" version 3.0.7 running on IRIX64 6.5, compiled on Sep 15 1999 11:21:21. Most of the identd replies do not contain indications such as IRIX does to specify the operating system. The following ident reply is that of a FreeBSD 4.2-stable machine: 0 , 0 : X-VERSION : 2.8.5 (Compiled: 11:18:59 Oct 23 2000) In the example above we cannot directly determine what operating system the remote host is running. Although we do not have *that* much information we can still match the version and compilation date to FreeBSD 4.2-stable. Advantages: fast, doesn't require any superuser privileges. Disadvantages: less reliable, easily logged, requires for auth to be running Identd OS Fingerprinting Tools: 1. identfp http://www.synnergy.net/Archives/Utilities/dethy/identfp.tar.gz 3. TCP Stack-based Fingerprinting (TSF) ======================================= This is a more reliable OS detection technique involving packet manipulation. Since we are crafting packets with TSF we require superuser privileges. We are relying on SOCK_RAW (or Net::RawIP). This method works as follows: +---------------+ SYN +-------------------+ | | ------------------------------> | | | Source | | Destination | | | <------------------------------ | | +---------------+ SYN|ACK +-------------------+ | | | +----------------------+ | Packet Information: | |----------------------| | | | Source: <src-addr> | | Src-Port: <src-port> | | Dest.: <dst-addr> | | Dst-Port: <dst-port> | | | |----------------------| | | | Window: <windowsize> | | TTL: <TTL value> | | ToS: <ToS value> | | DF: <ON or OFF> | | MSS: <MSS value> | | | +----------------------+ As you can see in the above diagram, we received a SYN|ACK reply back, which indicates the port is in LISTENING state. If it weren't a LISTENING port, we would receive an RST|ACK reply. Once we have received a SYN|ACK reply, a sequence of events has to take place before we can start fingerprinting the operating system: +---------+ | SYN|ACK | +---------+ | | +---------------------------+ ----> | <1> Information Gathering | +---------------------------+ | | +--------------------+ --> | <2> Value Matching | | Match ? YES or NO | +--------------------+ | | ------------------------------- | | v v +------------------------+ +-------------------------+ | YES: continue matching | | NO: unknown fingerprint | +------------------------+ +-------------------------+ | | v +--------------------------+ | <3> Host Path Projection | | Still a match? YES or NO | +--------------------------+ | | +-------------------------+ |--> | NO: unknown fingerprint | | +-------------------------+ | | +--------------------+ |--> | YES: OS identified | +--------------------+ <1> Information Gathering We need to gather the Window, TTL, ToS, and DF values so we can make an approximate match in the fingerprint database. This fingerprint database should be comprised of default windowsizes, ttl values, tos values, and DF (on or off). By adapting this format one can make an accurate assessment of the YES/NO tree structure diagram for TCP Stack Fingerprinting. Example TSF Database File: # os,version,architecture,window,ttl,tos,df # DF - 1 for ON / 0 for OFF AIX,4.2,,65535,64,0,1 AIX,3.0,,16384,64,0,1 Cisco IOS,11.3,Cisco Router,4128,255,16,1 Solaris,,x86,9112,255,0,1 Solaris,8,sparc,24656,64,0,1 <2> TCP Stack Value Matching After we have gathered the values, we have to run them against the database of known fingerprints and see if a match can be made. The TTL is no constant since it relies on the number of hops the packet travels through to get from the source host to the destination host. Hence, we'll accept this match and leave the TTL matching over to the Host Path Projection check. For the example we are gonna use www.sun.com.au again. # Packet information received from www.sun.com.au Window: 9112 / TTL: 232 / ToS: 0 / DF: ON # the Window, ToS, and DF are resemblant to those of the # Solaris operating system. The TTL on the other hand is # still in doubt.. since it is not 255 exactly. Here's where # host path projection comes in. <3> Host Path Projection (HPP) By projecting the path a packet traversed, we can determine a somewhat accurate TTL value and make a possible OS guess. The rule of thumb when dealing with TTL values is. Take the TTL value of the database and let it lay between that and the preceding TTL value + 1. +------------------------------------+ | TTL Value | TTL good match | |------------------------------------| | 32 | 0 - 32 | | 64 | 33 - 64 | | 128 | 65 - 128 | | 255 | 129 - 255 | +------------------------------------+ If we run our TTL value against the table above, we come up with the following: The packet TTL value of 232 lies between the TTL good match value of 129 through 255, so we can assume that the TTL on the target box is probably 255, giving us a positive match for: x86 Solaris Operating System (Solaris,,x86,9112,255,0,1) In practice the TTL Value of 255 won't come anywhere near that of 129 because that would be 126 hops, which seems kind of infeasible. But it's always a good rule of thumb for a positive match. The following is some example code for TSF, we haven't put up the entire sock_raw connection, just the fingerprinting part, and where to find it in the packet. If you want to know how to make a SOCK_RAW connection in Perl, we strongly suggest you download Net::RawIP (you'll prolly need it anyways) and "man" it afterwards. #!/usr/bin/perl use Net::RawIP; # here's where the SOCK_RAW connection goes. # you can either use Socket w/ SOCK_RAW or use Net::RawIP. # # You can set whatever flags you want depending on which type # of scan you want to perform. Just edit the syntax:) # # $packet->set({ ip => { saddr => $src, daddr => $daddr}, # tcp => { source => $sport, dest => $dport, syn => 1, psh => 1 } }); # sub fingerprint_it { $packet->bset(substr($_[2],$offset)); my ($tos, $ttl, $saddr, $desaddr, $soport, $deport, $windowsize) = $packet->get( {ip => [qw(tos ttl saddr daddr)], tcp => [qw(source dest window)] }); if($windowsize) { # yay! we've got a window!!! if($windowsize eq "9112") { # windowsize matching if(($ttl <= "255") && ($ttl >= "129")) { # HPP TTL matching $os="Solaris"; } } # here's where you can add some more OS matches # ... # ... else { print "\n\n Unknown Fingerprint\n\n"; exit(0); } } print "\n\n-- Operating System Guess: $os\n\n"; } You can read all the Window, TTL, ToS, and DF values into an array, which would make the code a little cleaner, and allow for easier updating. Just wanted to show how this fingerprinting works by using the "if" structure. Advantages: fast, more accurate then TSN fingerprinting Disadvantages: require superuser TCP Stack-based Fingerprinting tools: 1. nmap http://www.insecure.org/nmap 4. Multi-Flag TCP Stack-based Fingerprinting (Queso approach) ============================================================= In comparison to TCP Stack-based Fingerprinting (TSF), Queso relies on 7 checks instead of 1. When performing Queso fingerprinting, 7 packets are sent out from source to destination, each with different flags. Here's a concept diagram of the type of scans performed with Queso fingerprinting. +----------------+ | QueSO Concepts | +-----------------------------------------------------+ | SEND | INFO | |-----------------------------------------------------| | | | | SYN | Determine State of Port | | | | | SYN+ACK | SYN|ACK test | | | | | FIN | FIN test | | | | | FIN+ACK | FIN|ACK test | | | | | SYN+FIN | SYN|FIN test | | | | | PSH | PSH test | | | | | SYN+XXX+YYY | SYN|XXX|YYY test | | | | +-----------------------------------------------------+ First off, a SYN packet is sent to determine if the port is in LISTENING state. If it is, we will receive a SYN|ACK. If it is not, we will receive an RST|ACK reply. Besides the reply, each of the 7 checks also determine whether a seqnum, acknum, and window is present in the packet header. In order to narrow down the broad spectrum of possible operating systems, a queso packet which is sent out over the network (whether it's SYN, SYN|ACK, FIN,...) contains forged IP and TCP header information, as well as additional information dumped into two unused TCP flags (XXX and YYY). The unused TCP flags, XXX and YYY respectively in this example, usually do not change the state of the packet and are safe to use in conjunction with any other header values. The following is a diagram of the forged IP and TCP headers, along with its faked values. The information included in the following diagrams is based on that defined in "tcpip.c" included in the queso remote os detection tool. Depending on what kind of fingerprints file you are using, you might want to change these values as you see them fit. +-------------------+ | Forged IP Header | |------------------------------------------+ | header length | 5 | | ip version | 4 (IPv4) | | tos | 0 | | total length | 40 | | offset | 0 | | id | 31337 + <src-port> | | ttl | 255 | | source | <src-addr> | | destination | <dest-addr> | | ip checksum | variable | | protocol | tcp | +------------------------------------------+ +-------------------+ | Forged TCP Header | |------------------------------------------+ | source port | <src-port> | | destination port | <dest-port> | | seq | variable | | ack | 0 | | ( x2_offset | 0x50 (80) ) | | x2 (unused) | 0 unless x2_offset | | offset | 5 unless x2_offset | | flags | variable | | tcp checksum | variable | | window | 0x1234 (4660) | | urgent pointer | 0 | +------------------------------------------+ These forged IP and TCP headers are of great importance to the accuracy of the TCP flags tests. The following is an example of a full Queso scan ran against a Linux 2.0.35 machine: (T1-7 == test 1 through test 7). T1 - SYN +------------+ SYN +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ SYN|ACK +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: SYN|ACK | | seq: 1 (yes) | | ack: 1 (yes) | | window: 0x7FE0 (32736) | +-------------------------+ | T1:SA:1:1:0x7FE0 | +-------------------------+ T2 - SYN|ACK +------------+ SYN|ACK +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ RST +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: RST | | seq: 0 (no) | | ack: 0 (no) | | window: 0 (no) | +-------------------------+ | T2:R:0:0:0 | +-------------------------+ T3 - FIN +------------+ FIN +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ no reply +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: - (none) | | seq: - (none) | | ack: - (none) | | window: - (none) | +-------------------------+ | T3:-:-:-:- | +-------------------------+ T4 - FIN|ACK +------------+ FIN|ACK +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ RST +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: RST | | seq: 0 (no) | | ack: 0 (no) | | window: 0 (no) | +-------------------------+ | T4:R:0:0:0 | +-------------------------+ T5 - SYN|FIN +------------+ SYN|FIN +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ SYN|FIN|ACK +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: SYN|FIN|ACK | | seq: 1 (yes) | | ack: 1 (yes) | | window: 0x7FE0 (32736) | +-------------------------+ | T5:SFA:1:1:0x7FE0 | +-------------------------+ T6 - PSH +------------+ PSH +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ no reply +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: - (none) | | seq: - (none) | | ack: - (none) | | window: - (none) | +-------------------------+ | T6:-:-:-:- | +-------------------------+ T7 - SYN|XXX|YYY +------------+ SYN|XXX|YYY +-------------------+ | | -----------------------------------> | | | Source | | Destination | | | <----------------------------------- | | +------------+ SYN|ACK +-------------------+ | +-------------------------+ | Packet Information: | |-------------------------| | | | reply: SYN|ACK | | seq: 1 (yes) | | ack: 1 (yes) | | window: 0x7FE0 (32736) | +-------------------------+ | T7:SA:1:1:0x7FE0 | +-------------------------+ Once we've conducted the 7 tests it's time to find a match (or not) for them. T1:SA:1:1:0x7FE0 T2:R:0:0:0 T3:-:-:-:- T4:R:0:0:0 T5:SFA:1:1:0x7FE0 T6:-:-:-:- T7:SA:1:1:0x7FE0 We seem to have found a match: Linux 2.0.35 By performing these 7 tests and forging the TCP and IP headers we have a more accurate picture of a possible operating system. Different operating systems will handle these tests, and forged headers each in their own manner, which makes fingerprinting all the easier. This is the "the more, the merrier" way. The more stuff you send to the operating system, the more likely you're going to get a more accurate/detailed match. The following is some example code for Multi-Flag TCP Stack-based fingerprinting (The Queso approach). This is not the entire code because that would make this a codefile instead of what it's meant to be, a paper. In the following segment of code you can edit whatever flags you need to establish the 7 requests. #!/usr/bin/perl use Net::RawIP; # QueSO.pl [ by f0bic ] # [ well atleast part of it:) ] # # here's where the SOCK_RAW connection goes. # you can either use Socket w/ SOCK_RAW or use Net::RawIP. # # You can set whatever flags you want depending on which type # of scan you want to perform. Just edit the syntax:) # # $id = "31337" + $sport; # $csum = rand(); # # Test 5 - SYN|FIN # # $packet->set({ ip => { saddr => $src, daddr => $daddr, ihl => "5", version => "4", # tos => "0", tot_len => "40", frag_off => "0", ttl => "255", # id => $id, check => $csum }, # # tcp => { source => $sport, dest => $dport, syn => 1, fin => 1, # seq => $seq, ack_seq => "0", doff => "5", check => $csum, # window => "0x1234", urg_ptr => "0"} }); # # Houston, we have liftoff:) # sub fingerprint_syn_fin { # here's the fingerprinting process for the SYN|FIN scan; $packet->bset(substr($_[2],$offset)); my ($saddr, $desaddr, $soport, $deport, $windowsize, $ack, $fin, $syn, $psh, $urg, $rst, $seq, $seq_ack) = $packet->get( {ip => [qw(saddr daddr)], tcp => [qw(source dest window ack fin syn psh urg rst seq seq_ack)] }); # I'm sure from this point on you can figure it out on your own. # fin (=1 for yes / =0 for no), etc.. etc.. :) } Advantages: fast, more accurate then TSN and TSF fingerprinting. Disadvantages: require superuser, multiple scans might trigger IDS systems. Multi-Flag TCP Stack-based Fingerprinting (Queso) tools: 1. nmap http://www.insecure.org/nmap 2. QueSO http://packetstorm.securify.com/UNIX/scanners/queso-980922.tar.gz 5. Passive OS Fingerprinting/Network Mapping ============================================ Lance Spitzner released a real nice paper on this subject in which he described the technique of fingerprinting hosts without them knowing about it. The basic concept behind this idea is setting a network interface in promiscious mode and performing fingerprinting on the packets received. This is basically the same idea as TCP Stack-based Fingerprinting (TSF), but we cut the first step -sending a packet out--and thus we are sniffing network traffic. Making use of this technique, one can also gain information about open ports, and the like. In other words map the entire Internet (Copyright Subterrain.Net @ Toorcon/Defcon). Since this technique is very similar to TCP Stack-based Fingerprinting, we are not gonna go into much detail about this. Here's a basic diagram of the concept: +--> stream of network traffic (yea i know, looks lame) | | ==================================================================== | | +-----------------+ | | | Passive Sniffer | | | +-----------------+ | +---------------------------+ | Packets Sniffed: | |---------------------------| |#1 - Source: <src-addr> | | Dest. : <dst-addr> | | S-port: <src-port> | | D-port: <dst-port> | | window: <windowsize> | | tos : <tos> | | ttl : <ttl> | | mss : <mss> | | DF : ON/OFF | |---------------------------| |#2 - ...... | | | +---------------------------+ Based on these values that we gathered, we can make an Operating System guess in more or less that same way that we did with TSF. We are also using a file with fingerprint matches and try and combine the values we gathered with the values enclosed within the fingerprint file. Since Craig Smith developed passfing, a passive OS fingerprinting tool in perl, 'fobic' decided not to put up perl code, so you can look at his code and check it out. Advantages: fast, same level of accuracy as TSF, totally stealth. Disadvantages: require superuser, no target specified. Passive OS Fingerprinting/Network Mapping tools: 1. Siphon http://www.subterrain.net/projects/siphon/ 2. Passfing http://packetstorm.securify.com/UNIX/IDS/passfing.tar.gz Solution Although these OS detection techniques are pretty accurate, and give a clear view of a potential OS a host might be running, they cannot always give an operating system version. Some operating systems sometimes have the same fingerprint match, which makes accuracy all the harder. Then again, new techniques might come along that could allow us to fingerprint easier and maybe even in a more stealthy manner.