Add enhanced urlf4ck3r
This commit is contained in:
parent
dc9e81f06e
commit
21c7e1e6c6
7
catch-all/08_urlf4ck3r/.dockerignore
Normal file
7
catch-all/08_urlf4ck3r/.dockerignore
Normal file
@ -0,0 +1,7 @@
|
||||
README.md
|
||||
docker-compose.yaml
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
.git
|
||||
.gitignore
|
||||
.vscode
|
24
catch-all/08_urlf4ck3r/Dockerfile
Normal file
24
catch-all/08_urlf4ck3r/Dockerfile
Normal file
@ -0,0 +1,24 @@
|
||||
# Usa una imagen base de Python oficial
|
||||
FROM python:3.9-slim
|
||||
ARG maintaner="manuelver"
|
||||
|
||||
# Establece el directorio de trabajo dentro del contenedor
|
||||
WORKDIR /app
|
||||
|
||||
# Copia los archivos necesarios al contenedor
|
||||
COPY requirements.txt /app
|
||||
|
||||
# Instala las dependencias del script
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copia el script al contenedor
|
||||
COPY urlf4ck3r.py /app
|
||||
|
||||
# Da permisos de ejecución al script
|
||||
RUN chmod +x urlf4ck3r.py
|
||||
|
||||
# Define el comando predeterminado para ejecutar el script con argumentos
|
||||
ENTRYPOINT ["./urlf4ck3r.py"]
|
||||
|
||||
# Especifica el comando por defecto, que puede ser sobreescrito al correr el contenedor
|
||||
CMD ["-h"]
|
116
catch-all/08_urlf4ck3r/README.md
Normal file
116
catch-all/08_urlf4ck3r/README.md
Normal file
@ -0,0 +1,116 @@
|
||||
# 🕸️ URLf4ck3r 🕵️♂️
|
||||
|
||||
> Repositorio original: [URLf4ck3r](https://github.com/n0m3l4c000nt35/urlf4ck3r)
|
||||
|
||||
URLf4ck3r es una herramienta de reconocimiento diseñada para escanear y extraer URLs del código fuente de sitios web.
|
||||
|
||||
📝 **Tabla de contenidos**
|
||||
- [🕸️ URLf4ck3r 🕵️♂️](#️-urlf4ck3r-️️)
|
||||
- [🚀 Características principales](#-características-principales)
|
||||
- [📋 Requisitos](#-requisitos)
|
||||
- [🛠️ Instalación](#️-instalación)
|
||||
- [💻 Uso](#-uso)
|
||||
- [Con docker](#con-docker)
|
||||
- [Construir la imagen de Docker](#construir-la-imagen-de-docker)
|
||||
- [Ejecutar el contenedor](#ejecutar-el-contenedor)
|
||||
- [Ejecutar con Docker Compose:](#ejecutar-con-docker-compose)
|
||||
|
||||
|
||||
## 🚀 Características principales
|
||||
|
||||
- 🔍 Escaneo recursivo de URLs
|
||||
- 🌐 Detección de subdominios
|
||||
- ✍️ Detección de palabras sensibles en los comentarios
|
||||
- 🔗 Clasificación de URLs absolutas y relativas
|
||||
- 💠 Detección de archivos JavaScript
|
||||
- 🎨 Salida colorida para una fácil lectura
|
||||
- ⏱️ Interrumpible en cualquier momento
|
||||
|
||||
|
||||
## 📋 Requisitos
|
||||
|
||||
- Python 3.x
|
||||
- Bibliotecas: `requests`, `beautifulsoup4`, `pwntools` (Ver en el fichero [requirements.txt](requirements.txt))
|
||||
|
||||
|
||||
## 🛠️ Instalación
|
||||
|
||||
1. Descarga esta carpeta
|
||||
2. Instalá las dependencias:
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. Haz el script ejecutable:
|
||||
|
||||
```
|
||||
chmod +x urlf4ck3r.py
|
||||
```
|
||||
|
||||
4. Para ejecutar el script desde cualquier ubicación:
|
||||
|
||||
- Mueve el script a un directorio que esté en el PATH, por ejemplo:
|
||||
```
|
||||
sudo mv urlf4ck3r.py /usr/bin/urlf4ck3r
|
||||
```
|
||||
- O añade el directorio del script al PATH editando el archivo `.bashrc` o `.zshrc`:
|
||||
```
|
||||
echo 'export PATH=$PATH:/ruta/al/directorio/de/urlf4ck3r' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
|
||||
## 💻 Uso
|
||||
|
||||
Si seguiste el paso 4 de la instalación, puedes ejecutar el script desde cualquier ubicación simplemente con:
|
||||
|
||||
```
|
||||
urlf4ck3r -u <URL> -o output.txt
|
||||
```
|
||||
|
||||
De lo contrario, desde el directorio donde se encuentra ubicado el script:
|
||||
|
||||
```
|
||||
./urlf4ck3r.py -u <URL> -o output
|
||||
```
|
||||
|
||||
Ejemplo:
|
||||
|
||||
```
|
||||
urlf4ck3r -u https://ejemplo.com -o output.txt
|
||||
```
|
||||
|
||||
## Con docker
|
||||
|
||||
### Construir la imagen de Docker
|
||||
|
||||
Para construir la imagen desde el Dockerfile, navega al directorio donde se encuentra tu Dockerfile y ejecuta el siguiente comando:
|
||||
|
||||
```sh
|
||||
docker build -t urlf4ck3r .
|
||||
```
|
||||
|
||||
### Ejecutar el contenedor
|
||||
|
||||
Después de construir la imagen, puedes ejecutar tu script dentro de un contenedor de la siguiente manera:
|
||||
|
||||
```sh
|
||||
docker run --rm urlf4ck3r -u https://ejemplo.com -o output.txt
|
||||
```
|
||||
|
||||
El flag --rm asegura que el contenedor se elimina automáticamente después de que se complete su ejecución.
|
||||
|
||||
|
||||
### Ejecutar con Docker Compose:
|
||||
|
||||
En la línea de comandos, navega hasta el directorio donde guardaste estos archivos.
|
||||
|
||||
Ejecuta el siguiente comando para construir la imagen y ejecutar el contenedor usando Docker Compose:
|
||||
|
||||
```sh
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
Esto ejecutará urlf4ck3r y generará el archivo output.txt en el directorio ./output de tu máquina local.
|
||||
|
9
catch-all/08_urlf4ck3r/docker-compose.yaml
Normal file
9
catch-all/08_urlf4ck3r/docker-compose.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
services:
|
||||
urlf4ck3r:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
command: ["-u", "https://vergaracarmona.es", "-o", "output.txt"]
|
||||
volumes:
|
||||
- ./output:/app/output
|
||||
container_name: urlf4ck3r
|
3
catch-all/08_urlf4ck3r/requirements.txt
Normal file
3
catch-all/08_urlf4ck3r/requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
beautifulsoup4==4.12.3
|
||||
pwntools==4.13.0
|
||||
Requests==2.32.3
|
444
catch-all/08_urlf4ck3r/urlf4ck3r.py
Normal file
444
catch-all/08_urlf4ck3r/urlf4ck3r.py
Normal file
@ -0,0 +1,444 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import requests
|
||||
import signal
|
||||
import sys
|
||||
|
||||
from bs4 import BeautifulSoup, Comment
|
||||
from collections import defaultdict
|
||||
from urllib.parse import urljoin, urlparse
|
||||
from typing import Optional, Tuple, Dict, List, Set
|
||||
|
||||
|
||||
class URLf4ck3r:
|
||||
"""
|
||||
URLf4ck3r es una herramienta que extrae las URL's del código fuente de una
|
||||
página web. Además, puede extraer comentarios sensibles del código fuente
|
||||
y guardar las URL's en archivos de texto.
|
||||
"""
|
||||
|
||||
RED = "\033[91m"
|
||||
GREEN = "\033[92m"
|
||||
YELLOW = "\033[93m"
|
||||
BLUE = "\033[94m"
|
||||
GRAY = "\033[90m"
|
||||
PURPLE = "\033[95m"
|
||||
END_COLOR = "\033[0m"
|
||||
|
||||
SENSITIVE_KEYWORDS = [
|
||||
# Palabras clave originales
|
||||
"password", "user", "username", "clave", "secret", "key", "token",
|
||||
"private", "admin", "credential", "login", "auth", "api_key", "apikey",
|
||||
"administrator",
|
||||
|
||||
# # Criptografía y Seguridad
|
||||
# "encryption", "decrypt", "cipher", "security", "hash", "salt", "ssl",
|
||||
# "tls", "secure", "firewall", "integrity",
|
||||
|
||||
# # Gestión de Usuarios y Autenticación
|
||||
# "auth_token", "session_id", "access_token", "oauth", "id_token",
|
||||
# "refresh_token", "csrf", "sso", "two_factor", "2fa",
|
||||
|
||||
# # Información Personal Identificable (PII)
|
||||
# "social_security", "ssn", "address", "phone_number", "email", "dob",
|
||||
# "credit_card", "card_number", "ccv", "passport", "tax_id", "personal_info",
|
||||
|
||||
# # Configuración de Sistemas
|
||||
# "config", "database", "db_password", "db_user", "connection_string",
|
||||
# "server", "host", "port",
|
||||
|
||||
# # Archivos y Rutas
|
||||
# "filepath", "filename", "root_path", "home_dir", "backup", "logfile",
|
||||
|
||||
# # Llaves y Tokens de API
|
||||
# "aws_secret", "aws_key", "api_secret", "secret_key", "private_key",
|
||||
# "public_key", "ssh_key",
|
||||
|
||||
# # Finanzas y Pagos
|
||||
# "payment", "transaction", "account_number", "iban", "bic", "swift",
|
||||
# "bank", "routing_number", "billing", "invoice",
|
||||
|
||||
# # Cuentas y Roles de Administrador
|
||||
# "superuser", "root", "sudo", "admin_password", "admin_user",
|
||||
|
||||
# # Otros
|
||||
# "jwt", "cookie", "session", "bypass", "debug", "exploit"
|
||||
]
|
||||
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Inicializa las variables de instancia.
|
||||
"""
|
||||
|
||||
self.all_urls: Dict[str, Set[str]] = defaultdict(set)
|
||||
self.comments_data: Dict[str, List[str]] = defaultdict(list)
|
||||
self.base_url: Optional[str] = None
|
||||
self.urls_to_scan: List[str] = []
|
||||
self.flag = self.Killer()
|
||||
self.output: Optional[str] = None
|
||||
|
||||
|
||||
def banner(self) -> None:
|
||||
"""
|
||||
Muestra el banner de la herramienta.
|
||||
"""
|
||||
|
||||
print("""
|
||||
|
||||
█ ██ ██▀███ ██▓ █████▒▄████▄ ██ ▄█▀ ██▀███
|
||||
██ ▓██▒▓██ ▒ ██▒▓██▒ ▓██ ▒▒██▀ ▀█ ██▄█▒ ▓██ ▒ ██▒
|
||||
▓██ ▒██░▓██ ░▄█ ▒▒██░ ▒████ ░▒▓█ ▄ ▓███▄░ ▓██ ░▄█ ▒
|
||||
▓▓█ ░██░▒██▀▀█▄ ▒██░ ░▓█▒ ░▒▓▓▄ ▄██▒▓██ █▄ ▒██▀▀█▄
|
||||
▒▒█████▓ ░██▓ ▒██▒░██████▒░▒█░ ▒ ▓███▀ ░▒██▒ █▄░██▓ ▒██▒
|
||||
░▒▓▒ ▒ ▒ ░ ▒▓ ░▒▓░░ ▒░▓ ░ ▒ ░ ░ ░▒ ▒ ░▒ ▒▒ ▓▒░ ▒▓ ░▒▓░
|
||||
░░▒░ ░ ░ ░▒ ░ ▒░░ ░ ▒ ░ ░ ░ ▒ ░ ░▒ ▒░ ░▒ ░ ▒░
|
||||
░░░ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░░ ░
|
||||
░ ░ ░ ░ ░ ░ ░ ░ ░
|
||||
░
|
||||
""")
|
||||
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Ejecuta la herramienta.
|
||||
"""
|
||||
|
||||
self.banner()
|
||||
|
||||
args, parser = self.get_arguments()
|
||||
|
||||
if not args.url:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
if args.output:
|
||||
self.output = args.output
|
||||
|
||||
self.base_url = args.url
|
||||
self.all_urls["scanned_urls"] = set()
|
||||
self.urls_to_scan = [self.base_url]
|
||||
|
||||
_, domain, _ = self.parse_url(self.base_url)
|
||||
|
||||
print(f"\n[{self.GREEN}DOMAIN{self.END_COLOR}] {domain}\n")
|
||||
|
||||
while self.urls_to_scan and not self.flag.exit():
|
||||
url = self.urls_to_scan.pop(0)
|
||||
self.scan_url(url)
|
||||
|
||||
print()
|
||||
self.show_lists()
|
||||
self.save_files()
|
||||
|
||||
print(f"\n[{self.GREEN}URLS TO SCAN{self.END_COLOR}]:")
|
||||
|
||||
if self.flag.exit():
|
||||
print(
|
||||
f"[{self.RED}!{self.END_COLOR}] Quedaron por escanear {self.RED}{len(self.urls_to_scan)}{self.END_COLOR} URLs"
|
||||
)
|
||||
|
||||
elif not self.urls_to_scan:
|
||||
print(
|
||||
f"[{self.GREEN}+{self.END_COLOR}] Se escanearon todas las URLs posibles"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"[{self.RED}!{self.END_COLOR}] Quedaron por escanear {self.RED}{len(self.urls_to_scan)}{self.END_COLOR} URLs"
|
||||
)
|
||||
|
||||
|
||||
def get_arguments(self) -> Tuple[argparse.Namespace, argparse.ArgumentParser]:
|
||||
"""
|
||||
Obtiene los argumentos proporcionados por el usuario.
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="urlf4ck3r",
|
||||
description="Extraer las URL's del código fuente de una web",
|
||||
epilog="Creado por https://github.com/n0m3l4c000nt35 y modificado por gitea.vergaracarmona.es/manuelver"
|
||||
)
|
||||
parser.add_argument("-u", "--url", type=str, dest="url",
|
||||
help="URL a escanear", required=True)
|
||||
parser.add_argument("-o", "--output", type=str,
|
||||
dest="output", help="Nombre del archivo de salida")
|
||||
|
||||
return parser.parse_args(), parser
|
||||
|
||||
def scan_url(self, url: str) -> None:
|
||||
"""
|
||||
Escanea una URL en busca de URLs, comentarios sensibles y archivos JS.
|
||||
"""
|
||||
|
||||
if self.flag.exit():
|
||||
return
|
||||
|
||||
if url in self.all_urls["scanned_urls"]:
|
||||
return
|
||||
|
||||
self.all_urls["scanned_urls"].add(url)
|
||||
print(f"[{self.GREEN}SCANNING{self.END_COLOR}] {url}")
|
||||
|
||||
try:
|
||||
res = requests.get(url, timeout=5)
|
||||
soup = BeautifulSoup(res.content, 'html.parser')
|
||||
|
||||
self.extract_js_files(soup, url)
|
||||
self.extract_comments(soup, url)
|
||||
self.extract_hrefs(soup, url, res)
|
||||
|
||||
except requests.Timeout:
|
||||
print(f"[{self.RED}REQUEST TIMEOUT{self.END_COLOR}] {url}")
|
||||
self.all_urls['request_error'].add(url)
|
||||
|
||||
except requests.exceptions.RequestException:
|
||||
print(f"{self.RED}[REQUEST ERROR]{self.END_COLOR} {url}")
|
||||
self.all_urls['request_error'].add(url)
|
||||
|
||||
except Exception as e:
|
||||
print(
|
||||
f"[{self.RED}UNEXPECTED ERROR{self.END_COLOR}] {url}: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
def extract_hrefs(self, soup: BeautifulSoup, url: str, res: requests.Response) -> None:
|
||||
"""
|
||||
Extrae las URL's del código fuente de una página web.
|
||||
"""
|
||||
|
||||
for link in soup.find_all("a", href=True):
|
||||
href = link.get("href")
|
||||
scheme, domain, path = self.parse_url(href)
|
||||
schemes = ["http", "https"]
|
||||
|
||||
if href:
|
||||
full_url = urljoin(url, path) if not scheme else href
|
||||
|
||||
if full_url not in self.all_urls["all_urls"]:
|
||||
self.all_urls["all_urls"].add(full_url)
|
||||
|
||||
if not scheme:
|
||||
self.all_urls["relative_urls"].add(full_url)
|
||||
|
||||
else:
|
||||
self.all_urls["absolute_urls"].add(full_url)
|
||||
|
||||
if self.is_jsfile(url, res):
|
||||
self.all_urls["javascript_files"].add(url)
|
||||
|
||||
if (self.is_internal_url(self.base_url, full_url) or
|
||||
self.is_subdomain(self.base_url, full_url)):
|
||||
|
||||
if full_url not in self.all_urls["scanned_urls"] and full_url not in self.urls_to_scan:
|
||||
self.urls_to_scan.append(full_url)
|
||||
|
||||
|
||||
def extract_js_files(self, soup: BeautifulSoup, base_url: str) -> None:
|
||||
"""
|
||||
Extrae los archivos JS del código fuente de una página web.
|
||||
"""
|
||||
|
||||
js_files = set()
|
||||
|
||||
for script in soup.find_all('script', src=True):
|
||||
|
||||
js_url = script['src']
|
||||
|
||||
if not urlparse(js_url).netloc:
|
||||
|
||||
js_url = urljoin(base_url, js_url)
|
||||
|
||||
js_files.add(js_url)
|
||||
|
||||
self.all_urls["javascript_files"].update(js_files)
|
||||
|
||||
|
||||
def is_jsfile(self, url: str, res: requests.Response) -> bool:
|
||||
"""
|
||||
Verifica si un archivo es un archivo JS.
|
||||
"""
|
||||
|
||||
return url.lower().endswith(('.js', '.mjs')) or 'javascript' in res.headers.get('Content-Type', '').lower()
|
||||
|
||||
|
||||
def extract_subdomain(self, url: str) -> str:
|
||||
"""
|
||||
Extrae el subdominio de una URL.
|
||||
"""
|
||||
|
||||
netloc = urlparse(url).netloc.split(".")
|
||||
|
||||
return ".".join(netloc[1:] if netloc[0] == "www" else netloc)
|
||||
|
||||
|
||||
def is_subdomain(self, base_url: str, url: str) -> bool:
|
||||
"""
|
||||
Verifica si una URL es un subdominio del dominio base.
|
||||
"""
|
||||
|
||||
base_domain = self.extract_subdomain(base_url)
|
||||
sub = self.extract_subdomain(url)
|
||||
|
||||
return sub.endswith(base_domain) and sub != base_domain
|
||||
|
||||
|
||||
def is_internal_url(self, base_url: str, url: str) -> bool:
|
||||
"""
|
||||
Verifica si una URL es interna (pertenece al mismo dominio).
|
||||
"""
|
||||
|
||||
return urlparse(base_url).netloc == urlparse(url).netloc
|
||||
|
||||
|
||||
def extract_comments(self, soup: BeautifulSoup, url: str) -> None:
|
||||
"""
|
||||
Extrae los comentarios del código fuente de una página web.
|
||||
"""
|
||||
|
||||
comments = soup.find_all(string=lambda text: isinstance(text, Comment))
|
||||
|
||||
for comment in comments:
|
||||
|
||||
comment_str = comment.strip()
|
||||
|
||||
if any(keyword in comment_str.lower() for keyword in self.SENSITIVE_KEYWORDS):
|
||||
self.comments_data[url].append(comment_str)
|
||||
print(
|
||||
f"{self.YELLOW}[SENSITIVE COMMENT FOUND]{self.END_COLOR} {comment_str}"
|
||||
)
|
||||
|
||||
|
||||
def parse_url(self, url: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||
"""
|
||||
Parsea una URL y devuelve el esquema, dominio y path.
|
||||
"""
|
||||
|
||||
parsed_url = urlparse(url)
|
||||
|
||||
return parsed_url.scheme, parsed_url.netloc, parsed_url.path
|
||||
|
||||
|
||||
|
||||
def ensure_directory_exists(self, directory: str) -> None:
|
||||
"""
|
||||
Asegura que el directorio existe, y lo crea si no es así.
|
||||
"""
|
||||
|
||||
if not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
|
||||
def save_file(self, data: List[str], filename: str) -> None:
|
||||
"""
|
||||
Guarda los datos en un archivo.
|
||||
"""
|
||||
|
||||
try:
|
||||
# Asegurarse de que el directorio 'output' existe
|
||||
self.ensure_directory_exists("output")
|
||||
|
||||
if self.output:
|
||||
filename = f"{self.output}_{filename}"
|
||||
|
||||
filepath = os.path.join("output", filename)
|
||||
|
||||
with open(filepath, "w") as f:
|
||||
f.write("\n".join(data))
|
||||
|
||||
print(f"[{self.GREEN}+{self.END_COLOR}] Guardado en {filepath}")
|
||||
|
||||
except IOError as e:
|
||||
print(
|
||||
f"{self.RED}[FILE WRITE ERROR]{self.END_COLOR} No se pudo guardar el archivo {filename}: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
def save_files(self) -> None:
|
||||
"""
|
||||
Guarda las URLs y los comentarios extraídos en archivos.
|
||||
"""
|
||||
self.save_file(
|
||||
sorted(self.all_urls["all_urls"]),
|
||||
"all_urls.txt"
|
||||
)
|
||||
|
||||
self.save_file(
|
||||
sorted(self.all_urls["absolute_urls"]),
|
||||
"absolute_urls.txt"
|
||||
)
|
||||
|
||||
self.save_file(
|
||||
sorted(self.all_urls["relative_urls"]),
|
||||
"relative_urls.txt"
|
||||
)
|
||||
|
||||
self.save_file(
|
||||
sorted(self.all_urls["javascript_files"]),
|
||||
"javascript_files.txt"
|
||||
)
|
||||
|
||||
if self.comments_data:
|
||||
sensitive_comments = []
|
||||
|
||||
for url, comments in self.comments_data.items():
|
||||
sensitive_comments.append(f"\n[ {url} ]\n")
|
||||
sensitive_comments.extend(comments)
|
||||
|
||||
self.save_file(sensitive_comments, "sensitive_comments.txt")
|
||||
|
||||
|
||||
def show_lists(self) -> None:
|
||||
"""
|
||||
Muestra el resumen de las URLs extraídas.
|
||||
"""
|
||||
|
||||
print(
|
||||
f"\n[{self.GREEN}ALL URLS{self.END_COLOR}]: {len(self.all_urls['all_urls'])}"
|
||||
)
|
||||
print(
|
||||
f"[{self.GREEN}ABSOLUTE URLS{self.END_COLOR}]: {len(self.all_urls['absolute_urls'])}"
|
||||
)
|
||||
print(
|
||||
f"[{self.GREEN}RELATIVE URLS{self.END_COLOR}]: {len(self.all_urls['relative_urls'])}"
|
||||
)
|
||||
print(
|
||||
f"[{self.GREEN}JAVASCRIPT FILES{self.END_COLOR}]: {len(self.all_urls['javascript_files'])}"
|
||||
)
|
||||
print(
|
||||
f"[{self.GREEN}SENSITIVE COMMENTS{self.END_COLOR}]: {len(self.comments_data)}"
|
||||
)
|
||||
|
||||
class Killer:
|
||||
"""
|
||||
Clase utilizada para manejar la interrupción del script con Ctrl+C.
|
||||
"""
|
||||
|
||||
kill_now = False
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
||||
|
||||
|
||||
def exit_gracefully(self, signum, frame) -> None:
|
||||
"""
|
||||
Método llamado cuando se recibe la señal de interrupción.
|
||||
"""
|
||||
|
||||
self.kill_now = True
|
||||
|
||||
def exit(self) -> bool:
|
||||
"""
|
||||
Retorna True si el script debe terminar.
|
||||
"""
|
||||
|
||||
return self.kill_now
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
tool = URLf4ck3r()
|
||||
tool.run()
|
@ -6,12 +6,13 @@ Aquí iré dejando scripts y ejercicios que se me ocurran, con lo que no hay un
|
||||
|
||||
## Índice de ejercicios
|
||||
|
||||
| Nombre | Descripción | Nivel |
|
||||
| -------------------------------------------------------: | :------------------------------------------------------- | :--------: |
|
||||
| [Words Linux](./01_scripts_words_linux/README.md) | Script con el fichero: `/usr/share/dict/words` | fácil |
|
||||
| [Descifrador wargame](./02_scripts_descifrador_wargame/) | Script descifrador de código al estilo wargame | fácil |
|
||||
| [Clima España](./03_clima/) | Script conectado a API AEMET | intermedio |
|
||||
| [acortador de enlaces](./04_acortador_url/) | Script para acortar enlaces y redirigirlos con app Flask | fácil |
|
||||
| [Pruebas de infraestructuras](./05_infra_test/README.md) | Redis, RabbitMQ, Kafka, Prometheus, etc | intermedio |
|
||||
| [Bots Telegram](./06_bots_telegram/README.md) | Bots de Telegram con Python | avanzado |
|
||||
| [Diagram as code](./07_diagrams_as_code/README.md) | Diagramas de infraestructuras con Python | fácil |
|
||||
| Nombre | Descripción | Nivel |
|
||||
| -------------------------------------------------------: | :--------------------------------------------------------------- | :--------: |
|
||||
| [Words Linux](./01_scripts_words_linux/README.md) | Script con el fichero: `/usr/share/dict/words` | fácil |
|
||||
| [Descifrador wargame](./02_scripts_descifrador_wargame/) | Script descifrador de código al estilo wargame | fácil |
|
||||
| [Clima España](./03_clima/) | Script conectado a API AEMET | intermedio |
|
||||
| [acortador de enlaces](./04_acortador_url/) | Script para acortar enlaces y redirigirlos con app Flask | fácil |
|
||||
| [Pruebas de infraestructuras](./05_infra_test/README.md) | Redis, RabbitMQ, Kafka, Prometheus, etc | intermedio |
|
||||
| [Bots Telegram](./06_bots_telegram/README.md) | Bots de Telegram con Python | avanzado |
|
||||
| [Diagram as code](./07_diagrams_as_code/README.md) | Diagramas de infraestructuras con Python | fácil |
|
||||
| [urlf4ck3r](./08_urlf4ck3r/README.md) | Script para buscar enlaces en una web y guardarlos en un fichero | intermedio |
|
||||
|
Loading…
Reference in New Issue
Block a user