Bagaimana serangan skrip beracun dapat menargetkan data pengguna dan dana transfer secara bersamaan?Penulis artikel, sumber: Slow Mist Tech
Latar belakang
Baru-baru ini, petugas keamanan SlowMist dalam penggalian intelijen ancaman harian mereka, memantau kegiatan serangan yang melibatkan skrip terkait sistem layanan pelanggan Udesk yang telah diracuni. Tim kemudian mendapatkan dua sampel JavaScript, udeskApi.2026-10-16.cached.js dan deeps.js, serta melakukan analisis untuk melacak bagaimana kode jahat memanfaatkan skrip layanan pelanggan untuk memasuki halaman, serta apa yang dilakukannya terhadap data pengguna dan operasi bisnis.
Pemeriksaan terhadap sampel secara bertahap mengungkap dua jenis risiko: skrip jahat yang mengumpulkan data sesi dan informasi sensitif yang dikirimkan pengguna dari halaman web, sekaligus memodifikasi alamat pengisian dan menyalin konten sesuai aturan situs. Yang pertama dapat memungkinkan penyerang menyamar sebagai sesi login atau mengambil alih akun, sementara yang kedua dapat menyebabkan pengguna mengirim dana pengisian ke alamat penerima yang telah diganti. Kami memulai dari titik masuk pemuatan skrip layanan pelanggan, mengikuti logika pembacaan data, pengiriman jaringan, dan modifikasi halaman, untuk merekonstruksi cara kerja dan kondisi pemicu kedua perilaku ini.
MistEye merespons
MistEye adalah sistem intelijen ancaman Web3 dan pemantauan keamanan dinamis yang dikembangkan secara mandiri oleh SlowMist, yang mengintegrasikan kemampuan pemantauan keamanan dan agregasi intelijen untuk memberikan peringatan risiko real-time dan perlindungan aset kepada pengguna.
MistEye telah menyinkronkan risiko melalui push informasi dan saluran peringatan pelanggan secepatnya.

Malicious loader dan mekanisme pemuatan beban jarak jauh
Setelah membuka udeskApi.2026-10-16.cached.js, Anda dapat melihat kode untuk fitur-fitur seperti tombol layanan pelanggan, iframe obrolan, pelacakan pengunjung, dan komunikasi pesan. Lanjutkan memeriksa bagian akhir file, setelah struktur utama selesai, terdapat fungsi independen: ia mendekode dua string melalui _ud(), membuat elemen, dan menyisipkannya ke dalam head dokumen saat ini.
Bagian ini tidak secara langsung menulis nama tag dan URL jarak jauh. Jika hanya mencari domain dalam teks biasa, titik masuk pemuatan mudah terlewatkan. Kami memeriksa implementasi _ud() dan menemukan bahwa setiap kali ia mengambil dua karakter heksadesimal, lalu mengonversinya menjadi karakter; setelah memperluas konstanta, tujuan pemuatan menjadi jelas.
736372697074 didekodekan menjadi script, konstanta lainnya didekodekan menjadi https[:]//udeskqlobal[.]com/deeps.js. Domain tersebut dimulai dengan huruf q, dan ejaan qlobal harus dipertahankan saat pencarian. Loader mengatur skrip sebagai asinkron, lalu menyisipkannya ke halaman; ketika eksekusi mencapai posisi tersebut dan kebijakan browser serta jaringan mengizinkan, kode jarak jauh dapat masuk ke dokumen saat ini.
Beban yang sesuai dengan URL ini adalah deeps.js. Fokus penyelidikan berpindah dari SDK layanan pelanggan ke beban itu sendiri. Skrip klasik pihak ketiga dieksekusi dalam konteks dokumen yang disematkan, dan data yang dapat diaksesnya tergantung pada halaman atau iframe yang sedang berjalan. Jendela obrolan layanan pelanggan menggunakan iframe dan tidak secara otomatis mengisolasi skrip yang dimuat di halaman induk.
Mekanisme pengumpulan data web dan cakupan dampak
deeps.js awalnya membaca window.location.hostname, lalu menghasilkan konfigurasi C berdasarkan tiga aturan situs. Untuk menentukan halaman mana yang akan diambil, konfigurasi ini saja belum cukup: perlu dilacak lebih lanjut di mana posisi pengecekan keluar, apakah batasan ini berlaku untuk seluruh skrip atau hanya modul tertentu.
Dengan memeriksa alur kontrol secara berurutan, kita melihat bahwa pembacaan Cookie dan penyimpanan web, pengiriman snapshot awal, serta hook permintaan formulir dan otentikasi semuanya muncul sebelum if (!C) return;. Di bawah ini diambil pernyataan pengiriman snapshot dan hook XHR di akhir sesuai urutan kode sumber; komentar menandai kode yang dihilangkan di tengah, yang sesuai dengan tampilan diformat D:L100, D:L151–L166.
Posisi keputusan keluar telah memperjelas cakupan dampaknya: bahkan jika hostname tidak sesuai dengan tiga aturan situs, skrip tetap akan memasuki jalur pengumpulan data dan memasang hook, baru kemudian keluar dari modul alamat. Saat memeriksa halaman yang terbuka, jangan hanya fokus pada konfigurasi ketiga situs tersebut.
Saat dimulai, payload membaca Cookie, localStorage, dan sessionStorage yang dapat diakses oleh halaman web saat ini. Lokasi-lokasi ini dapat menyimpan status login, profil pengguna, dan data bisnis; jika di antaranya berisi token login yang masih berlaku dan dapat digunakan kembali, penyerang yang mendapatkannya dapat meniru sesi pengguna. Skrip juga menyertakan URL halaman tingkat atas dan origin dokumen saat ini, sehingga data tersebut dikirim bersama dengan halaman sumber.
Proses pengumpulan dilakukan dengan toleransi kesalahan per item. Saat pembacaan URL tingkat atas dari sumber lintas gagal, skrip menggantinya dengan x dan melanjutkan pemrosesan bidang lainnya; dua jenis penyimpanan halaman web diserialisasi menjadi JSON. Lingkup cookie dibatasi hanya pada konten yang dapat dibaca oleh document.cookie, dan cookie HttpOnly tidak termasuk di dalamnya.
Skrip juga menyediakan titik masuk untuk data yang akan dikirimkan selanjutnya. Saat pengguna mengirimkan formulir, skrip akan menelusuri elemen input, select, dan textarea, menyalin konten yang tidak kosong, lalu melanjutkan proses pengiriman asli. Bidang-bidang yang sebenarnya diisi oleh pengguna, seperti akun, kata sandi, dan kode verifikasi, berpotensi masuk ke jalur pengiriman data tambahan; jika bocor, data tersebut dapat digunakan untuk masuk ke akun atau mengambil alih akun.
Jalur ini diimplementasikan dengan membungkus HTMLFormElement.prototype.submit dan mendengarkan event submit pada tahap penangkapan. Untuk halaman yang mengirimkan data langsung melalui antarmuka, skrip juga membungkus fetch dan XHR: ketika permintaan memiliki badan dan URL yang mengandung kata kunci seperti login|signin|auth|register|signup|password, konten yang sesuai disalin sambil mempertahankan panggilan permintaan asli. Pada cabang fetch, URL harus berupa string, dan badan berasal dari opsi permintaan; objek seperti FormData yang langsung di-serialisasi ke JSON mungkin kehilangan bidang aktual.
Mekanisme kebocoran data dan saluran cadangan
Masukan pengumpulan di atas pada akhirnya memanggil _send() yang sama. Melanjutkan pelacakan fungsi ini, terlihat bahwa penerima tetap adalah https[:]//udeskqlobal[.]com/c.php. Snapshot awal menggunakan bidang s, o, c, l, ss untuk membawa alamat halaman, sumber saat ini, Cookie yang dapat dibaca, dan dua jenis penyimpanan web; formulir dan permintaan otentikasi berikutnya dikirim saat masing-masing dipicu.
Fungsi memisahkan parameter setelah tanda tanya pada URL, lalu memasukkannya ke dalam badan POST asinkron, dengan mengatur Content-Type: application/x-www-form-urlencoded. Di bawah ini adalah fungsi pengiriman yang dipertahankan secara lengkap (D:L45–L60):

Path pengiriman juga mencakup fallback permintaan gambar: ketika XHR gagal atau terjadi anomali sinkron selama pengiriman, skrip membuat objek Image, menetapkan URL dengan parameter ke src, dan mencoba mengirim ulang data melalui GET. URL dipotong menjadi 8.000 karakter JavaScript pertama, sehingga konten yang lebih panjang mungkin tidak lengkap.
Saat memahami jalur ini, perlu dibedakan antara "pengiriman permintaan" dan "pembacaan respons". Skrip tidak membaca respons dari c.php; POST lintas sumber yang memenuhi syarat permintaan sederhana dapat dikirim terlebih dahulu, lalu pembacaan respons dibatasi oleh browser, sehingga kesalahan CORS dapat terjadi bersamaan dengan pengiriman permintaan. Pemeriksaan log harus memeriksa badan POST dan parameter GET gambar, sedangkan kebijakan keluar memverifikasi connect-src dan img-src secara terpisah. Formulir biasa yang menyebabkan navigasi dokumen juga dapat memengaruhi kemampuan permintaan asinkron untuk selesai.
Dengan demikian, tujuan data sesi web dan konten yang dikirimkan selanjutnya telah jelas. Namun, beban masih menyisakan serangkaian operasi lain setelah pengecekan keluar dari situs: mengenali format alamat, mengubah teks halaman, dan mengambil alih jalur salin. Kode-kode ini memperdalam investigasi ke arah bisnis setoran.
Penggantian alamat setoran dan mekanisme pembajakan clipboard
Setelah if (!C) return; , skrip memasuki modul alamat. Tiga aturan hostname awal kini memiliki fungsi yang jelas: mencocokkan mgbx[.]com, bikingex[.], dan bitxex[.]io untuk memilih selector elemen alamat dan tombol salin yang berbeda untuk halaman yang berbeda.
Regex ini tidak memiliki anchor awal dan akhir, sehingga cakupan pencocokannya lebih luas daripada perbandingan domain tepat. Aturan halaman juga memeriksa location.href lengkap, dan parameter query atau fragmen dengan kata kunci seperti deposit, recharge, assets juga ikut dipertimbangkan. Setelah halaman, elemen, dan format alamat cocok, skrip akan memindai setiap 200 milidetik untuk mengganti alamat setoran yang teridentifikasi dengan nilai konfigurasi. Jika pengguna menggunakan alamat yang diganti untuk menyelesaikan transfer yang valid, tujuan penerimaan akan berubah menjadi alamat tersebut.
Tiga cabang situs menggunakan enam nilai konfigurasi bersama, yang ditandai dalam kode sebagai BTC, EVM, TRON, Solana, LTC, dan DOGE. Identifikasi alamat hanya berdasarkan bentuk karakter dan urutan kecocokan, tanpa memverifikasi jaringan atau checksum alamat yang dipilih pengguna, dan juga dapat salah mengenali indikator bisnis biasa.
Lanjutkan memeriksa kode yang disalin, dapat dilihat bahwa sampel secara bersamaan mengganggu tampilan halaman dan konten clipboard. Dengan demikian, pengguna bahkan ketika membandingkan alamat halaman dengan hasil salinan, mungkin tetap mendapatkan nilai yang telah dimodifikasi secara konsisten. Tiga jalur tersebut adalah:
- Mengemas API clipboard. navigator.clipboard.writeText terlebih dahulu memanggil R() untuk mengganti parameter, lalu menyerahkannya ke metode aslinya. Jalur ini hanya dibatasi oleh konfigurasi hostname, tidak memeriksa ulang kondisi halaman setoran, dan tidak bergantung pada pemindaian DOM untuk elemen yang sudah terdeteksi.
- Ganti tombol salin. Skrip mengkloning tombol yang cocok, memasang listener klik baru, dan mengganti node asli. Listener baru mencegah tindakan default dan penyebaran acara, lalu mencoba menyalin alamat yang disimpan dalam variabel bersama _cur.
- Blokir acara copy. Saat _cur tidak kosong dan aturan halaman terpenuhi, listener pada document akan mengganti konten yang disalin menjadi _cur, tanpa memeriksa apakah teks yang dipilih pengguna adalah alamat.
Di antaranya, wrapper API clipboard dan listener copy berdekatan dalam kode sumber (D:L260–L275), tetapi kondisi pemicunya berbeda:
_cur menyimpan alamat terakhir yang benar-benar diganti. Saat ada beberapa alamat di layar yang sama, penggantian berikutnya akan menimpa catatan sebelumnya, dan beberapa tombol mungkin menyalin nilai yang sama. Jika halaman awalnya sudah menampilkan alamat konfigurasi, pemindaian tidak akan menginisialisasi _cur, sehingga penambah listener tombol baru tidak akan menulis konten; atribut event inline HTML yang disalin tetap dapat berpartisipasi dalam pemrosesan event.
Analisis juga menemukan satu kecacatan implementasi yang memengaruhi penilaian perilaku: skrip mencoba membaca deskriptor properti sendiri dari textContent pada Element.prototype, sedangkan definisi properti standar berada di Node.prototype. Dalam hubungan prototipe standar, akses berikutnya ke .set akan memicu pengecualian. Setelah cabang ini gagal, catch akan menangkap pengecualian tersebut; dengan memeriksa kode sebelum dan sesudahnya, terlihat bahwa polling telah terdaftar, dan hook salin berikutnya tetap akan dipasang sesuai kondisi masing-masing. Kesalahan pada satu cabang tidak menghentikan modul address hijacking.
Summary
Setelah melacak loader di bagian akhir skrip layanan pelanggan, kami mengidentifikasi tujuan serangan sampel: mengumpulkan data yang dapat digunakan untuk penyalahgunaan sesi atau login akun, sekaligus mengganti alamat penerima pada halaman setoran dan operasi salin dengan nilai konfigurasi. Yang pertama tidak terbatas pada konfigurasi tiga situs, sedangkan yang kedua diaktifkan berdasarkan situs dan jalur salin spesifik, sehingga pemindaian harus mencakup berbagai skenario eksposur.
Bisnis yang masih memuat skrip terkait harus menghentikan distribusi lebih lanjut, menangani kredensial yang terbuka, dan memverifikasi tujuan setoran melalui backend tepercaya dan riwayat transaksi.
Saran
- Amankan dan hentikan distribusi sumber daya terkontaminasi. Jika produksi masih memuat skrip terkait, segera blokir setelah menyimpan respons aktual, rantai permintaan, informasi cache, dan waktu pengambilan; pulihkan dari versi tepercaya yang diverifikasi secara independen, dan periksa konfigurasi hosting situs, CDN, build, serta manajemen tag.
- Mengambil muatan dan catatan ekstraksi. Query gabungan untuk domain jahat, dua jalur, dan hash file; catatan ekstraksi juga memeriksa badan POST dan parameter GET. Saat memeriksa skrip terkompresi, cari juga URL heksadesimal dalam loader untuk menghindari kehilangan deteksi hanya karena teks biasa.
- Tutup dokumen yang terkontaminasi dan tangani kredensial yang terpapar. Tutup sepenuhnya halaman terkait atau dokumen WebView, hindari memuat ulang sumber daya lama. Sesuai cakupan paparan aktual, batalkan sesi, ganti token dan kata sandi dari lingkungan bersih; menghapus tag script tidak akan membatalkan hook dan timer yang telah dipasang.
- Verifikasi secara independen alamat pengisian dan transaksi. Untuk halaman yang menjalankan beban, verifikasi alamat pengisian asli, transaksi terkait, dan tujuan transfer aktual melalui saluran tepercaya, serta evaluasi dampak berdasarkan catatan transaksi.
- Verifikasi skrip dan batasan ekspor data. Gabungkan pengaturan bisnis untuk sumber skrip dan kontrol integritas, verifikasi kebijakan seperti connect-src dan img-src secara terpisah, serta batasi pemuatan skrip dan transmisi data ke udeskqlobal[.]com.
IOC
Domain
udeskqlobal[.]com
URL
https[:]//udeskqlobal[.]com/deeps[.]js
https[:]//udeskqlobal[.]com/c[.]php
Wallet address
BTC: bc1qhzppfj69ywp22swj50jwcfxdamg3ym245srng9
EVM: 0x9B6EcD0023a28E1391c5124eCe578A9751A337b2
TRON: TH4L5YAhhxtC8qALbZKbPZZgausbGi25nF
Solana: AFmCUe3nNbjTaC585CcdA3vvC9iWVR8YunooFKpaQx2Z
LTC: ltc1qwz0zp39ywl34kahvn9lyk7j5x63wsy9tcxhm3w
DOGE: DAoy2w8uvFtZ92q87s9qKEoHbWgV7mVThj
File berbahaya
filename: udeskApi.2026-10-16.cached.js
SHA256: 45b4e8f160d8d5177819f6c1dc67acc7abbdc65eeaffc909e668799dc778bcf6
filename: deeps.js
SHA256: 57c1441c4f5bb3260981a2df64f9ff35f117abde0d8667c8c66a047880074c59
Tentang MistEye
MistEye adalah platform intelijen ancaman Web3 dan pemantauan keamanan dinamis yang dikembangkan secara mandiri oleh SlowMist, yang menyediakan kemampuan deteksi aktivitas jahat dan peringatan risiko rantai pasokan untuk ekosistem paket open-source melalui API.
Semua paket jahat dan IOC yang terlibat dalam operasi ini telah terintegrasi ke dalam mesin deteksi ancaman MistEye; pengembang dapat melakukan deteksi otomatis terhadap dependensi proyek melalui API untuk dengan cepat menentukan apakah terkena paket jahat yang diketahui dan mendapatkan saran penanganan.


