sps-security 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sps_security-1.0.0/LICENSE +5 -0
- sps_security-1.0.0/PKG-INFO +14 -0
- sps_security-1.0.0/README.md +32 -0
- sps_security-1.0.0/setup.cfg +4 -0
- sps_security-1.0.0/setup.py +19 -0
- sps_security-1.0.0/sps_security/__init__.py +0 -0
- sps_security-1.0.0/sps_security/cli.py +27 -0
- sps_security-1.0.0/sps_security/core/__init__.py +0 -0
- sps_security-1.0.0/sps_security/core/binary_engine.py +23 -0
- sps_security-1.0.0/sps_security/core/hash_engine.py +15 -0
- sps_security-1.0.0/sps_security/core/heuristic_engine.py +30 -0
- sps_security-1.0.0/sps_security/core/scanner.py +88 -0
- sps_security-1.0.0/sps_security/core/signature_engine.py +21 -0
- sps_security-1.0.0/sps_security/database/__init__.py +0 -0
- sps_security-1.0.0/sps_security/utils/__init__.py +0 -0
- sps_security-1.0.0/sps_security/utils/hashing.py +17 -0
- sps_security-1.0.0/sps_security/utils/logger.py +17 -0
- sps_security-1.0.0/sps_security/utils/quarantine.py +19 -0
- sps_security-1.0.0/sps_security.egg-info/PKG-INFO +14 -0
- sps_security-1.0.0/sps_security.egg-info/SOURCES.txt +22 -0
- sps_security-1.0.0/sps_security.egg-info/dependency_links.txt +1 -0
- sps_security-1.0.0/sps_security.egg-info/entry_points.txt +2 -0
- sps_security-1.0.0/sps_security.egg-info/requires.txt +2 -0
- sps_security-1.0.0/sps_security.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sps-security
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Malware detection tool
|
|
5
|
+
Author: Samuel Pontes
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: tqdm
|
|
9
|
+
Requires-Dist: colorama
|
|
10
|
+
Dynamic: author
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
Dynamic: requires-dist
|
|
13
|
+
Dynamic: requires-python
|
|
14
|
+
Dynamic: summary
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# 🛡️ SPS-SECURITY
|
|
2
|
+
|
|
3
|
+
### Lightweight Malware Detection Tool
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
SPS-SECURITY is an open-source malware detection tool created for learning cybersecurity concepts.
|
|
12
|
+
|
|
13
|
+
It scans files and directories looking for malware using multiple detection engines.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🔍 Features
|
|
18
|
+
|
|
19
|
+
- Hash-based malware detection
|
|
20
|
+
- Signature detection
|
|
21
|
+
- Heuristic detection
|
|
22
|
+
- Binary scanning
|
|
23
|
+
- Multithread scanning
|
|
24
|
+
- Quarantine system
|
|
25
|
+
- JSON scan reports
|
|
26
|
+
- CLI interface
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ⚡ Usage
|
|
31
|
+
|
|
32
|
+
Scan a folder:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="sps-security",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
author="Samuel Pontes",
|
|
7
|
+
description="Malware detection tool",
|
|
8
|
+
packages=find_packages(),
|
|
9
|
+
install_requires=[
|
|
10
|
+
"tqdm",
|
|
11
|
+
"colorama",
|
|
12
|
+
],
|
|
13
|
+
entry_points={
|
|
14
|
+
"console_scripts": [
|
|
15
|
+
"sps=sps_security.cli:run",
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
python_requires=">=3.8",
|
|
19
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from sps_security.core.scanner import scan_folder
|
|
3
|
+
|
|
4
|
+
def load_file(path):
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
with open(path) as f:
|
|
8
|
+
return [line.strip() for line in f if line.strip()]
|
|
9
|
+
except:
|
|
10
|
+
return []
|
|
11
|
+
|
|
12
|
+
def run():
|
|
13
|
+
|
|
14
|
+
parser = argparse.ArgumentParser(description="SPS Security Scanner")
|
|
15
|
+
|
|
16
|
+
parser.add_argument("command", help="scan")
|
|
17
|
+
parser.add_argument("target", help="folder or file")
|
|
18
|
+
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
|
|
21
|
+
signatures = load_file("sps_security/database/signatures.txt")
|
|
22
|
+
hashes = load_file("sps_security/database/malware_hash_db.txt")
|
|
23
|
+
|
|
24
|
+
patterns = signatures
|
|
25
|
+
|
|
26
|
+
if args.command == "scan":
|
|
27
|
+
scan_folder(args.target, signatures, hashes, patterns)
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from colorama import Fore
|
|
2
|
+
|
|
3
|
+
def binary_scan(file, patterns):
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
|
|
7
|
+
with open(file, "rb") as f:
|
|
8
|
+
|
|
9
|
+
data = f.read()
|
|
10
|
+
|
|
11
|
+
text = data.decode("latin-1", errors="ignore")
|
|
12
|
+
|
|
13
|
+
for p in patterns:
|
|
14
|
+
|
|
15
|
+
if p in text:
|
|
16
|
+
|
|
17
|
+
print(Fore.YELLOW + f"[BINARY ALERT] {p} in {file}")
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
except:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
return False
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from sps_security.utils.hashing import get_hash
|
|
2
|
+
from colorama import Fore
|
|
3
|
+
|
|
4
|
+
def hash_scan(file, malware_hashes):
|
|
5
|
+
|
|
6
|
+
file_hash = get_hash(file)
|
|
7
|
+
|
|
8
|
+
if file_hash in malware_hashes:
|
|
9
|
+
|
|
10
|
+
print(Fore.RED + f"[HASH ALERT] {file}")
|
|
11
|
+
print(Fore.YELLOW + f"SHA256: {file_hash}")
|
|
12
|
+
|
|
13
|
+
return True
|
|
14
|
+
|
|
15
|
+
return False
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from colorama import Fore
|
|
2
|
+
|
|
3
|
+
HEURISTIC_PATTERNS = [
|
|
4
|
+
"powershell -enc",
|
|
5
|
+
"cmd.exe /c",
|
|
6
|
+
"nc -e",
|
|
7
|
+
"wget http",
|
|
8
|
+
"curl http",
|
|
9
|
+
"base64 -d"
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
def heuristic_scan(file):
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
|
|
16
|
+
with open(file, "r", errors="ignore") as f:
|
|
17
|
+
|
|
18
|
+
content = f.read()
|
|
19
|
+
|
|
20
|
+
for pattern in HEURISTIC_PATTERNS:
|
|
21
|
+
|
|
22
|
+
if pattern in content:
|
|
23
|
+
|
|
24
|
+
print(Fore.YELLOW + f"[HEURISTIC ALERT] {pattern} in {file}")
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
except:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
return False
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
+
from tqdm import tqdm
|
|
4
|
+
|
|
5
|
+
from sps_security.core.hash_engine import hash_scan
|
|
6
|
+
from sps_security.core.signature_engine import signature_scan
|
|
7
|
+
from sps_security.core.heuristic_engine import heuristic_scan
|
|
8
|
+
from sps_security.core.binary_engine import binary_scan
|
|
9
|
+
from sps_security.utils.quarantine import quarantine
|
|
10
|
+
from sps_security.utils.logger import log
|
|
11
|
+
|
|
12
|
+
# extensões ignoradas
|
|
13
|
+
IGNORE_EXT = (".py", ".pyc")
|
|
14
|
+
|
|
15
|
+
# pastas ignoradas
|
|
16
|
+
IGNORE_DIRS = ["quarantine", "__pycache__", "database"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def scan_file(file, signatures, hashes, patterns):
|
|
20
|
+
|
|
21
|
+
# ignorar arquivos de código
|
|
22
|
+
if file.endswith(IGNORE_EXT):
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
|
|
27
|
+
# HASH detection
|
|
28
|
+
if hash_scan(file, hashes):
|
|
29
|
+
log(f"HASH DETECTED: {file}")
|
|
30
|
+
quarantine(file)
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
# SIGNATURE detection
|
|
34
|
+
if signature_scan(file, signatures):
|
|
35
|
+
log(f"SIGNATURE DETECTED: {file}")
|
|
36
|
+
quarantine(file)
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
# HEURISTIC detection
|
|
40
|
+
if heuristic_scan(file):
|
|
41
|
+
log(f"HEURISTIC DETECTED: {file}")
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
# BINARY detection
|
|
45
|
+
if file.endswith((".exe", ".dll", ".apk", ".bin")):
|
|
46
|
+
if binary_scan(file, patterns):
|
|
47
|
+
log(f"BINARY DETECTED: {file}")
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
except Exception as e:
|
|
51
|
+
log(f"ERROR scanning {file}: {e}")
|
|
52
|
+
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def scan_folder(folder, signatures, hashes, patterns):
|
|
57
|
+
|
|
58
|
+
files = []
|
|
59
|
+
|
|
60
|
+
for root, dirs, names in os.walk(folder):
|
|
61
|
+
|
|
62
|
+
# remover diretórios ignorados
|
|
63
|
+
dirs[:] = [d for d in dirs if d not in IGNORE_DIRS]
|
|
64
|
+
|
|
65
|
+
for name in names:
|
|
66
|
+
files.append(os.path.join(root, name))
|
|
67
|
+
|
|
68
|
+
print("\n[SCAN] Starting analysis...\n")
|
|
69
|
+
|
|
70
|
+
threats = []
|
|
71
|
+
|
|
72
|
+
with ThreadPoolExecutor() as executor:
|
|
73
|
+
|
|
74
|
+
results = list(
|
|
75
|
+
tqdm(
|
|
76
|
+
executor.map(lambda f: scan_file(f, signatures, hashes, patterns), files),
|
|
77
|
+
total=len(files)
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
for i, result in enumerate(results):
|
|
82
|
+
|
|
83
|
+
if result:
|
|
84
|
+
threats.append(files[i])
|
|
85
|
+
|
|
86
|
+
print("\n[RESULT]")
|
|
87
|
+
print("Files scanned:", len(files))
|
|
88
|
+
print("Threats found:", len(threats))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from colorama import Fore
|
|
2
|
+
|
|
3
|
+
def signature_scan(file, signatures):
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
|
|
7
|
+
with open(file, "r", errors="ignore") as f:
|
|
8
|
+
|
|
9
|
+
content = f.read()
|
|
10
|
+
|
|
11
|
+
for sig in signatures:
|
|
12
|
+
|
|
13
|
+
if sig in content:
|
|
14
|
+
|
|
15
|
+
print(Fore.RED + f"[SIGNATURE ALERT] {sig} in {file}")
|
|
16
|
+
return True
|
|
17
|
+
|
|
18
|
+
except:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
return False
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
LOG_DIR = "logs"
|
|
5
|
+
LOG_FILE = os.path.join(LOG_DIR, "scan.log")
|
|
6
|
+
|
|
7
|
+
if not os.path.exists(LOG_DIR):
|
|
8
|
+
os.mkdir(LOG_DIR)
|
|
9
|
+
|
|
10
|
+
logging.basicConfig(
|
|
11
|
+
filename=LOG_FILE,
|
|
12
|
+
level=logging.INFO,
|
|
13
|
+
format="%(asctime)s - %(levelname)s - %(message)s"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def log(message):
|
|
17
|
+
logging.info(message)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
from colorama import Fore
|
|
4
|
+
|
|
5
|
+
QUARANTINE_FOLDER = "quarantine"
|
|
6
|
+
|
|
7
|
+
def quarantine(file):
|
|
8
|
+
|
|
9
|
+
if not os.path.exists(QUARANTINE_FOLDER):
|
|
10
|
+
os.mkdir(QUARANTINE_FOLDER)
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
|
|
14
|
+
shutil.move(file, QUARANTINE_FOLDER)
|
|
15
|
+
|
|
16
|
+
print(Fore.MAGENTA + f"[QUARANTINE] {file}")
|
|
17
|
+
|
|
18
|
+
except:
|
|
19
|
+
pass
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sps-security
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Malware detection tool
|
|
5
|
+
Author: Samuel Pontes
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: tqdm
|
|
9
|
+
Requires-Dist: colorama
|
|
10
|
+
Dynamic: author
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
Dynamic: requires-dist
|
|
13
|
+
Dynamic: requires-python
|
|
14
|
+
Dynamic: summary
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
sps_security/__init__.py
|
|
5
|
+
sps_security/cli.py
|
|
6
|
+
sps_security.egg-info/PKG-INFO
|
|
7
|
+
sps_security.egg-info/SOURCES.txt
|
|
8
|
+
sps_security.egg-info/dependency_links.txt
|
|
9
|
+
sps_security.egg-info/entry_points.txt
|
|
10
|
+
sps_security.egg-info/requires.txt
|
|
11
|
+
sps_security.egg-info/top_level.txt
|
|
12
|
+
sps_security/core/__init__.py
|
|
13
|
+
sps_security/core/binary_engine.py
|
|
14
|
+
sps_security/core/hash_engine.py
|
|
15
|
+
sps_security/core/heuristic_engine.py
|
|
16
|
+
sps_security/core/scanner.py
|
|
17
|
+
sps_security/core/signature_engine.py
|
|
18
|
+
sps_security/database/__init__.py
|
|
19
|
+
sps_security/utils/__init__.py
|
|
20
|
+
sps_security/utils/hashing.py
|
|
21
|
+
sps_security/utils/logger.py
|
|
22
|
+
sps_security/utils/quarantine.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sps_security
|