Linux libc's mktemp() Vulnerability
BID:79
Info
Linux libc's mktemp() Vulnerability
| Bugtraq ID: | 79 |
| Class: | Unknown |
| CVE: | |
| Remote: | No |
| Local: | Unknown |
| Published: | Apr 11 1998 12:00AM |
| Updated: | Apr 11 1998 12:00AM |
| Credit: | The vulnerability was published as "Linux libc5.4.33 dumbness w/ mk[s]temp()" by Greg Alexander <[email protected]> to the BugTraq mailing list on April 11, 1998. |
| Vulnerable: |
Linux libc 5.4.33 GNU glibc 2.0 |
| Not Vulnerable: |
GNU glibc 2.1 BSDI BSD/OS 4.0 |
Discussion
Linux libc's mktemp() Vulnerability
Linux libc5.4.33's mktemp() function can generate only 62 unique temporary file names per process. It requires that six X's be used in the template but only one of them is really used. The rest are the process id.
This can use used as a denial of service by creating all possible temporary files a process could use before it gets to open them and possibly in symbolic link attacks by having prior knowledge of the files the process will attempt to open.
Linux libc5.4.33's mktemp() function can generate only 62 unique temporary file names per process. It requires that six X's be used in the template but only one of them is really used. The rest are the process id.
This can use used as a denial of service by creating all possible temporary files a process could use before it gets to open them and possibly in symbolic link attacks by having prior knowledge of the files the process will attempt to open.
Exploit / POC
Linux libc's mktemp() Vulnerability
Currently the SecurityFocus staff are not aware of any exploits for this issue. If you feel we are in error or are aware of more recent information, please mail us at: [email protected].
Currently the SecurityFocus staff are not aware of any exploits for this issue. If you feel we are in error or are aware of more recent information, please mail us at: [email protected].
Solution / Fix
Linux libc's mktemp() Vulnerability
Solution:
This were the changes made between glibc 2.0 and 2.1. It can probably be
applied to glibc 2.0 will mimnimal effort and with some work to libc 5.
Index: sysdeps/posix/mkstemp.c
===================================================================
RCS file: /egcs/carton/cvsfiles/libc/sysdeps/posix/mkstemp.c,v
retrieving revision 1.5
retrieving revision 1.7
diff -u -r1.5 -r1.7
--- sysdeps/posix/mkstemp.c 1998/03/10 10:44:45 1.5
+++ sysdeps/posix/mkstemp.c 1998/04/07 12:52:50 1.7
@@ -19,9 +19,11 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/time.h>
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
@@ -33,8 +35,11 @@
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static uint32_t value;
+ struct timeval tv;
+ char *XXXXXX;
size_t len;
- size_t i;
+ int count;
len = strlen (template);
if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
@@ -43,20 +48,40 @@
return -1;
}
- if (sprintf (&template[len - 5], "%.5u",
- (unsigned int) getpid () % 100000) != 5)
- /* Inconceivable lossage. */
- return -1;
+ /* This is where the Xs start. */
+ XXXXXX = &template[len - 6];
- for (i = 0; i < sizeof (letters); ++i)
+ /* Get some more or less random data. */
+ __gettimeofday (&tv, NULL);
+ value += tv.tv_usec | getpid ();
+
+ for (count = 0; count < TMP_MAX; ++count)
{
+ uint32_t v = value;
int fd;
- template[len - 6] = letters[i];
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd >= 0)
+ /* The file does not exist. */
return fd;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
}
/* We return the null string if we can't find a unique file name. */
Index: sysdeps/posix/mktemp.c
===================================================================
RCS file: /egcs/carton/cvsfiles/libc/sysdeps/posix/mktemp.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- sysdeps/posix/mktemp.c 1996/11/06 04:24:39 1.8
+++ sysdeps/posix/mktemp.c 1998/04/07 09:08:11 1.9
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993, 1996, 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -16,13 +16,15 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
@@ -33,8 +35,11 @@
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static uint32_t value;
+ struct timeval tv;
+ char *XXXXXX;
size_t len;
- size_t i;
+ int count;
len = strlen (template);
if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
@@ -43,20 +48,39 @@
return NULL;
}
- if (sprintf (&template[len - 5], "%.5u",
- (unsigned int) getpid () % 100000) != 5)
- /* Inconceivable lossage. */
- return NULL;
+ /* This is where the Xs start. */
+ XXXXXX = &template[len - 6];
- for (i = 0; i < sizeof (letters); ++i)
+ /* Get some more or less random data. */
+ __gettimeofday (&tv, NULL);
+ value += tv.tv_usec | getpid ();
+
+ for (count = 0; count < TMP_MAX; ++count)
{
struct stat ignored;
+ uint32_t v = value;
- template[len - 6] = letters[i];
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
if (stat (template, &ignored) < 0 && errno == ENOENT)
/* The file does not exist. So return this name. */
return template;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
}
/* We return the null string if we can't find a unique file name. */
Solution:
This were the changes made between glibc 2.0 and 2.1. It can probably be
applied to glibc 2.0 will mimnimal effort and with some work to libc 5.
Index: sysdeps/posix/mkstemp.c
===================================================================
RCS file: /egcs/carton/cvsfiles/libc/sysdeps/posix/mkstemp.c,v
retrieving revision 1.5
retrieving revision 1.7
diff -u -r1.5 -r1.7
--- sysdeps/posix/mkstemp.c 1998/03/10 10:44:45 1.5
+++ sysdeps/posix/mkstemp.c 1998/04/07 12:52:50 1.7
@@ -19,9 +19,11 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/time.h>
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
@@ -33,8 +35,11 @@
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static uint32_t value;
+ struct timeval tv;
+ char *XXXXXX;
size_t len;
- size_t i;
+ int count;
len = strlen (template);
if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
@@ -43,20 +48,40 @@
return -1;
}
- if (sprintf (&template[len - 5], "%.5u",
- (unsigned int) getpid () % 100000) != 5)
- /* Inconceivable lossage. */
- return -1;
+ /* This is where the Xs start. */
+ XXXXXX = &template[len - 6];
- for (i = 0; i < sizeof (letters); ++i)
+ /* Get some more or less random data. */
+ __gettimeofday (&tv, NULL);
+ value += tv.tv_usec | getpid ();
+
+ for (count = 0; count < TMP_MAX; ++count)
{
+ uint32_t v = value;
int fd;
- template[len - 6] = letters[i];
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd >= 0)
+ /* The file does not exist. */
return fd;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
}
/* We return the null string if we can't find a unique file name. */
Index: sysdeps/posix/mktemp.c
===================================================================
RCS file: /egcs/carton/cvsfiles/libc/sysdeps/posix/mktemp.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- sysdeps/posix/mktemp.c 1996/11/06 04:24:39 1.8
+++ sysdeps/posix/mktemp.c 1998/04/07 09:08:11 1.9
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993, 1996, 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -16,13 +16,15 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
@@ -33,8 +35,11 @@
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static uint32_t value;
+ struct timeval tv;
+ char *XXXXXX;
size_t len;
- size_t i;
+ int count;
len = strlen (template);
if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
@@ -43,20 +48,39 @@
return NULL;
}
- if (sprintf (&template[len - 5], "%.5u",
- (unsigned int) getpid () % 100000) != 5)
- /* Inconceivable lossage. */
- return NULL;
+ /* This is where the Xs start. */
+ XXXXXX = &template[len - 6];
- for (i = 0; i < sizeof (letters); ++i)
+ /* Get some more or less random data. */
+ __gettimeofday (&tv, NULL);
+ value += tv.tv_usec | getpid ();
+
+ for (count = 0; count < TMP_MAX; ++count)
{
struct stat ignored;
+ uint32_t v = value;
- template[len - 6] = letters[i];
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
if (stat (template, &ignored) < 0 && errno == ENOENT)
/* The file does not exist. So return this name. */
return template;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
}
/* We return the null string if we can't find a unique file name. */
References
Linux libc's mktemp() Vulnerability
References:
References: