milenium 0.2.0__tar.gz → 0.3.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.
- {milenium-0.2.0 → milenium-0.3.0}/PKG-INFO +1 -1
- {milenium-0.2.0 → milenium-0.3.0}/milenium/cli.py +49 -39
- milenium-0.3.0/milenium/modules/aggregator.py +26 -0
- milenium-0.3.0/milenium/modules/breach_local.py +0 -0
- milenium-0.3.0/milenium/modules/dehashed.py +29 -0
- milenium-0.3.0/milenium/modules/leakcheck.py +16 -0
- milenium-0.3.0/milenium/modules/pwned_passwords.py +18 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium.egg-info/PKG-INFO +1 -1
- {milenium-0.2.0 → milenium-0.3.0}/milenium.egg-info/SOURCES.txt +5 -0
- {milenium-0.2.0 → milenium-0.3.0}/pyproject.toml +1 -1
- {milenium-0.2.0 → milenium-0.3.0}/README.md +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/__init__.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/__init__.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/breach.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/domain.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/dorker.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/email.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/ip.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/logger.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/permutator.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/phone.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/report.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/social.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium/modules/username.py +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium.egg-info/dependency_links.txt +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium.egg-info/entry_points.txt +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium.egg-info/requires.txt +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/milenium.egg-info/top_level.txt +0 -0
- {milenium-0.2.0 → milenium-0.3.0}/setup.cfg +0 -0
|
@@ -3,7 +3,7 @@ import click
|
|
|
3
3
|
from rich.console import Console
|
|
4
4
|
from rich.table import Table
|
|
5
5
|
from milenium.modules.logger import TeeLogger
|
|
6
|
-
from milenium.modules import username, email, phone, ip, domain, breach, social, report
|
|
6
|
+
from milenium.modules import username, email, phone, ip, domain, breach, social, report
|
|
7
7
|
|
|
8
8
|
console = Console()
|
|
9
9
|
|
|
@@ -19,50 +19,25 @@ def main():
|
|
|
19
19
|
|
|
20
20
|
@main.command()
|
|
21
21
|
@click.argument("nick")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def user(nick, permutations, dorks):
|
|
25
|
-
"""Глубокий поиск по нику + вариации + Google Dorks"""
|
|
22
|
+
def user(nick):
|
|
23
|
+
"""Прогон никнейма по соцсетям"""
|
|
26
24
|
logger = _init_logger()
|
|
27
|
-
|
|
25
|
+
results = username.check(nick)
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
table = Table(title=f"Username: {nick} (+ {len(results)-1} вариаций)")
|
|
33
|
-
table.add_column("Вариация")
|
|
34
|
-
table.add_column("Сайт")
|
|
35
|
-
table.add_column("Статус")
|
|
27
|
+
table = Table(title=f"Username: {nick}")
|
|
28
|
+
table.add_column("Site")
|
|
29
|
+
table.add_column("Status")
|
|
36
30
|
table.add_column("URL")
|
|
31
|
+
lines = [f"Username: {nick}"]
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
table.add_row(variant, site, "[green]FOUND[/green]", info["url"])
|
|
43
|
-
lines.append(f"{variant}\t{site}\tFOUND\t{info['url']}")
|
|
44
|
-
found_count += 1
|
|
33
|
+
for site, info in results.items():
|
|
34
|
+
status = "[green]found[/green]" if info["found"] else "[red]no[/red]"
|
|
35
|
+
table.add_row(site, status, info["url"])
|
|
36
|
+
lines.append(f"{site}\t{'FOUND' if info['found'] else 'NO'}\t{info['url']}")
|
|
45
37
|
|
|
46
38
|
console.print(table)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if dorks:
|
|
51
|
-
console.print("\n[bold cyan]Ищу через Google Dorks...[/bold cyan]")
|
|
52
|
-
dork_results = dorker.search_nick(nick, num=10)
|
|
53
|
-
if dork_results:
|
|
54
|
-
for q, links in dork_results.items():
|
|
55
|
-
console.print(f"\n[bold]{q}[/bold]")
|
|
56
|
-
lines.append(f"\nQUERY: {q}")
|
|
57
|
-
for link in links:
|
|
58
|
-
console.print(f" {link}")
|
|
59
|
-
lines.append(f" {link}")
|
|
60
|
-
else:
|
|
61
|
-
console.print("[yellow]Serper API не настроен или нет результатов[/yellow]")
|
|
62
|
-
lines.append("\nDorks: not configured")
|
|
63
|
-
|
|
64
|
-
path = report.save_text(lines, name=f"deep_{nick}")
|
|
65
|
-
console.print(f"\n[bold cyan]Отчёт:[/bold cyan] {path}")
|
|
39
|
+
path = report.save_text(lines, name=f"user_{nick}")
|
|
40
|
+
console.print(f"\n[bold cyan]Отчёт сохранён:[/bold cyan] {path}")
|
|
66
41
|
console.print(f"[bold cyan]Лог:[/bold cyan] {logger.path}")
|
|
67
42
|
logger.close()
|
|
68
43
|
|
|
@@ -157,5 +132,40 @@ def social_cmd(nick):
|
|
|
157
132
|
console.print(f"[bold cyan]Лог:[/bold cyan] {logger.path}")
|
|
158
133
|
logger.close()
|
|
159
134
|
|
|
135
|
+
@main.command()
|
|
136
|
+
@click.argument("password")
|
|
137
|
+
def pwned(password):
|
|
138
|
+
"""Проверить пароль через Pwned Passwords (бесплатно)"""
|
|
139
|
+
logger = _init_logger()
|
|
140
|
+
from milenium.modules import pwned_passwords
|
|
141
|
+
res = pwned_passwords.check_password(password)
|
|
142
|
+
if res.get("pwned"):
|
|
143
|
+
console.print(f"[red]ПАРОЛЬ В УТЕЧКАХ[/red] — встречается {res['count']} раз")
|
|
144
|
+
elif "error" in res:
|
|
145
|
+
console.print(f"[yellow]Ошибка:[/yellow] {res['error']}")
|
|
146
|
+
else:
|
|
147
|
+
console.print("[green]Пароль не найден в утечках[/green]")
|
|
148
|
+
logger.close()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@main.command()
|
|
152
|
+
@click.option("--email", default=None)
|
|
153
|
+
@click.option("--username", default=None)
|
|
154
|
+
@click.option("--phone", default=None)
|
|
155
|
+
@click.option("--password", default=None)
|
|
156
|
+
@click.option("--db-path", default=None, help="Путь к локальной базе BreachCompilation")
|
|
157
|
+
def full(email, username, phone, password, db_path):
|
|
158
|
+
"""Агрегатор: гоняет запрос по всем модулям"""
|
|
159
|
+
logger = _init_logger()
|
|
160
|
+
from milenium.modules import aggregator
|
|
161
|
+
import json
|
|
162
|
+
res = aggregator.run(email=email, username=username, phone=phone,
|
|
163
|
+
password=password, db_path=db_path)
|
|
164
|
+
console.print(json.dumps(res, indent=2, ensure_ascii=False))
|
|
165
|
+
path = report.save_text([json.dumps(res, indent=2, ensure_ascii=False)], name="full")
|
|
166
|
+
console.print(f"\n[bold cyan]Отчёт:[/bold cyan] {path}")
|
|
167
|
+
console.print(f"[bold cyan]Лог:[/bold cyan] {logger.path}")
|
|
168
|
+
logger.close()
|
|
169
|
+
|
|
160
170
|
if __name__ == "__main__":
|
|
161
171
|
main()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from milenium.modules import pwned_passwords, breach_local, hibp, dehashed, leakcheck
|
|
2
|
+
|
|
3
|
+
def run(email=None, username=None, phone=None, password=None, db_path=None):
|
|
4
|
+
out = {}
|
|
5
|
+
|
|
6
|
+
if password:
|
|
7
|
+
out["pwned_passwords"] = pwned_passwords.check_password(password)
|
|
8
|
+
|
|
9
|
+
if email:
|
|
10
|
+
out["hibp"] = hibp.check_email(email)
|
|
11
|
+
out["dehashed_email"] = dehashed.search(f'email:"{email}"')
|
|
12
|
+
out["leakcheck_email"] = leakcheck.search(email)
|
|
13
|
+
|
|
14
|
+
if username:
|
|
15
|
+
out["dehashed_username"] = dehashed.search(f'username:"{username}"')
|
|
16
|
+
out["leakcheck_username"] = leakcheck.search(username)
|
|
17
|
+
|
|
18
|
+
if phone:
|
|
19
|
+
out["leakcheck_phone"] = leakcheck.search(phone)
|
|
20
|
+
|
|
21
|
+
if db_path:
|
|
22
|
+
q = email or username or phone
|
|
23
|
+
if q:
|
|
24
|
+
out["breach_local"] = breach_local.search(q, db_path)
|
|
25
|
+
|
|
26
|
+
return out
|
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
DEHASHED_EMAIL = "vexxdev31@gmail.com" # твой email на dehashed.com
|
|
5
|
+
DEHASHED_KEY = "4ASpzd3EjjFo7v2KxFBeHiNzALJTnoKlhDJP46bJ/cthj88W3hyx+roE" # API key из личного кабинета
|
|
6
|
+
|
|
7
|
+
def search(query):
|
|
8
|
+
"""
|
|
9
|
+
query — например: email:"target@mail.com" или username:"hacker"
|
|
10
|
+
Без подписки вернёт пустой результат или 401.
|
|
11
|
+
"""
|
|
12
|
+
if not DEHASHED_EMAIL or not DEHASHED_KEY:
|
|
13
|
+
return {"error": "no dehashed credentials"}
|
|
14
|
+
|
|
15
|
+
auth = base64.b64encode(f"{DEHASHED_EMAIL}:{DEHASHED_KEY}".encode()).decode()
|
|
16
|
+
headers = {"Authorization": f"Basic {auth}", "Accept": "application/json"}
|
|
17
|
+
try:
|
|
18
|
+
r = requests.get(
|
|
19
|
+
"https://api.dehashed.com/v2/search",
|
|
20
|
+
params={"query": query, "size": 100},
|
|
21
|
+
headers=headers, timeout=20
|
|
22
|
+
)
|
|
23
|
+
if r.status_code == 200:
|
|
24
|
+
data = r.json()
|
|
25
|
+
return {"entries": data.get("entries", []), "total": data.get("total", 0)}
|
|
26
|
+
else:
|
|
27
|
+
return {"error": f"HTTP {r.status_code}: {r.text[:200]}"}
|
|
28
|
+
except Exception as e:
|
|
29
|
+
return {"error": str(e)}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
LEAKCHECK_KEY = "97059e7429c29bc190a1e93a97a28c1d6e8d8199" # ключ с https://leakcheck.io/
|
|
4
|
+
|
|
5
|
+
def search(term):
|
|
6
|
+
if not LEAKCHECK_KEY:
|
|
7
|
+
return {"error": "no leakcheck key"}
|
|
8
|
+
headers = {"X-API-Key": LEAKCHECK_KEY}
|
|
9
|
+
try:
|
|
10
|
+
r = requests.get(f"https://leakcheck.io/api/v2/query/{term}", headers=headers, timeout=20)
|
|
11
|
+
if r.status_code == 200:
|
|
12
|
+
return r.json()
|
|
13
|
+
else:
|
|
14
|
+
return {"error": f"HTTP {r.status_code}: {r.text[:200]}"}
|
|
15
|
+
except Exception as e:
|
|
16
|
+
return {"error": str(e)}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
def check_password(password):
|
|
5
|
+
"""Проверяет пароль через Pwned Passwords API (k-anonymity). Бесплатно, без ключа."""
|
|
6
|
+
sha1 = hashlib.sha1(password.encode("utf-8")).hexdigest().upper()
|
|
7
|
+
prefix, suffix = sha1[:5], sha1[5:]
|
|
8
|
+
try:
|
|
9
|
+
r = requests.get(f"https://api.pwnedpasswords.com/range/{prefix}", timeout=10)
|
|
10
|
+
if r.status_code != 200:
|
|
11
|
+
return {"error": f"HTTP {r.status_code}"}
|
|
12
|
+
for line in r.text.splitlines():
|
|
13
|
+
h, count = line.split(":")
|
|
14
|
+
if h == suffix:
|
|
15
|
+
return {"pwned": True, "count": int(count)}
|
|
16
|
+
return {"pwned": False, "count": 0}
|
|
17
|
+
except Exception as e:
|
|
18
|
+
return {"error": str(e)}
|
|
@@ -9,14 +9,19 @@ milenium.egg-info/entry_points.txt
|
|
|
9
9
|
milenium.egg-info/requires.txt
|
|
10
10
|
milenium.egg-info/top_level.txt
|
|
11
11
|
milenium/modules/__init__.py
|
|
12
|
+
milenium/modules/aggregator.py
|
|
12
13
|
milenium/modules/breach.py
|
|
14
|
+
milenium/modules/breach_local.py
|
|
15
|
+
milenium/modules/dehashed.py
|
|
13
16
|
milenium/modules/domain.py
|
|
14
17
|
milenium/modules/dorker.py
|
|
15
18
|
milenium/modules/email.py
|
|
16
19
|
milenium/modules/ip.py
|
|
20
|
+
milenium/modules/leakcheck.py
|
|
17
21
|
milenium/modules/logger.py
|
|
18
22
|
milenium/modules/permutator.py
|
|
19
23
|
milenium/modules/phone.py
|
|
24
|
+
milenium/modules/pwned_passwords.py
|
|
20
25
|
milenium/modules/report.py
|
|
21
26
|
milenium/modules/social.py
|
|
22
27
|
milenium/modules/username.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|