Cambiar contraseña de usuario de WordPress por línea de comandos

A veces, o tal vez regularmente, me ocurre que olvido la contraseña del usuario de WordPress de un sitio web, ya sea porque no la añado al gestor de contraseñas o en el momento invento una tan complicada que solo la recuerdo los días siguientes y luego la olvido para siempre. Ante esta situación siempre termino conectándome al servidor, luego a MariaDB/MySQL y luego cambio la contraseña insertando un hash al campo de contraseña del usuario al que quiero acceder.

Lo primero será conectarnos como usuario a MariaDB/MySQL, ya sea usando el todopoderoso usuario root o el mismo usuario de la base de datos que queremos editar.

# mysql -u root -p

Ahora seleccionamos la base de datos que queremos emplear y listamos las tablas, ya que en la instalación se puede emplear un prefijo diferente. De no haber hecho esto, la tabla en cuestión será wp_users

mysql> SHOW DATABASES;
mysql> USE basededatoswp;
mysql> SHOW TABLES;

Ahora buscamos el ID del usuario que deseamos cambiar:

mysql> SELECT ID, user_login, user_pass FROM wp_users;
+----+----------------------------+------------------------------------+
| ID | user_login                 | user_pass                          |
+----+----------------------------+------------------------------------+
|  1 | administrador              | $P$BdrP021yzdWQCN4Bm0u0jIESEq4Owr/ |
|  2 | usuario1                   | $P$B05MBOShAJwRrK4kSmbaEhk1WPWQ4O0 |
+----+----------------------------+------------------------------------+

Ahora actualizaremos la contraseña nueva

mysql> UPDATE wp_users SET user_pass = MD5('contraseña') WHERE ID = 1;

Existe una sintaxis alternativa, donde solo necesitamos conocer el nombre de usuario; sin embargo, no he logrado que esta actualice la contraseña a pesar que su sintaxis es correcta

mysql> UPDATE wp_users SET user_pass = MD5('contraseña') WHERE 'user_login' = 'administrador';

Podremos verificar así

mysql> SELECT ID, user_login, user_pass FROM wp_users;
+----+----------------------------+------------------------------------+
| ID | user_login                 | user_pass                          |
+----+----------------------------+------------------------------------+
|  1 | administrador              | 890bec3121ae0e73d2a22e3dd333ae5f   |
|  2 | usuario1                   | $P$B05MBOShAJwRrK4kSmbaEhk1WPWQ4O0 |
+----+----------------------------+------------------------------------+

Como se ve, el nuevo hash de la contraseña del usuario esta en formato MD5. Ahora podremos ingresar vía wp-login.php al tablero de WordPress. Una vez ingresemos, WordPress actualizará el hash una vez más en su mezcla propia de MD5 y PHPass.

Actualizando el BIOS de la Lenovo ThinkCentre M92p Tiny

Utilizo varias computadoras compactas Lenovo Tiny M92p como servidores en mi casa; una como NVR, una como servidor multimedia, una como servidor de archivos y otra como servidor de pruebas. Su tamaño compacto y bajo consumo eléctrico sumado a su hardware aún decente para la época considerando que existen desde 2012 (core i5, 8 GB RAM, SSD) la hace ideal para estos menesteres.

Trasteando, como es costumbre, en estos cacharros caí en cuenta que no tenían actualizado el BIOS algunas desde 2012. Así que me puse manos a la obra con esto. Investigando en el sitio de Lenovo, encuentro que la última versión disponible es 9SKT9CA y está disponible desde el 23 de diciembre de 2018.

Al ver el listado de archivos, veo que existen varias maneras de actualizarlas. La preferida, con imágenes de CD sería la más fácil. Existe manera de actualizar también desde una instalación de Windows en la misma computadora, opción que para mí no es viable, puesto que todas tienen instalada alguna distro Linux. Por último existe un modo de actualizar desde una memoria USB.

El primer paso sería formatear la memoria USB, pero primero averiguamos donde esta el dispositivo con fdisk -l.

Disco /dev/sdb: 22.37 GiB, 24015495168 bytes, 46905264 sectores
Modelo de disco: SanDisk SSD U100
Unidades: sectores de 1 * 512 = 512 bytes
Tamaño de sector (lógico/físico): 512 bytes / 512 bytes
Tamaño de E/S (mínimo/óptimo): 512 bytes / 512 bytes
Tipo de etiqueta de disco: gpt
Identificador del disco: 1E1FA4E7-62FD-4004-850F-A96DBA93BB73

Por lo general prefiero trabajar con una memoria USB completamente vacía, por lo que primero la formateo. De hecho no estoy completamente seguro si este paso es necesario.

# mkfs.vfat -F 32 /dev/sdc1

Luego bajar la versión de CD, el archivo ISO. Podemos verificar su contenido si lo montamos. Creamos el directorio primero

# mkdir biosupdate

Luego montamos el ISO

# mount -o loop -t iso9660 9sj99cusa.iso biosupdate

Y ver su contenido con el comando ls de toda la vida.

total 21317
-r-xr-xr-x 1 root root 16450560 dic 10  2018 9sjt9ca.img
-r-xr-xr-x 1 root root   216720 jun  8  2017 afudos.exe
-r-xr-xr-x 1 root root   137968 may 17  2012 amidedos.exe
-r-xr-xr-x 1 root root       39 nov 14  2012 autoexec.bat
-r-xr-xr-x 1 root root    10289 dic 10  2018 changes.txt
-r-xr-xr-x 1 root root    63810 jul 18  2012 chglogo.exe
-r-xr-xr-x 1 root root    69014 mar 24  2012 compdos.exe
-r-xr-xr-x 1 root root   138842 jul 23  2012 flash2.exe
-r-xr-xr-x 1 root root  4722688 dic 10  2018 image9s.cap
-r-xr-xr-x 1 root root      329 abr 15  2011 logo.bat
-r-xr-xr-x 1 root root    15750 ene 27  2016 readme.txt

Ya podemos desmontar

# umount biosupdate

y eliminar el directorio que acabamos de crear.

# rmdir biosupdate

Volcamos la imagen al dispositivo /dev/sdc. Notese que no es la partición sino el dispositivo mismo.

# dd if=9sj99cusa.iso of=/dev/sdc bs=4M status=progress; sync

Una vez hecho esto, ya podemos extraer el dispositivo y conectarlo a la Lenovo M92p Tiny. Al encender debe cargar automáticamente el contenido de la memoria USB que acabamos de ingresar. En caso tal de no iniciar automáticamente, podemos presionar F12 para cargar el menú de arranque del BIOS actual o con F1 editar las opciones de arranque. Una vez inicie, se mostrará una pantalla preguntando si deseas o no actualizar el BIOS. Presionamos Y y el proceso continuará de manera automática. En este lapso la computadora reiniciará al menos 2 veces, y hay que dejarla en paz hasta que terminé el proceso.

Una vez termine, volverá a iniciar la memoria USB, pero esta vez preguntara si deseas volver a instalar el BIOS ya que detecta que es la misma versión. En este punto ya habremos terminado. Presionamos N y te llevará a un prompt de DOS. Ya podemos extraer el dispositivo y verificar entrando a la BIOS presionando F1.

Administración básica en MariaDB/MySQL

Soy un fanático de la línea de comandos, razón por la cual comparto el 80% del tiempo frente a una pantalla de color negro con texto. Siempre he pensado en que es una herramienta sumamente poderosa y por ello, no escapo a la administración de bases de datos cuando se trata de sitios web.

Las tareas más comunes a realizar cuando uno administra bases de datos en sitios web, van desde crear la misma base de datos, los usuarios, asignar permisos y otras tarea comunes como hacer un respaldo completo de una base de datos o repararlas. La razón de esta entrada es resumir en un solo punto todas estas tareas para tener un lugar anecdótico donde revisar cuando se presente un problema.

Operaciones con bases de datos

Crear una base de datos: La operación más básica y fundamental al gestionar bases de datos con MariaDB:

mysql> CREATE DATABASE basededatos;

Borrar una base de datos: Si queremos borrar una base de datos completa:

mysql> DROP DATABASE basededatos;

Operaciones con usuarios

Crear un usuario local y asignarlo a una base de datos: crear un usuario tiene una tarea adicional que es asignarle una base de datos, de lo contrario no podría realizar operaciones ni con las bases de datos, ni las tablas que estas tengan:

mysql> CREATE USER 'usuario'@'localhost' IDENTIFIED BY 'contraseña';
mysql> GRANT ALL PRIVILEGES ON basededatos.* TO 'usuario'@'localhost';
mysql> FLUSH PRIVILEGES;

Crear un usuario remoto y asignarlo a una base de datos: cuando hay usuarios remotos, la operación es la misma pero identificando el host:

mysql> CREATE USER 'usuario'@'10.0.0.2' IDENTIFIED BY 'contraseña';
mysql> GRANT ALL PRIVILEGES ON basededatos.* TO 'usuario'@'10.0.0.2';
mysql> FLUSH PRIVILEGES;

Borrar usuario local: si queremos eliminar un usuario local:

mysql> DROP USER 'usuario'@'localhost';

Borrar usuario remoto: si queremos eliminar un usuario remoto:

mysql> DROP USER 'usuario'@'10.0.0.2';

Operaciones de listado

Listar base de datos: esto mostrará todas las bases de datos:

mysql> SHOW DATABASES;

Listar tablas de una base de datos: esto mostrará todas las tablas dentro de una base de datos:

mysql> USE basededatos;
mysql> SHOW TABLES;

Listar usuarios y hosts: esto mostrará todos los usuarios en la base de datos:

mysql> USE mysql;
mysql> SELECT host, user FROM mysql.user;

Importación y exportación de bases de datos

Exportar una base de datos: por seguridad esto debe ser realizado en 3 pasos, primero bloquear las tablas para que no se escriba sobre ellas, volcar el contenido de la misma a un archivo SQL usando mysqldump y luego desbloquear las tablas:

mysql> FLUSH TABLES WITH READ LOCK;
# mysqldump –u usuario -p basededatos > volcado.sql
mysql> UNLOCK TABLES;

Importar una base de datos: la operación contraria no involucra a mysqldump:

# mysql –u usuario -p basededatosdondevolcar < volcado.sql

Hasta aquí dejaré esta entrada, podría incluir más material, pero creo que perdería su propósito como punto de partida o su aspecto básico para administrar bases de datos. Tampoco he incluido por el momento los comandos para manipular datos, ya que he pensado dedicarles una entrada independiente.

Esquemas de particionado

Hoy cumple 28 años el kernel Linux y tengo también al menos ya 13 años usándolo en casi todas las computadoras que uso. Empecé con Ubuntu con las versiones Edgy Eft (6.10) y Dapper Drake (6.06) en aquel entonces y pase por todos sus releases hasta Lucid Lynx (10.04) hasta que implementaron el escritorio Unity que nunca me gustó. Use temporalmente y poco otras distros como Gentoo y Debian en ese entonces hasta que migré a Arch Linux el cual uso desde 2010 en mis computadoras del día a día.

Hay un tema común en todas estas distros por el que uno pasa cada vez que reinstala o empieza una instalación de cero con alguna distro, el particionado del disco duro. Al ser GNU/Linux modular y versátil hay muchas formas de realizarlo tanto para optimizar el sistema como para aumentar la seguridad. Ya me ocurrió en mis inicios que deje todo enchorizado en una sola partición y esto me costó perder todos los datos por aquel entonces. Después de esa amarga experiencia, creo que no hay una sola vez en que no haya empleado al menos 2 particiones.

Con todo lo que he ganado de experiencia a lo largo de estos años, he encontrado una forma de mantener optimizado el número de particiones según su uso, combinado con medidas de seguridad que montan particiones como solo lectura o desactivan la ejecución de scripts.

/boot

En /boot se aloja el cargador de arranque y los distintos kernels que tengamos. Luego del arranque esta partición no es utilizada y debe ser leída de manera sencilla y directa por el BIOS para que inicie el sistema operativo, por esta razón no puede ser cifrada. En los sistemas actuales que emplean UEFI es necesaria esta partición en formato vfat en /boot/efi y almacena también cargadores de arranque y algunos archivos para el arranque con systemd. /boot y /boot/efi pueden estar separadas para tener más flexibilidad a la hora de hacer cambios sobre un sistema existente.

Se puede montar con la opción de solo lectura ro o directamente no montarlo noauto como medida de seguridad para evitar que un atacante pueda editar el arranque; sin embargo, al hacer esto se debe tener en cuenta el hecho que una actualización del cargador de arranque o del kernel directamente podría no ser instalada y obligarnos a remontar la partición antes de actualizar.

/

De la raíz cuelgan todos los otros directorios y es aquí donde están la mayoría de los archivos del sistema operativo. Una partición de 30 Gb suele ser suficiente para estos fines, pero en caso de tener un servidor web o base de datos que emplee el directorio /var, entonces este último valdrá la pena separarlo en una partición adicional.

/home

El directorio /home almacena los datos de usuario y suele crecer de manera exagerada al ser un directorio de uso diario. Su tamaño depende mucho del uso que le demos al sistema. Como es un sitio donde podemos escribir libremente, podemos montarlo con las opciones nosuid impidiendo así cierto tipo de ataques que involucran el flag setuid y también impedir la creación de ficheros de dispositivo con la opción nodev. Opcionalmente podemos limitar la ejecución de programas impidiendo el permiso de ejecución (x) con la opción noexec.

También podemos extender el sistema de permisos con reglas de control de acceso acl y atributos extendidos de usuario user_xattr pero esto ya sería para gestión avanzada como por ejemplo dar permiso al usuario de un servidor web para que acceda a un directorio situado en otro punto de montaje, pero restringiendo a la vez el acceso a los demás usuarios del sistema.

Otros

En un sistema de uso común, puede ser una computadora de escritorio o portátil, con solo tener los puntos anteriores suele ser suficiente. Pero si tenemos un sistema dedicado a sitios web o que almacena bases de datos, hay otras particiones que deberíamos considerar.

/var

/var/www Si tenemos un servidor web, todos los archivos que se sirvan estarán en este directorio. Incluso si servimos archivos muy grandes sería buena idea utilizar un sistema de archivos como xfs en lugar de ext4.

/var/lib/mysql es el sitio donde se almacenan las bases de datos y archivos relacionados. Se puede asignar un tamaño adecuado y como solo se escribe sobre ella, no serían necesarios permisos como de ejecución.

/var/log si queremos mantener separados los logs del resto este es el sitio ideal para asignar un punto de montaje.

swap

Dependiendo de como uno quiera optimizar el sistema hay varias formas de llevar la paginación. Una opción es llevarla a un disco SSD aunque en consecuencia esto acortaría la vida del SSD. En un sistema como amplia RAM se puede utilizar un HDD normal ya que su uso sería más infrecuente al haber suficiente memoria RAM. O como última opción también se puede emplear un archivo como swap.

/tmp

/tmp es un directorio temporal del sistema, por lo que el contenido de esta partición para mejor gestión podemos administrarlo como un ramdisk, o sea, un disco virtual en la memoria RAM. Al momento de escribir esta entrada el tamaño de mi carpeta /tmp asciende a unos 12 kB, por lo que un tamaño fijo de 512 MB es más que suficiente, claro que depende de su uso.

En esta tabla se resume el tamaño general, punto de montaje y opciones o atributos de montaje de las particiones que suelo usar:

Partición y punto de montajeOpciones de montaje en /etc/fstabTamaño
/defaults,discard,noatime,errors=remount-ro30 GB
/bootdefaults,noatime250 MB
/homedefaults,noatime,acl,user_xattr,nodev,nosuid
/tmpdefaults,nodev,nosuid,noexec,size=512m(ramdisk de 512 MB)
/var/wwwdefaults,noatime,acl,user_xattr,nodev,nosuiddepende del uso
/var/lib/mysqldefaults,noatime,acl,user_xattr,nodev,nosuiddepende del uso
swapswal menos la mitad de la RAM disponible

Mantener las particiones separadas permite trabajar mejor y recuperar más rápido un sistema ante un eventual desastre aparte que mejora la seguridad al utilizar ciertas opciones de montaje. Siempre hay que planear el particionado en la manera más conveniente para el uso que le daremos a nuestro sistema.

SFTP con jaula chroot

Este es un tema que siempre me ha costado trabajo configurar, básicamente por problemas de permisos de directorios y usuarios. Luego de muchos intentos y horas de investigación lo más cercano era que los usuarios ingresaran a un directorio común desde donde podían escribir en sus directorios, pero podían ver todo el contenido de los otros usuarios.

Ante el problema anterior finalmente di con la manera de configurar una jaula chroot que contiene los archivos de un sitio web, para usuarios SFTP. El dilema a resolver es el siguiente: tenemos una instalación de nginx con varios sitios web. Crearemos un usuario sin acceso a shell que se pueda conectar vía SFTP para editar el mismo directorio desde donde se sirven los archivos.

Crear un grupo para los usuarios SFTP

Como nginx trabaja por defecto con el grupo www-data, usaremos este mismo. Opcionalmente si queremos crear un grupo exclusivo para estos menesteres.

$ sudo groupadd solosftp

Pero debemos ajustar la configuración de nginx para que utilice este nuevo grupo.

Añadir usuarios al grupo SFTP

Lo siguiente es crear y añadir el usuario que vamos a utilizar al grupo www-data o el que hemos creado en el paso previo. Antes de esto, el árbol de directorio que uso para guardar los sitios web es el siguiente: /var/www/sitio.web/public_html.

$ sudo useradd -g www-data -s /bin/false -m -d /var/www/sitio.web usuariosftp
  • -g www-data añade al grupo www-data el usuario que estamos creando.
  • -s /bin/false elimina el acceso vía shell, el usuario no podrá conectarse vía SSH.
  • -m -d /var/www/sitio.web crea el directorio del usuario

En mi caso prefiero utilizar llaves ssh para los usuarios regulares del servidor y contraseñas de texto a los usuarios SFTP.

$ sudo passwd usuariosftp

Lo siguiente es el paso más crítico, que corresponde a los permisos. Anteriormente los asignaba de manera incorrecta en el árbol de directorios. Con un error aquí puedes evitar que el usuario no ingrese o que el servidor rechace la conexión. El directorio home del usuario debe pertenecer al usuario root y tener permisos 755.

$ sudo chown root: /var/www/sitio.web
$ sudo chmod 755 /var/www/sitio.web

Ahora podemos crear los directorios que usaremos dentro de la carpeta, asignar los permisos y la propiedad y grupo que necesitamos.

$ sudo mkdir /var/www/sitio.web/{public_html,uploads}
$ sudo chmod 755 /var/www/sitio.web/{public_html,uploads}
$ sudo chown usuariosftp:www-data /var/www/sitio.web/{public_html,uploads}

Con esto hay que tener en cuenta que al crear el archivo de configuración del sitio web de nginx, la raíz apunte al directorio que hemos creado public_html.

Configurando SSH

Ahora editaremos el archivo de configuración de SSH /etc/ssh/sshd_config, editando la línea Subsystem sftp y añadiendo el bloque Match Group

Subsystem sftp internal-sftp

Match Group www-data
  ChrootDirectory %h
  ForceCommand internal-sftp
  AllowTcpForwarding no
  X11Forwarding no

Una vez hecho estos cambios reiniciamos el servidor SSH.

$ sudo systemctl restart ssh

Probando

Ahora que hemos terminado de configurar la jaula chroot podemos probar la conexión. En el mismo servidor podemos hacerlo como se detalla o bien si nos conectamos remotamente, reemplazamos localhost por la ip del servidor.

$ sftp usuariosftp@localhost

Una vez inicie el proceso, el servidor nos preguntara la contraseña de la cuenta sftp y luego podremos utilizar los comandos pwd y ls para verificar el directorio de trabajo y listar los archivos y directorios.

usuariosftp@localhost's password:
Connected to usuariosftp@localhost.
sftp> pwd
Remote working directory: /
sftp> ls
public_html  upload
sftp>

Y hasta aquí termina esta guía que espero sea de ayuda para quienquiera se aventure a hacer esto. El resultado, varios sitios web en un solo servidor con nginx y a los cuales cada uno se puede acceder vía sftp de manera exclusiva sin que el usuario vea el contenido de otros usuarios.

VirtualBox en modo headless

Es altamente común que se utilicen máquinas virtuales para el desarrollo de software, regularmente uso VirtualBox desde el entorno gráfico en Arch Linux para hacer estas cosas, pero muchas veces solo necesito que este corriendo una distro con ciertos servicios sin necesidad de usar entorno gráfico alguno y aquí es donde entra el modo headless. Para esto tenemos la aplicación VBoxManage.

# Listar máquinas virtuales
$ VBoxManage list vms
"experiment-1" {fdb95c20-45c8-4811-8ee6-3fabdd5bd969}
"mysql" {31355c2b-ec28-4392-929e-094b288aa002}
"mongodb" {4934f61c-b007-44b0-b730-a450e885a616}

# Arrancar máquina virtual en modo headless
$ VBoxManage startvm experiment-1 --type headless

# Apagar máquina virtual
$ VBoxManage controlvm experiment-1 poweroff