I have been discussing the effectiveness of GNU libc's fclose()
function to thwart successful exploitation of trivial vulnerabilities due to segmentation fault when called without a valid pointer to a FILE data structure (implementations of libc on other operating systems fail silently). For instance, given a simple vulnerable function using strcpy()
such as:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
foo(const char *str)
{
char buffer[256];
int ret = 123456;
FILE *fp = tmpfile();
strcpy(buffer, str);
if (ret != 500)
fclose(fp);
}
int
main(int argc, const char **argv)
{
foo(argv[1]);
return 0;
}
Even when compiled with most memory-protection mechanisms disabled:
cc -m32 -ggdb -fno-stack-protector -z execstack -z norelro main.c
The function, regardless of being overwritten up to EIP
would never return since:
(gdb) r $(python -c "print 'A' * 286")
Program received signal SIGSEGV, Segmentation fault.
0xf7e3e307 in fclose@@GLIBC_2.1 () from /lib/libc.so.6
(gdb) ba
#0 0xf7e3e307 in fclose@@GLIBC_2.1 () from /lib/libc.so.6
#1 0x080484bc in foo (str=0x41414141 <error: Cannot access memory...
#2 0x41414141 in ?? ()
#3 0x41414141 in ?? ()
Could there be a way to achieve code execution for such trivial function?. Since the ret
variable can be overwritten, can it be set to 500 so that the if condition which determines if fclose()
is called or not could be bypassed?
fclose()
is not really a problem.ret
andfp
are overwritten it's possible to writefp
with its address before the overflow and it'd work on non-ASLR systems, but the in-stack address would differ from system to system. As far as I know,ret
cannot be overwritten to 500 again.