[ntp:questions] Re: "Listen on" semantics

Luc Pardon xntp at skopos.be
Thu Sep 21 07:44:02 UTC 2006



Harlan Stenn wrote:
>>>> In article <45110BAE.8040106 at skopos.be>, xntp at skopos.be (Luc Pardon) writes:
> 
> Lots of good stuff.
> 
> Luc>     Case in point #1: back in 2001, there was a bug in - yes - (x)ntpd
> Luc> that allowed remote root access. See, for example:
> Luc> http://archive.cert.uni-stuttgart.de/archive/bugtraq/2001/04/msg00064.html
> 
> First, please compare this history to other root-running processes and tell
> me how (x)ntpd compares.  Especially given the length of time (x)ntpd has
> been in the field.
> 

     We wouldn't be having this discussion if I was of the opinion that 
(x)ntpd had a lousy track record. I wouldn't bother.

     I mentioned this only to show that there can be buffer overflow 
bugs in otherwise correct code.

     To put it another way: if I want to serve a web site, I _must_ have 
something listening at tcp/80. In that case, the track record _is_ 
relevant: I'll select a server with a good one, hope for the best and 
prepare for the worst. Sooner or later, there _will_ be an exploit and 
then I have to patch as fast as I can. It is a risk, but I have no 
choice. In return for taking the risk, I have a website. Now, if I don't 
need a website on that machine, why run a web server, no matter how good 
its track record?

     To keep the time (in my setup, which I believe to be typical for 
the majority of users), there is no need to have a server on a public 
interface. Taking the risk buys me nothing and therefore I am not 
prepared to accept it, no matter how good the track record of the daemon.

  > Luc>     Case in point #2: only last week, my logs were being flooded
> Luc> because somebody sent icmp port unreachable packets to udp/123. 
> 
> Fair point, and Real Soon Now we're going to have better configuration
> control over logfiles.  

     The problem is that you can't distinguish between real and fake 
packets. If you suppress the fake "connection refused", you may be 
wiping real problems under the carpet as well.

 > And I thought syslog() was pretty good about "Last
> message repeated N times".

     Point taken, I did forget that. It issues a "repeated" every 
second, so our attacker would not be ready by Sunday. Unless he can find 
another way - preferably with (x)ntpd - to generate a syslog entry and 
alternate that with the port unreachable packets. A "grep syslog *.c | 
grep LOG_ERR" yields some promising candidates.

    Out of curiosity, I had a quick look at the ntp-dev-4.2.3p39 code.

   <black hat on>

  At first sight, it seems possible to craft a packet that will end up 
in process_private() in ntp_request.c and trigger the sanity check in 
there.

    In ntp_proto.c(388), it says:

         hismode = (int)PKT_MODE(pkt->li_vn_mode);
         hisstratum = PKT_TO_STRATUM(pkt->stratum);
         if (hismode == MODE_PRIVATE) {
                 if (restrict_mask & RES_NOQUERY) {
                         sys_restricted++;
                         return;                 /* no query private */
                 }
                 process_private(rbufp, ((restrict_mask &
                     RES_NOMODIFY) == 0));
                 return;
         }

   So I'd set the li_vn_mode to PRIVATE (whatever that means <g>) and 
I'd fake the source address to 127.0.0.1 to steer it past the restrict 
rules in most setups. If and when I make it into process_private(), I 
have a choice of 4 fields in the packet that I can load with invalid 
values, or I could make it too long or too short. In ntp_request.c(433) 
my malicious eyes see the following code that makes me drool:

         /*
          * Do some sanity checks on the packet.  Return a format
          * error if it fails.
          */
         ec = 0;
         if (   (++ec, ISRESPONSE(inpkt->rm_vn_mode))
             || (++ec, ISMORE(inpkt->rm_vn_mode))
             || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION)
             || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION)
             || (++ec, INFO_SEQ(inpkt->auth_seq) != 0)
             || (++ec, INFO_ERR(inpkt->err_nitems) != 0)
             || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0)
             || (++ec, rbufp->recv_length < REQ_LEN_HDR)
                 ) {
                 msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test 
%d failed, pkt from %s", ec, stoa(srcadr));
                 req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
                 return;
         }

   Too bad the restrict rules are in front of it, otherwise I could use 
my own IP (or that of one of my zombies) and I'd get an ack if I 
succeeded, then start faking source IP's.

   <black hat off>

   Again: this is just the result of a quick look at unfamiliar code. 
More likely than not, I'm missing something obvious so that this won't 
fly. But it sure looks promising and if it should work, I have my siege 
engine complete. By alternating one of these with an icmp packet, I can 
flood the log just fine.

    Again, this would not be an issue at all if (x)ntpd didn't take 
candy from strangers.

> 
> Regardless, I would like to see all these issues resolved, and I'm happy to
> work cooperatively with anybody to see this happen.
> 
> H
> 
> _______________________________________________
> questions mailing list
> questions at lists.ntp.isc.org
> https://lists.ntp.isc.org/mailman/listinfo/questions



More information about the questions mailing list