From e01f33f7a50ed71ffec886d366de9f16d8ffbece Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 23 Jan 2025 16:56:26 -0500 Subject: [PATCH] revert f5145de to make function work on target, not locally --- lib/msf/core/post/linux/kernel.rb | 661 +++++++++++++++--------------- 1 file changed, 334 insertions(+), 327 deletions(-) diff --git a/lib/msf/core/post/linux/kernel.rb b/lib/msf/core/post/linux/kernel.rb index 19b2dd8b4ff2..6f0bfb4ce1b4 100644 --- a/lib/msf/core/post/linux/kernel.rb +++ b/lib/msf/core/post/linux/kernel.rb @@ -1,331 +1,338 @@ # -*- coding: binary -*- module Msf -class Post -module Linux -module Kernel - include ::Msf::Post::Common - include Msf::Post::File - # - # Returns uname output - # - # @return [String] - # - def uname(opts='-a') - cmd_exec("uname #{opts}").to_s.strip - rescue - raise "Failed to run uname #{opts}" - end - - # - # Returns the kernel release - # - # @return [String] - # - def kernel_release - uname('-r') - end - - # - # Returns the kernel version - # - # @return [String] - # - def kernel_version - uname('-v') - end - - # - # Returns the kernel name - # - # @return [String] - # - def kernel_name - uname('-s') - end - - # - # Returns the kernel hardware - # - # @return [String] - # - def kernel_hardware - uname('-m') - end - - # - # Returns the kernel hardware architecture - # Based on values from https://en.wikipedia.org/wiki/Uname - # - # @return [String] - # - def kernel_arch - arch = kernel_hardware - return ARCH_X64 if arch == 'x86_64' || arch == 'amd64' - return ARCH_AARCH64 if arch == 'aarch64' || arch == 'arm64' - return ARCH_ARMLE if arch.start_with?'arm' - return ARCH_X86 if arch.end_with?'86' - return ARCH_PPC if arch == 'ppc' - return ARCH_PPC64 if arch == 'ppc64' - return ARCH_PPC64LE if arch == 'ppc64le' - return ARCH_MIPS if arch == 'mips' - return ARCH_MIPS64 if arch == 'mips64' - return ARCH_SPARC if arch == 'sparc' - return ARCH_RISCV32LE if arch == 'riscv32' - return ARCH_RISCV64LE if arch == 'riscv64' - return ARCH_LOONGARCH64 if arch == 'loongarch64' - arch - end - - # - # Returns the kernel boot config - # - # @return [Array] - # - def kernel_config - release = kernel_release - output = read_file("/boot/config-#{release}").to_s.strip - return if output.empty? - config = output.split("\n").map(&:strip).reject(&:empty?).reject {|i| i.start_with? '#'} - config - rescue - raise 'Could not retrieve kernel config' - end - - # - # Returns the kernel modules - # - # @return [Array] - # - def kernel_modules - read_file('/proc/modules').to_s.scan(/^[^ ]+/) - rescue - raise 'Could not determine kernel modules' - end - - # - # Returns a list of CPU flags - # - # @return [Array] - # - def cpu_flags - cpuinfo = read_file('/proc/cpuinfo').to_s - - return unless cpuinfo.include? 'flags' - - cpuinfo.scan(/^flags\s*:(.*)$/).flatten.join(' ').split(/\s/).map(&:strip).reject(&:empty?).uniq - rescue - raise'Could not retrieve CPU flags' - end - - # - # Returns true if kernel and hardware supports Supervisor Mode Access Prevention (SMAP), false if not. - # - # @return [Boolean] - # - def smap_enabled? - cpu_flags.include? 'smap' - rescue - raise 'Could not determine SMAP status' - end - - # - # Returns true if kernel and hardware supports Supervisor Mode Execution Protection (SMEP), false if not. - # - # @return [Boolean] - # - def smep_enabled? - cpu_flags.include? 'smep' - rescue - raise 'Could not determine SMEP status' - end - - # - # Returns true if Kernel Address Isolation (KAISER) is enabled - # - # @return [Boolean] - # - def kaiser_enabled? - cpu_flags.include? 'kaiser' - rescue - raise 'Could not determine KAISER status' - end - - # - # Returns true if Kernel Page-Table Isolation (KPTI) is enabled, false if not. - # - # @return [Boolean] - # - def kpti_enabled? - cpu_flags.include? 'pti' - rescue - raise 'Could not determine KPTI status' - end - - # - # Returns true if user namespaces are enabled, false if not. - # - # @return [Boolean] - # - def userns_enabled? - return false if read_file('/proc/sys/user/max_user_namespaces').to_s.strip.eql? '0' - return false if read_file('/proc/sys/kernel/unprivileged_userns_clone').to_s.strip.eql? '0' - true - rescue - raise 'Could not determine userns status' - end - - # - # Returns true if Address Space Layout Randomization (ASLR) is enabled - # - # @return [Boolean] - # - def aslr_enabled? - aslr = read_file('/proc/sys/kernel/randomize_va_space').to_s.strip - (aslr.eql?('1') || aslr.eql?('2')) - rescue - raise 'Could not determine ASLR status' - end - - # - # Returns true if Exec-Shield is enabled - # - # @return [Boolean] - # - def exec_shield_enabled? - exec_shield = read_file('/proc/sys/kernel/exec-shield').to_s.strip - (exec_shield.eql?('1') || exec_shield.eql?('2')) - rescue - raise 'Could not determine exec-shield status' - end - - # - # Returns true if unprivileged bpf is disabled - # - # @return [Boolean] - # - def unprivileged_bpf_disabled? - unprivileged_bpf_disabled = read_file('/proc/sys/kernel/unprivileged_bpf_disabled').to_s.strip - return (unprivileged_bpf_disabled == '1' || unprivileged_bpf_disabled == '2') - rescue - raise 'Could not determine kernel.unprivileged_bpf_disabled status' - end - - # - # Returns true if kernel pointer restriction is enabled - # - # @return [Boolean] - # - def kptr_restrict? - read_file('/proc/sys/kernel/kptr_restrict').to_s.strip.eql? '1' - rescue - raise 'Could not determine kernel.kptr_restrict status' - end - - # - # Returns true if dmesg restriction is enabled - # - # @return [Boolean] - # - def dmesg_restrict? - read_file('/proc/sys/kernel/dmesg_restrict').to_s.strip.eql? '1' - rescue - raise 'Could not determine kernel.dmesg_restrict status' - end - - # - # Returns mmap minimum address - # - # @return [Integer] - # - def mmap_min_addr - mmap_min_addr = read_file('/proc/sys/vm/mmap_min_addr').to_s.strip - return 0 unless mmap_min_addr =~ /\A\d+\z/ - mmap_min_addr - rescue - raise 'Could not determine system mmap_min_addr' - end - - # - # Returns true if Linux Kernel Runtime Guard (LKRG) kernel module is installed - # - def lkrg_installed? - directory?('/proc/sys/lkrg') - rescue - raise 'Could not determine LKRG status' - end - - # - # Returns true if grsecurity is installed - # - def grsec_installed? - File.exists?('/dev/grsec') && File.chardev?('/dev/grsec') - rescue - raise 'Could not determine grsecurity status' - end - - # - # Returns true if PaX is installed - # - def pax_installed? - read_file('/proc/self/status').to_s.include? 'PaX:' - rescue - raise 'Could not determine PaX status' - end - - # - # Returns true if SELinux is installed - # - # @return [Boolean] - # - def selinux_installed? - cmd_exec('id').to_s.include? 'context=' - rescue - raise 'Could not determine SELinux status' - end - - # - # Returns true if SELinux is in enforcing mode - # - # @return [Boolean] - # - def selinux_enforcing? - return false unless selinux_installed? - - sestatus = cmd_exec('/usr/sbin/sestatus').to_s.strip - raise unless sestatus.include?('SELinux') - - return true if sestatus =~ /Current mode:\s*enforcing/ - false - rescue - raise 'Could not determine SELinux status' - end - - # - # Returns true if Yama is installed - # - # @return [Boolean] - # - def yama_installed? - ptrace_scope = read_file('/proc/sys/kernel/yama/ptrace_scope').to_s.strip - return true if ptrace_scope =~ /\A\d\z/ - false - rescue - raise 'Could not determine Yama status' - end - - # - # Returns true if Yama is enabled - # - # @return [Boolean] - # - def yama_enabled? - return false unless yama_installed? - !read_file('/proc/sys/kernel/yama/ptrace_scope').to_s.strip.eql? '0' - rescue - raise 'Could not determine Yama status' - end -end # Kernel -end # Linux -end # Post + class Post + module Linux + module Kernel + include ::Msf::Post::Common + include Msf::Post::File + # + # Returns uname output + # + # @return [String] + # + def uname(opts = '-a') + cmd_exec("uname #{opts}").to_s.strip + rescue StandardError + raise "Failed to run uname #{opts}" + end + + # + # Returns the kernel release + # + # @return [String] + # + def kernel_release + uname('-r') + end + + # + # Returns the kernel version + # + # @return [String] + # + def kernel_version + uname('-v') + end + + # + # Returns the kernel name + # + # @return [String] + # + def kernel_name + uname('-s') + end + + # + # Returns the kernel hardware + # + # @return [String] + # + def kernel_hardware + uname('-m') + end + + # + # Returns the kernel hardware architecture + # Based on values from https://en.wikipedia.org/wiki/Uname + # + # @return [String] + # + def kernel_arch + arch = kernel_hardware + return ARCH_X64 if arch == 'x86_64' || arch == 'amd64' + return ARCH_AARCH64 if arch == 'aarch64' || arch == 'arm64' + return ARCH_ARMLE if arch.start_with? 'arm' + return ARCH_X86 if arch.end_with? '86' + return ARCH_PPC if arch == 'ppc' + return ARCH_PPC64 if arch == 'ppc64' + return ARCH_PPC64LE if arch == 'ppc64le' + return ARCH_MIPS if arch == 'mips' + return ARCH_MIPS64 if arch == 'mips64' + return ARCH_SPARC if arch == 'sparc' + return ARCH_RISCV32LE if arch == 'riscv32' + return ARCH_RISCV64LE if arch == 'riscv64' + return ARCH_LOONGARCH64 if arch == 'loongarch64' + + arch + end + + # + # Returns the kernel boot config + # + # @return [Array] + # + def kernel_config + release = kernel_release + output = read_file("/boot/config-#{release}").to_s.strip + return if output.empty? + + config = output.split("\n").map(&:strip).reject(&:empty?).reject { |i| i.start_with? '#' } + config + rescue StandardError + raise 'Could not retrieve kernel config' + end + + # + # Returns the kernel modules + # + # @return [Array] + # + def kernel_modules + read_file('/proc/modules').to_s.scan(/^[^ ]+/) + rescue StandardError + raise 'Could not determine kernel modules' + end + + # + # Returns a list of CPU flags + # + # @return [Array] + # + def cpu_flags + cpuinfo = read_file('/proc/cpuinfo').to_s + + return unless cpuinfo.include? 'flags' + + cpuinfo.scan(/^flags\s*:(.*)$/).flatten.join(' ').split(/\s/).map(&:strip).reject(&:empty?).uniq + rescue StandardError + raise 'Could not retrieve CPU flags' + end + + # + # Returns true if kernel and hardware supports Supervisor Mode Access Prevention (SMAP), false if not. + # + # @return [Boolean] + # + def smap_enabled? + cpu_flags.include? 'smap' + rescue StandardError + raise 'Could not determine SMAP status' + end + + # + # Returns true if kernel and hardware supports Supervisor Mode Execution Protection (SMEP), false if not. + # + # @return [Boolean] + # + def smep_enabled? + cpu_flags.include? 'smep' + rescue StandardError + raise 'Could not determine SMEP status' + end + + # + # Returns true if Kernel Address Isolation (KAISER) is enabled + # + # @return [Boolean] + # + def kaiser_enabled? + cpu_flags.include? 'kaiser' + rescue StandardError + raise 'Could not determine KAISER status' + end + + # + # Returns true if Kernel Page-Table Isolation (KPTI) is enabled, false if not. + # + # @return [Boolean] + # + def kpti_enabled? + cpu_flags.include? 'pti' + rescue StandardError + raise 'Could not determine KPTI status' + end + + # + # Returns true if user namespaces are enabled, false if not. + # + # @return [Boolean] + # + def userns_enabled? + return false if read_file('/proc/sys/user/max_user_namespaces').to_s.strip.eql? '0' + return false if read_file('/proc/sys/kernel/unprivileged_userns_clone').to_s.strip.eql? '0' + + true + rescue StandardError + raise 'Could not determine userns status' + end + + # + # Returns true if Address Space Layout Randomization (ASLR) is enabled + # + # @return [Boolean] + # + def aslr_enabled? + aslr = read_file('/proc/sys/kernel/randomize_va_space').to_s.strip + aslr.eql?('1') || aslr.eql?('2') + rescue StandardError + raise 'Could not determine ASLR status' + end + + # + # Returns true if Exec-Shield is enabled + # + # @return [Boolean] + # + def exec_shield_enabled? + exec_shield = read_file('/proc/sys/kernel/exec-shield').to_s.strip + exec_shield.eql?('1') || exec_shield.eql?('2') + rescue StandardError + raise 'Could not determine exec-shield status' + end + + # + # Returns true if unprivileged bpf is disabled + # + # @return [Boolean] + # + def unprivileged_bpf_disabled? + unprivileged_bpf_disabled = read_file('/proc/sys/kernel/unprivileged_bpf_disabled').to_s.strip + return unprivileged_bpf_disabled == '1' || unprivileged_bpf_disabled == '2' + rescue StandardError + raise 'Could not determine kernel.unprivileged_bpf_disabled status' + end + + # + # Returns true if kernel pointer restriction is enabled + # + # @return [Boolean] + # + def kptr_restrict? + read_file('/proc/sys/kernel/kptr_restrict').to_s.strip.eql? '1' + rescue StandardError + raise 'Could not determine kernel.kptr_restrict status' + end + + # + # Returns true if dmesg restriction is enabled + # + # @return [Boolean] + # + def dmesg_restrict? + read_file('/proc/sys/kernel/dmesg_restrict').to_s.strip.eql? '1' + rescue StandardError + raise 'Could not determine kernel.dmesg_restrict status' + end + + # + # Returns mmap minimum address + # + # @return [Integer] + # + def mmap_min_addr + mmap_min_addr = read_file('/proc/sys/vm/mmap_min_addr').to_s.strip + return 0 unless mmap_min_addr =~ /\A\d+\z/ + + mmap_min_addr + rescue StandardError + raise 'Could not determine system mmap_min_addr' + end + + # + # Returns true if Linux Kernel Runtime Guard (LKRG) kernel module is installed + # + def lkrg_installed? + directory?('/proc/sys/lkrg') + rescue StandardError + raise 'Could not determine LKRG status' + end + + # + # Returns true if grsecurity is installed + # + def grsec_installed? + cmd_exec('test -c /dev/grsec && echo true').to_s.strip.include? 'true' + rescue StandardError + raise 'Could not determine grsecurity status' + end + + # + # Returns true if PaX is installed + # + def pax_installed? + read_file('/proc/self/status').to_s.include? 'PaX:' + rescue StandardError + raise 'Could not determine PaX status' + end + + # + # Returns true if SELinux is installed + # + # @return [Boolean] + # + def selinux_installed? + cmd_exec('id').to_s.include? 'context=' + rescue StandardError + raise 'Could not determine SELinux status' + end + + # + # Returns true if SELinux is in enforcing mode + # + # @return [Boolean] + # + def selinux_enforcing? + return false unless selinux_installed? + + sestatus = cmd_exec('/usr/sbin/sestatus').to_s.strip + raise unless sestatus.include?('SELinux') + + return true if sestatus =~ /Current mode:\s*enforcing/ + + false + rescue StandardError + raise 'Could not determine SELinux status' + end + + # + # Returns true if Yama is installed + # + # @return [Boolean] + # + def yama_installed? + ptrace_scope = read_file('/proc/sys/kernel/yama/ptrace_scope').to_s.strip + return true if ptrace_scope =~ /\A\d\z/ + + false + rescue StandardError + raise 'Could not determine Yama status' + end + + # + # Returns true if Yama is enabled + # + # @return [Boolean] + # + def yama_enabled? + return false unless yama_installed? + + !read_file('/proc/sys/kernel/yama/ptrace_scope').to_s.strip.eql? '0' + rescue StandardError + raise 'Could not determine Yama status' + end + end # Kernel + end # Linux + end # Post end # Msf