0

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 '17 at 10:31
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.

Source

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;
    spin_lock(&dcache_lock);
    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);
        spin_unlock(&dcache_lock);

        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
        spin_unlock(&dcache_lock);

out:
    path_put(&pwd);
    path_put(&root);
    free_page((unsigned long) page);
    return error;
}

TL;DR

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, privacy policy and cookie policy

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