luke-goddard / enumy

Linux post exploitation privilege escalation enumeration
MIT License
253 stars 33 forks source link

Segfault when statically linked against musl #19

Open luke-goddard opened 4 years ago

luke-goddard commented 4 years ago

Bug only reproducible inside of release binary when compiled with musl in Alpine, with multiple threads enabled.

/**
 * This function will check the current file to see if it resides in a location 
 * that should be read only
 */
static void check_global_write(All_Results *ar, File_Info *fi)
{
    if (!has_global_write(fi))
        return;

    /* Check to see if the file is protected by any parent directories */
    char parent_buf[MAXSIZE] = {'\0'};
    char issue_buf[MAXSIZE + 50] = {'\0'};

    if (get_first_dir_that_protects_file(fi->location, parent_buf, ar))
    {
        /* The directory is protected */
        snprintf(issue_buf, (sizeof(issue_buf) - 1), "Found a protected world writable file in: %s", parent_buf);
        struct stat stats;
        if ((stat(parent_buf, &stats) != 0))
        {
            log_error_errno_loc(ar, "Failed to stat directory", parent_buf, errno);
            printf("%i -> %i -> %s -> %i -> %s\n", LOW, AUDIT, fi->location, ar == NULL, issue_buf);
            add_issue(LOW, AUDIT, fi->location, ar, issue_buf, "ENUMY failed to stat the parent directory");
            return;
        }
        struct passwd *data = getpwuid(stats.st_uid); <======== Segfault here 
        if (data == NULL)
        {
            log_error_errno_loc(ar, "Failed to stat directory", parent_buf, errno);
            add_issue(LOW, AUDIT, fi->location, ar, issue_buf, "ENUMY failed to got the owner of the directory");
            return;
        }
        add_issue(LOW, AUDIT, fi->location, ar, issue_buf, data->pw_name);
        return;
    }
debug extra-> src/all_scans.c:99:scan_file_for_issues(): Scanning file ->/home/luke/some_file
[!] - ERROR -> Failed to stat directory: No data available /home/luke/

This file does exist and previous stat calls worked on the same file.

$ gdb ouput/enumy64
@gdb-peda$ set follow-fork-mode parent 
@gdb-peda$ start -t 12 
@gdb-peda$ c
...Stopped reason: SIGSEGV
@gdb-peda$ backtrace 
#0  unmap_chunk (self=0x7ffffa5dc930) at src/malloc/malloc.c:515
#1  free (p=p@entry=0x7ffffa5dc940) at src/malloc/malloc.c:526
#2  0x00007ffff7fe0eb6 in realloc (p=0x7ffffa5dc940, n=<optimized out>, n@entry=0x32) at src/malloc/malloc.c:436
#3  0x00007ffff7fea1a6 in getdelim (s=s@entry=0x7ffff7ffe350 <line>, n=n@entry=0x7ffff7ffe318 <size>, delim=delim@entry=0xa, f=f@entry=0x7ffffa65b120) at src/stdio/getdelim.c:38
#4  0x00007ffff7fe276e in getline (s=s@entry=0x7ffff7ffe350 <line>, n=n@entry=0x7ffff7ffe318 <size>, f=f@entry=0x7ffffa65b120) at src/stdio/getline.c:5
#5  0x00007ffff7fe1961 in __getpwent_a (f=f@entry=0x7ffffa65b120, pw=pw@entry=0x7ffff7ffe320 <pw>, line=line@entry=0x7ffff7ffe350 <line>, size=size@entry=0x7ffff7ffe318 <size>, res=res@entry=0x7ffff7f33bb8) at src/passwd/getpwent_a.c:19
#6  0x00007ffff7fe9044 in __getpw_a (name=name@entry=0x0, uid=0x3e8, pw=pw@entry=0x7ffff7ffe320 <pw>, buf=buf@entry=0x7ffff7ffe350 <line>, size=size@entry=0x7ffff7ffe318 <size>, res=res@entry=0x7ffff7f33bb8) at src/passwd/getpw_a.c:36
#7  0x00007ffff7fe18f0 in getpwuid (uid=<optimized out>) at src/passwd/getpwent.c:28
#8  0x00007ffff7fdac56 in check_global_write (ar=0x7ffff8000860, fi=0x7ffffa6c6360) at src/scans/permissions_scan.c:80
#9  0x00007ffff7fdaa57 in permissions_scan (fi=0x7ffffa6c6360, ar=0x7ffff8000860, users=0x7ffff80ea500) at src/scans/permissions_scan.c:50
#10 0x00007ffff7fcf5b9 in scan_file_for_issues (thread_pool_args=0x7ffff8000940) at src/all_scans.c:106
#11 0x00007ffff7fd527b in thread_do (thread_p=0x7ffff8b25880) at src/thpool.c:362
#12 0x00007ffff7fe6270 in start (p=0x7ffff7f34ee8) at src/thread/pthread_create.c:192
#13 0x00007ffff7fe6f23 in __clone () at src/thread/x86_64/clone.s:22
@gdb-peda$ frame 8
@gdb-peda$ stats = {
  st_dev = 0x30,
  st_ino = 0x75c0,
  st_nlink = 0xc,
  st_mode = 0x41c0,
  st_uid = 0x3e8,
  st_gid = 0x3d9,
  __pad0 = 0x0,
  st_rdev = 0x0,
  st_size = 0x17c,
  st_blksize = 0x1000,
  st_blocks = 0x0,
  st_atim = {
    tv_sec = 0x5ed7a82e,
    tv_nsec = 0x3cbe13
  },
  st_mtim = {
    tv_sec = 0x5ed7a7b2,
    tv_nsec = 0x23cd2232
  },
  st_ctim = {
    tv_sec = 0x5ed7a7b2,
    tv_nsec = 0x23cd2232
  },
  __unused = {0x0, 0x0, 0x0}
}
data = 0x0
parent_buf = "/run/user/1000/", '\000' <repeats 2033 times>
issue_buf = "Found a protected world writable file in: /run/user/1000/", '\000' <repeats 2041 times>
@gdb-peda$ x/10i $rip-10
   0x7ffff7fe0eac <realloc+368>:        mov    edi,esp
   0x7ffff7fe0eae <realloc+370>:        mov    r12,r14
   0x7ffff7fe0eb1 <realloc+373>:        call   0x7ffff7fe0d05 <free>
=> 0x7ffff7fe0eb6 <realloc+378>:        add    rsp,0x18
   0x7ffff7fe0eba <realloc+382>:        mov    rax,r12

I've commented the code causing the segfault

johnthesecond commented 4 years ago

pull request #26 should address this issue.