Defeat Nmap OS Fingerprinting with ippersonality & iplog
Remote OS Fingerprinting is becoming more and more important, not only for security pen-testers,but for the black-hat. Just because Nmap is getting popularity as the tool for guessing which OS is running in a remote system, some security tools have been developed to fake Nmap in its OS Fingerprinting purpose. This document describes a solution to defeat Nmap and behave like another chosen operating system, as well as a demonstration on how can be accomplished.
IP Personality
The first and probably, best option is IP Personality. (Homepage) It’s netfilter module (then, only available for 2.4 Linux kernels) that allows us to change the IP stack behavior and ‘personality’, having multiple network personalities depending on parameters that you can specify as an iptables rule. Actually, we can change the following options:
- TCP Initial Sequence Number (ISN)
- TCP initial window size
- TCP options (their types, values and order in the packet)
- IP ID numbers
- answers to some pathological TCP packets
- answers to some UDP packets
An IP Personality overall summary is that we can change the way we answer to some packets, and we can specify which packets we want to answer in such way (it could be depending on the source ip address, the destination port, or, and that’s we are going to use, those crafted packets coming from Nmap)
Installation is fairly straight forward and well explained in the INSTALL file provided by the package; for our test purposes, our test box is a stable Debian box running a 2.4.19 kernel. By default, IP Personality netfilter module is not available in latest kernel, so we need to patch our kernel sources. Patch for adding IP Personality feature to our netfilter core is available in the IP Personality site. We also need to patch the iptables command so that it can recognize our new feature available. Once the kernel is patched and compiled, we need to reboot our box just because the patch also modifies other netfilter files (the connection tracking).
Next step is include our iptables rules related to IP Personality in our working kernel. Before doing it, we run Nmap to check our current OS:
# nmap (V. 3.10ALPHA4) scan initiated Wed Feb 19 20:26:52 2003 as: nmap -sS -O -oN nmap1.log 192.168.0.19
Interesting ports on 192.168.0.19:
(The 1597 ports scanned but not shown below are in state: closed)
Port State Service
22/tcp open ssh
25/tcp open smtp
80/tcp open http
143/tcp open imap2
Remote operating system guess: Linux Kernel 2.4.0 - 2.5.20
Uptime 106.832 days (since Tue Nov 5 00:29:33 2002)
# Nmap run completed at Wed Feb 19 20:26:58 2003 -- 1 IP address (1 host up) scanned in 7.957 seconds
Now, we can reboot to run our new patched kernel and add the iptables rules needed to fake Nmap OS guess:
voodoo:~/ippersonality-20020819-2.4.19/samples#/usr/local/sbin/iptables -t mangle -A PREROUTING -s 192.168.0.50 -d192.168.0.19 -j PERS --tweak dst --local --conf dreamcast.confi
voodoo:~/ippersonality-20020819-2.4.19/samples#/usr/local/sbin/iptables -t mangle -A OUTPUT -s 192.168.0.19 -d192.168.0.50 -j PERS --tweak src --local --conf dreamcast.conf
What we are doing with those filter rules is:
- The first one means that all packets coming from 192.168.0.50 (me) against 192.168.0.19 (server) have to be mangled and rewritten simulating a Dreamcast behavior. The PREROUTING chain is the one that can do that.
- The second one means that all packets coming from 192.168.0.19 (server) against 192.168.0.50 (me) have to be mangled and rewritten simulating a Dreamcast behavior. As is a packet going out the server, the OUTPUT chain is the responsible for that.
Checking our set-up:
voodoo:~/ippersonality-20020819-2.4.19/samples#/usr/local/sbin/iptables -L -t mangle Chain PREROUTING (policy ACCEPT) target prot opt source destination PERS all 192.168.0.50 192.168.0.19 tweak:dst local id:Dreamcast Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination PERS all 192.168.0.19 192.168.0.50 tweak:src local id:Dreamcast Chain POSTROUTING (policy ACCEPT) target prot opt source destination
It’s time to see if Nmap can report that we are still running a Linux kernel 2.4.0-2.5.20 or perhaps we can find out that our OS has changed:
# nmap (V. 3.10ALPHA4) scan initiated Wed Feb 19 21:49:18 2003 as: nmap -sS -O -oN nmap2.log 192.168.0.19
Interesting ports on 192.168.0.19:
(The 1597 ports scanned but not shown below are in state: closed)
Port State Service
22/tcp open ssh
25/tcp open smtp
80/tcp open http
143/tcp open imap2
Remote operating system guess: Sega Dreamcast
# Nmap run completed at Wed Feb 19 21:49:23 2003 -- 1 IP address (1 host up) scanned in 5.886 seconds
As you can see, we’ve fooled Nmap with our response. It’s easy to choose the OS we want to ‘run’ in the Nmap OS fingerprint and tell IP Personality to behave like that chosen OS. Let’s take a look to the dreamcast.conf file that we’ve specified when adding our iptables rules:
/* Our new OS identification */
id "Dreamcast";
/* only incoming packets will be mangled and TCP window sizes will not be changed*/
tcp {
incoming yes;
outgoing no;
max-window 32768;
}
/* We need to emulate the Dreamcast ISN time dependant generator; this can be done with the fixed-inc generator and a small increment */
tcp_isn {
type fixed-inc 2;
initial-value random;
}
tcp_options {
keep-unknown yes;
keep-unused no;
isolated-packets yes;
code { copy(mss); }
}
/* now we have to follow nmap Dreamcast signature and answer like a Dreamcast */
tcp_decoy {
code {
if (option(mss)) { /* nmap has mss on all of its pkts */
set(df, 0);
if (listen) {
if (flags(syn&ece)) { /* nmap test 1 */
set(win, 0x1D4C);
set(ack, this + 1);
set(flags, ack|syn);
insert(mss, this+1);
reply;
}
if (flags(null)) { /* nmap test 2 */
set(win, 0);
set(ack, this);
set(flags, ack|rst);
reply;
}
if (flags(syn&fin&urg&push)) { /* nmap test 3 */
set(win, 0x1D4C);
set(ack, this + 1);
set(flags, ack|syn);
insert(mss, this+1);
reply;
}
if (ack(0) && flags(ack) && !flags(syn|push|urg|rst)) { /* nmap test 4 */
set(win, 0);
set(ack, this);
set(flags, rst);
reply;
}
} else {
set(win, 0);
if (flags(syn) && !flags(ack)) { /* nmap test 5 */
set(ack, this);
set(flags, ack|rst);
reply;
}
if (ack(0) && flags(ack) && !flags(syn|push|urg|rst)) { /* nmap test 6 */
set(ack, this);
set(flags, rst);
reply;
}
if (flags(fin&push&urg)) { /* nmap test 7 */
set(ack, this + 1);
set(flags, ack|rst);
reply;
}
}
}
}
}
/* No ICMP response for connections to closed UDP ports */
udp_unreach {
reply no;
df no;
max-len 56;
tos 0;
mangle-original {
ip-len 32;
ip-id same;
ip-csum zero;
udp-len 308;
udp-csum same;
udp-data same;
}
}
IP Personality is even more powerful. You can set up a Linux firewall/router that will change the answer of the hosts behind it. All your hosts protected by that Linux router can appear to be Sega Dreamcast consoles to any attacker!
There is also a great Nmap patch in the same site, named osdet, that allows us to OS Fingerprint an ip address (using Nmap engine), but with the fancy add-on that we can see the packets that are sent and their answer in tcpdump output format. Sometimes it’s very helpful and easier to understand the OS Fingerprint technique watching the packets flowing on our screen (all Nmap tests and its answers).
IP Log
IPlog is a TCP/IP logger that also detects some scans (XMAS, FIN, SYN, …). For our purposes, it has an option (-z) that allows to fool Nmap queries, and, although we can’t behave as other OS, we can completely fool Nmap when guessing remotely our OS.
Now it’s time to run IPlog to check the results:
voodoo:~#iplog -o -L -z -i eth0
The options are the following: -o (don’t fork and stay in foreground), -L (results to stdout), -z (fool Nmap), -i eth0 (listen to eth0).If I run a Nmap against the box, iplog starts to write a lot of information to stdout, about all connections made, and even which type of scanning is being performed; I’ve included only the relevant information about Nmap OS Fingerprinting in the iplog’s output:
Feb 20 13:20:54 TCP: SYN scan detected [ports 10082,1430,770,815,440,86,848,797,560,5998,...] from 192.168.0.50 [port 49047] Feb 20 13:20:56 TCP: Bogus TCP flags set by 192.168.0.50:49054 (dest port 22) Feb 20 13:20:56 UDP: dgram to port 1 from 192.168.0.50:49047 (300 data bytes) Feb 20 13:20:56 ICMP: 192.168.0.50: port is unreachable to (udp: dest port 1, source port 49047) Feb 20 13:20:58 UDP: dgram to port 1 from 192.168.0.50:49047 (300 data bytes) Feb 20 13:20:58 ICMP: 192.168.0.50: port is unreachable to (udp: dest port 1, source port 49047) Feb 20 13:21:01 UDP: dgram to port 1 from 192.168.0.50:49047 (300 data bytes) Feb 20 13:21:01 ICMP: 192.168.0.50: port is unreachable to (udp: dest port 1, source port 49047) Feb 20 13:21:04 TCP: Xmas scan detected [ports 1,9,49055,49056,49054] from 192.168.0.50 [ports 49060,49056,49054,9] Feb 20 13:21:05 UDP: dgram to port 1 from 192.168.0.50:49047 (300 data bytes) Feb 20 13:21:05 ICMP: 192.168.0.50: port is unreachable to (udp: dest port 1, source port 49047) Feb 20 13:21:12 TCP: null scan detected [ports 9,49056,49060,49054] from 192.168.0.50 [ports 49055,9,1,49056,49054,...] Feb 20 13:21:13 TCP: FIN scan detected [ports 49060,49054,9,1] from 192.168.0.50 [ports 1,9,49055,49056,49054,...] Feb 20 13:21:56 TCP: SYN scan mode expired for 192.168.0.50 - received a total of 1647 packets (33440 bytes). Feb 20 13:21:56 TCP: Xmas scan mode expired for 192.168.0.50 - received a total of 33812 packets (676300 bytes). Feb 20 13:22:03 TCP: null scan mode expired for 192.168.0.50 - received a total of 16462 packets (329300 bytes). Feb 20 13:22:04 TCP: FIN scan mode expired for 192.168.0.50 - received a total of 16343 packets (326860 bytes)
Iplog does recognize the bogus TCP flags, null packet, … every Nmap OS Fingerprint attempt. That’s why it can act accordingly and send a fake answer to fool Nmap. Nmap output is the following:
# nmap (V. 3.10ALPHA4) scan initiated Thu Feb 20 13:20:54 2003 as: nmap -vv -sS -O -oN nmap3.log 192.168.0.19 Insufficient responses for TCP sequencing (1), OS detection may be less accurate Insufficient responses for TCP sequencing (1), OS detection may be less accurate Insufficient responses for TCP sequencing (1), OS detection may be less accurate Interesting ports on voodoo (127.0.0.1): (The 1599 ports scanned but not shown below are in state: closed) Port State Service 22/tcp open ssh 25/tcp open smtp 80/tcp open http 143/tcp open imap2 No exact OS matches for host (If you know what OS is running on it, see http://www.insecure.org/cgi-bin/nmap-submit.cgi). TCP/IP fingerprint: SInfo(V=3.10ALPHA4%P=i586-pc-linux-gnu%D=2/20%Time=3E54C833%O=9%C=1) T1(Resp=Y%DF=Y%W=7FFF%ACK=S++%Flags=AS%Ops=MNNTNW) T2(Resp=Y%DF=N%W=0%ACK=O%Flags=BA%Ops=) T2(Resp=Y%DF=Y%W=100%ACK=O%Flags=BARF%Ops=) T2(Resp=Y%DF=Y%W=100%ACK=O%Flags=BPF%Ops=) T3(Resp=Y%DF=N%W=0%ACK=O%Flags=BA%Ops=) T4(Resp=Y%DF=Y%W=0%ACK=O%Flags=R%Ops=) T5(Resp=Y%DF=Y%W=0%ACK=S++%Flags=AR%Ops=) T6(Resp=Y%DF=Y%W=0%ACK=O%Flags=R%Ops=) T7(Resp=Y%DF=N%W=0%ACK=O%Flags=BA%Ops=) T7(Resp=Y%DF=Y%W=0%ACK=S++%Flags=AR%Ops=) PU(Resp=Y%DF=N%TOS=C0%IPLEN=164%RIPTL=148%RID=E%RIPCK=E%UCK=E%ULEN=134%DAT=E) # Nmap run completed at Thu Feb 20 13:21:07 2003 -- 1 IP address (1 host up) scanned in 13.633 seconds
As you can see, iplog answers to all the packets with specific options; we can have a look to iplog source code:
file iplog_tcp.c, line 99: if (opt_enabled(FOOL_NMAP) && ((tcp_flags & TH_BOG) || (tcp_flags == TH_PUSH) || (tcp_flags == 0) || ((tcp_flags & (TH_SYN | TH_FIN | TH_RST)) && (tcp_flags & TH_URG)) || ((tcp_flags & TH_SYN) && (tcp_flags & (TH_FIN | TH_RST)))))
That ‘if’ statement means that if we have executed iplog with the ‘-z’ switch (fool Nmap), and the TCP header options are:
- bogus (use of the reserved bits), or
- only PUSH , or
- NULL (no options), or
- SYN+URG, FIN+URG, RST+URG, or
- SYN+FIN, SYN+RST
then it will create a new packet for answering with the options we want (some options depend on the machine time, for example DF, that’s why sometimes is 1 and other 0, or the window size which is defined as current_time & 1).
Of course we could change the file iplog_tcp.c so that iplog always behave as a Sega Dreamcast for those nasty packets, but we do not have the flexilibity to have multiple personalities or specify that we want to behave as a Dreamcast only for a specific traffic or ip address. It’s a good idea to answer in this way to abnormal packets, but it’s better to have the control and be more granular.














Post a comment