1

I have a binary that is SUID which I can currently use a buffer overflow exploit to obtain an elevated EUID shell.

However I haven't worked much with changing IDs through shellcode, and the file I need to access requires me to have a GID equal to the EUID I have obtained. However, after obtaining my shell, my GID stays the same as previously.

My question: What system calls or shellcode do I need to execute to elevate my GID to be equal to my EUID when the shell is spawned?

Also: So far I have tried setregid and setegid system calls in shellcode before spawning the shell, however both return "-1" when using a GID that is not already my unprivileged GID.

Thank you.

  • Is it suid root? – forest Apr 22 '18 at 23:59
  • 1
    No, it is suid another non-privileged user. I did some more research and I'm not sure it's even possible to change GID without a root account.. – Sif Apr 23 '18 at 0:47
  • That is correct. I posted an answer to that effect. – forest Apr 23 '18 at 1:02
0

According to setgid(2), the syscall will fail unless the calling process is privileged:

   EPERM  The calling process is not privileged (does not have the
          CAP_SETGID capability), and gid does not match the real group
          ID or saved set-group-ID of the calling process.

Unless you are running with the correct capabilities (specifically CAP_SETGID, provided by root), you cannot change your GID to a value which is not your real or saved GID. This limitation applies to any syscall that changes the GID. The manual page on credentials(7) is extremely helpful.

You can actually see where this is done in the kernel:

SYSCALL_DEFINE1(setgid, gid_t, gid)
{
    struct user_namespace *ns = current_user_ns();
    const struct cred *old;
    struct cred *new;
    int retval;
    kgid_t kgid;

    kgid = make_kgid(ns, gid);
    if (!gid_valid(kgid))
        return -EINVAL;

    new = prepare_creds();
    if (!new)
        return -ENOMEM;
    old = current_cred();

    retval = -EPERM;
    if (ns_capable(old->user_ns, CAP_SETGID))
        new->gid = new->egid = new->sgid = new->fsgid = kgid;
    else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
        new->egid = new->fsgid = kgid;
    else
        goto error;

    return commit_creds(new);

error:
    abort_creds(new);
    return retval;
}

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.