Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve flimsy architecture detection #19465

Open
bcoles opened this issue Sep 17, 2024 · 0 comments
Open

Improve flimsy architecture detection #19465

bcoles opened this issue Sep 17, 2024 · 0 comments
Labels
arm arm library not-stale Label to stop an issue from being auto closed

Comments

@bcoles
Copy link
Contributor

bcoles commented Sep 17, 2024

Much of the platform and architecture detection code within Framework and accompanying libraries has grown naturally as needed over the past 20 years.

Many patches and enhancements were implemented as needed, usually in a manner similar to the following:
  1. x64 is new, let's add support! If the arch detection fails then it must x64
  2. x86 is old school - we're all about x64 now. Let's check a version string for 64, and if it's not x64 then it must be x86
  3. ARM is becoming popular. If the x86 / x64 detection fails then it must be ARM. Let's check for ARM first (32-bit of course), then fall back to x86 / x64 detection
  4. x64 means x86_64, but there are other 64 bit architectures. Even ARM is 64 bit now.
  5. ...
  6. If it doesn't match <large collection of string comparison conditional statements>, then assume it's x86

This evolution is not unique to Metasploit and has played out many times across many projects.

The resulting code patterns are often brittle. In particular, in instances where:

  • anything containing 64 is expected to be x86_64, ignoring 64-bit ARM and RISC-V (and MIPS64 and LoongArch64 and SPARC64 and ...).
  • anything that isn't _________ is presumed to be __________. (ie; anything that isn't <expected architectures> is presumed to be x86)

This will become more of an issue due to the increasing popularity of ARM (OSX on Apple M1 and official support for running Windows on ARM) and RISC-V.

Issues will also arise with a lot of the Windows Meterpreter code if we ever add ARM native Meterpreter (#15025).

We have Msf::Post::Architecture now, which is a good start for local execution on Windows platforms.

Creating a thread to track instances where this should be addressed in Framework and supporting libraries.

Feel free to edit this post, post in this thread, or creating a new issue referencing this issue.


Modules

payload_arch_old = framework.payloads.create(@payload_name).arch.first
# convert the old style archetecture to the new style
@payload_arch = ARCH_X64 if payload_arch_old.include?('64')


if payload.arch.first == ARCH_X64 && sysinfo['Architecture'] !~ /64/
fail_with(Failure::NoTarget, 'The target platform is x86. 64-bit payloads are not supported.')
end


# Try to autodetect the target architecture
def detect_architecture(res)
if (res.body =~ /<td.*?OSArch.*?(x86_64|amd64|x86|i386|i686).*?<\/td>/m)
case arch
when 'x86', 'i386', 'i686'
return ARCH_X86
when 'x86_64', 'amd64'
return ARCH_X64
end
end
nil
end


Libraries

MySQL (arm is supported; RISC-V is not officially supported yet)

def map_compile_arch_to_architecture(compile_arch)
return '' if compile_arch.blank?
compile_arch = compile_arch.downcase.encode(::Encoding::BINARY)
if compile_arch.match?('sparc')
if compile_arch.include?('64')
arch = ARCH_SPARC64
else
arch = ARCH_SPARC
end
elsif compile_arch.match?('arm')
if compile_arch.match?('64')
arch = ARCH_AARCH64
elsif compile_arch.match?('arm')
arch = ARCH_ARMLE
end
elsif compile_arch.match?('64')
arch = ARCH_X86_64
elsif compile_arch.match?('86') || compile_arch.match?('i686')
arch = ARCH_X86
else
arch = compile_arch
end
arch
end

MSSQL:

# MS SQL Server currently only supports 64 bit but older installs may be x86
def map_compile_arch_to_architecture(server_info)
return '' if server_info.blank?
arch_data = server_info.downcase.encode(::Encoding::BINARY)
if arch_data.match?('x64')
arch = ARCH_X86_64
elsif arch_data.match?('x86')
arch = ARCH_X86
elsif arch_data.match?('64')
arch = ARCH_X86_64
elsif arch_data.match?('32-bit')
arch = ARCH_X86
else
arch = arch_data
end
arch
end

PostgreSQL for comparison:

def map_compile_arch_to_architecture(compile_arch)
return '' if compile_arch.blank?
compile_arch = compile_arch.downcase.encode(::Encoding::BINARY)
if compile_arch.match?('sparc')
if compile_arch.include?('64')
arch = ARCH_SPARC64
else
arch = ARCH_SPARC
end
elsif compile_arch.include?('mips')
arch = ARCH_MIPS
elsif compile_arch.include?('ppc')
arch = ARCH_PPC
elsif compile_arch.match?('arm')
if compile_arch.match?('64')
arch = ARCH_AARCH64
elsif compile_arch.match?('arm')
arch = ARCH_ARMLE
end
elsif compile_arch.match?('64')
arch = ARCH_X86_64
elsif compile_arch.match?('86') || compile_arch.match?('i686')
arch = ARCH_X86
else
# Return the query result if the value can't be mapped
arch = compile_arch
end
arch
end


def mysql_get_arch
print_status "Checking target architecture..."
res = mysql_get_variable("@@version_compile_os")
return :unknown unless res
case res
when /Win64/i
:win64
when /Win32/i
:win32
when /Linux/i
# we need a second query to determine bits
res = mysql_get_variable("@@version_compile_machine")
return :unknown unless res
if res =~ /x86_64/i
:linux64
else
:linux32
end
else
res
end
end


# Guess the architecture
case (ua_str.downcase)
when /ppc/
fp[:arch] = ARCH_PPC
when /x64|x86_64/
fp[:arch] = ARCH_X64
when /i.86|wow64/
# WOW64 means "Windows on Windows64" and is present
# in the useragent of 32-bit IE running on 64-bit
# Windows
fp[:arch] = ARCH_X86
when /android|iphone|ipod|ipad/
fp[:arch] = ARCH_ARMLE
else
fp[:arch] = ARCH_X86
end


# Try to autodetect the target architecture
#
# @param res [Rex::Proto::Http::Response] the http response where fingerprint architecture from
# @return [String, nil] The target architecture or nil
def detect_architecture(res)
if res && res.body =~ /<td.*?OSArch.*?(x86_64|amd64|x86|i386|i686).*?<\/td>/m
arch = $1
if arch =~ /^(x86_64|amd64)$/i
return ARCH_X64
elsif arch =~ /^(x86|i386|i686)$/i
return ARCH_X86
end
end
nil
end

@bcoles bcoles added library not-stale Label to stop an issue from being auto closed arm arm labels Sep 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arm arm library not-stale Label to stop an issue from being auto closed
Projects
None yet
Development

No branches or pull requests

1 participant