30 abril, 2020

Bypass UAC Fileless usando AppPaths sdclt.exe

Bypass UAC tipo Fileless

La idea de los bypass de UAC (User Account Control) tipo fileless es detectar binarios de Windows firmados por Microsoft y que tienen el atributo autoElevate a true de su manifest. Con una política por defecto de UAC en Windows, estos binarios se ejecutan en un contexto de integridad alto, interactuando con el registro no encuentran las claves en la rama HKCU. Cuando en la consulta se obtiene un resultado NAME NOT FOUND y esta se hace antes de que se ejecute el propio binario, se podría escribir en esa rama HKCU en la que si tendremos permisos haciendo referencia a la invocación de otro binario como por ejemplo un cmd.exe. Esto provocará que este cmd.exe se ejecute antes y de forma privilegiada logrando así el bypass del UAC. 

Para comprobar el manifest de un binario podemos usar la herramienta de sigcheck de Sysinternals con su parámetro -m seguido del binario que se le indique.

Figura 1: Comprobar atributo autoElevate en el manifest de un binario con sigcheck.

Existen multitud de binarios con el atributo autoElevate a true y que usan consultas en el registro para poder ejecutarse. La primera técnica fue descubierta Enigma0x3 con el binario eventvwr.exe (visor de eventos de Windows) publicada en 2016. El mismo autor en 2017 publicó el mismo dos bypass fileless nuevos que afectan a los binarios sdclt.exe (panel de control de copias de seguridad y restauración) y fodhelper.exe (instalación de características avanzadas).

Como ejemplo este artículo se enfoca al bypass UAC fileless que afecta al binario sdclt.exe. Enigma0x3 ha subido a su repositorio un script en Powershell para aprovechar la explotación de esta vulnerabilidad.

Con procmon de Sysinternals podemos monitorear la ejecución de procesos en el sistema. Esto nos permite analizar el seguimiento de ejecución de un binario que filtremos y enfocarnos en un tipo de operación que realiza en el registro.

En el caso de sdclt.exe vemos que realiza consultas en la existencia de claves del registro en la rama HKCU intentando encontrar un binario control.exe en el path:
HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\control.exe
Como no lo encuentra se obtiene un valor NAME NOT FOUND y continua su ejecución comprobando en más ramas hasta invocar al control.exe que como parámetro abrirá al sdclt.exe. Esto significa que si creamos esa rama y en su valor 'Default' agregamos la ejecución de una cmd.exe podremos invocarla de forma privilegiada ya que como se ve en procmon esta consulta al registro se realiza en un contexto de integridad alto.

Figura 2: Rama del registro NAME NOT FOUND en la ejecución del binario sdclt.exe

Sabiendo esto podemos crear la estructura de ramas adecuada e invocar en la valor por defecto una cmd.exe. Esta se ejecutará el mismo contexto es decir, de forma privilegiada. Dejo un pequeño script que ejecuta una función para poder crear la estructura de ramas de forma automática. Pasando como parámetro -Payload el ruta absoluta "C:\Windows\System32\cmd.exe"
function AppPathSdcltBypass {
Param (
    [Parameter(Mandatory)]
    $Payload
)
$path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\control.exe"
if (-not (Test-Path $path)) {
    New-Item -Path $path -Force
    New-ItemProperty -Path $path -Name '(Default)' -PropertyType String -Value $Payload -Force | Out-Null
}
else {
    Write-Host "La ruta ya existe"
    break
}
Start-Process "C:\Windows\system32\sdclt.exe"
}

AppPathSdcltBypass -Payload "C:\Windows\System32\cmd.exe"
Cuando se inicie la cmd podemos comprobar con whoami /groups que efectivamente se ejecuta de forma privilegiada.

Figura 3: Comprobar el contexto de integridad cmd.exe (whoami /groups).

Un detalle a tener en cuenta, a diferencia de otros bypass de UAC como eventvwr.exe, este fileless no permite la entrada de parámetros tipo "cmd.exe /c <intrucciones>", limitando y dificultando su aprovechamiento para una ejecución de ordenes de forma remota.

En la siguiente captura se puede ver la prueba de concepto de la ejecución y como se realiza este bypass de UAC fileless de sdclt.exe. Por defecto y aunque el usuario pertenezca al grupo administradores sino ejecutó como administrador una cmd (botón derecho "ejecutar como administrador") no podría escribir en C:\.

Figura 4: PoC - Bypass UAC Fileless sdclt.exe.

Saludos!

Autor: Adrián Lois

19 abril, 2020

Gestión de políticas de contraseñas en Linux: login.defs y pam_pwquality (pam_cracklib)

Antes de entrar en materia y comentar donde se definen las directivas de contraseñas en entornos Linux, es necesario conocer los campos que estructuran al fichero donde almacenan cifradas las contraseñas de usuarios locales /etc/shadow.

Este fichero nos muestra el estado actual de como se están aplicando estas directivas a los usuarios y que nos resulta útil en procesos de auditoria interna para conocer esta información.

Estructura del fichero /etc/shadow

Figura 1: Estructura del fichero /etc/shadow.
  • 1. Nombre de usuario.
  • 2. Contraseña cifrada. Se establece con la estructura $id$salt$hashed. El tipo de algoritmo utilizado se define en el inicio en números entre los símbolos $.
    • $1$ - MD5.
    • $2a$ - Blowfish.
    • $2y$ - Blowfish.
    • $5$ - SHA-256.
    • $6$ - SHA-512.
  • 3. Último cambio de contraseña desde el 1/Enero/1970 (epoch).
  • 4. Cantidad de días restantes para que el usuario cambie su contraseña. -1 significa que nunca expira.
  • 5. Número máximo de días que la contraseña es válida después del cambio de contraseña por parte del usuario.
  • 6. Días antes de que caduque la contraseña, advierte al usuario para que la cambie.
  • 7. Días después de que caduque la contraseña, esa cuenta estará deshabilitada.
  • 8. Días desde el 1/Enero/1970. Fecha absoluta que especifica cuando ya no se pueda usar el inicio de sesión para esa cuenta.

Comando chage (caducidad en las contraseñas)

Con el comando chage (change age) podemos establecer la caducidad de contraseñas y cuentas de usuario. Esto no afecta a los nuevos usuarios, se establece de forma nominal a usuarios existentes.

Para aplicar estas opciones a nuevos usuarios y así generar estas directivas por defecto habría que hacer uso de login.defs que se comenta más adelante en este artículo.

Opciones del comando chage:
  • -d, --lastday: Establece el día del último cambio de la contraseña.
  • -E, --expiredate: Establece la fecha de caducidad.
  • -I, --inactive: Deshabilita la cuenta después inactividad de días de la fecha de caducidad.
  • -l, --list: Muestra la información de la edad de la cuenta.
  • -m, --mindays: Establece el número mínimo de días antes de cambiar la contraseña.
  • -M, --maxdays: Establece el número máximo de días antes de cambiar la contraseña.
  • -R, --root: Directorio en el que hacer chroot.
  • -W, --warndays: Establece los días de aviso de expiración.
Con el parámetro -l podemos ver información sobre las cuentas.
# chage -l pepe
Last password change                                    : Apr 18, 2020
Password expires                                        : never
Password inactive                                       : never
Account expires                                         : never
Minimum number of days between password change          : 0
Maximum number of days between password change          : 90
Number of days of warning before password expires       : 5 
Más información sobre el comando chage: https://linux.die.net/man/1/chage

Cumplimiento de directivas de seguridad en la calidad de contraseñas seguras de usuarios

Al igual que en sistemas Windows es necesario implementar un mínimo cumplimiento de seguridad en el hardening de contraseñas estableciendo directivas a nivel de dominio para definir la complejidad de contraseña, longitud mínima, días de expiración, contraseñas no repetidas respecto a las anteriores, etc.

En sistemas Linux, aplicaciones de terceros o servicios exógenos que hacen uso de usuarios Linux, también es necesario establecer políticas de seguridad estrictas al tratarse de cuentas que pueden tener el mismo riesgo de ser vulneradas y poder pivotar a otros sistemas que sean de un mayor interés para los atacantes.

Lógicamente también dependerá de la infraestructura y su ecosistema. En entornos de producción no sería conveniente provocar la desactivación o bloqueo de una cuenta de usuario y dejar inoperativo un servicio crítico que dependa de dicha cuenta. Independientemente de estos casos es recomendable y diría que necesario establecer este tipo de criterios para garantizar y elevar un poco más las medidas de seguridad de los sistemas de la empresa.

Se pueden establecer políticas por defecto en el momento de creación de nuevas cuentas en el sistema, sin la necesidad de usar chage nominalmente a cada usuario como vimos anteriormente.

login.defs

Se trata de un fichero de texto situando en /etc/login.defs de forma nativa se encuentra en cualquier entorno Linux. Se definen las políticas de gestión de contraseñas para la creación de nuevos usuarios. También podemos establecer otros directivas como el valor umask por defecto, si el usuario tendrá un home para el si no se le especifica en su creación (useradd -m), cambiar la secuencia de ID (por defecto suelen ser 1000 y algo para usuarios normales), mensaje de bienvenida del inicio de sesión del usuario (motd_file), etc.

El motivo de este artículo será enfocado únicamente a las que tengan que ver con las políticas de contraseñas.

Algunas de las directivas más comunes que podemos establecer:
  • PASS_MAX_DAYS: Número máximo de días que se puede usar una contraseña.
  • PASS_MIN_DAYS: Número mínimo de días permitido entre cambios de contraseña
  • PASS_WARN_AGE: Número de días de advertencia antes de que caduque una contraseña.
  • PASS_MIN_LEN y PASS_MAX_LEN: Número mínimo y máximo de caracteres que debe tener la contraseña.
  • PASS_ALWAYS_WARN: Advierte sobre contraseñas débiles.
  • PASS_CHANGE_TRIES: Número máximo de intentos de cambiar la contraseña si se rechaza por que es demasiado "fácil".
  • ENCRYPT_METHOD: Tipo de cifrado que tendrá la contraseña (SHA256 $5$ o SHA512 $6$).
  • LOGIN_RETRIES: Número máximo de reintentos de inicio de sesión en el caso de que la contraseña sea incorrecta.
  • LOGIN_TIMEOUT: Tiempo máximo en segundos para iniciar sesión

Más información sobre login.defs: https://linux.die.net/man/5/login.defs

pam_cracklib y pam_pwquality

Si queremos tener una mayor nivel de detalle en la personalización de las directivas en la complejidad de contraseñas para las cuentas de usuarios sería más interesante hacer uso de los módulos PAM (Pluggable Authentication Modules) pam_cracklib y pam_pwquality.

pwquality es una versión más actual y mejorada de cracklib. pwquality llama a una rutina cracklib para verificar si la contraseña es parte de un diccionario si este se especifica en la directiva dictpath. En este caso haré referencia siempre a pam_pwquality.

En entornos RHEL/Centos se incorpora de forma nativa, es compatible con derivados Debian pero será necesario instalarlo.
sudo apt install -y libpam-cracklib libpam-pwquality libpwquality-tools
Una vez instalado el módulo de libpwquality podemos editar sus opciones en el fichero "/etc/security/pwquality.conf".

Opciones para definir las políticas: 
  • difok: Número de caracteres en una nueva contraseña que no deben estar presentes en la contraseña anterior.
  • minlen: Tamaño mínimo aceptable para la nueva contraseña.
  • dcredit: Crédito máximo por tener dígitos en la nueva contraseña.
  • ucredit: Crédito máximo por tener letras mayúsculas en la nueva contraseña.
  • lcredit: Crédito máximo por tener letras minúsculas en la nueva contraseña.
  • ocredit: Crédito máximo por tener otros caracteres en la nueva contraseña.
  • minclass: Número mínimo de clases de caracteres requeridas para la nueva contraseña
  • maxrepeat: Número máximo de caracteres repetidos.
  • maxclassrepeat: Número máximo de caracteres consecutivos en la misma clase.
  • gecoscheck: Verifica si las palabras individuales de más de 3 caracteres del campo passwd GECOS (campo de comentarios) del usuario están contenidas en la nueva contraseña.
  • dictpath: Ruta a los diccionarios de clacklib.
  • badwords: Lista de palabras separadas por espacios que no deben incluirse en la contraseña.

Sistema de créditos, valores negativos y clases en pwquality

Créditos

Para definir la calidad y complejidad de las contraseñas se utiliza un sistema de créditos. Esto es muy interesante, básicamente se obtienen créditos por la complejidad. Una contraseña más corta podría ser aceptable si es más compleja en otras formas.

Por ejemplo una contraseña "ahwouwtdye" podría pasar una prueba minlen = 10. Si dcredit se establece en 2, una contraseña "ahwouw12" pasaría la prueba por que obtendríamos 2 créditos por cada dígito, entonces 8 caracteres más 2 créditos se valoran como 10 caracteres. Esto dependerá de como se establezcan los parámetros ucredit, lcredit, dcredit y ocredit.

Valores negativos

Establecer valores de créditos negativos significa que debe tener al menos ese tipo de carácter. Por ejemplo, establecer dcredit a -1 significaría que debe incluir al menos un dígito para que se acepte una contraseña. Es decir, no se trata de una suma de créditos sino de un requerimiento obligatorio.

Clases (minclass)

Otra configuración interesante es minclass. Determina cuántas clases diferentes de caracteres se deben usar para que una contraseña sea aceptable. Hay 4 tipos de clases: minúsculas, mayúsculas, dígitos, caracteres especiales (símbolos o signos).

Por ejemplo, un minclass = 2 exige que una contraseña contenga la combinación de dos tipos de clases. Ya sean mayúsculas o minúsculas, mayúsculas y caracteres especiales, minúsculas y dígitos, etc. Lo mismo pasaría si se establece a minclass = 4, la contraseña debería contener

También se puede establecer un límite al número máximo de caracteres de cualquier tipo de clase. Por ejemplo, con el parámetro maxclassrepeat = 4 indicamos que las contraseñas no pueden contener más de 4 minúsculas, mayúsculas, dígitos y otros caracteres especiales. 

Más información sobre el uso de directivas del fichero de pwquality: https://linux.die.net/man/8/pam_pwquality

Probando el cumplimiento de requisitos con varias contraseñas.
# passwd pepe
Nueva contraseña:
CONTRASEÑA INCORRECTA: La contraseña tiene menos de 8 caracteres.

# passwd pepe
Nueva contraseña:
CONTRASEÑA INCORRECTA: La contraseña no supera la verificación de diccionario - No contiene suficientes caracteres DIFERENTES.

# passwd pepe
Nueva contraseña:
CONTRASEÑA INCORRECTA: La contraseña no supera la verificación de diccionario - Es demasiado simple/sistemática.

# passwd pepe
Nueva contraseña:
CONTRASEÑA INCORRECTA: La contraseña contiene más de 3 caracteres de la misma clase en forma consecutiva

pwscore

pwquality (libpwquality-tools) dispone de una herramienta llamada pwscore que podemos usar para comprobar la complejidad de una contraseña en base a los criterios establecidos en pwquality. Algunos ejemplos de uso.
# echo 123 | pwscore
Falló la comprobación de calidad de la contraseña:
 La contraseña tiene menos de 8 caracteres

# echo abc123.. | pwscore
Falló la comprobación de calidad de la contraseña:

 La contraseña no supera la verificación de diccionario - Es demasiado simple/sistemática.

# echo L3h5as/2a$-ls=72 | pwscore
100

Conclusión

Estos módulos PAM también pueden comprobar si las contraseña son un palíndromo o si solamente se cambió un solo carácter de mayúscula a minúscula o viceversa, si las contraseñas anteriores son similares o ya han sido usadas anteriormente, si contiene el nombre del usuario, o si hay alguna coincidencia con el campo passwd GECOS (campo de comentarios) de /etc/passwd. Dependiendo el nivel de complejidad que se establezca sería difícil establecerse una mala contraseña.

En definitiva, ofrecen una serie de comprobaciones que ayudan a garantizar un nivel de robustez y calidad de las contraseñas. Así como en la mayoría de compañías se aplican para entornos Windows, intentar aplicar estas políticas de seguridad en sistemas Linux y que no habiten en el olvido.

Saludos!

Autor: Adrián Lois

02 abril, 2020

sshuttle: Múltiples túneles SSH y "VPN" (Proxy transparente)

sshuttle. Se trata de un cliente SSH desarrollado en pyhton que actúa como un proxy transparente funcionando como una "VPN". No se trata de una VPN como definición, sshuttle crea de forma automática distintas reglas usando pfctl (pf - Packet Filter) o en su defecto iptables para un múltiple reenvío de puertos a través de una conexión tunelizada vía SSH.

Ya comentara las diferencias entre los distintos tipos de túneles SSH. Esta aplicación nos abstrae de los detalles de realizar manualmente cada reenvío -port forwarding- a cada IP/Puerto hacia la red remota a la que queremos acceder.


La funcionalidad es como si realmente estuviéramos utilizando una VPN pero canalizada por una única conexión SSH a través de un host de la red remota que hará de equipo puente realizando múltiples túneles de reenvío. Su principal desarrollador Brian May, la define como "la VPN para el hombre pobre".

Soporta tunelización de DNS redireccionando todo el tráfico DNS local a través de la conexión SSH al host remoto, como si estuviéramos utilizando las direcciones DNS de la red remota. Por lo que toda la navegación es como si la hiciésemos a través de la red remota a la que nos conectamos, algo similar a un -dynamic port forwarding- o Proxy SOCKS

Si nos conectamos en un red wifi abierta o pública y queremos estar más seguros navegando y/o acceder a recursos internos de nuestra red doméstica sin necesidad de implementar o alquilar servicio VPN externo de terceros, esta aplicación es una muy buena solución.

Es compatible con Linux y MacOS (Windows con cygwin instalado).

Instalar sshuttle

git clone https://github.com/sshuttle/sshuttle.git
cd sshuttle
sudo ./setup.py install
En mi caso dispongo de una  RaspberryPi con el servicio SSH expuesto a Internet en un puerto no estándar.

Uso de sshuttle

sshuttle [-l [ip:]port] [-r [user@]sshserver[:port]] <subnets...>
sshuttle -v --dns -r USUARIO@IP:PUERTO 192.168.0.0/24
La opción --dns indica el tunelizado de tráfico DNS. 

En el caso de MacOS usa reglas de filtrado de redirección con pf (pfctl). Ejemplo de autenticación con clave pública.
MacOS:~ adrian$ sshuttle -v --dns -r USER@IP/DNS:PORT 10.0.0.0/24
Starting sshuttle proxy.
firewall manager: Starting firewall with Python version 2.7.16
firewall manager: ready method name pf.
IPv6 enabled: True
UDP enabled: False
DNS enabled: True
User enabled: False
TCP redirector listening on ('::1', 12300, 0, 0).
TCP redirector listening on ('127.0.0.1', 12300).
DNS listening on ('::1', 12299, 0, 0).
DNS listening on ('127.0.0.1', 12299).
Starting client with Python version 2.7.16
c : connecting to server...
Starting server with Python version 3.6.9
 s: latency control setting = True
 s: auto-nets:False
c : Connected.
firewall manager: setting up.
>> pfctl -s Interfaces -i lo -v
>> pfctl -s all
>> pfctl -a sshuttle6-12300 -f /dev/stdin
>> pfctl -E
>> pfctl -s Interfaces -i lo -v
>> pfctl -s all
>> pfctl -a sshuttle-12300 -f /dev/stdin
>> pfctl -E
c : DNS request from ('10.0.0.16', 51556) to None: 31 bytes

En el caso de Ubuntu usa reglas de filtrado de redirección con iptables. Ejemplo de autenticación con password.
adrian@ubuntu:~$ sshuttle -v --dns -r USER@DNS/IP:PORT 10.0.0.0/24
Starting sshuttle proxy.
firewall manager: Starting firewall with Python version 3.6.9
firewall manager: ready method name nat.
IPv6 enabled: False
UDP enabled: False
DNS enabled: True
TCP redirector listening on ('127.0.0.1', 12300).
DNS listening on ('127.0.0.1', 12300).
Starting client with Python version 3.6.9
c : connecting to server...
USER@DNS/IP's password:
Starting server with Python version 2.7.17
 s: latency control setting = True
 s: available routes:
c : Connected.
 s:   2/10.0.0.0/24
 s:   2/172.17.0.0/16
 s:   2/172.18.0.0/16
firewall manager: setting up.
>> iptables -t nat -N sshuttle-12300
>> iptables -t nat -F sshuttle-12300
>> iptables -t nat -I OUTPUT 1 -j sshuttle-12300
>> iptables -t nat -I PREROUTING 1 -j sshuttle-12300
>> iptables -t nat -A sshuttle-12300 -j RETURN --dest 127.0.0.1/32 -p tcp
>> iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 10.0.0.0/24 -p tcp --to-ports 12300 -m ttl ! --ttl 42
>> iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 127.0.0.53/32 -p udp --dport 53 --to-ports 12300 -m ttl ! --ttl 42
En el caso de Windows se complica el uso de esta herramienta.

Se propone instalar una máquina virtual Linux en modo puente que haga la conexión con sshuttle y desde la máquina anfitrión Windows enrutar todo el tráfico hacia la máquina Linux.

Info: https://sshuttle.readthedocs.io/en/stable/windows.html

Saludos!

Autor: Adrián Lois