feat: Semaine 10
@@ -0,0 +1 @@
|
||||
3.12
|
||||
@@ -0,0 +1,240 @@
|
||||
# Travail Pratique 01 - Florian POMPIDOU
|
||||
|
||||
> Vous intégrez l'équipe Red Team de Synapse Security, une société de conseil en sécurité offensive. Premier dossier du matin : votre chef de mission vous transmet un bref email.
|
||||
> "Tesla vient de signer un contrat d'audit de surface. Ils exposent du SaaS B2B. On a zéro doc interne — commencez par mapper ce qui est visible de l'extérieur. Périmètre : tesla.com et ses sous-domaines. Reconnaissance passive uniquement. Réunion client dans 4h — je veux un livrable exploitable. Bon courage."
|
||||
> Vous n'avez aucun template, aucune liste de tâches. C'est une vraie mission.
|
||||
|
||||
## 0. Les prérequis
|
||||
|
||||
- L'usage veut que j'ai quelques sécurités derrière moi. En temps normal, je me connecterais au réseau TOR quitte à sacrifier de la vitesse, sur le navigateur dédié. Pour l'exercice, je vais simplement passer sur un **VPN double-connexion Islande -> Pays-Bas -> Ordinateur**.
|
||||
- En plus de cela, j'utiliserais Kali 2025.4 sur VirtualBox, l'image officielle de Kali, mais avec 8 vCPUs et 8GB RAM. Parce qu'elle était déjà installée et que ça ira plus vite.
|
||||
- Un compte SHODAN (que je ne connaissais pas mais qui va sembler pratique) avec un compte enregistré par un alias SimpleLogin gratuit derrière un compte ProtonMail secondaire.
|
||||
|
||||
## 1. Plan de reconnaissance documenté
|
||||
|
||||
- Voir ce qu'on obtient en cherchant dans un moteur de recherche
|
||||
- Voir un résultat WHOIS
|
||||
- Voir un résultat SHODAN
|
||||
- Voir un rapport récupéré de quelqu'un d'autre qui aurait fait un NMAP (c'est passif !)
|
||||
|
||||
### Moteur de recherche
|
||||
|
||||
tesla.com, c'est facile à taper. On regarde la première page et voyons ce qu'on peut relever :
|
||||
|
||||

|
||||
|
||||
Evidemment, on a la vitrine commerciale, Wikipédia et les réseaux sociaux. On peut tenter un "More results from this site" pour filtrer sur le domaine :
|
||||
|
||||

|
||||
|
||||
Bon, j'ai beaucoup du domaine principal, mais je détecte en fin de page 1 (et rien en page 2) trois sous-domaines intéressants :
|
||||
|
||||

|
||||
|
||||
"IR", avec en intitulé "Investor Relations". J'ouvre avec WebArchive pour voir un peu :
|
||||
|
||||

|
||||
|
||||
Han. Je regarde sur ma machine Kali et même chose :
|
||||
|
||||

|
||||
|
||||
Ca n'aime pas les VPNs ! Tant mieux, je n'ai pas envie d'investir dans cette boîte de merde et donner de la valeur à son abruti de patron. Et puis j'ai pas d'argent.
|
||||
|
||||
### WHOIS
|
||||
|
||||
La première solution passive pour scanner un peu ce qui se tape de l'extérieur, c'est un très simple [WHOIS](https://www.whois.com). Je pourrais le faire depuis mon terminal, mais considérons que c'est de l'actif dans le cas présent.
|
||||
|
||||
[J'obtiens un rapport classique](https://www.whois.com/whois/tesla.com) :
|
||||
|
||||

|
||||
|
||||
Enregistré à San Francisco, depuis 1992, sécurité de base, etc. Ca ne m'apprend pas grand chose comme ça.
|
||||
|
||||
Quelque peu déçu, je passe sur [https://mxtoolbox.com/](MXToolBox) pour avoir un WHOIS complet (incluant MX, TXT, etc) et c'est déjà plus intéressant :
|
||||
- [TXT](https://mxtoolbox.com/SuperTool.aspx?action=txt%3atesla.com&run=toolpage)
|
||||
- [MX](https://mxtoolbox.com/SuperTool.aspx?action=txt%3atesla.com&run=toolpage)
|
||||
- [CNAME](https://mxtoolbox.com/emailhealth/tesla.com/) => J'ai un 403. Intéressant. Ils veulent vraiment bloquer ça...
|
||||
- [SPF](https://mxtoolbox.com/SuperTool.aspx?action=txt%3atesla.com&run=toolpage) => Que de l'adresse fixe. On peut connaître les étendues d'IP aptes à utiliser les services Tesla, ce qui veut dire qu'en recoupant chacune et avec un test actif dans NMAP, on peut retrouver quasi TOUT l'écosystème "agreé" tesla.com.
|
||||
- [DNS](https://mxtoolbox.com/SuperTool.aspx?action=txt%3atesla.com&run=toolpage)
|
||||
- [DMARC](https://mxtoolbox.com/SuperTool.aspx?action=txt%3atesla.com&run=toolpage)
|
||||
|
||||
Je fais deux autres services dédiés CNAME et j'ai des retours négatifs. Hm. Mais j'ai UN rapport de [WhatsMyDNS](https://www.whatsmydns.net/dns-lookup/cname-records?query=tesla.com&server=cloudflare) qui indique des autorités DNS :
|
||||
|
||||
```
|
||||
id 64655, opcode QUERY, rcode NOERROR, flags QR RD RA
|
||||
;QUESTION
|
||||
tesla.com. IN CNAME
|
||||
;ANSWER
|
||||
;AUTHORITY
|
||||
tesla.com. 86400 IN SOA edns69.ultradns.com. domain.teslamotors.com. 2016025264 1800 86400 86400 86400
|
||||
;ADDITIONAL
|
||||
```
|
||||
|
||||
On a un autre domaine "teslamotors.com" qui pourrait faire l'affaire. On note en tout cas.
|
||||
|
||||
### SHODAN
|
||||
|
||||
Je ne connais pas, mais je pense que ça sera plus complet. Pour "tester" comme un béotien moyen, je tape juste "tesla.com" dans la barre de recherche.
|
||||
|
||||
Et bien... je ne suis malgré tout pas déçu :
|
||||
|
||||

|
||||
|
||||
ALors je n'obtiens paaaas grand chose comme ça, mais j'ai déjà un rapport un peu plus détaillé sur ce qui est ouvert ou non :
|
||||
|
||||

|
||||
|
||||
Des ports, du service web, des emplacements... des versions TLS. Empreintes JARM et JA3S... voilà, faisons comme si je connaissais. Je regarde vite fait et j'obtiens cette définition d'un article de Fastly.com (inconnu au bataillon) dans l'article "What is TLS fingerprinting ?" :
|
||||
|
||||
> JARM is used to scan and identify servers and provides more uniqueness compared to JA3S. Unlike JA3S, which utilizes passive observation, JARM involves active scanning to solicit information from servers.
|
||||
|
||||
Bon, je crois comprendre à peu près. Ce ne me servira pas à grand chose présentement.
|
||||
|
||||
### Conclusion
|
||||
|
||||
Frustré de n'être que le passif dans cette relation, je cherche un peu par mot-clefs et j'obtiens un rapport de 2020 faisant état d'un NMAP sur tesla.com : [Recon Pipeline](https://recon-pipeline.readthedocs.io/en/latest/overview/viewing_results.html). C'est peut-être obsolète, mais sachant qu'une boîte de cette taille peut avoir des dettes techniques de 15-20 ans, je considère pour l'exercice qu'elle est encore à peu près à jour. Et c'est la poule aux oeufs d'or :
|
||||
|
||||
```
|
||||
[db-2] recon-pipeline> view targets --paged
|
||||
3.tesla.cn
|
||||
3.tesla.com
|
||||
api-internal.sn.tesla.services
|
||||
api-toolbox.tesla.com
|
||||
api.mp.tesla.services
|
||||
api.sn.tesla.services
|
||||
api.tesla.cn
|
||||
api.toolbox.tb.tesla.services
|
||||
|
||||
[db-2] recon-pipeline> view endpoints --paged
|
||||
[200] http://westream.teslamotors.com/y
|
||||
[301] https://mobileapps.teslamotors.com/aspnet_client
|
||||
[403] https://209.133.79.49/analog.html
|
||||
[302] https://209.133.79.49/api
|
||||
[403] https://209.133.79.49/cgi-bin/
|
||||
[200] https://209.133.79.49/client
|
||||
|
||||
[db-2] recon-pipeline> view nmap-scans --paged
|
||||
2600:9000:21d4:7800:c:d401:5a80:93a1 - http
|
||||
===========================================
|
||||
|
||||
[db-2] recon-pipeline> view ports --paged
|
||||
apmv3.go.tesla.services: 80
|
||||
autodiscover.teslamotors.com: 80
|
||||
csp.teslamotors.com: 443
|
||||
image.emails.tesla.com: 443
|
||||
marketing.teslamotors.com: 443
|
||||
partnerleadsharing.tesla.com: 443
|
||||
service.tesla.cn: 80
|
||||
shop.uk.teslamotors.com: 8080
|
||||
sip.tesla.cn: 5061
|
||||
|
||||
[db-2] recon-pipeline> view searchsploit-results --paged
|
||||
52.209.48.104, 34.252.120.214, 52.48.121.107, telemetry-eng.vn.tesla.services
|
||||
=============================================================================
|
||||
local | 40768.sh | Nginx (Debian Based Distros + Gentoo) - 'logrotate' Local Privilege
|
||||
| Escalation
|
||||
remote | 12804.txt| Nginx 0.6.36 - Directory Traversal
|
||||
local | 14830.py | Nginx 0.6.38 - Heap Corruption
|
||||
webapps | 24967.txt| Nginx 0.6.x - Arbitrary Code Execution NullByte Injection
|
||||
dos | 9901.txt | Nginx 0.7.0 < 0.7.61 / 0.6.0 < 0.6.38 / 0.5.0 < 0.5.37 / 0.4.0 <
|
||||
| 0.4.14 - Denial of Service (PoC)
|
||||
remote | 9829.txt | Nginx 0.7.61 - WebDAV Directory Traversal
|
||||
remote | 33490.txt| Nginx 0.7.64 - Terminal Escape Sequence in Logs Command Injection
|
||||
remote | 13822.txt| Nginx 0.7.65/0.8.39 (dev) - Source Disclosure / Download
|
||||
remote | 13818.txt| Nginx 0.8.36 - Source Disclosure / Denial of Service
|
||||
remote | 38846.txt| Nginx 1.1.17 - URI Processing SecURIty Bypass
|
||||
remote | 25775.rb | Nginx 1.3.9 < 1.4.0 - Chuncked Encoding Stack Buffer Overflow
|
||||
| (Metasploit)
|
||||
dos | 25499.py | Nginx 1.3.9 < 1.4.0 - Denial of Service (PoC)
|
||||
remote | 26737.pl | Nginx 1.3.9/1.4.0 (x86) - Brute Force
|
||||
remote | 32277.txt| Nginx 1.4.0 (Generic Linux x64) - Remote Overflow
|
||||
webapps | 47553.md | PHP-FPM + Nginx - Remote Code Execution
|
||||
|
||||
[db-2] recon-pipeline> view web-technologies --type "Programming languages"
|
||||
PHP (Programming languages)
|
||||
===========================
|
||||
|
||||
- www.tesla.com
|
||||
- dummy.teslamotors.com
|
||||
- 209.10.208.20
|
||||
- 211.147.80.206
|
||||
- trt.tesla.com
|
||||
- trt.teslamotors.com
|
||||
- cn-origin.teslamotors.com
|
||||
- www.tesla.cn
|
||||
- events.tesla.cn
|
||||
- 23.67.209.106
|
||||
- service.teslamotors.com
|
||||
|
||||
Python (Programming languages)
|
||||
==============================
|
||||
|
||||
- api-toolbox.tesla.com
|
||||
- 52.26.53.228
|
||||
- 34.214.187.20
|
||||
- 35.166.29.132
|
||||
- api.toolbox.tb.tesla.services
|
||||
- toolbox.teslamotors.com
|
||||
- 209.133.79.93
|
||||
|
||||
Ruby (Programming languages)
|
||||
============================
|
||||
|
||||
- storagesim.teslamotors.com
|
||||
- 209.10.208.39
|
||||
```
|
||||
|
||||
Voilà. Je m'arrête là, dans deux minutes je déclare la guerre nucléaire à cette entreprise des enfers.
|
||||
|
||||
## 2. Script Python `crtsh_recon.py`
|
||||
|
||||
> Écrivez un script Python qui interroge l'API publique de crt.sh et extrait automatiquement les sous-domaines du domaine cible.
|
||||
> Comportement attendu :
|
||||
```
|
||||
$ python crtsh_recon.py tesla.com
|
||||
[*] Interrogation de crt.sh pour tesla.com...
|
||||
[+] 14 certificats trouvés
|
||||
[+] Sous-domaines uniques :
|
||||
api.tesla.com
|
||||
staging.tesla.com
|
||||
vpn.tesla.com
|
||||
...
|
||||
[*] Export → tesla_subdomains.txt
|
||||
```
|
||||
> Le script doit : dédupliquer les résultats, filtrer les wildcards (*.tesla.com), exporter vers un fichier texte, et gérer proprement les erreurs réseau.
|
||||
|
||||
### Erreur 502
|
||||
|
||||
Site trop demandé visiblement :3 c'est pas d'bol.
|
||||
|
||||
Sinon j'avais trouvé [ce script par "YashGoti"](https://github.com/YashGoti/crtsh) qui semblait parfait. J'aurais sûrement fait un truc en rapport, en modifiant pour répondre aux critères (affiche dynamique, export en fichier teste [format CSV je pense] etc.)
|
||||
|
||||
Je pourrais prendre leur paquet en local, mais ça serait de l'actif.
|
||||
|
||||
### Alternative 1
|
||||
|
||||
Je regarde un post Reddit demandant une alternative à CRT.sh et je tombe sur SSLBoard.com. Après tout, pourquoi pas ?
|
||||
|
||||
Alors, il n'y a pas d'API on dirait, alors je prends [juste un rapport Web](https://sslboard.com/report/aa6986c4-8db7-493d-8fd7-6011d01e890f) en attendant :
|
||||
|
||||

|
||||

|
||||
|
||||
Alors il y a une version payante, donc... hm.
|
||||
|
||||
### Alternative 2
|
||||
|
||||
Dans le même post Reddit, j'apprends l'existence de "Merklemap". Je tente une recherche dessus et [j'obtiens encore un Pay2Gain](https://www.merklemap.com/search?query=*.tesla.com&page=0), mais exploitable en soit :
|
||||
|
||||

|
||||
|
||||
Plus de 500 certificats ? Et beh.
|
||||
|
||||
### Les alternatives
|
||||
|
||||
Sur le site de Let's Encrypt (je suis d'avis qu'ils s'y connaissent en certificat, mais je ne saurais l'affirmer 🥸) j'obtiens une liste de ces services ouverts : https://community.letsencrypt.org/t/certificate-transparency-search-resources/203368
|
||||
|
||||
On a deux autres services offrant une API, CertStream en Python : https://github.com/CaliDog/certstream-python
|
||||
|
||||
Mais il est presque l'heure de rendre, j'abandonne l'idée d'un script manuellement rédigé pour le moment.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Travail Pratique 02 - Florian POMPIDOU
|
||||
|
||||
> Vous avez vos sous-domaines. Maintenant votre chef de mission remonte la pression :
|
||||
> "Bien. On a les sous-domaines — maintenant je veux savoir ce qui tourne derrière. Versions, ports, CVE éventuelles. Et je veux que ce soit automatisé — si demain le client change d'infra, on relance le script et on a les résultats en 30 secondes. Je ne veux plus faire ça à la main."
|
||||
|
||||
## 0. Préparation
|
||||
|
||||
- Définir la portée du projet
|
||||
- Voir le dépôt Python officiel de Shodan
|
||||
- Amorcer le projet
|
||||
- Commencer le script
|
||||
- Tester le script
|
||||
- Hélitreuiller le lama
|
||||
|
||||
## 1. Documentation
|
||||
|
||||
Le site a un onglet "Developer" et de là des liens vers des API selon la stack. Je prends Python : https://github.com/achillean/shodan-python
|
||||
|
||||
Faisant détox de l'IA, mais ayant pour seule doc un site tiers de 2014 (en python 2... on n'est pas dans la merde), je tente avec une IA (Gemini Pro) mais l'éthique la force à dire "non". Je pourrais lui tirer les vers du nez, truander, mais... non, je tente autre chose de tout nouveau qui vient de sortir : "faire mes propres recherches". Incroyable.
|
||||
|
||||
## 2. Script Python
|
||||
|
||||
Je mets en place une clef API (si j'oublie de l'enlever du document, pas d'inquiétude, je vais la réinitialiser à la fin) et je fais un banal script qui prend une IP en argument :
|
||||
|
||||

|
||||
|
||||
Bon, ça marche, j'ai un bloc JSON non structuré. Ca promet d'être marrant.
|
||||
|
||||
Je tombe sur un script qui fait à peu près ce que je veux (https://github.com/TiiTcHY/ShoDomain-Seeker/blob/main/ShoDomain_Seeker.py) et je me dis qu'après tout, hein. Voilà quoi. Je pique juste ce qui m'intéresse.
|
||||
|
||||
Sauf que c'est pour un compte payant.
|
||||
|
||||
Je ré-écris tout pour taper sur la bibliothèque publique Shodan...
|
||||
|
||||
Et j'ai encore du 403 :
|
||||
|
||||

|
||||
|
||||
### Oh et puis zut
|
||||
|
||||
Je ne vois pas comment je peux faire ça en 3 heures avec une doc pétée en n'étant guère développeur de base. Mais je garde de la technicité dans mon approche. J'ai besoin d'une IA, mais sans censure. J'installe alors un modèle personnalisé de Qwen3.5 9B totalement chargé sur ma carte graphique, et j'enregistre un serveur MCP local pour l'agent IA de VSCode et je fais tourner la bourrique.
|
||||
|
||||
Parce que "convertir" un script de 200 lignes sur une autre stack à une heure du rendu, très peu pour moi.
|
||||
|
||||
### Mais c'est un complot en fait
|
||||
|
||||
BON, maintenant j'ai un 401 parce que j'ai encore confondu PAT et clef API. Je réadapate le script pour un PAT et...
|
||||
|
||||
```
|
||||
[*] Démarrage du scan global v3 pour : tesla.com
|
||||
[-] Erreur API (403): {"title":"Forbidden","status":403,"detail":"This endpoint requires an organization ID for API access. Free users can only access this endpoint through the Platform UI."}
|
||||
```
|
||||
|
||||
Non mais là c'est bon.
|
||||
|
||||
J'abandonne l'idée d'avoir un résultat et je vais juste commenter le code censys. Définir les fonctions et le rendre maintenable.
|
||||
|
||||
## 3. Test de la plateforme
|
||||
|
||||
A défaut de faire des requêtes en script, je tente sur la Plateforme, que je vois un peu le résultat.
|
||||
|
||||
Je réussis à faire une requête pour avoir un retour attendu en script :
|
||||
|
||||
```sql
|
||||
((host.dns.names: "tesla.com" and host.services.endpoints.http.uri: *) and host.ip: *) and host.services.port = "21"
|
||||
```
|
||||
|
||||
Je filtre par "21", port FTP par défaut, parce que c'est notoirement un port tout pourri. Je trouve un résultat qui me permet de regarder un peu le détail :
|
||||
|
||||

|
||||
|
||||
Bon, il n'y a rien... mais s'il y avait eu, il aurait fallut payer :
|
||||
|
||||

|
||||
|
||||
Non mais à ce stade faisons du NMAP et recoupons avec Metasploit. La main manuelle de l'homme, y a que ça de vrai.
|
||||
@@ -0,0 +1,56 @@
|
||||
import requests
|
||||
import sys
|
||||
|
||||
def get_subdomains_certspotter(domain):
|
||||
url = f"https://api.certspotter.com/v1/issuances?domain={domain}&include_subdomains=true&expand=dns_names"
|
||||
print(f"[*] Interrogation de Cert Spotter pour {domain}...")
|
||||
|
||||
try:
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
|
||||
response = requests.get(url, headers=headers, timeout=15)
|
||||
|
||||
if response.status_code == 429:
|
||||
print("[-] Erreur 429 : Limite de requêtes atteinte. Patiente un peu avant de réessayer.")
|
||||
return
|
||||
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
if not data:
|
||||
print("[-] Aucun certificat trouvé pour ce domaine.")
|
||||
return
|
||||
|
||||
subdomains = set()
|
||||
|
||||
for entry in data:
|
||||
for name in entry.get('dns_names', []):
|
||||
name = name.strip().lower()
|
||||
|
||||
if not name.startswith('*.') and name.endswith(domain):
|
||||
subdomains.add(name)
|
||||
|
||||
subdomains = sorted(list(subdomains))
|
||||
|
||||
print(f"[+] {len(subdomains)} sous-domaines uniques trouvés :")
|
||||
for sub in subdomains:
|
||||
print(f" {sub}")
|
||||
|
||||
output_file = f"{domain.replace('.', '_')}_certspotter.txt"
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
for sub in subdomains:
|
||||
f.write(f"{sub}\n")
|
||||
|
||||
print(f"[*] Export → {output_file}")
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
print("[-] Erreur : Délai d'attente dépassé.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"[-] Erreur réseau :\n {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: python {sys.argv[0]} <domaine>")
|
||||
sys.exit(1)
|
||||
|
||||
target_domain = sys.argv[1]
|
||||
get_subdomains_certspotter(target_domain)
|
||||
@@ -0,0 +1,61 @@
|
||||
import requests
|
||||
import sys
|
||||
|
||||
def get_subdomains(domain):
|
||||
url = f"https://crt.sh/?q=%.{domain}&output=json"
|
||||
print(f"[*] Interrogation de crt.sh pour {domain}...")
|
||||
|
||||
try:
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
|
||||
response = requests.get(url, headers=headers, timeout=20)
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
|
||||
if not data:
|
||||
print("[-] Aucun certificat trouvé pour ce domaine.")
|
||||
return
|
||||
|
||||
print(f"[+] {len(data)} certificats trouvés (bruts)")
|
||||
|
||||
subdomains = set()
|
||||
|
||||
for entry in data:
|
||||
name_value = entry.get('name_value', '')
|
||||
|
||||
for name in name_value.split('\n'):
|
||||
name = name.strip().lower()
|
||||
|
||||
if not name.startswith('*.') and name.endswith(domain):
|
||||
subdomains.add(name)
|
||||
|
||||
subdomains = sorted(list(subdomains))
|
||||
|
||||
print("[+] Sous-domaines uniques :")
|
||||
for sub in subdomains:
|
||||
print(f" {sub}")
|
||||
|
||||
output_file = f"{domain.replace('.', '_')}_subdomains.txt"
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
for sub in subdomains:
|
||||
f.write(f"{sub}\n")
|
||||
|
||||
print(f"[*] Export → {output_file}")
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"[-] Erreur HTTP de la part de crt.sh (probablement une 502 ou 503) :\n {e}")
|
||||
except requests.exceptions.Timeout:
|
||||
print("[-] Erreur : Délai d'attente dépassé (Timeout). crt.sh est trop lent actuellement.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"[-] Erreur réseau critique :\n {e}")
|
||||
except ValueError:
|
||||
print("[-] Erreur de parsing JSON. crt.sh a probablement renvoyé une page HTML d'erreur.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: python {sys.argv[0]} <domaine>")
|
||||
sys.exit(1)
|
||||
|
||||
target_domain = sys.argv[1]
|
||||
get_subdomains(target_domain)
|
||||
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 368 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 196 KiB |
|
After Width: | Height: | Size: 265 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 318 KiB |
|
After Width: | Height: | Size: 224 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 229 KiB |
|
After Width: | Height: | Size: 182 KiB |
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "jour-01"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"censys>=2.2.19",
|
||||
"shodan>=1.31.0",
|
||||
]
|
||||
@@ -0,0 +1,89 @@
|
||||
apf-api.eng.vn.cloud.tesla.com
|
||||
apf-api.prd.vn.cloud.tesla.com
|
||||
assets.extgithub.tesla.com
|
||||
auth-stage.tesla.com
|
||||
auth.eng.euw1.vn.cloud.tesla.com
|
||||
auth.eng.usw.vn.cloud.tesla.com
|
||||
autobidder-preprd.powerhub.energy.tesla.com
|
||||
autobidder.powerhub.energy.tesla.com
|
||||
avatars.extgithub.tesla.com
|
||||
ca.tesla.com
|
||||
chat-staging.bottlerocket.tesla.com
|
||||
cn.tesla.com
|
||||
codeload.extgithub.tesla.com
|
||||
consul.bottlerocket.tesla.com
|
||||
containers.extgithub.tesla.com
|
||||
de.tesla.com
|
||||
dhc.tesla.com
|
||||
digitalassets-shop.tesla.com
|
||||
digitalassets.tesla.com
|
||||
diner-api-stage.tesla.com
|
||||
diner-api.tesla.com
|
||||
diner-webapp-stage.tesla.com
|
||||
diner-webapp.tesla.com
|
||||
discovery-service.bottlerocket.tesla.com
|
||||
discovery.bottlerocket.tesla.com
|
||||
docker.extgithub.tesla.com
|
||||
docs.bottlerocket.tesla.com
|
||||
embed-staging.bottlerocket.tesla.com
|
||||
employeefeedback.tesla.com
|
||||
energy-technician.bottlerocket.tesla.com
|
||||
energy.bottlerocket.tesla.com
|
||||
engage.tesla.com
|
||||
engagetesla.com
|
||||
extgithub.tesla.com
|
||||
feedback.tesla.com
|
||||
fleet-api.eng.na.vn.cloud.tesla.com
|
||||
fleet-api.prd.eu.vn.cloud.tesla.com
|
||||
fleet-api.prd.na.vn.cloud.tesla.com
|
||||
fleetview.america.fn.tesla.com
|
||||
fleetview.europe.fn.tesla.com
|
||||
fleetview.fn.tesla.com
|
||||
fleetview.prd.america.fn.tesla.com
|
||||
fleetview.prd.eu.fn.tesla.com
|
||||
fleetview.prd.europe.fn.tesla.com
|
||||
fleetview.prd.euw1.fn.tesla.com
|
||||
fleetview.prd.na.fn.tesla.com
|
||||
fleetview.prd.usw2.fn.tesla.com
|
||||
genai.tesla.com
|
||||
gf.tesla.com
|
||||
gist.extgithub.tesla.com
|
||||
gridlogic.energy.tesla.com
|
||||
gridlogic.powerhub.energy.tesla.com
|
||||
inference-eu-staging.bottlerocket.tesla.com
|
||||
inference-eu.bottlerocket.tesla.com
|
||||
inference-staging.bottlerocket.tesla.com
|
||||
inference.bottlerocket.tesla.com
|
||||
ir.bottlerocket.tesla.com
|
||||
maven.extgithub.tesla.com
|
||||
media.extgithub.tesla.com
|
||||
mfg.tesla.com
|
||||
mobile-links.eng.vn.cloud.tesla.com
|
||||
notebooks.extgithub.tesla.com
|
||||
npm.extgithub.tesla.com
|
||||
nuget.extgithub.tesla.com
|
||||
nv.tesla.com
|
||||
ny.tesla.com
|
||||
pages.extgithub.tesla.com
|
||||
paloalto.tesla.com
|
||||
powerhub.energy.tesla.com
|
||||
raw.extgithub.tesla.com
|
||||
reply.extgithub.tesla.com
|
||||
rubygems.extgithub.tesla.com
|
||||
sentry.app.tesla.com
|
||||
signaling-alpha.prd.vn.cloud.tesla.com
|
||||
signaling-robotics.eng.vn.cloud.tesla.com
|
||||
staging.bottlerocket.tesla.com
|
||||
sts-broker.bottlerocket.tesla.com
|
||||
taffy.bottlerocket.tesla.com
|
||||
tesla.com
|
||||
teslacmgna01.tesla.com
|
||||
tf-poc.tesla.com
|
||||
tokens-staging.bottlerocket.tesla.com
|
||||
tripx-alpha.prd.vn.cloud.tesla.com
|
||||
tripx.eng.usw2.vn.cloud.tesla.com
|
||||
tripx.prd.vn.cloud.tesla.com
|
||||
tx.tesla.com
|
||||
uploads.extgithub.tesla.com
|
||||
veritas-staging.bottlerocket.tesla.com
|
||||
viewscreen.extgithub.tesla.com
|
||||
@@ -0,0 +1,360 @@
|
||||
"""
|
||||
tesla_security_scan.py - Enhanced Security Scanner for Tesla Subdomains using Shodan API
|
||||
|
||||
Features:
|
||||
- Read subdomains from .txt file or command line
|
||||
- Query Shodan API for each host with detailed info (ports, services, versions)
|
||||
- Detect CVEs using OS and service banner intelligence
|
||||
- Generate structured JSON report with vulnerability analysis
|
||||
- Provide executive summary review
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import shodan
|
||||
import re
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def load_subdomains_from_file(file_path):
|
||||
"""Load subdomains from a .txt file."""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
domains = [line.strip() for line in f if line.strip()]
|
||||
return domains
|
||||
|
||||
def search_host_shodan(ip_address, api_key):
|
||||
"""Get detailed host information from Shodan API."""
|
||||
try:
|
||||
api = shodan.Shodan(api_key)
|
||||
|
||||
results = api.host(ip_address)
|
||||
|
||||
return {
|
||||
'ip': ip_address,
|
||||
'ports': [],
|
||||
'services': {},
|
||||
'os': results.get('os', None),
|
||||
'org': results.get('org', 'Unknown'),
|
||||
'last_update': datetime.now().isoformat(),
|
||||
'banners': [],
|
||||
'vulnerabilities': []
|
||||
}
|
||||
except shodan.APIError as e:
|
||||
return {
|
||||
'ip': ip_address,
|
||||
'error': str(e),
|
||||
'ports': [],
|
||||
'services': {},
|
||||
'os': None,
|
||||
'org': 'Unknown',
|
||||
'last_update': datetime.now().isoformat(),
|
||||
'banners': []
|
||||
}
|
||||
|
||||
|
||||
def extract_service_info(shodan_data):
|
||||
"""Extract and organize service information from Shodan data."""
|
||||
services = {}
|
||||
|
||||
if not shodan_data or 'ports' not in shodan_data:
|
||||
return services
|
||||
|
||||
for port_entry in shodan_data.get('ports', []):
|
||||
port_num = port_entry.get('port')
|
||||
banner = port_entry.get('banner', '')
|
||||
|
||||
service_info = {
|
||||
'port': port_num,
|
||||
'protocol': port_entry.get('transport', 'tcp'),
|
||||
'service': port_entry.get('name', 'unknown'),
|
||||
'version': port_entry.get('product') or port_entry.get('version', 'unknown'),
|
||||
'banners': []
|
||||
}
|
||||
|
||||
if banner:
|
||||
try:
|
||||
banner_lines = banner.split('\n')
|
||||
service_info['banners'].append({
|
||||
'raw': '\n'.join(banner_lines[:10]),
|
||||
'hostname': port_entry.get('host', ''),
|
||||
'app': port_entry.get('app', '')
|
||||
})
|
||||
|
||||
banner_upper = banner.upper()
|
||||
if 'TLS' in banner_upper or 'SSL' in banner_upper:
|
||||
service_info['ssl'] = True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
services[str(port_num)] = service_info
|
||||
|
||||
return services
|
||||
|
||||
|
||||
def detect_os_cves(os_string):
|
||||
"""Detect CVEs mentioned in OS information."""
|
||||
if not os_string:
|
||||
return []
|
||||
|
||||
cve_pattern = r'(CVE-[0-9]{4}-[0-9]+)'
|
||||
detected_cves = re.findall(cve_pattern, os_string)
|
||||
|
||||
os_info = {
|
||||
'cves': detected_cves,
|
||||
'os_type': os_string.split(' ')[0] if os_string else None,
|
||||
'kernel_version': os_string.split(' (')[0].split('.')[-1] if ' (' in os_string else None
|
||||
}
|
||||
|
||||
return [{'cve_id': cve_id, 'source': 'OS', 'description': f'Potential vulnerability in {os_string}'} for cve_id in detected_cves]
|
||||
|
||||
|
||||
def detect_service_cves(banners):
|
||||
"""Detect CVEs mentioned in service banners."""
|
||||
all_cves = []
|
||||
|
||||
if not banners:
|
||||
return all_cves
|
||||
|
||||
cve_pattern = r'(CVE-[0-9]{4}-[0-9]+)'
|
||||
|
||||
for banner_info in banners:
|
||||
raw_content = banner_info.get('raw', '')
|
||||
|
||||
detected_cves = re.findall(cve_pattern, raw_content)
|
||||
|
||||
if detected_cves:
|
||||
for cve_id in detected_cves:
|
||||
all_cves.append({
|
||||
'cve_id': cve_id,
|
||||
'source': banner_info.get('app', 'Service'),
|
||||
'port': banner_info.get('port', 0),
|
||||
'description': f'Potential vulnerability found in {banner_info.get("hostname", "service")}'
|
||||
})
|
||||
|
||||
return all_cves
|
||||
|
||||
|
||||
def analyze_host_vulnerabilities(host_data):
|
||||
"""Analyze a host for vulnerabilities from OS and services."""
|
||||
detected_cves = []
|
||||
|
||||
os_cves = detect_os_cves(host_data.get('os'))
|
||||
detected_cves.extend(os_cves)
|
||||
|
||||
service_cves = detect_service_cves(host_data.get('banners', []))
|
||||
detected_cves.extend(service_cves)
|
||||
|
||||
host_data['vulnerabilities'] = detected_cves
|
||||
|
||||
return host_data
|
||||
|
||||
|
||||
def scan_subdomain(subdomain, api_key):
|
||||
"""Scan all hosts associated with a subdomain."""
|
||||
api = shodan.Shodan(api_key)
|
||||
|
||||
try:
|
||||
results = api.search(f"hostname:{subdomain}")
|
||||
|
||||
if not results.get('matches'):
|
||||
return {
|
||||
'subdomain': subdomain,
|
||||
'hosts': [],
|
||||
'total_hosts': 0,
|
||||
'unique_services': set(),
|
||||
'vulnerable_hosts': []
|
||||
}
|
||||
|
||||
hosts = []
|
||||
unique_ports = set()
|
||||
all_services = set()
|
||||
vulnerable_count = 0
|
||||
|
||||
for match in results['matches']:
|
||||
ip = match.get('ip_str')
|
||||
if not ip:
|
||||
continue
|
||||
|
||||
host_info = search_host_shodan(ip, api_key)
|
||||
services = extract_service_info(host_info)
|
||||
unique_ports.update(str(p) for p in host_info.get('ports', []))
|
||||
all_services.update(services.keys())
|
||||
vulnerable_host = analyze_host_vulnerabilities(host_info)
|
||||
|
||||
if vulnerable_host['vulnerabilities']:
|
||||
vulnerable_count += 1
|
||||
|
||||
hosts.append({
|
||||
'ip': host_info['ip'],
|
||||
'org': host_info.get('org', 'Unknown'),
|
||||
'os': host_info.get('os'),
|
||||
'ports_count': len(host_info.get('ports', [])),
|
||||
'services': services,
|
||||
'banners': host_info.get('banners', []),
|
||||
'vulnerabilities': vulnerable_host['vulnerabilities']
|
||||
})
|
||||
|
||||
return {
|
||||
'subdomain': subdomain,
|
||||
'hosts': hosts,
|
||||
'total_hosts': len(hosts),
|
||||
'unique_ports': unique_ports,
|
||||
'unique_services': all_services,
|
||||
'vulnerable_hosts': vulnerable_count
|
||||
}
|
||||
|
||||
except shodan.APIError as e:
|
||||
print(f"Error querying Shodan for {subdomain}: {e}", file=sys.stderr)
|
||||
return {
|
||||
'subdomain': subdomain,
|
||||
'hosts': [],
|
||||
'total_hosts': 0,
|
||||
'unique_services': set(),
|
||||
'vulnerable_hosts': 0
|
||||
}
|
||||
|
||||
|
||||
def generate_summary_report(all_results):
|
||||
"""Generate a summary of scan results."""
|
||||
total_hosts = sum(r['total_hosts'] for r in all_results)
|
||||
unique_services = set()
|
||||
vulnerable_hosts_count = 0
|
||||
|
||||
for result in all_results:
|
||||
unique_services.update(result.get('unique_services', []))
|
||||
vulnerable_hosts_count += result.get('vulnerable_hosts', 0)
|
||||
|
||||
hosts_with_cves = sum(1 for r in all_results if r['vulnerable_hosts'] > 0)
|
||||
|
||||
return {
|
||||
'total_subdomains_scanned': len(all_results),
|
||||
'total_hosts_found': total_hosts,
|
||||
'unique_services_identified': len(unique_services),
|
||||
'hosts_with_cves': hosts_with_cves,
|
||||
'total_vulnerable_hosts': vulnerable_hosts_count,
|
||||
'scan_timestamp': datetime.now().isoformat()
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Enhanced Security Scanner for Tesla Subdomains using Shodan API",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python tesla_security_scan.py -d tesla.com -s YOUR_API_KEY -o report.json
|
||||
python tesla_security_scan.py -i subdomains.txt -s YOUR_API_KEY --json-output scan_results.json
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-d", "--domain",
|
||||
dest="domain",
|
||||
help="Single domain to scan (e.g., tesla.com)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i", "--input-file",
|
||||
dest="file_name",
|
||||
help=".txt file containing subdomains to scan"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s", "--shodan-key",
|
||||
dest="shodan_key",
|
||||
required=True,
|
||||
help="Shodan API Key"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o", "--json-output",
|
||||
dest="json_output",
|
||||
default=None,
|
||||
help="Output JSON file for detailed results (default: console)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q", "--quick-summary",
|
||||
action="store_true",
|
||||
help="Print quick summary only"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.domain and not args.file_name:
|
||||
print("Error: Please provide either -d (domain) or -i (input file)", file=sys.stderr)
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
api = shodan.Shodan(args.shodan_key)
|
||||
except shodan.APIError as e:
|
||||
print(f"Error initializing Shodan API: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if args.file_name:
|
||||
subdomains = load_subdomains_from_file(args.file_name)
|
||||
else:
|
||||
subdomains = [args.domain]
|
||||
|
||||
print(f"[*] Starting security scan for {len(subdomains)} target(s)...")
|
||||
print(f"[+] API Key validated (Shodan)")
|
||||
print()
|
||||
|
||||
all_results = []
|
||||
total_hosts = 0
|
||||
total_services = set()
|
||||
vulnerable_count = 0
|
||||
|
||||
for i, subdomain in enumerate(subdomains, 1):
|
||||
print(f"[*] Scanning {i}/{len(subdomains)}: {subdomain}...")
|
||||
|
||||
result = scan_subdomain(subdomain, args.shodan_key)
|
||||
all_results.append(result)
|
||||
|
||||
total_hosts += result['total_hosts']
|
||||
total_services.update(result.get('unique_services', []))
|
||||
vulnerable_count += result.get('vulnerable_hosts', 0)
|
||||
|
||||
summary = generate_summary_report(all_results)
|
||||
|
||||
if args.json_output:
|
||||
full_report = {
|
||||
'summary': summary,
|
||||
'detailed_results': all_results
|
||||
}
|
||||
|
||||
with open(args.json_output, 'w', encoding='utf-8') as f:
|
||||
json.dump(full_report, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"\n[+] Detailed JSON report saved to: {args.json_output}")
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("EXECUTIVE SECURITY SUMMARY")
|
||||
print("=" * 70)
|
||||
print()
|
||||
|
||||
print(f"[INFO] Total Subdomains Scanned : {summary['total_subdomains_scanned']}")
|
||||
print(f"[INFO] Total Hosts Identified : {summary['total_hosts_found']:.0f}")
|
||||
print(f"[INFO] Unique Services Detected : {summary['unique_services_identified']:.0f}")
|
||||
print()
|
||||
|
||||
vuln_summary = summary.get('hosts_with_cves', 0)
|
||||
total_vuln = summary.get('total_vulnerable_hosts', 0)
|
||||
|
||||
if vuln_summary > 0:
|
||||
print(f"[ALERT] Hosts with CVE Detection : {vuln_summary}")
|
||||
print(f"[CRITICAL] Total Vulnerable Hosts : {total_vuln}")
|
||||
|
||||
if total_vuln > 0:
|
||||
vulnerability_rate = (total_vuln / summary['total_hosts_found'] * 100) if summary['total_hosts_found'] > 0 else 0
|
||||
print(f"[STAT] Vulnerability Rate : {vulnerability_rate:.2f}%")
|
||||
elif total_hosts > 0:
|
||||
print(f"[INFO] No CVEs Detected in {summary['total_subdomains_scanned']} hosts")
|
||||
|
||||
print()
|
||||
print("=" * 70)
|
||||
print("SCAN COMPLETE")
|
||||
print("=" * 70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,138 @@
|
||||
import sys, json, argparse
|
||||
from datetime import datetime
|
||||
import requests
|
||||
|
||||
CENSYS_API_BASE = "https://api.platform.censys.io/v3"
|
||||
|
||||
def search_host_censys(ip_address, token):
|
||||
"""
|
||||
Récupère les détails d'un hôte via l'API Censys avec un Personal Access Token.
|
||||
Parce que les clefs API c'est pour ceux qui raquent.
|
||||
"""
|
||||
url = f"{CENSYS_API_BASE}/global/asset/host/{ip_address}"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
services = data.get('services', [])
|
||||
|
||||
vulnerabilities = data.get('vulnerabilities', [])
|
||||
for srv in services:
|
||||
if isinstance(srv, dict) and srv.get('vulnerabilities'):
|
||||
vulnerabilities.extend(srv['vulnerabilities'])
|
||||
|
||||
has_cve = len(vulnerabilities) > 0
|
||||
|
||||
return {
|
||||
'ip': ip_address,
|
||||
'ports': [srv.get('port') for srv in services if isinstance(srv, dict) and srv.get('port')],
|
||||
'os': data.get('operating_system', {}).get('product', None),
|
||||
'org': data.get('autonomous_system', {}).get('name', 'Unknown'),
|
||||
'last_update': datetime.now().isoformat(),
|
||||
'services': services,
|
||||
'vulnerabilities': vulnerabilities,
|
||||
'potentially_vulnerable': has_cve
|
||||
}
|
||||
else:
|
||||
return {'ip': ip_address, 'error': f"HTTP {response.status_code}", 'ports': [], 'services': [], 'potentially_vulnerable': False}
|
||||
except Exception as e:
|
||||
return {'ip': ip_address, 'error': str(e), 'ports': [], 'services': [], 'potentially_vulnerable': False}
|
||||
|
||||
def scan_domain_censys(domain, token):
|
||||
"""
|
||||
Recherche tous les hôtes liés à un domaine via l'API Censys.
|
||||
"""
|
||||
url = f"{CENSYS_API_BASE}/global/search/query"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"query": f"host.names: {domain}",
|
||||
"page_size": 50
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=payload, timeout=15)
|
||||
if response.status_code != 200:
|
||||
print(f"[-] Erreur API ({response.status_code}): {response.text}", file=sys.stderr)
|
||||
return {'domain': domain, 'hosts': [], 'total_hosts': 0, 'unique_ports': set(), 'vulnerable_hosts': 0}
|
||||
|
||||
data = response.json()
|
||||
hits = data.get('results', [])
|
||||
|
||||
hosts = []
|
||||
unique_ports = set()
|
||||
vulnerable_hosts = 0
|
||||
|
||||
for hit in hits:
|
||||
ip = hit.get('ip') or hit.get('host.ip')
|
||||
if not ip:
|
||||
continue
|
||||
|
||||
host_info = search_host_censys(ip, token)
|
||||
if 'error' in host_info:
|
||||
continue
|
||||
|
||||
unique_ports.update(str(p) for p in host_info['ports'])
|
||||
if host_info.get('potentially_vulnerable'):
|
||||
vulnerable_hosts += 1
|
||||
hosts.append(host_info)
|
||||
|
||||
return {
|
||||
'domain': domain,
|
||||
'hosts': hosts,
|
||||
'total_hosts': len(hosts),
|
||||
'unique_ports': unique_ports,
|
||||
'vulnerable_hosts': vulnerable_hosts
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"[-] Erreur réseau : {e}", file=sys.stderr)
|
||||
return {'domain': domain, 'hosts': [], 'total_hosts': 0, 'unique_ports': set(), 'vulnerable_hosts': 0}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Scanner de sous-domaines générique pour l'API Censys")
|
||||
parser.add_argument("-d", "--domain", default="example.com", help="Domaine cible à analyser")
|
||||
parser.add_argument("-t", "--token", required=True, help="Votre Censys Personal Access Token")
|
||||
parser.add_argument("-o", "--output", help="Nom du fichier de sortie JSON")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"[*] Démarrage du scan global pour : {args.domain}")
|
||||
result = scan_domain_censys(args.domain, args.token)
|
||||
|
||||
summary = {
|
||||
'scan_timestamp': datetime.now().isoformat(),
|
||||
'domain_scanned': args.domain,
|
||||
'total_hosts_found': result['total_hosts'],
|
||||
'vulnerable_hosts_found': result['vulnerable_hosts']
|
||||
}
|
||||
|
||||
full_report = {
|
||||
'summary': summary,
|
||||
'detailed_results': result['hosts']
|
||||
}
|
||||
|
||||
if args.output:
|
||||
with open(args.output, 'w', encoding='utf-8') as f:
|
||||
json.dump(full_report, f, indent=2, ensure_ascii=False)
|
||||
print(f"[+] Rapport enregistré avec succès dans : {args.output}")
|
||||
else:
|
||||
results_print = "RÉSULTATS DE L'AUDIT PASSÉ (CENSYS)"
|
||||
print(" ")
|
||||
print("=" * len(results_print))
|
||||
print(results_print)
|
||||
print("=" * len(results_print))
|
||||
print(f"[INFO] Hôtes uniques découverts : {summary['total_hosts_found']}")
|
||||
print(f"[INFO] Hôtes vulnérables découverts : {summary['vulnerable_hosts_found']}")
|
||||
print(f"[INFO] Ports distincts ouverts : {', '.join(result.get('unique_ports', []))}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,302 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "argcomplete"
|
||||
version = "3.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backoff"
|
||||
version = "2.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001, upload-time = "2022-10-05T19:19:32.061Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148, upload-time = "2022-10-05T19:19:30.546Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "censys"
|
||||
version = "2.2.19"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "argcomplete" },
|
||||
{ name = "backoff" },
|
||||
{ name = "requests" },
|
||||
{ name = "rich" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/41/aa/ed0d0faf4f7015bac902cdad929f487f9baefd224ab6fa9aba5635dd5d60/censys-2.2.19.tar.gz", hash = "sha256:9202e17c2583d4b3d0af32a5be161ddb505edd390a9ca909f2e7470d4af19a97", size = 62101, upload-time = "2025-12-11T16:08:47.421Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/66/4b/96c1ebc5f8534c18527c81b4df9cdb2a96151010f540ecbb4c9c2af4fee4/censys-2.2.19-py3-none-any.whl", hash = "sha256:eaad49779a3bbe290e244222563a48e78ca33777fbbdf6d329d8b52223fc1084", size = 80582, upload-time = "2025-12-11T16:08:46.368Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.5.20"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.4.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.4.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click-plugins"
|
||||
version = "1.1.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/34847b59150da33690a36da3681d6bbc2ec14ee9a846bc30a6746e5984e4/click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261", size = 8343, upload-time = "2025-06-25T00:47:37.555Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6", size = 11051, upload-time = "2025-06-25T00:47:36.731Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.29.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/f9/f38573ed5844586db374d085911740a501ccfa373b455fc9413f09f85237/filelock-3.29.1.tar.gz", hash = "sha256:d97e6b1b9757569626c58caa07dc4beb1613f4a2938b1e8cc81afca398906c9e", size = 59335, upload-time = "2026-06-03T15:19:04.053Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/a0/614c5fe402fd88951df45f4dda2fa3b4e17a99ecd92340771929169b3b95/filelock-3.29.1-py3-none-any.whl", hash = "sha256:85199dfd706869641b72b2e8955d5416a4b2b7dc4b0e8e6d97b4cc1299a6983b", size = 40750, upload-time = "2026-06-03T15:19:02.959Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.18"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jour-01"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "censys" },
|
||||
{ name = "shodan" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "censys", specifier = ">=2.2.19" },
|
||||
{ name = "shodan", specifier = ">=1.31.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "4.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.20.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.34.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "charset-normalizer" },
|
||||
{ name = "idna" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "requests-file"
|
||||
version = "3.0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "requests" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3c/f8/5dc70102e4d337063452c82e1f0d95e39abfe67aa222ed8a5ddeb9df8de8/requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576", size = 6967, upload-time = "2025-10-20T18:56:42.279Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/d5/de8f089119205a09da657ed4784c584ede8381a0ce6821212a6d4ca47054/requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2", size = 4514, upload-time = "2025-10-20T18:56:41.184Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "15.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shodan"
|
||||
version = "1.31.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "click-plugins" },
|
||||
{ name = "colorama" },
|
||||
{ name = "requests" },
|
||||
{ name = "tldextract" },
|
||||
{ name = "xlsxwriter" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c5/06/c6dcc975a1e7d89bc764fd271da8138b318e18080b48e7f1acd2ab63df28/shodan-1.31.0.tar.gz", hash = "sha256:c73275386ea02390e196c35c660706a28dd4d537c5a21eb387ab6236fac251f6", size = 57939, upload-time = "2023-12-17T01:42:02.426Z" }
|
||||
|
||||
[[package]]
|
||||
name = "tldextract"
|
||||
version = "5.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "filelock" },
|
||||
{ name = "idna" },
|
||||
{ name = "requests" },
|
||||
{ name = "requests-file" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/7b/644fbbb49564a6cb124a8582013315a41148dba2f72209bba14a84242bf0/tldextract-5.3.1.tar.gz", hash = "sha256:a72756ca170b2510315076383ea2993478f7da6f897eef1f4a5400735d5057fb", size = 126105, upload-time = "2025-12-28T23:58:05.532Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/42/0e49d6d0aac449ca71952ec5bae764af009754fcb2e76a5cc097543747b3/tldextract-5.3.1-py3-none-any.whl", hash = "sha256:6bfe36d518de569c572062b788e16a659ccaceffc486d243af0484e8ecf432d9", size = 105886, upload-time = "2025-12-28T23:58:04.071Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xlsxwriter"
|
||||
version = "3.2.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940, upload-time = "2025-09-16T00:16:21.63Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" },
|
||||
]
|
||||