A veces necesitamos un script bash que puedan ejecutar los usuarios (por ejemplo, mediante un acceso directo en un fichero .desktop), pero dentro de él hay contraseñas o algún fragmento código que no nos interesa hacer público.
Por poner un ejemplo práctico, imaginemos un script que levanta/apaga a voluntad la red wifi de 5ghz de nuestros puntos de acceso DLink, que en mi caso mantengo apagada por defecto.
Usamos sshpass para entrar por ssh y ejecutar el comandod de apagado/encendido sin que se pida contraseña al usuario. El problema que tenemos es que si distribuimos el script tal que así, cualquier usuario puede ver la contraseña de administración del router DLink (la que he puesto es figurada) y eso no es tolerable.
Entre las diversas soluciones a este problema una consiste en hacer el script ilegible ofuscando su contenido. De las herramientas y trucos que hay para eso el mas potente que he encontrado es usando la aplicación "shc", que compila un script generando un fichero ejecutable ilegible. Nosotros nos quedaremos con el código fuente del script y a los usuarios les distribuiremos el ejecutable. Es raro esto de compilar scripts, pero para la situación descrita viene de perillas.
Una vez instalado compilaremos el script haciendo:
# shc -r -f wifi5ghz.sh -o wifi5ghz
Esto nos creará un fichero ejecutable wifi5ghz que hará lo mismo que wifi5ghz.sh sin que sea visible su código (si el usuario hace un cat sobre él verá un galimatías ASCII). El parámetro "-r" es importante porque permite que ese ejecutable pueda ejecutarse en otras máquinas distintas a aquella dónde se compila el script (si no se pone el ejecutable deja de funcionar a los pocos días).
Como apunte adicional, si consultamos los parámetros de shc veremos que tiene cosas bastante interesantes, como por ejemplo la posibilidad de hacer que el ejecutable caduque en una fecha predeterminada.
Como buen fanático del terminal, siempre prefiero hacer cosas de administración de sistemas tecleando antes que con ratón. En Unix esto es lo más habitual, pero en Windows no lo ponen tan fácil.
En cualquier caso siempre viene bien tener la opción de conectar con una consola remota de Windows y escribir los comandos en ella, sin necesidad de desplazarnos físicamente a la máquina ni de iniciar una sesión remota completa con rdesktop. En principio con un servidor OpenSSH en el equipo destino es suficiente. Un servidor ssh es un software que en Linux viene de serie mientras que en Windows, entre varias opciones, podemos poner una versión GPL liberada por Microsoft.
Pero no, vamos a ver una forma alternativa de ejecutar comandos de consola de forma remota en Windows que no necesita instalar nada especial en el PC destino. Contemplaremos 2 métodos: lanzar la ejecución de los comandos desde un equipo con Windows y hacerlo desde un equipo con Linux.
1. Consideraciones previas.
Para hacer que nuestros Windows estén dispuestos a aceptar órdenes remotas hay que prepararlos antes tocando varias configuraciones:
1.1. Abrir el puerto 445.
Para comunicarnos y dar órdenes al Windows remoto necesitamos comunicar con él por su puerto 445, denominado "microsoft-ds", que sirve para un montón de cosas incluida la entrada de virus ;-).
Como este puerto está cerrado normalmente por el firewall de Windows debemos primeramente abrirlo para que acepte conexiones entrantes. Podemos hacerlo con el confuso interface gráfico de configuración del firewall y tardar varios minutos:
o bien abrir una consola de comandos en modo administrador y teclear:
Seguramente después haya que reiniciar el servicio de firewall para que se aplique de forma efectiva.
Supongo que con este ejemplo de método gráfico versus método de terminal queda claro por qué muchas veces es preferible usar la línea de comandos.
1.2. Modificar el registro para permitir el acceso a los "administrative shares"
Si el equipo remoto trabaja con Windows 10 hay que añadir una entrada al registro para permitir las conexiones entrantes que ejecutarán comandos, ya que por defecto UAC impide que usuarios administradores se conecten a los "administrative shares". De nuevo lo haremos desde consola:
Si no creamos esta entrada de registro obtendremos errores de "Acceso denegado" al intentar ejecutar comandos remotos.
1.3. Solo para Linux: activar SMB v1.
Esto solo debe hacerse si el equipo desde el que lanzamos el comando es un Linux.
Debido a la aparición del ransomware WannaCry, que aprovechaba una vulnerabilidad en SMB llamada EternalBlue (con la que seguramente los servicios de seguridad de USA nos han estado espiando a todos durante años) hubo que improvisar soluciones transitorias . Una de ellas, rápida y sucia, era deshabilitar SMB1 en Windows y así impedir la entrada de WannaCry.
Como efecto colateral, el programa que usamos en Linux para mandar comandos al Windows deja de funcionar, ya que necesita que SMB1 esté activo. Por tanto, dependiendo que tengamos o no activo SMB1 en nuestro Windows podrá funcionar o no la ejecución remota. A día de hoy EternalBlue ya ha sido solucionado con los parches de Microsoft, por lo que SMB1 puede estar de nuevo activo.
Para ver su estado abrimos una consola de PowerShell y tecleamos "Get-SmbServerConfiguration"
Nos pedirá reiniciar para que sea efectivo el cambio. Este Windows es maravilloso: activas un protocolo y tienes que reiniciar la máquina completa, ahí queda eso.
Como curiosidad aquí tenemos recopilados todos los comandos para ver/cambiar el estado de los servicios SMBx.
2. Desde un equipo con Windows.
Bueno, ya tenemos el Windows remoto receptivo, vamos ahora a ver como darle órdenes. Necesitamos instalar las pstools en el PC desde donde daremos órdenes. Ojo: esto se instala en el PC desde donde se ejecuta el comando, el PC destinatario no necesita que instalemos nada, el único requisito para él es lo indicado en el apartado 1.
No viene mal echar un vistazo a todas las utilidades, son una maravilla que conviene poner de serie en todos nuestros Windows. La que usaremos nosotros es psexec. Veamos como ejecutar un comando remoto desde el Windows donde tenemos instalado psexec contra otro Windows:
psexec \\a20-o14 "ipconfig"
Esto anterior se ejecutaría usando las credenciales del usuario actual en el PC remoto. Si queremos dar otras credenciales especificamos el usuario (que debe ser un administrador) y contraseña:
psexec -u administrador -p password \\a20-o14 "ipconfig"
PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
Starting PSEXESVC service on a20-o14...........
Configuración IP de Windows
Adaptador de Ethernet Ethernet:
Sufijo DNS específico para la conexión. . : vguadalupe
Vínculo: dirección IPv6 local. . . : fe80::f938:6376:3936:6a45%3
Dirección IPv4. . . . . . . . . . . . . . : 172.24.XXX.12
Máscara de subred . . . . . . . . . . . . : 255.255.255.0
Puerta de enlace predeterminada . . . . . : 172.24.XXX.2
Adaptador de túnel isatap.vguadalupe:
Estado de los medios. . . . . . . . . . . : medios desconectados
Sufijo DNS específico para la conexión. . : vguadalupe
Como se ve conectamos con el equipo a20-o14 y ejecutamos el comando "ipconfig" sobre él, dándonos la dirección IP y configuración de red el equipo. Con:
psexec \\a20-o14 "cmd"
PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
Starting PSEXESVC service on a20-o14...........
Microsoft Windows [Versión 6.3.9600]
(c) 2013 Microsoft Corporation. Todos los derechos reservados.
C:\Windows\system32>
Se nos abre una consola de comandos remota, que ejecutará en la otra máquina lo que tecleemos.
Si alguna de las dos órdenes anteriores produce errores del tipo:
Couldn't access a20-o14:
No se ha encontrado la ruta de acceso de la red.
Make sure that the default admin$ share is enabled on a20-o14.
En mi caso era síntoma de que el puerto 445 estaba cerrado. Si ese es tu caso, abrelo como hemos comentado en la parte 1 y ya debería funcionar. Si además dice:
Para ver cuantas sesiones hay abiertas en una máquina remota ejecutamos el comando de Windows "query session":
psexec \\a20-o19 query session
NOMBRE DE SESIÓN NOMBRE DE USUARIO ID ESTADO TIPO DISPOSITIVO
>services 0 Desc
console GM_SEGUNDO 1 Activo
rdp-tcp#1 Administrado 2 Activo
rdp-tcp 5536 Escuchar
Vemos que en consola hay una sesión abierta con el usuario GM_SEGUNDO y en remote desktop hay otra abierta con el usuario Administrador (¿cómo consigo sesiones de escritorio de usuarios concurrentes sobre un mismo Windows?: instalando rdpwrapper).
Psexec está concebido para ejecutar comandos de consola, con entrada/salida en texto. Cualquier aplicación gráfica que lancemos aparecerá en el escritorio remoto. Por ejemplo:
psexec \\a20-o19 -i 1 -d notepad
Hará que al usuario GM_SEGUNDO del ejemplo anterior (el de la sesión con ID 1, de ahí el parámetro "-i 1". Este es el valor por defecto) se le abra el bloc de notas en la pantalla ante su total estupefacción. Esta es la teoría, pero en las pruebas prácticas que he hecho se abre una ventana con el contenido en negro y que no permite interactuar. Debe ser algún bug o feature de Windows 10.
Si queremos lanzar aplicaciones gráficas en un Windows remoto y que aparezcan en nuestro escritorio local (sería una conexión Remota tipo VNC o Remote Desktop pero a nivel de aplicación en lugar de a nivel de escritorio completo) habría que usar SeamlessRDP, pero ese tema escapa al contenido de este artículo.
A modo de resumen: psexec es adecuado para ejecutar comandos de terminal de forma remota sin tener que iniciar sesión en los escritorios Windows. Como truco: cuando queremos ejecutar varios comandos la mejor solución es ponerlos dentro de un script .bat en una carpeta compartida por Samba accesible por todos los Windows y lanzar dicho script desde psexec.
3. Desde un equipo con Linux.
Bueno, ¿y que pasa si el equipo cliente es un Linux y desde él queremos ejecutar los comandos remotamente en nuestros Windows? ¿Hay algun psexec para Linux?
Pues si hay algo que se le parece: winexe, que sigue la idea de usar el puerto 445 para mandar ordenes a los Windows de forma remota. Es un proyecto algo abandonado y del cual no hay paquetes oficiales en .deb ni en .rpm (para Manjaro/Arch por supuesto que sí, pero es que ahí jugamos en otra liga). Además es fácil encontrar la versión 1.0, pero la que ahora funciona con Windows 10 es la 1.1.
Al final lo he encontrado aquí, con versiones .deb para Debian y Ubuntu. En mi caso he bajado el paquete winexe-static-1.1-0-jessie.deb para ejecutarlo desde mi servidor montado Debian Jessie.
El paquete se llama "static" porque tiene las librerías de Samba metidas dentro del ejecutable durante la compilación. La causa es que al cambiar la versión de Samba esto tiende a fallar, así que han optado por llevarlas al estilo años 70, embebidas en el ejecutable para evitar errores.
# dpkg -i winexe-static-1.1-0-jessie.deb
# winexe-static
winexe version 1.1
This program may be freely redistributed under the terms of the GNU GPLv3
Usage: winexe-static [OPTION]... //HOST COMMAND
Options:
-h, --help Display help message
-V, --version Display version number
-U, --user=[DOMAIN/]USERNAME[%PASSWORD] Set the network username
-A, --authentication-file=FILE Get the credentials from a file
-N, --no-pass Do not ask for a password
-k, --kerberos=STRING Use Kerberos, -k [yes|no]
-d, --debuglevel=DEBUGLEVEL Set debug level
--uninstall Uninstall winexe service after
remote execution
--reinstall Reinstall winexe service before
remote execution
--system Use SYSTEM account
--profile Load user profile
--convert Try to convert characters
between local and remote
code-pages
--runas=[DOMAIN\]USERNAME%PASSWORD Run as the given user (BEWARE:
this password is sent in
cleartext over the network!)
--runas-file=FILE Run as user options defined in a
file
--interactive=0|1 Desktop interaction: 0 -
disallow, 1 - allow. If allow,
also use the --system switch
(Windows requirement). Vista
does not support this option.
--ostype=0|1|2 OS type: 0 - 32-bit, 1 - 64-bit,
2 - winexe will decide.
Determines which version (32-bit
or 64-bit) of service will be
installed.
Como se ve los parámetros son muy distintos a los de psexec, ya que es una herramienta independiente. En este enlace se ve un buen repaso de todos ellos.
Veamos como ejecutar un comando:
# winexe-static --convert -U administrador%password //a20-o14 "ipconfig"
Error: error Unknown argument (get codepage)
CTRL: Probably old version of service, reinstalling.
Configuración IP de Windows
Adaptador de Ethernet Ethernet:
Sufijo DNS específico para la conexión. . : vguadalupe
Vínculo: dirección IPv6 local. . . : fe80::f938:6376:3936:6a45%3
Dirección IPv4. . . . . . . . . . . . . . : 172.19.XXX.100
Máscara de subred . . . . . . . . . . . . : 255.255.255.0
Puerta de enlace predeterminada . . . . . : 172.19.XXX.2
Adaptador de túnel isatap.vguadalupe:
Estado de los medios. . . . . . . . . . . : medios desconectados
Sufijo DNS específico para la conexión. . : vguadalupe
O abrir un interpréte de comandos remoto y escribir las órdenes allí:
# winexe-static --convert -U administrador%password //a20-o04 "cmd"
Microsoft Windows [Versión 6.3.9600]
(c) 2013 Microsoft Corporation. Todos los derechos reservados.
C:\Windows\system32>cd \users
cd \users
C:\Users>dir
dir
El volumen de la unidad C no tiene etiqueta.
El número de serie del volumen es: B62C-6CE1
Directorio de C:\Users
16/06/2016 08:09 DIR .
16/06/2016 08:09 DIR ..
26/01/2017 12:45 DIR Administrador
22/08/2013 16:36 DIR Public
20/07/2017 05:43 DIR UpdatusUser
28/07/2017 08:04 DIR usuario
0 archivos 0 bytes
6 dirs 33.118.711.808 bytes libres
C:\Users>exit
exit
#
Si en algún momento da este error:
# winexe-static -U administrador%password //a20-o04 "cmd"
ERROR: Failed to open connection - NT_STATUS_CONNECTION_RESET
La causa mas probable es que esté desactivado SMB1 en el PC remoto, lo cual se soluciona como vimos en el apartado 1.
Finalizamos con una recopilación de errores:
ERROR: Failed to open connection - NT_STATUS_LOGON_FAILURE : credenciales incorrectas.
ERROR: CreateService failed. NT_STATUS_ACCESS_DENIED : puerto 445 cerrado o registro no modificado según apartado 1.1 y 1.2.
ERROR: Failed to open connection - NT_STATUS_CONNECTION_RESET : servicio SMB1 deshabilitado. Habilitar según apartado 1.3 .
Y con esto ya tenemos expuestas todas las posibilidades para interactuar con nuestros Windows desde terminal.
Me despido con una imagen impactante que no tiene nada que ver con el blog, pero que está aquí al lado y no puedo dejar pasar:
Esto tiene 66.700 años según las últimas dataciones y es la prueba mas antigua de arte realizada por un homo sapiens de la especie vecina, la neanderthalensis. En esa época los homo sapiens sapiens estábamos empezando a salir de África por Oriente Próximo y andábamos ocupados en otras cosas. Y aquí, al lado de la Ribera del Marco ya había una especie que desarrollaba pensamiento simbólico en este planeta. Impresionante.
Es nuestro pequeño Gobekli Tepe, espero que sepamos cuidarlo.