一場持續不斷、范圍廣泛的惡意軟件活動在超過 300,000 個瀏覽器中強制安裝惡意的 Google Chrome 和 Microsoft Edge 瀏覽器擴展程序,修改瀏覽器的可執行文件以劫持主頁并竊取瀏覽歷史記錄。
安裝程序和擴展程序通常無法被防病毒工具檢測到,其目的在于竊取數據并在受感染的設備上執行命令。
該活動是由ReasonLabs的研究人員發現的,他們警告說,其背后的威脅行為者采用各種惡意廣告主題來實現初始感染。
ReasonLabs 表示,感染始于受害者從 Google 搜索結果中惡意廣告宣傳的虛假網站下載軟件安裝程序。
該惡意軟件活動使用了 Roblox FPS Unlocker、TikTok Video Downloader、YouTube 下載器、VLC 視頻播放器、Dolphin Emulator 和 KeePass 密碼管理器等誘餌。
下載的安裝程序由“Tommy Tech LTD”進行數字簽名,并在 ReasonLabs 分析時成功逃避了 VirusTotal 上所有 AV 引擎的檢測。
然而,它們不包含任何類似于承諾的軟件工具的東西,而是運行下載到 C:\Windows\System32\PrintWorkflowService.ps1 的 PowerShell 腳本,該腳本從遠程服務器下載有效負載并在受害者的計算機上執行。
同一腳本還會修改 Windows 注冊表,強制安裝來自 Chrome 網上應用店和 Microsoft Edge 附加組件的擴展程序。
還創建了一個計劃任務,以不同的時間間隔加載 PowerShell 腳本,從而允許威脅行為者推送進一步的惡意軟件或安裝其他有效負載。
據發現,該惡意軟件安裝了大量不同的 Google Chrome 和 Microsoft Edge 擴展程序,這些擴展程序會劫持您的搜索查詢、更改您的主頁并通過威脅行為者的服務器重定向您的搜索,以便竊取您的瀏覽歷史記錄。
ReasonLabs 發現以下Google Chrome 擴展程序與此活動有關:
以下Microsoft Edge擴展與此活動相關:
通過這些擴展,惡意行為者劫持了用戶的搜索查詢,并將其重定向到惡意結果或廣告頁面,從而為威脅行為者創造收入。
此外,他們還可以捕獲登錄憑據、瀏覽歷史記錄和其他敏感信息,監視受害者的在線活動,并執行從命令和控制 (C2) 服務器收到的命令。
即使激活了開發者模式,擴展程序仍然隱藏在瀏覽器的擴展程序管理頁面中,因此刪除它們很復雜。
該惡意軟件使用各種方法在機器上保持持久性,因此很難刪除。可能需要卸載并重新安裝瀏覽器才能完成刪除。
PowerShell 負載將搜索并修改所有 Web 瀏覽器快捷方式鏈接,以強制加載惡意擴展程序并在瀏覽器啟動時禁用瀏覽器的自動更新機制。這是為了防止 Chrome 的內置保護功能更新并檢測到惡意軟件。
然而,它也阻止了未來安全更新的安裝,使得 Chrome 和 Edge 容易受到新發現的漏洞的影響。
由于許多人依賴 Chrome 的自動更新過程而從不手動執行,因此這可能會長時間未被發現。
更加狡猾的是,該惡意軟件會修改 Google Chrome 和 Microsoft Edge 使用的 DLL,將瀏覽器主頁劫持為威脅行為者控制的主頁,例如 https://microsearch[.]me/。
ReasonLabs 解釋道:“該腳本的目的是定位瀏覽器的 DLL(如果 Edge 是默認瀏覽器,則定位 msedge.dll)并更改其中特定位置的特定字節”。
“這樣做可以讓腳本劫持 Bing 或 Google 的默認搜索到對手的搜索門戶。它會檢查安裝了哪個版本的瀏覽器并相應地搜索字節。”
刪除此修改的唯一方法是升級到新版本的瀏覽器或重新安裝它,這將替換修改后的文件。
BleepingComputer 已聯系 Google,要求其對 Web Store 上仍然可用的四個 Chrome 擴展程序做出澄清,我們正在等待他們的回復。
為了從系統中清除感染,受害者必須經過多步驟刪除惡意文件。
首先,從 Windows 任務計劃程序中刪除計劃任務,查找指向腳本的可疑條目(例如“NvWinSearchOptimizer.ps1”),通常位于“C:\Windows\system32\”。
其次,打開注冊表編輯器(“Win+R”> regedit)并導航至:刪除惡意注冊表項:
HKEY_LOCAL_MACHINE\SOFTWARE\策略\谷歌\Chrome\ExtensionInstallForcelist
HKEY_LOCAL_MACHINE\SOFTWARE\策略\微軟\Edge\ExtensionInstallForcelist
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\策略\谷歌\Chrome\ExtensionInstallForcelist HKEY_LOCAL_MACHINE
\SOFTWARE\WOW6432Node\策略\微軟\Edge\ExtensionInstallForcelist
右鍵單擊每個帶有惡意擴展名稱的鍵,然后選擇“刪除”將其刪除。
最后,使用 AV 工具從系統中刪除惡意軟件文件,或者導航到“C:\Windows\System32”并刪除“NvWinSearchOptimizer.ps1”(或類似文件)。
清理過程后可能不需要重新安裝瀏覽器,但由于惡意軟件執行了高度侵入性的修改,因此強烈建議這樣做。
引擎代碼:
import (
"errors"
"fmt"
"github.com/go-redis/redis"
"sync"
)
//分布式workflow
type DFlow struct {
RC *redis.ClusterClient
LockKey string
Func map[string]Func
Depend map[string][]string
Force bool
}
//workflow引擎
type flowCore struct {
funcs map[string]*flowStruct
}
type Func func(interface{}) (interface{}, error)
type flowStruct struct {
Deps []string
Ctr int
Fn Func
C chan error
Res interface{}
force bool
once sync.Once
}
//workflow節點已執行
func (fs *flowStruct) done(e error) {
for i :=0; i < fs.Ctr; i++ {
fs.C <- e
}
}
//關閉workflow節點channel
func (fs *flowStruct) close() {
fs.once.Do(func() {
close(fs.C)
})
}
//初始化channel
func (fs *flowStruct) init() {
fs.C=make(chan error)
}
//創建workflow
func create() *flowCore {
return &flowCore{
funcs: make(map[string]*flowStruct),
}
}
//增加workflow節點
func (flw *flowCore) add(name string, d []string, fn Func, fc bool) *flowCore {
flw.funcs[name]=&flowStruct{
Deps: d,
Fn: fn,
Ctr: 1,
force: fc,
}
return flw
}
//workflow檢查并啟動
func (flw *flowCore) start() map[string]error {
for name, fn :=range flw.funcs {
for _, dep :=range fn.Deps {
// prevent self depends
if dep==name {
return map[string]error{name: errors.New(name + " not depends of it self")}
}
// prevent no existing dependencies
if _, exists :=flw.funcs[dep]; exists==false {
return map[string]error{dep: errors.New(dep + " not exists")}
}
flw.funcs[dep].Ctr++
}
}
return flw.do()
}
//執行workflow節點
func (flw *flowCore) do() map[string]error {
result :=map[string]error{}
for name, f :=range flw.funcs {
f.init()
go func(name string, fs *flowStruct) {
do :=true
defer func() {
if r :=recover(); r !=nil {
fmt.Println(r)
}
}()
if len(fs.Deps) > 0 {
for _, dep :=range fs.Deps {
err, ok :=<-flw.funcs[dep].C
if !fs.force && (err !=nil || !ok) {
do=false
}
}
}
if do {
//匹配pipeline條件
if len(fs.Deps)==1 {
fs.Res, result[name]=fs.Fn(flw.funcs[fs.Deps[0]].Res)
} else {
fs.Res, result[name]=fs.Fn(nil)
}
fs.done(result[name])
} else {
for _, fn :=range flw.funcs {
fn.close()
}
}
}(name, f)
}
return result
}
//運行workflow
func (df *DFlow) Run() map[string]error {
lock :=SyncMutex{LockKey: df.LockKey, LockTime: 15, Rc: df.RC}
//加鎖
if lock.Lock() {
defer func() {
// 釋放鎖
lock.UnLock()
}()
fl :=create()
for k, v :=range df.Depend {
fl.add(k, v, df.Func[k], df.Force)
}
return fl.start()
}
return nil
}
運行示例:
var (
RC, _=RedisConnect()
)
type test struct {
}
func (t *test) a(interface{}) (interface{}, error) {
fmt.Println("a")
fmt.Println("==========")
return "a ok", nil
}
func (t *test) b(i interface{}) (interface{}, error) {
fmt.Println(i)
fmt.Println("b")
fmt.Println("==========")
return "b ok", nil
}
func (t *test) c(i interface{}) (interface{}, error) {
fmt.Println(i)
fmt.Println("c")
fmt.Println("==========")
return nil, errors.New("c error")
}
func (t *test) d(i interface{}) (interface{}, error) {
fmt.Println(i)
fmt.Println("d")
fmt.Println("==========")
return "d ok", nil
}
func init() {
t :=test{}
Func :=map[string]common.Func{"a": t.a, "b": t.b, "c": t.c, "d": t.d}
Depend :=map[string][]string{"a": {}, "b": {"a"}, "c": {"b"}, "d": {"c"}}
df :=common.DFlow{RC: RC, LockKey: "workflow_test", Func: Func, Depend: Depend}
result :=df.Run()
fmt.Println(result)
}
執行結果: