Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
__pycache__/
*.pyc
*.pyo
*.pyd
.build/
.env
.venv
.git
.gitignore
.dist/
**/.mypy_cache/
**/.pytest_cache/
**/.ruff_cache/
**/.DS_Store
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM python:3.12-slim

WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir .

ENTRYPOINT ["svscan"]
CMD ["--help"]
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
PYTHON ?= python3
PIP ?= $(PYTHON) -m pip

.PHONY: install dev uninstall help build docker-build docker-run

help:
@echo "Targets: install, dev, uninstall, build, docker-build, docker-run"

install:
$(PIP) install .

dev:
$(PIP) install -e .

uninstall:
-$(PIP) uninstall -y svscan

build:
$(PYTHON) -m build

docker-build:
docker build -t svscan:latest .

docker-run:
docker run --rm svscan:latest --help
75 changes: 73 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,73 @@
# NetNinjaScan
Сканер сети и уязвимостей
# NetNinjaScan — модульный сканер сети и уязвимостей

Небольшой консольный аналог Nessus/OpenVAS/NetScanPro: быстрый сетевой сканер (TCP connect), лёгкое фингерпринтинг‑сканирование и локальная база сигнатур уязвимостей.

## Возможности (MVP)
- Сканер сети: асинхронный TCP connect, CIDR/hostname/IP, настраиваемые порты и параллелизм
- Сканер уязвимостей: базовый фингерпринтинг HTTP/SSH/FTP/SMTP и сопоставление с локальной БД (`svscan/data/vuln_db.json`)
- Удобный CLI с подкомандами: `svscan net scan`, `svscan vuln scan`
- Простая установка: Docker и Python пакет

## Установка

### Вариант 1: Docker (самый быстрый)
```bash
docker build -t svscan:latest .
docker run --rm svscan:latest --help
```

### Вариант 2: pipx (рекомендуется для локальной установки)
После публикации на GitHub:
```bash
pipx install git+https://github.com/<your_org>/svscan
svscan --help
```
Локально из исходников:
```bash
pipx install /workspace
svscan --help
```

### Вариант 3: pip (в пользовательскую директорию)
```bash
python3 -m pip install -e . --user
~/.local/bin/svscan --help
```

## Примеры использования
- Скан сети (диапазон):
```bash
svscan net scan 192.168.1.0/24 -p 22,80,443 --json
```
- Скан уязвимостей (фингерпринтинг + локальные сигнатуры):
```bash
svscan vuln scan example.com -p 21,22,25,80,443 -o report.json
```

## Архитектура
- `svscan/cli.py` — CLI (Typer), подкоманды `net` и `vuln`
- `svscan/scanners/network_scanner.py` — сетевой сканер (async TCP connect), парсинг целей/портов
- `svscan/scanners/vuln_scanner.py` — фингерпринтинг (HTTP/SSH/FTP/SMTP) + сопоставление с БД
- `svscan/data/vuln_db.json` — минимальная локальная БД сигнатур
- Пакетирование: `pyproject.toml` (entrypoint `svscan`)
- Контейнеризация: `Dockerfile`

Модульность: код сканера сети и уязвимостей расположен в отдельных папках. Легко добавлять новые модули (например, `svscan/scanners/udp_scanner.py`).

## Как развивать
- Новые протоколы: SMB, RDP, TLS (шифросьюты), SNMP, Redis, MySQL/PostgreSQL
- UDP‑сканирование, ОС‑детектирование, баннер‑граббинг с эвристиками, HTTP‑краулер
- Экспорт: JSON/SARIF/JUnit, интеграции Jira/GitLab
- Планировщик, кэш, продолжение прерванных сканов, лимиты скорости
- Автообновление БД уязвимостей из NVD/OSV/CISA KEV, расчёт CVSS
- TUI/Web‑UI, REST API, плагинная система (SDK для правил/сценариев)

## Монетизация (идеи)
- Freemium: базовый скан бесплатный; Pro — расширенные плагины, Web‑UI, планировщик, отчёты, интеграции
- Подписка на обновления сигнатур/отчётов (обогащение данными, приоритетные обновления)
- Коммерческая поддержка/SLAs, аудит, консультации
- Marketplace плагинов (корпоративные правила, интеграции SIEM/SOAR)
- Cloud SaaS‑версия: сканы через управляемую облачную очередь/агенты

## Дисклеймер
Используйте инструмент только на ресурсах, на тест‑стендах или при наличии письменного разрешения. Ответственность не лежит на egorTriceps. Ответственность за использование лежит только на пользователе.
43 changes: 43 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[build-system]
requires = ["setuptools>=68.0"]
build-backend = "setuptools.build_meta"

[project]
name = "svscan"
version = "0.1.0"
description = "Modular security scanner (network + vulnerability) with fast, easy install."
readme = "README.md"
requires-python = ">=3.10"
license = { text = "MIT" }
authors = [
{ name = "SVScan Authors", email = "maintainers@example.com" }
]
keywords = ["security", "scanner", "network", "vulnerability", "cli"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Topic :: Security",
"Intended Audience :: System Administrators",
"Intended Audience :: Developers"
]
dependencies = [
"typer>=0.12.3"
]

[project.urls]
Homepage = "https://github.com/example/svscan"
Issues = "https://github.com/example/svscan/issues"

[project.scripts]
svscan = "svscan.cli:app"

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["."]
include = ["svscan*"]

[tool.setuptools.package-data]
"svscan.data" = ["*.json"]
23 changes: 23 additions & 0 deletions svscan.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Metadata-Version: 2.4
Name: svscan
Version: 0.1.0
Summary: Modular security scanner (network + vulnerability) with fast, easy install.
Author-email: SVScan Authors <maintainers@example.com>
License: MIT
Project-URL: Homepage, https://github.com/example/svscan
Project-URL: Issues, https://github.com/example/svscan/issues
Keywords: security,scanner,network,vulnerability,cli
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Security
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Developers
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: typer>=0.12.3
Dynamic: license-file

# NetNinjaScan
Сканер сети и уязвимостей
21 changes: 21 additions & 0 deletions svscan.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
LICENSE
README.md
pyproject.toml
svscan/__init__.py
svscan/cli.py
svscan/version.py
svscan.egg-info/PKG-INFO
svscan.egg-info/SOURCES.txt
svscan.egg-info/dependency_links.txt
svscan.egg-info/entry_points.txt
svscan.egg-info/requires.txt
svscan.egg-info/top_level.txt
svscan/data/__init__.py
svscan/data/vuln_db.json
svscan/reporting/__init__.py
svscan/reporting/serialize.py
svscan/scanners/__init__.py
svscan/scanners/network_scanner.py
svscan/scanners/vuln_scanner.py
svscan/utils/__init__.py
svscan/utils/targets.py
1 change: 1 addition & 0 deletions svscan.egg-info/dependency_links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 2 additions & 0 deletions svscan.egg-info/entry_points.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[console_scripts]
svscan = svscan.cli:app
1 change: 1 addition & 0 deletions svscan.egg-info/requires.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
typer>=0.12.3
1 change: 1 addition & 0 deletions svscan.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
svscan
1 change: 1 addition & 0 deletions svscan/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .version import VERSION as __version__
Binary file added svscan/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file added svscan/__pycache__/cli.cpython-313.pyc
Binary file not shown.
Binary file added svscan/__pycache__/version.cpython-313.pyc
Binary file not shown.
91 changes: 91 additions & 0 deletions svscan/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import asyncio
import json
from typing import List, Optional

import typer

from svscan.version import VERSION
from svscan.scanners.network_scanner import (
scan_targets,
parse_ports,
)
from svscan.scanners.vuln_scanner import run_vuln_scan

app = typer.Typer(no_args_is_help=True, help="SVScan: modular network and vulnerability scanner")

net_app = typer.Typer(help="Network scanning commands")
vuln_app = typer.Typer(help="Vulnerability scanning commands")

app.add_typer(net_app, name="net")
app.add_typer(vuln_app, name="vuln")


@app.command()
def version() -> None:
"""Show version information."""
typer.echo(f"svscan {VERSION}")


@net_app.command("scan")
def net_scan(
targets: List[str] = typer.Argument(..., help="Targets: IPs, hostnames, or CIDRs (e.g. 192.168.1.0/24)"),
ports: str = typer.Option("22,80,443", "--ports", "-p", help="Comma-separated ports"),
timeout: float = typer.Option(0.5, help="Per-connection timeout (seconds)"),
concurrency: int = typer.Option(200, help="Max concurrent connections"),
output: Optional[str] = typer.Option(None, "--output", "-o", help="Write results to file (json)"),
as_json: bool = typer.Option(False, "--json", help="Print JSON to stdout"),
) -> None:
"""Run a TCP connect network scan."""
port_list = parse_ports(ports)
results = asyncio.run(scan_targets(targets, port_list, timeout=timeout, concurrency=concurrency))

if as_json or output:
data = json.dumps(results, indent=2)
if output:
with open(output, "w", encoding="utf-8") as f:
f.write(data)
if as_json:
typer.echo(data)
else:
for host_result in results:
typer.echo(f"Host: {host_result['host']}")
open_ports = host_result.get("open_ports", [])
if not open_ports:
typer.echo(" No open ports found")
else:
for port in open_ports:
typer.echo(f" Port {port}")


@vuln_app.command("scan")
def vuln_scan(
targets: List[str] = typer.Argument(..., help="Targets: IPs, hostnames, or CIDRs"),
ports: str = typer.Option("22,80,443", "--ports", "-p", help="Comma-separated ports"),
timeout: float = typer.Option(0.8, help="Per-connection timeout (seconds)"),
concurrency: int = typer.Option(200, help="Max concurrent connections"),
output: Optional[str] = typer.Option(None, "--output", "-o", help="Write results to file (json)"),
as_json: bool = typer.Option(False, "--json", help="Print JSON to stdout"),
) -> None:
"""Run a vulnerability scan (network scan + lightweight fingerprinting + DB match)."""
port_list = parse_ports(ports)
results = asyncio.run(run_vuln_scan(targets, port_list, timeout=timeout, concurrency=concurrency))

if as_json or output:
data = json.dumps(results, indent=2)
if output:
with open(output, "w", encoding="utf-8") as f:
f.write(data)
if as_json:
typer.echo(data)
else:
for host in results:
typer.echo(f"Host: {host['host']}")
if not host.get("findings"):
typer.echo(" No vulnerabilities found (based on local signatures)")
continue
for finding in host["findings"]:
typer.echo(
f" [{finding['severity'].upper()}] {finding['id']} on {finding['service']}\n"
f" Evidence: {finding.get('evidence', '')}\n"
f" Description: {finding.get('description', '')}"
)
Empty file added svscan/data/__init__.py
Empty file.
34 changes: 34 additions & 0 deletions svscan/data/vuln_db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"id": "CVE-2021-41773",
"service": "http",
"match": { "type": "header_regex", "header": "server", "pattern": "Apache/2\\.4\\.49" },
"severity": "high",
"description": "Apache HTTP Server 2.4.49 path traversal and RCE in default configs.",
"references": ["https://httpd.apache.org/security/vulnerabilities_24.html#CVE-2021-41773"]
},
{
"id": "CVE-2016-0777",
"service": "ssh",
"match": { "type": "banner_regex", "pattern": "OpenSSH_7\\.[01]" },
"severity": "medium",
"description": "OpenSSH roaming vulnerability leads to potential key leak.",
"references": ["https://www.openssh.com/txt/release-7.1p2"]
},
{
"id": "CVE-2019-10149",
"service": "smtp",
"match": { "type": "banner_regex", "pattern": "Exim 4\\.92" },
"severity": "high",
"description": "Exim 4.92 local privilege escalation via string expansion flaw.",
"references": ["https://nvd.nist.gov/vuln/detail/CVE-2019-10149"]
},
{
"id": "CVE-2011-2523",
"service": "ftp",
"match": { "type": "banner_regex", "pattern": "vsFTPd 2\\.3\\.4" },
"severity": "critical",
"description": "vsftpd 2.3.4 backdoor allows remote code execution.",
"references": ["https://nvd.nist.gov/vuln/detail/CVE-2011-2523"]
}
]
Empty file added svscan/reporting/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions svscan/reporting/serialize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import json
from typing import Any


def to_json(data: Any) -> str:
return json.dumps(data, indent=2)
Empty file added svscan/scanners/__init__.py
Empty file.
Binary file added svscan/scanners/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading