I am working on a challenge where it is possible to manipulate environmental variables (in C).

I know that with PATH it is possible to execute arbitrary programs when relative path is used, for example: execv("ls", 0);

export PATH=path/to/attackers/dir/:$PATH (This works as well by changing the PATH environmental within the program's memory, e.g char **envp)

I have read something about IFS but I think is only applicable on scripts.

export IFS=/ (so /bin/ls will become bin ls)

Is there any other environmental that can be used for exploitation?

I was trying for example to mess with PWD in order to influence fopen("file") with a file in different directory than the current but it didn't work. (the fopen eventually calls getcwd which I could not identify how exactly it operates).

export PWD=new/pwd (It changes the prompt but the pwd command returns the right current working directory)

Operating system: Ubuntu (latest kernel)

  • 1
    most of these tricks only apply to shell scripts, not C programs
    – Igor Skochinsky
    Mar 24, 2017 at 10:31

1 Answer 1


How exactly did you set the path? Can you confirm the output of pwd changes?

get_current_dir_name() will malloc(3) an array big enough to hold the absolute pathname of the current working directory. If the environment variable PWD is set, and its value is correct, then that value will be returned.


Which operating system do you use?

Under Linux, the function getcwd() is a system call (since 2.1.92). On older systems it would query /proc/self/cwd. Straight from the kernel source:

 * NOTE! The user-level library version returns a
 * character pointer. The kernel system call just
 * returns the length of the buffer filled (which
 * includes the ending '\0' character), or a negative
 * error value. So libc would do something like
 *  char *getcwd(char * buf, size_t size)
 *  {
 *      int retval;
 *      retval = sys_getcwd(buf, size);
 *      if (retval >= 0)
 *          return buf;
 *      errno = -retval;
 *      return NULL;
 *  }
SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
    int error;
    struct path pwd, root;
    char *page = (char *) __get_free_page(GFP_USER);

    if (!page)
        return -ENOMEM;

    get_fs_root_and_pwd(current->fs, &root, &pwd);

    error = -ENOENT;
    if (!d_unlinked(pwd.dentry)) {
        unsigned long len;
        struct path tmp = root;
        char *cwd = page + PAGE_SIZE;
        int buflen = PAGE_SIZE;

        prepend(&cwd, &buflen, "\0", 1);
        error = prepend_path(&pwd, &tmp, &cwd, &buflen);

        if (error)
            goto out;

        /* Unreachable from current root */
        if (!path_equal(&tmp, &root)) {
            error = prepend_unreachable(&cwd, &buflen);
            if (error)
                goto out;

        error = -ERANGE;
        len = PAGE_SIZE + page - cwd;
        if (len <= size) {
            error = len;
            if (copy_to_user(buf, cwd, len))
                error = -EFAULT;
    } else

    free_page((unsigned long) page);
    return error;


glibc only specifies a stub looking up the PWD variable, it it is not set, the filesystem implementation has to handle the job


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.