COMMAND
TCP Timestamping
SYSTEMS AFFECTED
unices
PROBLEM
Following is based on a paper called TCP Timestamping - Obtaining
System Uptime Remotely by Bret McDanel.
TCP Timestamping can be used to retrieve information about your
system that you may not wish to be public. Bret started
investigating this after some discussion of NetCraft's server
uptime stats, and their reliability. Ant Mitchell was very polite
in telling him NetCraft would not disclose how they obtain these
figures, only that he feels they are reliable. So Bret started
looking into how they could get this information. What he
discovered was TCP Timestamping is equal to the uptime (after a
fashion) of many systems, and as such can give you extra
information about the running system.
What is Timestamping? How can it be used to gain information
about a running system? Timestamping is a TCP option, which may
be set, and if set takes 12 bytes in the header (for each packet)
in addition to the 20 bytes a TCP header normally takes. This is
exclusive of any other options. What good is this overhead?
According to RFC1323:
"The timestamps are used for two distinct mechanisms: RTTM
(Round Trip Time Measurement) and PAWS (Protect Against
Wrapped Sequences).".
Bret suggest that anyone interested in TCP Timestamps read RFC1323
(these are not the IP timestamping options). The fact that
timestamping exists isn't anything special in itself, but how the
value is populated and how the value is set is somewhat
interesting.
- 4.4BSD increments the timestamp clock once every 500ms and this
timestamp clock is reset to 0 on a reboot -- TCP/IP ILLUS v1,
p349
- The timestamp value to be sent in TSval is to be obtained from a
(virtual) clock that we call the "timestamp clock". Its values
must be at least approximately proportional to real time, in
order to measure actual RTT. -- RFC1323 May 1992
Note that the RFC does not dictate that the timestamp clock be
tied to system uptime, so any system that doesn't conform to this
is perfectly valid (ie Windows 2000). Additionally the rate at
which each system increments the clock need not be disclosed
either, as the timestamp value is only echoed back to the sender
for the sender to process.
This means that in 4.4BSD we can use this number to directly tell
the time that a system has been up. All we have to do is make a
connection and record the received timestamp. Not everyone
implements timestamping this way however. This yields various
results on different operating systems. Linux for instance
increments every 1 ms, Cisco IOS increments every .1 ms. Windows
95/98/NT4 do not support Timestamping (although rumor has it that
there is a patch to enable RFC1323 functionality on 95/98/NT4)
Win2k does, but this value does not appear to be directly related
to uptime. This means that in order to tell the uptime we need
to know what OS we are looking at, or at the very least make
multiple connections and try to guess what the increment is based
on elapsed time vs increment.
There are some limitations to using this method for recording
uptime. Certain systems have a maximum limit on how long their
'uptime' can be. The timestamp is a 32 bit number (signed). As
such it will overflow into the sign bit after 2147483647 ticks.
Based on the number of ticks per second, you can easily determine
when this will roll over.
(leap year included)
OS Ticks/sec Rollover time
4.4BSD 2 34 years, 8 days, 17:27:27
Solaris 2 10 6 years, 293 days, 22:53:00
Linux 2.2+ 100 248 days, 13:13:56
Cisco IOS 1000 24 days, 20:31:23
One can also map out the number of systems in a load balanced
environment by connecting repeatedly to the group of machines,
and inspecting the Timestamps. For each different time you have
a different machine.
RFC1323 talks about the frequency the 'timestamp clock' should be
updated
The receiver algorithm does place some requirements on the
frequency of the timestamp clock.
(a) The timestamp clock must not be "too slow".
It must tick at least once for each 2**31 bytes sent. In
fact, in order to be useful to the sender for round trip
timing, the clock should tick at least once per window's
worth of data, and even with the RFC-1072 window extension
2**31 bytes must be at least two windows.
To make this more quantitative, any clock faster than 1
tick/sec will reject old duplicate segments for link
speeds of ~8 Gbps. A 1ms timestamp clock will work at
link speeds up to 8 Tbps (8*10**12) bps!
(b) The timestamp clock must not be "too fast".
Its recycling time must be greater than MSL seconds. Since
the clock (timestamp) is 32 bits and the worst-case MSL is
255 seconds, the maximum acceptable clock frequency is one
tick every 59 ns.
However, it is desirable to establish a much longer
recycle period, in order to handle outdated timestamps on
idle connections (see Section 4.2.3), and to relax the MSL
requirement for preventing sequence number wrap-around.
With a 1 ms timestamp clock, the 32-bit timestamp will
wrap its sign bit in 24.8 days. Thus, it will reject old
duplicates on the same connection if MSL is 24.8 days or
less. This appears to be a very safe figure; an MSL of
24.8 days or longer can probably be assumed by the gateway
system without requiring precise MSL enforcement by the
TTL value in the IP layer.
Based upon these considerations, we choose a timestamp clock
frequency in the range 1 ms to 1 sec per tick. This range
also matches the requirements of the RTTM mechanism, which
does not need much more resolution than the granularity of
the retransmit timer, e.g., tens or hundreds of milliseconds.
As you can see all of these systems are within the RFC in their
timings, however varied. It has come to the attention that nmap
2.54beta20 released March 09, 2001 included support for detecting
(multiple pass, guess at tick rate) uptimes.
If you want to quickly get the Timestamp value, you can fire up
tcpdump, and watch for it. Here is an example of what you may
see and how to interpret the data:
> myhost.12345 > theirhost.22: . 1:1(0) ack 1 win 5840
<nop,nop,timestamp 6426701 865450440> (DF)
The timestamps are located near the end of the line, where the
TCP Options are printed. The first timestamp is sent by 'myhost',
the second is what 'theirhost' last sent us (we are expected to
return that to them). The numbers are the number of ticks that
have accumulated in the 'timestamp clock' and if the OS supports
it, can reveal an uptime.
Included below are information obtained by Bret and several people
running various OSs that let me scan them and compare the actual
uptime vs the timestamp returned. We do not have access to all
systems to test, however Bret tried to include as much vendor
information on RFC1323 compliance as reasonably possible.
If you are considering disabling timestamping on your system
please read RFC1323 for more information (especially if you are
on a fast network).
* Windows
- Win2k sends the timestamp after the syn/ack handshake is
complete (sends 0 TS during the 3-way handshake)
- 95/98 does not support TS
- NT 3.5/4 does not support TS
- 2000 increment every 100ms initial number random
* Linux
- Sends TS on first packet replied to - default always get TS
- To disable echo 0 >/proc/sys/net/ipv4/tcp_timestamps
- To enable echo 1 >/proc/sys/net/ipv4/tcp_timestamps
- Increments 100 ticks/sec
- 2.0.x does not support TCP Timestamps
- 2.1.90+ Supports Timestamps
- 2.2.x Supports Timestamps
- 2.4.x Supports Timestamps
* 4.4BSD - OpenBSD BSDi BSD/OS (2.1 & 3.0) FreeBSD (2.1.5)
- To enable/disable sysctl -w TCPCTL_DO_RFC1323={true,false}
- Or sysctl -w net.inet.tcp.rfc1323={true,false}
- 4.4BSD spec is applied, 2 ticks/sec
* MacOS (Open Transport)
- Supports Timestamps
* Novell Netware
- 5 Does not support Timestamps
* IRIX
- 5.3+ Support Timestamps
- 5.3-6.1 /var/sysgen/master.d/bsd contains the kernel variables
after editing you must use /etc/autoconfig and reboot (WTF!)
- 6.5 edit /var/sysgen/mtune/bsd or use systune (like BSDs
sysctl) tickrate 2/sec
* HPUX
- 9.x No (9.05 and 9.07 have patches to support Timestamps)
- To enable you must poke the kernel variable tcp_dont_tsecho to
0
- 10.00,01,10,20,30 Support Timestamps
- 11 Enabled by default
* AIX
- 3.2 & 4.1 Support Timestamps
- Tunable via the 'no' command
* SunOS
- 4.1.4 No (May be purchased as a Sun Consulting Special)
* Solaris
- To Enable
- 2.5 No (May be purchased as a Sun Consulting Special)
- 2.6 may be uptime but rolls over quickly, increments 1000
ticks/second
- 2.7 tickrate 100/sec (its not exactly uptime there was a 5
minute skew on a 112 day uptime)
- 8 it is uptime, 100 ticks/second
- to enable ndd /dev/tcp tcp_tstamp_always 1
- If the parameter is set (non-zero), then the TCP timestamp
option will always be negotiated during connection initiation.
The scale option will always be used if the remote system sent
a timestamp option during connection initiation. To use the
timestamp, both hosts have to support RFC 1323.
* ios (cisco)
- By default disabled To change [no] ip tcp timestamp
- Bret tested only against a Cisco 2524 running 12.0(9) cisco
2524 (68030) processor (revision J) with 14336K/2048K bytes of
memory.
- Updates 1000 ticks/sec resets to 0 at boot
* comos (livingston/lucent portmasters)
- Do not support TS
* Netopia
- Do not support TS
* ConvexOS
- 11.0 Supports Timestamps
* CRI Unicos
- 8.0 Supports Timestamps
* (Compaq) Digital Unix
- 3.2 & 4.0 Does not support Timestamps
Bret did his testing under linux, and in order to easily retrieve
the remote Timestamp he had to make a small kernel change.
Because he is running 2.4.x and a lot of people may not Bret
documented this as generically as possible, note this should
work fairly easily on 2.2 kernels however your results may be
different (therefore we are not responsible if you choose to do
this and it breaks *anything*, use at your own risk). If these
directions are not clear enough then you probably shouldn't be
editing your kernel. We could have included diffs, however 2.2
kernels are quite different so line numbers would not match, and
Bret has other mods that would prevent patch from working
correctly anyway.
Here is what Bret did; all of these start at your kernel root
directory (ie /usr/src/linux)
include/linux/tcp.h -- Add the following to the section 'TCP socket options'
#define TCP_RCV_TIMESTAMP 12 /* The received Timestamp */
#define TCP_SND_TIMESTAMP 13 /* The sent Timestamp */
net/ipv4/tcp.c -- Add to the routine tcp_getsockopt() in the select statement
case TCP_RCV_TIMESTAMP:
if (tp->tstamp_ok)
val = tp->rcv_tsval;
else
val = 0;
break;
case TCP_SND_TIMESTAMP:
if (tp->tstamp_ok)
val = tp->rcv_tstamp;
else
val = 0;
break;
Remake your kernel and reboot. Now you need a program that will
connect and display the timestamps.. That is fairly straight
forward now.
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/tcp.h>
#define TCP_RCV_TIMESTAMP 12 /* The received Timestamp */
#define TCP_SND_TIMESTAMP 13 /* The sent Timestamp */
int connserver(char *host,int port)
{
int sd,addr,flag=1;
struct hostent *he;
struct sockaddr_in sa;
/* try to resolve the host */
if((addr=inet_addr(host))!= -1) {/* dotted decimal */
memcpy(&sa.sin_addr,(char *)&addr,sizeof(addr));
} else {
if((he=gethostbyname(host))==NULL) {
printf("Unable to resolve %s\n",host);
return(-1);
}
memcpy(&sa.sin_addr,he->h_addr,he->h_length);
}
sa.sin_port=htons(port);
sa.sin_family=AF_INET;
if((sd=socket(AF_INET,SOCK_STREAM,0))<0) {
perror("socket");
return(-1);
}
/* make sure that we use timestamping if the kernel has it defaulted to not send them
* This is not required for the linux systems I have seen as they always try to
* negotiate timestamps if they are enabled in the kernel, but better safe than
* wondering why it doesn't work
*/
if(setsockopt(sd, IPPROTO_TCP, TCPOPT_TIMESTAMP, (char *) &flag, sizeof(int))<0)
perror("setsockopt TCP_TIMESTAMP");
if(connect(sd,(struct sockaddr *)&sa,sizeof(sa))<0) {
perror("connect");
exit(1);
}
return(sd);
}
unsigned int get_ts(char *host,int port)
{
int optsize=sizeof(long);
unsigned int l;
char buff[15];
int sd;
if((sd=connserver(host,port))==-1) exit(0);
if (!getsockopt(sd, IPPROTO_TCP, TCP_RCV_TIMESTAMP, &l, &optsize)) {
if(l!=0) {
close(sd);
return(l);
} else {
/* Win2k workaround, If we are here, either the box doesnt support
* Timestamps or its win2k which sends a 0 TS in the handshake
*/
sprintf(buff,"ooga booga\n");
send(sd,buff,strlen(buff),0);
/* wait for data
* potential problem with it hanging forever if no data is returned
*/
while(!recv(sd,buff,sizeof(buff),0)) ;
if (!getsockopt(sd, IPPROTO_TCP, TCP_RCV_TIMESTAMP, &l, &optsize)) {
close(sd);
return(l); /* 0 if remote system doesnt support Timestamping */
} else perror("getsockopt");
}
} else perror("getsockopt");
close(sd);
return(0);
}
int main(int argc, char **argv)
{
int ts1,ts2,tickrate;
int sec,min,hour,day;
if(argc!=3) {
printf("Usage: %s <ip> <port>\n",argv[0]);
exit(0);
}
ts1=get_ts(argv[1],atoi(argv[2]));
sleep(1); /* wait for the remote system to increment the counter a bit */
ts2=get_ts(argv[1],atoi(argv[2]));
printf("TimeStamp1: %d\n",ts1);
printf("TimeStamp2: %d\n",ts2);
tickrate=(ts2-ts1);
printf("Unmodified tickrate %d\n",tickrate);
/* compensate for network delays +-30% */
if(tickrate) {
if(tickrate<1300 && tickrate > 700) tickrate=1000;
else if(tickrate<130 && tickrate > 70) tickrate=100;
else if(tickrate<30 && tickrate > 7) tickrate=10;
else if(tickrate<4 && tickrate > 1) tickrate=2;
else printf("Unknown tickrate - will try but may be incorrect\n");
day=(ts2/tickrate)/86400;
sec=(ts2/tickrate)%86400;
hour=sec/3600;
sec=sec%3600;
min=sec/60;
sec=sec%60;
printf("%s (Tickrate %d/sec) Uptime: %u days, %02d:%02d:%02d\n",argv[1],tickrate,day,hour,min,sec);
} else
printf("The remote system does not appear to support TCP Timestamping\n");
return(0); /* as per C89 spec main() returns an int */
}
For people who want to explore this without kernel recompilation
and for those who aren't using Linux, this remote-uptime
capability has been available to Nmap users (using raw TCP
packets) for more than a month. Troels Walsted Hansen posted a
patch to the nmap-dev list on Feb. 3.
Another under-exploited TCP/IP property is IP.ID prediction.
Antirez and others have posted in recent years about the fun you
can have with systems that simply increment this field for each
packet sent. Yet most operating sytems remain vulnerable.
Recent versions of Nmap will report on this with the "-O -v"
options.
One other known TCP/IP sequencing problem is ISN prediction. Over
the years this hole has been gradually declining. Lately we have
seen that even Cisco has began to recognize the problem! But
there are still plenty of susceptible machines out there. Nmap
offers a report on this as well (not a new feature).
SOLUTION
Nothing yet.