Nmap Development mailing list archives

Re: Spurious port closed bug.


From: James Rogers <jamesmrogers () gmail com>
Date: Mon, 18 Jun 2012 15:56:10 -0400

On Wed, Jun 13, 2012 at 3:27 PM, James Rogers <jamesmrogers () gmail com> wrote:
When a scan of this form is sent

 sudo ./nmap  -n -p 80 nmap.org --packet-trace

 it almost always comes back like this:

SENT (0.2146s) TCP 192.168.5.96:62799 > 74.207.254.18:443 S ttl=57
id=26684 iplen=44  seq=3835492086 win=1024 <mss 1460>
SENT (0.2148s) TCP 192.168.5.96:62799 > 74.207.254.18:80 A ttl=58
id=4759 iplen=40  seq=0 win=1024
SENT (0.7961s) TCP 192.168.5.96:62799 > 74.207.254.18:80 S ttl=55
id=26240 iplen=44  seq=4209866743 win=1024 <mss 1460>

RCVD (0.9954s) TCP 74.207.254.18:80 > 192.168.5.96:62799 SA ttl=52
id=0 iplen=44  seq=3953231165 win=14600 <mss 1356>

and the http is reported as open:
Host is up (0.53s latency).
PORT   STATE SERVICE
80/tcp open  http

(I am ignoring the ICMP packets for this to make the results clearer.)

On a good, fast network it is almost impossible to get the wrong
result.  This makes trouble shooting the issue a problem.  When you
can't recreate it, did you fix the issue, or did the network
congestion just get better.

But on a network that is dropping packets or delivering them out of
order it is a different story. Depending on how bad the network is you
can get a wrong result anywhere from 1 in 10 to 1 in 5 packets.  The
McDonald's network was really bad this morning.

The bad results look like:

SENT (0.2067s) TCP 192.168.5.96:33389 > 74.207.254.18:443 S ttl=40
id=35821 iplen=44  seq=298682555 win=1024 <mss 1460>
SENT (0.2069s) TCP 192.168.5.96:33389 > 74.207.254.18:80 A ttl=46
id=2272 iplen=40  seq=0 win=1024
SENT (0.4014s) TCP 192.168.5.96:33389 > 74.207.254.18:80 S ttl=59
id=16598 iplen=44  seq=2367880103 win=1024 <mss 1460>

RCVD (0.4049s) TCP 74.207.254.18:80 > 192.168.5.96:33389 R ttl=52 id=0
iplen=40  seq=298682555 win=0

Host is up (0.17s latency).
PORT   STATE  SERVICE
80/tcp closed http

Nmap done: 1 IP address (1 host up) scanned in 0.43 seconds

Or even this:

SENT (0.2372s) TCP 192.168.5.96:49360 > 74.207.254.18:443 S ttl=49
id=50774 iplen=44  seq=3212604348 win=1024 <mss 1460>
SENT (0.2374s) TCP 192.168.5.96:49360 > 74.207.254.18:80 A ttl=40
id=24380 iplen=40  seq=0 win=1024
SENT (0.4769s) TCP 192.168.5.96:49360 > 74.207.254.18:80 S ttl=58
id=27597 iplen=44  seq=235178041 win=1024 <mss 1460>

RCVD (0.4823s) TCP 74.207.254.18:443 > 192.168.5.96:49360 SA ttl=52
id=0 iplen=44  seq=155794850 win=14600 <mss 1356>
RCVD (0.4825s) TCP 74.207.254.18:80 > 192.168.5.96:49360 R ttl=52 id=0
iplen=40  seq=3212604348 win=0

Host is up (0.20s latency).
PORT   STATE  SERVICE
80/tcp closed http

This is what RFC 793 says starting on page 64:

If the state is LISTEN then

     second check for an ACK

       Any acknowledgment is bad if it arrives on a connection still in
       the LISTEN state.  An acceptable reset segment should be formed
       for any arriving ACK-bearing segment.  The RST should be
       formatted as follows:

         <SEQ=SEG.ACK><CTL=RST>

       Return.

     third check for a SYN

       If the SYN bit is set, check the security.  If the
       security/compartment on the incoming segment does not exactly
       match the security/compartment in the TCB then send a reset and
       return.

         <SEQ=SEG.ACK><CTL=RST>

       If the SEG.PRC is greater than the TCB.PRC then if allowed by
       the user and the system set TCB.PRC<-SEG.PRC, if not allowed
       send a reset and return.

         <SEQ=SEG.ACK><CTL=RST>

       If the SEG.PRC is less than the TCB.PRC then continue.

       Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other
       control or text should be queued for processing later.  ISS
       should be selected and a SYN segment sent of the form:

         <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>

       SND.NXT is set to ISS+1 and SND.UNA to ISS.  The connection
       state should be changed to SYN-RECEIVED.  Note that any other
       incoming control or data (combined with SYN) will be processed
       in the SYN-RECEIVED state, but processing of SYN and ACK should
       not be repeated.  If the listen was not fully specified (i.e.,
       the foreign socket was not fully specified), then the
       unspecified fields should be filled in now.

If a syn comes in on a listen port, then it is supposed to send a
syn-ack back.
If an ack comes in on a listen port, then it is supposed to send rst back.

I believe that is happening is that the two packets we send to port
80, an ACK and a SYN are returning in different orders depending on
network quality/congestion.   If the packets get there in SYN - ACK
order then that could really confuse the host on the other side,
especially considering how the sequence numbers are not properly
aligned for a syn, syn-ack, ack handshake.

I am noticing that we never get the receive for all three packets. and
if we get more than just the SA packet back then we think the
connection is closed.

How can I match up the returning packet to the packet that was sent?
I'm not seeing a clear way to differentiate between an RST on the A
packet and the one on the SYN packet.

The strange thing is that the seq number in the RST packet from port
80 on the other host is always equal to the sequence number in the
segment we sent to port 443.   So I am really confused about which
segment this RST belongs to.

I am thinking that if I send all three packets from different ports
then I would know for sure which returning packet belonged to which
sent packet, is that a practical solution?   Is there a command line
option to do that?   Do we match the packets by the ACK  (number - 1)?
 If I put the ack number in the --packet-trace output could this help
us line the acks up to the sends better?

Greetings All,

I was able to  stop the bug from happening by incrementing the port of
the first ack in massping().

Evidently this earlier ack is sometimes triggering a reset to be sent
which we were seeing as the response to the later packet.

I traced back to where we set the default ports inside
validate_scan_lists() and instead of setting them to 443 and 80 for
the syn and ack host detection packets I set them to random values
above 32,000.  Ports in these higher ranges are often allowed to
receive packets when port 80 or 443 are heavily guarded by firewall
and packet filter rules.

By randomizing these host detection ports each time we scan, we could
make nmap less predictable and harder to spot.

An alternative is to change port 80 to a random higher value if we are
tcp scanning for port 80 later.  Unfortunately this information is not
available to validate_scan_lists at the time port 80 and port 443 are
being added to the ping syn and ping ack lists.

Thanks,
James Rogers

Attachment: spuriousPortClosedBugFix2.diff
Description:

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/

Current thread: