Long story short: if there is an implicit declaration of a function because a header file wasn't included, GCC will warn about the implicit use but allow it. Without the header, GCC doesn't know the expected arguments or return value of the function (logically, it has no prototypes to reference). If the linker can find the function being used, it is linked to during that step.
Consider this contrived and barely functional code sample:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void (*fp)(void);
void handle_error(void)
{
printf("you're doing it wrong\n");
}
void handle200(void)
{
printf("you're still not doing it right\n");
}
void setvalue(int x)
{
if (x == 200)
{
fp = handle200;
}
else
{
fp = handle_error;
}
}
int main(int argc, char *argv[])
{
time_t mytime;
int x;
size_t bufsize = 65 * 1024;
char *buf;
buf = malloc(bufsize);
memset(buf, 0, sizeof(buf));
fgets(buf, bufsize-1, stdin);
x = atoi(buf);
setvalue(x);
mytime = time();
printf("my time is %u\n", mytime);
fp();
free(buf);
return 0;
}
There is no inclusion of time.h as required for the time function, but the code compiles and executes. If GCC is issuing warnings, during compilation it will say timebug.c:44: warning: implicit declaration of function ‘time’.
I was an idiot for not having warnings enabled while compiling the code I was working on, it would have saved me tons of time (u see wat i did there?)
The prototype for time() is:
time_t time(time_t *t);
And the action taken by time() is as follows:
Get the time from the system.
If the time_t pointer supplied as the only argument is not NULL,
dereference it and store the time there.
Return the time.
In the code sample, since the last value pushed to the stack is the value passed to setvalue(), and as it still resides on the stack when time() is called, it is taken as the argument to time(). If the atoi() call on the buffer returns anything that is not 0 (aka NULL), then time() will treat it as a valid pointer, dereference and write the time to it. This wreaked havoc on my code as in my case, the last value to the stack was a structure pointer full of linked lists and things, and the bug didn't trigger until free() happened on those lists. Serious pain.
Clever uses of this could be done to stage a fun CTF service. If an attacker had this vulnerable app to work with and a means of manipulating time (like a MITM of the Network Time Protocol), they could have a fun instant write-4-anywhere. Additionally, every 4.2 minutes the lower 8 bits of time rotates. Every 18.2 hours, the lower 16 bits rotates. By properly offsetting (say, only overwrite the high 16 bits of a function pointer/EIP) in conjunction with heap massaging or exploiting other application-specific traits, this bug could be fun ;]

