2023/07/09

MD5 como IOC apesta

Qué es un IOC

Cuando hay ataque, en sus distintas etapas, se van generando acciones y artefactos, que deberían quedar registradas en algún lado y que son detectables.

Por ejemplo, te envían un link malicioso, para que te descargues un archivo, que al ejecutarse accede a una url para bajar componentes adicionales, exfiltrar información o recibir órdenes. Además, se escribe en el disco como persistencia y agrega una clave en el registro para reiniciarse cuando el sistema lo haga, ¿qué tenemos?

  • Una url maliciosa
  • Un archivo malicioso
  • Más archivos maliciosos
  • Más urls
  • Claves en el registro

Si vos ves este ataque, podés tomar nota de identificadores de cada una de estas piezas y luego, ante cada intento de acceder a urls comparar con las maliciosas, al bajar, escribir o leer un archivo hacerlo con los maliciosos y revisar el registro buscando claves.... maliciosas.


El caso particular del archivo no es muy práctico tomarlo como referencia pues puede ser grande, lo mejor es calcularle un hash y guardar ese Indicator Of Compromise.

 

Pequeña pieza de recomendación

 

Lamentablemente, incluso entre la gente técnica, la falta de conocimiento detallado hace que se cometan errores de concepto, por ejemplo el que paso a reportar, pues lo he visto varias veces con varias personas.

Ponele que tenés dos herramientas que entienden IOCs, el DNS y el proxy saliente.

Te llega este IOC, ¿dónde lo ponés?

https://3984274.aws.com

Muy bien, en cualquiera o ambos.

¿Y este?

https://3984274.aws.com/api/service/34

Si tuvieras la tentación de decir lo mismo, antes mirá este:

https://www.afip.gob.ar/api/service/34

Hay personas que han dicho:

"Pongamos en ambos"

Hay dos problemas, el de seguridad y el conceptual técnico.

El de seguridad es que si para bloquear  

https://www.afip.gob.ar/api/service/34

ponés  "www.afip.gob.ar" en el DNS, generás una denegación de servicio a todo afip sólo por una ruta comprometida. Podría ser válido, razonando "si tiene esa ruta comprometida, puede estar todo el resto, no interactuemos en absoluto con afip hasta que corrijan", ok, es una decisión.

En la conversación de esa decisión es cuando detecté el problema conceptual técnico:

El DNS no entiende ni "https://" ni "/api/service/34"

La única manera de bloquear sin "daños colaterales" es en el proxy.

Sigamos....

 

Qué es MD5


Hashing es una operación que se hace sobre un dato y devuelve un hash, que es un número largo y en teoría cambia ante cualquier modificación sobre el dato. Si calculás un hash de un dato, modificás un bit, recalculás, te da otro hash.

Por alguna falta de visión, pues esto de los IOCs es relativamente reciente, se utilizan como IOCs de archivos hashes MD5, que se diseñó en 1991 y ya desde 1993 se le han hallado problemas criptográficos que en el mejor de los casos, parecería que ya desde 2010 se considera deprecado.

Digo falta de visión pues si buscamos en wikipedia IOC, el artículo nace en 2013, como que ya existían varios SHA para ese entonces, pero seguro que lo de los IOC con MD5 entraron de la mano de gente de seguridad no técnica y programadores sin conocimientos de seguridad que buscaban ahorrar espacio y tiempo de ejecución.

Ojo, siempre es fácil señalar los errores del pasado desde el futuro, pero bueno.

 

La colisión "accidental"

 

Una colisión de hash es cuando dos datos distintos dan el mismo hash. Las colisiones son esperables pues la variedad de datos es infinita y los hashes son números, en el caso de MD5 entre 0 y 2 a la 128, que aunque es un número grande, claramente es muy muy muy inferior a infinito.

 

Se podría argumentar que dada la baja probabilidad de colisión y la ventaja del ahorro de espacio y tiempo de ejecución no importa, aunque ya tenemos al menos un caso conocido.

 

Dice este reporte que no sé de dónde saqué, pero se parece a la situación habitual de malware, en este caso Trojan.Win64.CoinMiner, un minero:

https://itsafety.net/report/20200515-65ade21dc82c01972891285581d85866-servermanager-exe_process-partofthreat

Trojan.Win64.CoinMiner
Trojan.Win64.CoinMiner


Fijate que dice que la mayor parte de los antivirus no lo detecta, ¿por qué será?

Dice Microsoft, que respecto a windows debe tener una cierta autoridad

https://learn.microsoft.com/en-us/windows-server/administration/server-manager/server-manager

Microsoft
Microsoft


Puede ser que estemos hablando de distintas piezas, pero si buscás en virustotal ese hash (65ade21dc82c01972891285581d85866), te trae

 

VirusTotal
VirusTotal

De paso observá que el hash que te muestra es un SHA256, correcto.

No tengo las ganas de buscar cada versión legítima del archivo hasta encontrar el que coincide con esa firma, para demostrar fehacientemente el punto pues su demostración pasa por otro lado.

 

La colisión a propósito


Desde hace años en mis charlas muestro este ejemplo:


angel devil
angel devil

Vemos que dos programas generan distinto output, miden lo mismo, tienen la misma longitud pero son distintos, con sha256 eso no pasa.

 

sha256
sha256


La verdad verdad, no sé bien de dónde lo saqué, tampoco importa muchísimo pues se trata de criptoarqueología y no hay nadie que discuta que MD5 no sirve.

Es un programa en C con un buffer. En ese buffer hay un valor, se compila y al ejecutar se comprueba que sea ese valor. En este caso se ejecuta angel().


Luego, con fastcoll y longEgg se manipula ese buffer en la copia de angel llamada devil hasta que da el mismo hash MD5. Al ejecutar y fallar la comprobación, se ejecuta devil().

 

int main() {
  if (strcmp(dummya, dummyb) != 0) {
    return angel();
  } else {
    return devil();
  }
}



Lo que importa, es que probablemente se puedan tomar dos programas de la misma longitud, manipular una parte y hacerles concidir los hashes, con lo cual para cada ejecutable legítimo del sistema

Digo probablemente pues como script kiddie todo esto parece fácil, pero no lo he comprobado.

Me pregunto por qué no se hace y apuesto a que no vale la pena, es demasiado fácil contrarestar, leyendo el archivo de atrás para adelante para el MD5 o tomando otro SHA cualquiera basta para detectar correctamente, salvo en las herramientas más precarias, para decirles de alguna manera....

lectura invertida
lectura invertida


Para qué puede servir MD5

 

MD5 es útil en situaciones sin adversarios. Por ejemplo, tenés dos archivos del mismo tamaño y no sabés si son iguales. Si están en la misma máquina corrés cmp y listo, te lo dice. Pero si están en distintas máquinas, tendrías que copiar uno a la otra o montar en una una carpeta de otra.... mucho trabajo. El MD5 de cada archivo te puede confirmar si son distintos, no tanto que sean iguales, pero ya dije, sin adversarios.

Me ha servido para hacer unas pruebas con FPGA, tal cual relato en un montón de entradas....

Y por supuesto sirve para demostrar lo inseguro que es.

Aprovechando pantallas obsoletas: la implementación

 

Esto viene de una idea.

Obviamente la experiencia que transité no corresponde a lo que he dejado registrado, al ser una investigación ha habido una ida y vuelta y varias de las pruebas infructuosas no quedaron registradas

 

Implementación

Lo que terminé haciendo es VNC al Remoto, para el momento de iniciar la aplicación y hacer ssh -X al principal. Luego se puede minimizar y volver a maximizar cuando hace falta interactuar. En el caso de xwindows pelado como es con una tablet, la interacción es desde la tablet.


Los pasos del setup


Principal

sudo apt install remmina-plugin-vnc

 

Remoto linux

Como es i32, tengo un Linux Mint 19 con XFCE.

 

Autologin

sudo vi /etc/lightdm/lightdm.conf

    [Seat:*]
    autologin-session=xfce
    autologin-user=YourDesiredAutoLoginUserName
    autologin-user-timeout=0


VNC server

sudo apt install x11vnc
x11vnc -storepasswd somefile


Cuando te conectás te aparece un botón efímero en Secundario. Para evitarlo, le ponemos autenticación más que por seguridad.

Autostart de VNC

  Settings ->
    Session and startup ->
      Application autostart ->
         add x11vnc
            x11vnc -rfbauth somefile


Ver IP

sudo apt install xfce4-genmon-plugin

 
panel -> add new items -> generic monitor
armar script con este contenido y ponerlo en "command"


ip a | grep inet.*global | cut -d" " -f 6

 


Remoto android


samsung tab 3 lite sm-t110 android 4.2.2

Hay que instalar XServer-XSDL en su versión v1.20.41_apkpure de
https://sourceforge.net/projects/libsdl-android/files/apk/XServer-XSDL/

Cuando falla con "Error: X server failed to launch", hay que reiniciar y configurar seleccionar

resolución nativa
x1
device configuration ->
   mouse emulation ->
      mouse emulation mode ->
         desktop, no emulation

Cuando aparece la cuenta regresiva, tocar hasta tener display number = 3

Sacado de https://www.youtube.com/watch?v=TcgTrkA8Oj0

Me falta autostart, por ahora puedo prescindir. Estaría bueno un vnc server pero no hay, quizás lo mejor sería ver de meter un linux, no vale la pena.



Los pasos de la conexión

 

A linux

Via VNC, conectar a Secundario, la IP debe estar en el Panel

Abrir una terminal

ssh -X a Principal

Ejecutar el comando deseado, por ejemplo, "top"

 

A android

En la pantalla de la tablet debe haber instrucciones tipo:

export DISPLAY=192.168.1.105:3

export PULSE_SERVER=tcp:192.168.1.105:4713


Se invoca así:

xwindows-manager & mate-terminal -e top


o así:

mate-terminal --display=$DISPLAY -e top

 

Detalles de uso


xed 

en linux Secundario hace el render en el principal, debe ser por su integración con Mate, así que hay que usar otro, yo puse /opt/sublime_text/sublime_text


screensaving y powersaving

En todos los Secundarios hay que apagar los salvapantallas y poner al máximo o infinito los tiempos de activación de bajo cosumo.

Firefox

En linux:

firefox -P remoto https://www.google.com

En android, muy difícil de interactuar:

firefox -P remoto --display=$DISPLAY  https://www.google.com

 

En tablet 

 

teclado

Para hacer aparecer el teclado en la tablet que tengo, hay que apretar el botón del medio para elegir la xserver y ahí aparece con el teclado que luego se quita con el botón de volver.


move y resize

se puede mover, pero no conseguí cambiar el tamaño, voy a ver uno de estos días si al menos se puede setear al invocar el comando.


Evidencias


En esta imagen podemos ver en la conexión de VNC a una netbook, una terminal con ssh -X de retorno al sistema principal y una tablet con x-windows aguardando conexiones.


Conexiones abiertas
Conexiones abiertas

En esta, hemos abierto un xcalc en el principal con su render en la netbook y el top de la principal con su render en la tablet.


Programas en ejecución
Programas en ejecución


2023/07/04

Reflexiones sobre rbash

Supongamos que tenemos un linux al cual se accede por ssh. La situación normal es que a nivel de permisos tenemos root y el resto.

El usuario root puede hacer todo, listo.

Dentro de ese resto, manejando grupos y permisos podríamos más o menos manejar algún tipo de restricción. Una medida común es utilizar sudo, que habilita  una lista de acciones que podrá ejecutar quien tenga los permisos.

Pero, ponele que en lugar de estar viendo como le permitimos a los usuarios hacer algunas tareas administrativas, estamos buscando restringir lo que ya pueden hacer. Si el usuario en realidad es una cuenta para que un script pueda ejecutar algunas consultas sobre el sistema, no hay motivo para que pueda ejecutar ningún otro comando que no corresponda a lo que va a hacer.

Para este requerimiento, se puede usar rbash.

Si, si, ahí los del fondo, escuché que existe selinux y apparmor, pero esas son palabras mayores, quedémonos con lo sencillo.


Lo que hace rbash es empezar por desabilitar un montón de comportamiento provisto por bash, acá está la lista completa, lo más importante es que no permite cd ni cambiar la ruta de invocación de comandos.

Además:

The restricted shell mode is only one component of a useful restricted environment. It should be accompanied by setting PATH to a value that allows execution of only a few verified commands (commands that allow shell escapes are particularly vulnerable), changing the current directory to a non-writable directory other than $HOME after login, not allowing the restricted shell to execute shell scripts, and cleaning the environment of variables that cause some commands to modify their behavior (e.g., VISUAL or PAGER). 


Sumado a eso, en .bashrc o similar hay que setear el PATH a una carpeta con symlinks a los ejecutables permitidos, según he visto que se hace.


Luego, se debe considerar que:

When a command that is found to be a shell script is executed (see Shell Scripts), rbash turns off any restrictions in the shell spawned to execute the script.

Estoy citando pues como tengo casi nula experiencia con rbash, me siento irresponsable. Pero mi ínfima experiencia algo me ha hecho pensar.

 

Vamos ahora al escenario concreto, quiero:

  • que exista una cuenta
  • que tenga shell restringido
  • a la que sólo se pueda acceder vía ssh
    • esto implica no login por consola ni "desplazamiento lateral" tipo su o login

Este comando lo hace:

$ sudo adduser  --shell /usr/bin/rbash --disabled-login  prueba

Si estás modificando un usuario existente, editás /etc/password para que tenga el shell correcto y /etc/password para deshabilitar el login.

También se hace con 

$ sudo passwd -l prueba

Que le agrega a "!" al password existente.

De un modo u otro lo controlás con:

$ sudo grep prueba /etc/passwd /etc/shadow
/etc/passwd:prueba:x:1001:1001:,,,:/home/prueba:/usr/bin/rbash
/etc/shadow:prueba:!:19542:0:99999:7:::

Solo vía ssh, hay que habilitar la key ya que se trata de clientes script, no de personas ingresando claves, aunque con la key un usuario puede entrar.

$ ssh-keygen -f prueba.key -t ecdsa

En la carpeta del usuario prueba, hay que crear .ssh con rwx------ y el archivo authorized_keys con permisos rw------- y el contenido de prueba.key.pub.

 

rbash en acción
rbash en acción

El problema que hay acá es que si ejecutás:

$ ssh prueba@localhost -t bash

sshd ignora el shell de /etc/passwd y te da un shell irrestricto.

 

rbash bypass
rbash bypass

Se arregla de dos maneras, una global y otra específica para cada usuario.


La global es poner en sshd_config esta línea, que no la probé:

ForceCommand rbash

Tiene la ventaja de restringir a todos por si alguno se te escapa, pero si querías tener uno que haga de administrador, vas a tener que ponerle específicamente que pueda ejecutar sudo.
 
La específica para cada usuario es poner no-pty  en  .ssh/authorized_keys
a la key con la que se autentica.Queda algo asi:


no-pty ssh-ed25519 AAAAC3NzaC1....

El problema es que perdés el prompt y bash completion, algo completamente irrelevante para un script.

 
rbash con no-tty en authorized_keys
rbash con no-tty en authorized_keys

 

no login
no login

Mis reflexiones

 

Porque no password al azar

Se podría poner un password al azar, pero al ser un password existente hay una increíblemente remota posibilidad de que alguien le acierte. También que al azar sea un password en un diccionario. O que en el momento de la creación haya leak.

Es mejor poner "!" antes que usar azar pues es un indicador visual y fácil de controlar de modo automático que luego no cambie la situación.

Es mejor dejar solo "!" pues agrega que no haya ninguna posibilidad de login.


Porque no ForceCommand rbash

Si la idea es que en ese equipo no haya ningún usuario remoto sin rbash, de acuerdo con ForceCommand rbash. Pero eso implica que al menos a algún usuario hay que habilitarle que pueda ejecutar sudo, además de las reglas de sudoers.

Me parece más sencillo configurar no-pty en .ssh/authorized_keys para cada usuario a restringir.

Igual en este aspecto mi opinión no es tan fuerte como con el punto anterior. De hecho, mientras escribo esto, no puedo dejar de notar que ForceCommand rbash + sudo responde más a la política de denegar todo y luego permitir de a uno, como que cambiaría de idea muy fácil... listo, ya cambié de idea.

Igual mi instinto algo me dice a favor de no-pty, por el lado de evitar una denegación de servicio. Si vuelvo a cambiar de idea, lo registraré.

Mi posición actual es, depende del perfil de uso del equipo, si es de uso general y hay que restringir a un usuario de servicio, no-pty, si nadie debería acceder salvo ciertas tareas de mantenimiento, ForceCommand rbash + sudo.

 

Disclaimer

No tomes este post como ninguna autoridad de cómo implementar correctamente rbash, no he investigado la parte de las variables de entorno ni sometido a pruebas exhaustivas.