kern/109836: Security patch for rtld,
a lack of environment sanitization
Guasconi Vincent
tyoptyop at gmail.com
Sun Mar 4 06:50:03 UTC 2007
>Number: 109836
>Category: kern
>Synopsis: Security patch for rtld, a lack of environment sanitization
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: update
>Submitter-Id: current-users
>Arrival-Date: Sun Mar 04 06:50:03 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator: Guasconi Vincent
>Release: 7.0
>Organization:
Student
>Environment:
FreeBSD 7.0-CURRENT-200609 (GENERIC)
>Description:
Hi!
I'm french so excuse my english :p.
Here's a security problem I solved (I think).
<---------->
Lack of environment sanitization in the FreeBSD, OpenBSD, NetBSD
dynamic loaders.
Impact: Serious. May lead to privilege escalation.
A class of security vulnerabilities has resurfaced in the dynamic loaders
of FreeBSD, OpenBSD, and NetBSD in the sanitization of environment
variables for suid and sgid binaries.
[...]
Due to either badly implemented sanitization or a lack of it, a setuid
binary may execute other processes with a tainted environment.
No attempt is made to clear dangerous variables. The
FreeBSD dynamic loaders simply do not process the variables
when ruid does not equal euid.
<---------->
complete source :
http://lists.grok.org.uk/pipermail/full-disclosure/2006-November/050829.html
Already fix in NetBSD since 3 months :
http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/rtld.c.diff?r1=1.110&r2=1.111&f=h
--
Guasconi Vincent
French student.
http://altmylife.blogspot.com [fr]
>How-To-Repeat:
vulnerable root-suid program example:
main()
{
setuid(0);
execl("/usr/bin/id","id",0);
}
evil shared library:
__attribute__ ((constructor)) main()
{
printf("[+] Hello from shared library land\n");
execle("/bin/sh","sh",0,0);
}
>Fix:
So here's the patch for libexec/rtld-elf/rtld.c 1.120 (my first so be cool ^-^).
I've test it on my FreeBSD 7.0-CURRENT-200609 (GENERIC),
it works perfectly.
I don't know if you need I reproduce it for 6.2? I'm not really aware of the procedure.
26c26
< * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.120 2007/01/09 17:50:05 jhb Exp $
---
> * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.120 2007/03/04 04:42:00 jhb Exp $
140a141,142
> static void rtld_env_destroyer(char **);
> static void rtld_unsetenv(const char *, char **);
360,361c362,366
< } else
< dangerous_ld_env = 0;
---
> } else {
> /* issetugid isn't able to catch a setuid() so... */
> rtld_env_destroyer(env);
> dangerous_ld_env = 0;
> }
3325a3331,3374
> }
>
> /* ... Let's start the war. */
> /* env destructor in case of issetugid, security fix. */
> static void
> rtld_env_destroyer(char **env)
> {
> ld_debug = NULL;
> ld_library_path = NULL;
> libmap_disable = 0;
> libmap_override = NULL;
> ld_preload = NULL;
> rtld_unsetenv(LD_ "DEBUG", env);
> rtld_unsetenv(LD_ "LIBRARY_PATH", env);
> rtld_unsetenv(LD_ "LIBMAP_DISABLE", env);
> rtld_unsetenv(LD_ "LIBMAP", env);
> rtld_unsetenv(LD_ "PRELOAD", env);
> return ;
> }
>
> /* Thanks to OpenBSD */
> /* unset all var occurences from env */
> static void
> rtld_unsetenv(const char *var, char **env)
> {
> char *ep;
>
> while ((ep = *env)) {
> const char *vp = var;
>
> while (*vp && *vp == *ep) {
> vp++;
> ep++;
> }
> if (*vp == '\0' && *ep++ == '=') {
> char **P;
>
> for (P = env;; ++P)
> if (!(*P = *(P + 1)))
> break;
> } else
> env++;
> }
> return ;
Hope it helps. Thx in advance.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list