Alexis Draussin


C: interaction with shell variables

2024-04-29


Fetch shell environment variables through C main declaration

In the last couple of days, we can see people talking about the security aspect of this behaviour. In C, we can in fact easily interact with shell variables with the char *getenv(const char *name) standard function:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
        printf("PATH: %s\r\n", getenv("PATH"));
        return (0);
}

But the C offers a way to access them directly as passing argument into the main function, just like **argv. The definition of main can indeed have 0, 2 or 3 arguments:

The third and option argument is then our way to access shell variables, e.g.:

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv, char **envp)
{
	unsigned short timeout = 0;
	while ((*envp != NULL) && (timeout++ < (1 << 15))) {
		if (strncmp(*(envp++), "PATH", 4) == 0) {
			printf("%s\r\n", *(envp - 1));
			return (0);
		}
	}
	printf("Timeout error\r\n");
	return (1);
}

Note that this third definition of main is not part of the C99 Standard (par. 5.1.2.2.1), making it de facto POSIX-specific though widely supported. You could however achieve the same result by overflowing the **argv parameter:

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
	unsigned short timeout = 0;
	argv += argc + 1;
	while ((*argv != NULL) && (timeout++ < (1 << 15))) {
		if (strncmp(*(argv++), "PATH", 4) == 0) {
			printf("%s\r\n", *(argv - 1));
			return (0);
		}
	}
	printf("Timeout error\r\n");
	return (1);
}

You can find many examples and applications of this new main argument online, sometimes with another name (e.g. **environ) as, again, it is not standard.