Volcado de memoria con LiME y análisis con Volatility

Un volcado de memoria consiste en almacenar todo lo que está en la RAM de nuestro sistema a un fichero para poder analizarlo posteriormente.

En la RAM se almacena toda aquella información volátil (que se destruye al apagar el sistema) y que contiene información útil sobre la ejecución de los procesos en funcionamiento en nuestro sistema operativo. Ahí también se almacenan contraseñas que están en uso para desbloquear por ejemplo ficheros o particiones cifradas. Así que la opción de “tirar del cable del servidor” para mitigar el problema, puede ser el peor error cometido. ¿Como demuestras quien estaba conectado a la máquina en el momento que ocurrió el problema? ¿Qué procesos se estaban ejecutando?

Nos puede interesar realizar un volcado de memoria por ejemplo si un ransomware está en ejecución y está cifrando los datos de nuestro sistema, para localizar datos se acceso a programas y servicios, identificar fallos y problemas con un software o analizar el funcionamiento de nuestro sistema.
Hay varias formas de realizar un dump de la memoria, todas se basan en el dispositivo “/dev/mem”. La más conocida es memdump, pero en algunos sistemas ejecutar memdump > fichero.dump implica un fallo total de nuestro sistema (¡Vamos! Que se reinicia solo). En resumen: “NO HAGAS ESTO!” (y aún menos en un sistema en producción). La mejor opción si queremos exportar el contenido de “/dev/mem” es hacer uso de dd

# dd if=/dev/mem of=volcado.mem bs=1M 

Si esto nos devuelve un fichero de un tamaño mucho inferior al …

Desplegando un servidor web con alta capacidad

Aquí estoy lamiéndome las heridas de esta noche pasada. Hace unas semanas un cliente me contactó para preparar para alta capacidad una página web que administra. La página web sirve para hacer las inscripciones a una carrera de motos y el día de las inscripciones aquello se pone a fuego.

Tras un presupuesto super ajustado, el cliente opta por la opción más económica. El resultado? pues tras varios “yaque” (instálame un servidor de correo “yaqueestás”), prisas y cambios a último momento, un aumento considerable del tráfico respeto el año pasado y vete a saber que más, el servidor ha estado super saturado y no ha podido servir todas las peticiones necesarias en tiempo y forma; al menos lo importante, que son las inscripciones, se hicieron y con un bajo porcentaje de fallo.

La aplicación está hecha con zendframework2, ergo php5.6, con configuraciones a fuego en el código de la configuración del servidor, correo, etc. Además la web se encontraba en un servidor CentOS 7.0 (del 2014), con unas configuraciones crípticas, no, lo siguiente. ¿Lo de respetar los directorios según LHFS?, ¡¿pa’qué?!.

Para no tener que tocar la configuración del servidor que estaba funcionando, decidí desplegar la página web en otro servidor en mi humilde infraestructura y realizar primero ahí las pruebas.

El entorno de pruebas
Se montó una maquina virtual lxc con debian 11, con 8Gb de RAM y 2 CPU Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz, en mi humilde infraestructura tengo un cuello de botella pendiente de …

Consultar procesos con Celery dentro de uwsgi

Después de unos días de trabajo en mi entorno de desarrollo ha llegado el momento de poner la última versión de la aplicación que estoy haciendo a producción. Como el entorno de producción tiene una configuración distinta que la del entorno de desarrollo, aquí han empezado a aparecer los problemas.

Lo primero es que tenemos una cosa ahí enmedio que se llama uwsgi y es quien ejecuta el código, en lugar del python manage.py runserver. Una de las cosas que me he encontrado es que el trozo de código que comprueba que hay tareas ejecutándose en Celery, no funciona correctamente. En mi caso estaba usando

import time, json
_stats = os.popen('celery inspect stats --json').read()
time.sleep(1)
_stats = json.loads(_stats)

No funcionaba correctamente. He tenido que quebrarme un poco la cabeza para inspeccionar que es lo que estaba ocurriendo, por suerte existe una librería que se llama remote_pdb

(venv) root@app-dev:/var/www/html/app# pip3 install remote-pdb

Y añadimos lo siguiente en el trozo de código que queramos inspeccionar que esté corriendo a través de uwsgi

from remote_pdb import RemotePdb
RemotePdb('127.0.0.1', 4444).set_trace()

Y nos connectaremos al trace por telnet

root@digitplan-dev:~# telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
/var/www/html/app/web/rrd.py(465)check_task_status()
-"""
(Pdb) 

A partir de aquí he podido comprobar que algo le pasa a celery, ya que cualquier comando que ejecutase con celery devolvía vacío. No me ha quedado otra que realizar esta comprobación de otra forma

from celery import Celery
_app = Celery("nombreapp")
_running_tasks = _app.control.inspect().active()['celery@' + str(hostname)]
_status 

Django: tareas en background con celery y rabbitmq

Venga, con este post vamos a subir un poco el nivel de nuestras aplicaciones!

Una de las problemáticas que te encuentras al programar con django es que el envío de mails es horrorosamente lento, el proceso de enviar el mail es relativamente rápido, pero no termino de entender el porqué en general es lento (la conexión y sobre todo la desconexión). Para ello una de las soluciones que más o menos ya había aplicado a mi manera con command hacía que la ejecución cada minuto se solapase con la ejecución de minutos anteriores. Hice una ñapa hace unos días hasta encontrar una solución un poco más elegante. Aquí os la traigo! :D

Hay varios posts que hablan de celery, incluso el libro que uso de consulta “Django 3 by Example”, hablan de usar @tank, pero esta opción está descontinuada para la versión 5, así que aquí veremos como hacerlo con Celery 5. Toda la info la he sacado de éste post.

Configurar e instalar celery y rabbitmq en nuestro proyecto/sistema
Lo primero será instalar celery en nuestro proyecto

laura@melatonina:~/dev/whistleblowerbox$ source venv/bin/activate
(venv) laura@melatonina:~/dev/whistleblowerbox$ pip install celery

A continuación instalamos rabbitmq en nuestro sistema. Rabbitmq es el servicio que encolará las tareas que le pasemos y luego las ejecutará en background

root@melatonina:~# apt -y install rabbitmq-server

Ahora en el fichero settings.py de nuestro proyecto añadimos

(venv) laura@melatonina:~/dev/whistleblowerbox$ vi wbox/settings.py
CELERY_BROKER_URL = 'amqp://localhost'

A continuación, en el mismo directorio donde se encuentra el fichero settings.py vamos a crear uno que se …

Configurar mutt

Mutt es un cliente de correo electrónico de consola, muy útil por ejemplo para ver los mails que envía el sistema. Es muy básico, pero es de gran utilidad para entender un poco más tus sistemas.

En mi caso me encuentro que necesito analizar un script que se ejecuta cada minuto y para ello necesito ver en el listado de mails la hora y que se me pongan los mails nuevos arriba en lugar de abajo.

Para ello voy a modificar (o crear si no está) el fichero ~/.muttrc con este contenido

#set date_format="%d %b %R"   # 06 May 07:55
set date_format="%F %T"       # 2021-05-06 09:20:03
set index_format="%4C %Z %D %-15.15L (%4l) %s"
set sort_aux = last-date-received
set sort = reverse-threads

Aquí el manual de mutt.…

Django: definir variables de entorno

Cuando estamos desarrollando una aplicación con django es común que tengamos que ir haciendo cambios en el fichero settings.py, también es común que tengamos unas URL y configuración de la base de datos distinta en cada entorno, sea el desarrollo como el de producción.

En esta entrada veremos como definir variables de entorno que podremos cargar de forma independiente depende de la instancia en la que nos encontremos. Esto también nos permitirá de cara al futuro desplegar una aplicación mediante docker, donde definiremos las variables “desde fuera”.

Vamos a empezar pues.

Lo primero será instalar la librería django-environ (cuidado que está environ, esta no nos sirve)

(venv) laura@melatonina:~/dev/proyecto$ pip3 install django-environ

A continuación en el directorio donde está el fichero settings.py de nuestro proyecto añadiremos un fichero con el siguiente contenido:

(venv) laura@melatonina:~/dev/proyecto$ vi proyecto/.env
DJANGO_SECRET_KEY=************************************************
DJANGO_ALLOWED_HOSTS=localhost,proyecto.capa8.net
DJANGO_DEBUG=True
DATABASE_URL=postgres://proyecto_user:********@localhost:5432/proyecto_db
ENV=development

# Database settings
DB_NAME=proyecto_db
DB_USER=proyecto_user
DB_PASSWORD=********
DB_HOST=localhost

Es importante que no haya ningún espacio ni antes ni después del =, ya que sino fallará.

A continuación en el fichero proyecto/settings.py modificamos las siguientes líneas:

(venv) laura@melatonina:~/dev/proyecto$ vi proyecto/settings.py
import environ, os

env = environ.Env()
environ.Env.read_env()

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('DJANGO_SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
# False if not in os.environ because of casting above
DEBUG = env('DJANGO_DEBUG')

ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", [])

# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
    'default': env.db('DATABASE_URL'),

Proxmox: redireccionar puerto con iptables y preservar la ip

Hace un par de años hice éste post sobre como redireccionar puertos a los contenedores que se encuentran dentro de un proxmox. Esta solución me fué de maravilla hasta que me di cuenta que el servidor nginx que estaba escuchando en los puertos 80 y 443 en lugar de guardar la IP del cliente que se conectaba, aparecía la IP del proxmox, cosa que creaba algunos problemas a la hora de bloquear intentos de acceso, ya que bloqueabas el acceso a todo el mundo… vamos… un pequeño problemilla de nada :P

Hace unos meses me propuse encontrar la solución pero hasta ahora no me ha sido urgente solucionarlo, ya que tengo que configurar otro proxmox con una ip compartida entre varios contenedores, cada uno de ellos con sus servicios y la cosa era mirar como afinaba esto… así que tras unos 4 días de estar rascando, aquí os traigo la solución :)

iptables -A PREROUTING -t nat -i vmbr0 -d 163.172.109.193 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.2:443
iptables -A FORWARD -p tcp -d 192.168.1.2 --dport 443 -j ACCEPT
iptables -A FORWARD -i vmbr1 -j ACCEPT
iptables -A FORWARD -i vmbr0 -o vmbr1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i vmbr1 -o vmbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -A POSTROUTING -o vmbr0 -j MASQUERADE

– La primera regla de PREROUTING, los paquetes entran por la interfaz vmbr0 des de la ip 163.172.109.193, que es la ip pública del servidor. Mandamos todo el …

Thinkpad no suspende con debian 11

Toda la instalación de debian 11 en mi thinkpad yoga 260, perfecta, solo un problema que ya me encontré el otro día con una thinkpad T460 que le vendí a un cliente; tras suspender el portátil al cerrar la tapa, este no vuelve a levantar una vez abierta de nuevo y se tiene que tirar de botonazo.

Gestionar wordpress por terminal con wp-cli

Lo bonito de meterte en problemas es que para salir de ellos tienes que rebanarte los sesos para encontrar soluciones. Dentro de estas soluciones suelen aparecer metodologías, programas y funcionalidades nuevas. En el post de hoy, tras el marronaco del otro día, la herramienta que reapareció en mi terminal fue wp-cli (como los libros aquellos que has oído a hablar de ellos, pero un día aparece de nuevo y te lo comes como un sabroso manjar).

Este fin de semana pasado el proyecto de kaosenalred.net se ha reconvertido a lanueve.info. En su momento hice este otro post explicando como crawlear una página web con wordpress con httrack. El cliente, en lugar de esperar unas horas mas y arreglar el problema de su wordpress, decidió montar otro wordpress. En el lapso de tiempo de la web vieja y la nueva, en el nuevo wordpress han creado la friolera de 2600 entradas nuevas. A la hora de fusionar las dos webs había varias formas, la escogida esta vez ha sido usar Herramientas Exportar, lo cual te genera un fichero .xml (WXR) con las categorías, los autores, los medios y las entradas. Mi experiencia en importaciones de este tipo en el pasado ha sido que en blogs con mucho contenido es timeout y problemas asegurados, así que otra solución es wp-cli. wp-cli es un programa para gestionar instancias de wordpress.

Para instalarlo, descargaremos el fichero wp-cli.phar, le daremos permisos de ejecución y lo guardaremos al directorio /usr/local/bin/ como wp:

root@planet3D:~# curl 

Searx: Buscar sin ser traceado

Hace unas semanas instalé searx, una solución para hacer búsquedas en los principales buscadores de internet sin ser traceado, es decir, sin dar tu identidad directamente a los buscadores, cosa que hará que cuando aparezca publicidad no te salga nada relacionado con lo que has buscado previamente. ¿Te preguntas como es que en internet los proveedores saben tanto de ti? pues uno de los sitios es por aquí. Searx es una opción para ocultar un poco tus intereses en internet ;)

Searx consta de 3 partes, searx, filtron y morty.

Searx es la interfaz y el programa como tal, filtron es un servicio para limitar el número de búsquedas para evitar que robots se sablen con tu instancia y morty es el proxy que oculta tu información a los buscadores.

Para hacer la instalación seguiremos la documentación de searx

Empezamos con la instalación:

Primero las dependencias

root@searx:~# apt -y upgrade && apt -y dist-upgrade && apt -y install git curl nginx sudo

A continuación clonamos el código de searx y ejecutamos los scripts de instalación

root@searx:/usr/local# git clone https://github.com/searx/searx searx
root@searx:/usr/local# cd searx
root@searx:/usr/local/searx# sudo -H ./utils/searx.sh install all
root@searx:/usr/local/searx# sudo -H ./utils/filtron.sh install all
root@searx:/usr/local/searx# sudo -H ./utils/morty.sh install all

Una vez instalado la cosa nos quedará así:

root@searx:/usr/local# netstat -lanp |grep 'LISTEN '
tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      391/uwsgi           
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      122/morty           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      395/master          
tcp        0      0 127.0.0.1:4004          0.0.0.0:*               LISTEN      764/filtron         
tcp        0      0 127.0.0.1:4005          0.0.0.0:*               LISTEN      764/filtron