Last active
July 5, 2024 16:13
-
-
Save alonsoir/5758eab35d014ba0a9988ef346b6a5f8 to your computer and use it in GitHub Desktop.
Un script para interactuar con shodan. Requiere un api key que debes dejar en un fichero .env. pip install shodan. https://github.com/achillean/shodan-python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import re | |
from selenium.webdriver.firefox.service import Service | |
from webdriver_manager.firefox import GeckoDriverManager | |
from selenium.webdriver import FirefoxOptions | |
from selenium.webdriver import Firefox | |
from selenium.webdriver.common.by import By | |
from selenium.webdriver.support.ui import WebDriverWait | |
def has_valid_credentials_github(): | |
"""Realiza un intento de login en GitHub de manera automática utilizando Selenium. | |
Returns: | |
bool: Retorna True si el login es exitoso, False si falla. | |
""" | |
# Inicialización del driver de Firefox con opciones predeterminadas | |
service = Service(GeckoDriverManager().install()) | |
options = FirefoxOptions() | |
driver = Firefox(service=service, options=options) | |
# Navegación a la página de login de GitHub | |
driver.get("https://github.com/login") | |
# Credenciales de usuario de prueba | |
usuario = "testuser" | |
password = "password" | |
# Inserción de credenciales en los campos correspondientes | |
driver.find_element(By.ID, "login_field").send_keys(usuario) | |
driver.find_element(By.ID, "password").send_keys(password) | |
# Envío del formulario de login | |
driver.find_element(By.NAME, "commit").click() | |
# Espera hasta que la página esté completamente cargada | |
WebDriverWait(driver=driver, timeout=10).until( | |
lambda x: x.execute_script("return document.readyState == 'complete'") | |
) | |
# Verificación de mensajes de error | |
err_msg = "Incorrect username or password" | |
errors = driver.find_elements(By.CLASS_NAME, "js-flash-alert") | |
# Decisión basada en la presencia de mensajes de error | |
if any(err_msg in e.text for e in errors): | |
print("[!] El login no ha tenido éxito.") | |
driver.close() | |
return False | |
else: | |
print("[+] El login ha tenido éxito.") | |
driver.close() | |
return True | |
def has_valid_credentials(instance): | |
""" | |
Verifica si una instancia de DVWA (Damn Vulnerable Web Application) tiene configuradas las credenciales por defecto. | |
Args: | |
instance (dict): Un diccionario que contiene la IP, el puerto y si el protocolo SSL está habilitado en la forma: | |
{'ip_str': '127.0.0.1', 'port': 80, 'ssl': True o False} | |
Returns: | |
bool: True si las credenciales por defecto son aceptadas, False en caso contrario. | |
Raises: | |
requests.exceptions.ConnectionError: Si no se puede establecer una conexión con la instancia DVWA. | |
Exception: Si hay problemas al extraer el token CSRF de la página de login. | |
""" | |
# Inicializa la sesión HTTP | |
sess = requests.Session() | |
proto = 'https' if 'ssl' in instance else 'http' | |
login_page = f"{proto}://{instance['ip_str']}:{instance['port']}/login.php" | |
# Intenta acceder a la página de login | |
try: | |
response = sess.get(login_page, verify=False) # No verifica el certificado SSL del servidor | |
except requests.exceptions.ConnectionError as e: | |
print(f"[!] Error al intentar conectarse al host {instance['ip_str']}: {e}") | |
return False | |
if response.status_code != 200: | |
print(f"[!] Error en la respuesta del servidor. Respuesta: {response.status_code}") | |
return False | |
# Intenta obtener el token CSRF para la autenticación | |
try: | |
token = re.search(r"user_token' value='([0-9a-f]+)'", response.text).group(1) | |
except Exception as e: | |
print(f"[!] Error al obtener el token CSRF: {e}") | |
return False | |
# Envía los datos de login con las credenciales por defecto | |
response = sess.post( | |
login_page, | |
data=f"username=admin&password=password&user_token={token}&Login=Login", | |
allow_redirects=False, | |
verify=False, | |
headers={'Content-Type': 'application/x-www-form-urlencoded'} | |
) | |
# Evalúa si la respuesta indica un login exitoso | |
if response.status_code == 302 and response.headers.get('Location') == 'index.php': | |
return True | |
else: | |
return False | |
if __name__ == "__main__": | |
resultado = has_valid_credentials_github() | |
print(f"Resultado del login: {resultado}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from dotenv import load_dotenv | |
from shodansearch import ShodanSearch | |
def main(): | |
""" | |
Función principal que carga la configuración del entorno, inicializa una búsqueda en Shodan | |
y muestra los resultados de la búsqueda. | |
""" | |
# Carga variables de entorno desde un archivo .env | |
load_dotenv() | |
# Obtiene la clave API de Shodan del entorno | |
shodan_api_key = os.getenv("SHODAN_API_KEY") | |
# Verifica si la clave API está disponible | |
if not shodan_api_key: | |
raise ValueError("La clave API de SHODAN no está definida en las variables de entorno.") | |
try: | |
str(shodan_api_key) | |
# Crea un objeto ShodanSearch con la clave API | |
shodan_search = ShodanSearch(shodan_api_key) | |
# Realiza una búsqueda en Shodan | |
resultados = shodan_search.search("title:dvwa", page=1) | |
# Verifica que haya resultados disponibles | |
if resultados is None or 'matches' not in resultados or not resultados['matches']: | |
print("No se encontraron resultados.") | |
return | |
# Imprime detalles de los primeros 10 resultados | |
for i in range(10): | |
if i >= len(resultados['matches']): | |
break | |
resultado = resultados['matches'][i] | |
print(f"\nResultado {i + 1}") | |
print(f"Direccion IP: {resultado.get('ip_str', 'No disponible')}") | |
print(f"Hostnames: {resultado.get('hostnames', [])}") | |
print(f"Localizacion: {resultado.get('location', 'No disponible')}") | |
except ValueError as e: | |
raise ValueError(f"La clave API de SHODAN no es un número entero. {e}") | |
except Exception as e1: | |
raise ValueError(f"{type(e1)} {e1}") | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SHODAN_API_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import shodan | |
class ShodanSearch: | |
"""Clase para realizar búsquedas utilizando la API de Shodan. | |
Attributes: | |
client (shodan.Shodan): Cliente de Shodan configurado con una clave API. | |
""" | |
def __init__(self, api_key): | |
"""Inicializa la instancia de ShodanSearch con la clave API proporcionada. | |
Args: | |
api_key (str): Clave API de Shodan para autenticar las peticiones a la API. | |
""" | |
self.client = shodan.Shodan(api_key) | |
def search(self, query, page=1): | |
"""Realiza una consulta en Shodan y devuelve una página de resultados. | |
Args: | |
query (str): Consulta de búsqueda para enviar a la API de Shodan. | |
page (int, optional): Número de página de los resultados a recuperar. Por defecto es 1. | |
Returns: | |
dict: Un diccionario con los resultados de la búsqueda si es exitosa. | |
""" | |
try: | |
results = self.client.search(query, page=page) | |
return results | |
except Exception as e: | |
print('Error al realizar la petición a la API de Shodan:', e) | |
exit(-1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment