Skip to content

Instantly share code, notes, and snippets.

@alonsoir
Last active July 5, 2024 16:13
Show Gist options
  • Save alonsoir/5758eab35d014ba0a9988ef346b6a5f8 to your computer and use it in GitHub Desktop.
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
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}")
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()
SHODAN_API_KEY=
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