WorstFit: Mengungkap Transformers Tersembunyi di Windows ANSI
(blog.orange.tw)- Konversi karakter Best-Fit di Windows mengganti string UTF-16 menjadi karakter yang tampak mirip saat diubah ke halaman kode ANSI, dan perilaku ini menjadi permukaan serangan WorstFit yang dapat berujung pada Path Traversal, Argument Injection, dan RCE
- Masalah ini muncul dari tumpang tindih antara ANSI API, runtime C/C++, kode startup yang disisipkan compiler, serta penggunaan API karakter non-wide oleh pengembang; jalur
GetCommandLineA,GetEnvironmentVariableA,getenv, danint main()terdampak - CVE-2024-4577 membypass patch PHP-CGI ketika U+00AD berubah menjadi
-pada halaman kode Chinese/Japanese, sementara Filename Smuggling menciptakan kebingungan jalur saat¥,₩, dan fullwidth slash berubah menjadi/atau\ - Argument Splitting dapat membuat karakter parsing command line dari fullwidth double quote atau tanda Yen/Won, sehingga argumen bisa diinjeksi ke tool CLI seperti
wget.exe,tar.exe,openssl.exe, danjava.exe; escaping argumen umum di PHP, Python, Node.js, dan Rust saja sulit untuk mencegahnya - Untuk mitigasi, aktifkan opsi UTF-8 di Windows, atau pengembang perlu memakai Wide Character API serta jalur karakter wide seperti
_wgetcwd,_wgetenv, danwmain(); masalah serupa dapat terus berulang sampai Microsoft mengaktifkan UTF-8 sebagai default di semua edisi Windows
Struktur encoding Windows dan Best-Fit
- Pada awalnya Windows menggunakan halaman kode ANSI, dan halaman kode berbeda-beda menurut wilayah bahasa, seperti 1252, 932, 936, 949, dan 950
- ACP (ANSI Code Page) digunakan untuk sebagian besar aplikasi dan pengaturan sistem, seperti operasi file dan variabel lingkungan
- OEMCP (Original Equipment Manufacturer Code Page) terutama digunakan untuk komunikasi perangkat seperti baca/tulis konsol
chcpmenampilkan OEMCP, bukan ACP, sehingga bukan cara untuk memeriksa ACP yang menjadi fokus riset ini
- Windows beralih ke Unicode pada pertengahan 1990-an, dan API inti saat ini menggunakan wide character berbasis UTF-16
- API inti seperti sistem file, informasi sistem, dan pemrosesan teks beralih ke API karakter wide
- Fitur UTF-8 memang ada, tetapi belum aktif secara default di sebagian besar bahasa, dan dalam tulisan ini disebut berada pada tahap beta
- Karena kompatibilitas ke belakang, Windows API menyediakan versi ANSI dan Unicode secara bersamaan
- ANSI API memiliki sufiks
A, sepertiGetEnvironmentVariableA - Unicode API memiliki sufiks
W, sepertiGetEnvironmentVariableW - Saat ANSI API dipanggil, Windows mengonversi string UTF-16 internal menjadi string ANSI dengan
RtlUnicodeStringToAnsiStringatauWideCharToMultiByte
- ANSI API memiliki sufiks
Bagaimana Best-Fit menjadi WorstFit
- Best-Fit adalah perilaku yang memetakan karakter UTF-16 ke karakter yang tampak atau terasa mirip ketika karakter tersebut tidak dapat direpresentasikan secara tepat di halaman kode ANSI tujuan
- Misalnya, pada Windows-1252,
∞U+221E dipetakan menjadi8 - Jika
√π⁷≤∞melewati ANSI API, hasilnya dapat berubah menjadi seperti"vp7=8"
- Misalnya, pada Windows-1252,
- Mapping bekerja berbeda di tiap halaman kode
¥U+00A5 dipetakan menjadi\pada halaman kode Japanese 932- Pada halaman kode Central European 1250, karakter itu dipetakan menjadi
Y - Pada sebagian besar halaman kode lain, karakter itu tidak berubah
- Konversi yang sama terjadi bukan hanya pada pemanggilan Windows API secara langsung, tetapi juga pada fungsi CRT dan jalur fungsi
mainyang umum- Konversi Best-Fit diterapkan pada fungsi CRT non-wide seperti
getenv - Konversi juga ikut terlibat ketika argumen dan variabel lingkungan diterima dalam bentuk
int main(int argc, char* argv[], char* envp[]) - Hal ini terjadi karena kode startup CRT yang disisipkan compiler berpadu dengan penggunaan ANSI Windows API
- Konversi Best-Fit diterapkan pada fungsi CRT non-wide seperti
- Untuk memeriksa mapping, rujuk Best-fit Mapping Grepper dan data mapping mentah WindowsBestFit dari Unicode.org
Kasus WorstFit pertama: PHP-CGI CVE-2024-4577
- CVE-2024-4577 adalah contoh serangan WorstFit yang memungkinkan server PHP-CGI dengan halaman kode Chinese/Japanese dikompromikan hanya melalui request
?%ADs- Halaman kode yang terdampak adalah 932 (Japanese), 936 (Simplified Chinese), dan 950 (Traditional Chinese)
- Karakter ancamannya adalah
U+00AD
- Kerentanan PHP-CGI tahun 2012 adalah argument injection yang terjadi ketika Apache otomatis memperlakukan query string sebagai argumen pertama program CGI
- Dengan menambahkan
?-s, kebocoran source code halaman dan RCE menjadi mungkin - Patch PHP menghentikan parsing argumen jika query string diawali dash
- Dengan menambahkan
- Karena Best-Fit, soft hyphen U+00AD dikonversi menjadi
-pada halaman kode Chinese/Japanese sehingga patch lama dapat dibypass- Dari sudut pandang PHP-CGI,
?%ADsdapat berperilaku seperti-s - Melalui kasus ini, tim riset pertama kali berhadapan dengan istilah Best-Fit
- Dari sudut pandang PHP-CGI,
Filename Smuggling: masalah konversi karakter jalur
- Filename Smuggling adalah serangan yang dapat menciptakan path traversal ketika karakter Unicode dalam nama file berubah menjadi
/atau\di jalur ANSI API- API terkait mencakup
GetCurrentDirectoryA,getcwd,FindFirstFileA,findfirst*,GetFullPathNameA, dan lainnya - Halaman kode yang terdampak adalah 874, 125x, 932 (JP), dan 949 (KR)
- Karakter ancamannya adalah
/U+FF0F,\U+FF3C,¥U+00A5 (JP), dan₩U+20A9 (KR)
- API terkait mencakup
d8.exe, Developer Shell milik Chrome V8, menggunakanGetCurrentDirectoryA()dalam implementasi internalnya untuk mendapatkan direktori kerja saat ini- Jika direktori kerja yang berisi karakter Unicode berbahaya dapat dibuat, karakter tersebut berubah menjadi payload path traversal saat diakses melalui ANSI API
- Sebagai contoh, akses tak disengaja ke
C:/windows/win.inimenjadi mungkin
- Implementasi Windows dari
Dir.getwd()di mruby bergantung pada fungsi ANSI CRT_getcwd()- Nilai kembaliannya dapat terkontaminasi dan dapat berujung pada Path Traversal
Cuckoo Sandbox: dari Path Traversal hingga RCE
- Akses sistem file Windows di Python sebelumnya dapat menggunakan wide API atau ANSI API, tergantung apakah string-nya wide atau narrow
- Setelah PEP 529, encoding sistem file Windows distandardisasi menjadi UTF-8
- Python 2 dan Python 3 sebelum Python 3.6 tetap rentan terhadap serangan WorstFit
- Cuckoo Sandbox adalah platform analisis malware otomatis, dan versi resmi terbarunya bergantung pada Python 2.7
- Cuckoo terdiri dari Cuckoo Host dan VM Cluster
- Sampel yang diunggah dijalankan secara terisolasi di VM, lalu paket jaringan, file drop, dan log disinkronkan melalui mekanisme internalnya
- Jika malware membuat file drop dengan nama file Unicode, Path Traversal dapat terjadi dalam pemrosesan path Python di Cuckoo Host
- Contoh PoC membuat path
AAAA\u00a5..\u00a5..\u00a5..\u00a5..\u00a5..\u00a5conf\u00a5cuckoo.conf - Setelah analisis selesai, saat pengguna menekan tombol unduh di antarmuka web, operasi file Python terpicu
- Cuckoo Host dapat memproses path hasil konversi yang berisi
../dan mengirim data sensitif kepada penyerang
- Contoh PoC membuat path
- Penyerang dapat mengunduh
cuckoo.conf, mengumpulkan informasi sensitif yang diperlukan untuk menghitung Flask PIN, lalu mencapai RCE di Sandbox Host- Video demo tersedia sebagai Video 11
Argument Splitting: Best-Fit yang mengubah parsing command line
- Argument Splitting adalah serangan ketika string command line berubah dan argumen terpecah pada output
GetCommandLineAatau jalur non-Unicodeint main()- API dan jalur terkait adalah
GetCommandLineA,int main() - Code page yang terdampak adalah 874, 125x, 932(JP), 949(KR)
- Karakter ancaman adalah
"U+FF02,\U+FF3C,¥U+00A5(JP),₩U+20A9(KR)
- API dan jalur terkait adalah
- Contoh kode PHP membungkus URL dengan aman memakai
escapeshellarg()lalu menjalankanwget.exe -q, tetapi input" --use-askpass=calc "memungkinkan eksekusicalc.exe- Input yang sama tetap tidak tertangkal meski diganti ke Node.js, Rust, atau Python
- Ini juga bekerja pada contoh
subprocess.run(["wget", "-q", ...])di versi terbaru Python
- Windows meneruskan seluruh command line ke proses baru sebagai satu string, dan executable mem-parsing-nya sendiri
- Strukturnya bukan seperti keluarga UNIX yang selalu meneruskan array argumen
- API
CreateProcessmenerima parameterlpCommandLinesecara langsung
- Dalam parsing command line umum, karakter pentingnya adalah spasi dan tab, double quote, serta backslash
- Spasi dan tab memisahkan argumen saat bukan dalam quote mode
"mengalihkan quote mode\meng-escape double quote dan backslash pada urutan tertentu
- Standard library di sebagian besar bahasa meng-escape argumen pengguna sesuai aturan ini, tetapi escaping selesai sebelum konversi Best-Fit
- PHP
escapeshellargmengganti double quote menjadi spasi, membungkus argumen dengan quote, dan menangani backslash - Python
subprocessmeng-escape denganlist2cmdlineagar sesuai aturan parsing command line Microsoft CRT - Setelah itu, jika dalam konversi ANSI
"U+FF02 berubah menjadi"U+0022, sintaks command line aslinya berubah
- PHP
- Program yang hanya menggunakan
int main()juga bisa rentan- Compiler membuat
mainCRTStartupdi dalam binary, dan fungsi startup ini ditautkan dengan library CRT - Jika bagian internal CRT mengambil command line melalui ANSI API lalu mem-parsing-nya, konversi Best-Fit ikut terlibat
- Karena perilaku ini, sulit mencegah serangan sepenuhnya hanya dengan standard library dari bahasa pemrograman tertentu
- Compiler membuat
Kasus nyata Argument Splitting
- ElFinder adalah manajer file web open source berbasis backend PHP, dan secara default mendukung server Windows serta pembuatan dan ekstraksi arsip
- Pemrosesan arsip diimplementasikan dengan eksekusi shell command, dan argumen di-escape dengan
escapeshellarg - Untuk pemrosesan format tar digunakan
tar.exebawaan Windows - Dengan nama file tar seperti
aaa" "--use-compress-program=calc" "bbb.tar, argumen--use-compress-programdapat disisipkan untuk menjalankan perintah arbitrer - Demo dilakukan pada Windows server berkonfigurasi bahasa Inggris dengan Code Page 1252, dan dirangkum bahwa ini seharusnya juga bekerja pada code page 125x dan Code Page 874
- Video demo tersedia sebagai Video 12
- Pemrosesan arsip diimplementasikan dengan eksekusi shell command, dan argumen di-escape dengan
- Kasus
plink.exeyang dimodifikasi dan digunakan di TortoiseGit dapat memicu eksekusi kode jika URI berbahaya dimasukkan sebagai input clone- Detailnya dapat dilihat di curated list
- Video demo adalah Video 13
- RStudio mendukung version control SVN, dan jika sebuah proyek SVN berada di folder yang dibuat secara berbahaya, kalkulator dapat dijalankan dengan satu klik
- Detailnya dapat dilihat di curated list
- Video demo adalah Video 14
- Kasus Microsoft Excel adalah CVE-2024-49026 yang menggabungkan Argument Splitting dengan fitur “Open-With” Windows
- Windows mempertahankan handler table untuk tiap ekstensi file, yang dapat diperiksa dengan
ftypedanassoc - Karena nama file menjadi bagian dari argumen program handler, serangan dapat diterapkan melalui nama file
- Nama file yang mengubah dot, slash, backslash, dan double quote ke bentuk fullwidth memicu argument injection ke
Excel.exe - Karena Excel sendiri tidak memiliki argumen yang cocok untuk eksploitasi lanjutan, RCE dicapai dengan menggunakan NTLM Relay bersama RBCD/ADCS
- Video demo adalah Video 15
- Windows mempertahankan handler table untuk tiap ekstensi file, yang dapat diperiksa dengan
Kebingungan Variabel Lingkungan
- Kebingungan Variabel Lingkungan terjadi ketika
GetEnvironmentVariableA,GetEnvironmentStringsA, danchar *getenv()mengembalikan versi variabel lingkungan yang telah dikonversi dengan Best-Fit- Code page yang terdampak dan karakter ancamannya tidak disebutkan secara spesifik
- Dalam kasus Apache HTTPd, 0x00-0xFF terkait
- Agar serangan ini berhasil, variabel lingkungan harus dapat dikendalikan oleh pengguna
- Ini berlaku ketika proses induk meneruskan informasi ke proses anak yang dibuatnya
- Pada CGI, sebagian besar informasi permintaan HTTP seperti query string dan HTTP header diteruskan sebagai variabel lingkungan
- Contoh bypass WAF membahas situasi ketika skrip CGI bertindak seperti routing service
- Konfigurasi Apache memiliki aturan yang menolak
REQUEST_URIyang berisi/adminuntuk mencegah akses jarak jauh ke/cgi.pl/admin - Karena perilaku WorstFit pada Windows Perl, bypass dimungkinkan jika sebagian dari
admindiganti dengan padanan Best-Fit - Pada Code Page 1250,
àU+00E0 berubah menjadiaselama konversi ANSI - Permintaan
/cgi.pl/%E0dminterlihat sebagai jalur berbeda oleh aturan sisi server, tetapi ketika skrip Perl CGI membacaPATH_INFOmelalui ANSI API, permintaan itu diproses sebagai/admin
- Konfigurasi Apache memiliki aturan yang menolak
- Pada PHP-CGI di Windows, dalam konfigurasi tertentu telah dikonfirmasi adanya oracle pengecekan keberadaan file dan potensi LFI
- Penyebabnya adalah cara pemrosesan
PATH_INFOdan variabel lingkungan terkait path lainnya - Permintaan
/index.php/foo/barditeruskan, dari sudut pandang Apache, sebagai variabel lingkungan sepertiREDIRECT_URL,REQUEST_URI,PATH_INFO, danPATH_TRANSLATED - Dengan informasi ini saja, sulit membedakan secara jelas batas antara nama file PHP dan tambahan
PATH_INFO, sehinggaphp-cgi.exemenafsirkannya
- Penyebabnya adalah cara pemrosesan
- Jika memanfaatkan
¥pada code page Jepang, interpretasi path antara web server dan PHP-CGI menjadi berbeda- Web server memperlakukan keseluruhan
/..¥..¥windows/win.ini/foosebagai tambahanPATH_INFO - PHP-CGI menerima nilai yang telah dikonversi seperti
REQUEST_URI=/index.php/..\..\windows/win.ini/foodan mengalami kebingungan dalam proses membedakan file PHP sebenarnya dariPATH_INFO - Pada Apache, file existence oracle dimungkinkan melalui perbedaan respons antara file yang tidak ada dan file yang ada
- Pada IIS, jika directive
doc_rootdisetel, LFI yang meng-include dan membacaC:\Windows\win.inidimungkinkan melalui path seperti/index.php/..¥..¥..¥windows/win.ini/ - Jika file yang disertakan dapat dieksekusi atau berisi kode yang dapat dikendalikan pengguna, hal ini berpotensi berujung pada RCE, tetapi skenario tersebut diklasifikasikan lebih sebagai bug yang jarang terjadi pada aplikasi nyata
- Web server memperlakukan keseluruhan
Kesulitan dalam Proses Pengungkapan dan Perbaikan
- Tim peneliti melaporkan berbagai masalah pada bahasa pemrograman, proyek open source, dan program CLI bawaan Windows kepada masing-masing upstream maintainer
- Perdebatan paling banyak terjadi pada Argument Splitting
- Sebagian vendor menganggap tindakan meneruskan input pengguna ke command line itu sendiri sebagai kerentanan
- Ketidakjelasan tanggung jawab juga menjadi masalah
- Kode bermasalah tersebar di
mainCRTStartup()yang disisipkan otomatis saat kompilasi dan pemanggilan ANSI API internal MSVCRT/UCRT - Sulit membedakan apakah masalahnya karena developer tidak menggunakan
wmain(), atau karena CRT salah membagi command line lalu meneruskan argumen yang keliru kemain() - Sebagian proyek hanya menyediakan source code, sementara Windows prebuilt executable didistribusikan oleh relawan pihak ketiga di internet
- Kode bermasalah tersebar di
- Perbaikannya tidak sesederhana mengganti
main()menjadi versi wide-character- Jika function signature berubah, definisi variabel dan logika parsing argumen harus ditulis ulang dari berbasis
char *menjadi berbasiswchar_t * - Proses ini menyakitkan dan rentan kesalahan
- Jika function signature berubah, definisi variabel dan logika parsing argumen harus ditulis ulang dari berbasis
- Curl menjawab bahwa ini adalah fitur Windows dan tidak berencana memperbaikinya, sedangkan Curl yang di-port oleh Microsoft memperbaiki entry menjadi
wmain()sehinggacurl.exebawaan Windows tidak terdampak- Binary build resmi Curl terdampak serangan Argument Splitting
- Laporan lengkap dipublikasikan di HackerOne
- OpenSSL dapat memproses argumen dalam format wide character melalui variabel lingkungan
OPENSSL_WIN32_UTF8- Tujuan awalnya adalah memperbaiki masalah tampilan UTF-8 di UI, tetapi ini juga memitigasi serangan Argument Splitting
- Dalam penggunaan OpenSSL default, banyak developer tidak tahu bahwa mereka harus menyetel variabel lingkungan ini, dan eksekusi kode arbitrer dimungkinkan menggunakan argumen
-engine
- Distribusi resmi Perl tidak menyediakan Windows prebuilt executable, dan installer pihak ketiga seperti Strawberry Perl dan ActiveState Perl umum digunakan
- Kedua distribusi tersebut terdampak serangan Argument Splitting
- Setelah berdiskusi dengan maintainer Perl, disimpulkan bahwa ini “lebih mirip bug Microsoft daripada bug Perl”, sehingga saat ini masih belum terselesaikan
- Tiga kasus dilaporkan ke Microsoft melalui MSRC, dan semuanya awalnya ditolak karena tidak memenuhi kriteria tingkat keparahan
- Setelah dibuka kembali beberapa kali, hanya kasus Excel yang diterima setelah percobaan ketiga
- Kasus lainnya masih belum terselesaikan hingga saat ini
- MSRC menjawab bahwa kasus ini bergantung pada kerentanan aplikasi terpisah yang menjalankan input tidak tepercaya dengan memasukkannya ke command line, dan technique yang membuat eksploitasi itu memungkinkan tidak memenuhi syarat sebagai kerentanan
- Bantuan juga diminta kepada CERT/CC, dan beberapa bulan kemudian Microsoft menambahkan peringatan keamanan ke dokumentasi
GetCommandLineA- Peringatan hanya ditambahkan pada
GetCommandLineA, sementara masih ada ANSI API lain yang perlu diwaspadai
- Peringatan hanya ditambahkan pada
Target Terdampak yang Dilaporkan dan Statusnya
- Item yang dikonfirmasi dan dilaporkan selama proses pengungkapan adalah sebagai berikut
- 2024/05/07: PHP
php-cgi.exe— CVE-2024-4577 - 2024/06/13: Curl Official Build — Won’t Fix
- 2024/06/13: Apache Subversion
svn.exe— CVE-2024-45720 - 2024/06/16: Microsoft Tar
tar.exe— Won’t Fix - 2024/06/19: Microsoft Excel
excel.exe— CVE-2024-49026 - 2024/06/19: Microsoft PhoneBook
rasphone.exe— Won’t Fix - 2024/06/19: Oracle Java
java.exe— Pending Fix - 2024/06/19: Perl
perl.exe— Won’t Fix - 2024/07/15: Perforce
p4.exe— CVE-2024-8067 - 2024/08/05: PostgreSQL
psql.exe— Won’t Fix - 2024/08/08: Putty
plink.exe— Fixed - 2024/08/19: OpenSSL
openssl.exe— Other - 2024/08/19: wkhtmltopdf
wkhtmltopdf.exe— EOL - 2024/08/19: GNU Wget — No Reply
- 2024/05/07: PHP
Mitigasi dan Permukaan Serangan yang Tersisa
- Serangan WorstFit adalah masalah di tingkat sistem operasi, sehingga hingga Microsoft mengaktifkan UTF-8 sebagai default di semua edisi Windows, isu serupa dapat terus muncul kembali
- Tindakan yang dapat dilakukan pengguna adalah memeriksa dan mengaktifkan opsi UTF-8 di Windows
- Fitur ini masih ditandai berada pada tahap beta, dan belum jelas apakah ada efek samping
- Developer sebaiknya menggunakan Wide Character API sebisa mungkin
- CRT juga menyediakan versi wide character seperti
_wgetcwddan_wgetenv - Jika terus menggunakan jalur non-wide, implementasi internal dapat memanggil ANSI API dan terekspos pada serangan WorstFit
- CRT juga menyediakan versi wide character seperti
- Karena kompatibilitas mundur Windows, kemungkinan masih ada tempat lain tempat ANSI API tersembunyi
- Sebagai contoh, query Windows Registry seperti
RegQueryValueAdapat terdampak, tetapi skenario kerentanannya perlu dicari - Tim peneliti juga mengamati perilaku Best-Fit di Active Directory
- Sebagai contoh, query Windows Registry seperti
1 komentar
Komentar Hacker News
Ini masalah yang cukup rumit. Pemetaan kode “best fit” milik Microsoft adalah pemeta yang mengubah Unicode yang luas menjadi ASCII; memang terbuka, tetapi pada praktiknya berbasis “perkiraan rasa”, dan tertanam di seluruh sistem
Pemeta ini terhubung secara default di sangat banyak tempat, dan melihat cara Microsoft menangani kompatibilitas mundur, tampaknya mau tak mau akan terus disertakan. Eksploit umumnya muncul ketika code point yang tidak biasa dipetakan secara “terasa mirip” menjadi slash, hyphen, atau tanda kutip. Di dalam bahasa modern ia diperiksa sebagai Unicode yang benar, tetapi saat diteruskan ke perintah shell atau Win32 API, setelah kontrol diserahkan ia direduksi dengan cara yang berbeda. Seperti kata maintainer curl, di sini “curl adalah korban”, tetapi pertanyaannya adalah siapa pelakunya. Jika server memvalidasi input pengguna secara berbeda dari cara ia merusaknya saat menyerahkannya ke library sistem, pada akhirnya masalah memang akan muncul. Opsi untuk mematikan konversi best fit di sisi Win32 mungkin bisa menjadi solusi, tetapi saya bukan ahli Windows jadi ini hanya dugaan. Bahkan jika begitu, tetap akan ada interaksi dengan API resmi atau perangkat lunak yang masih belum dimatikan
"w", bukan"a". Pendekatan ini juga menyelesaikan masalah path lebih dari 260 karakter jika menambahkan prefiks"\\?\"atau mengatur manifest dengan benar, dan ini sudah dimungkinkan serta direkomendasikan sejak Windows XPSaya tidak terlalu paham mengapa API non-Unicode masih sesering ini dipakai. Sulit membayangkan alasannya karena masih ingin mendukung Windows 98 atau Windows 2000
Hal lain yang dibutuhkan adalah semacam linting. Dalam aplikasi modern biasanya tidak ada alasan untuk memanggil fungsi ANSI WinAPI. Memang ada pendekatan mengatur locale ke UTF-8 lalu hanya memakai fungsi 8-bit, tetapi saya tidak tahu seberapa baik itu bekerja. Setahu saya ada beberapa pengaturan dan header yang membuat
argv,printf,std::coutbekerja dengan UTF-8 dan memaksa kita hanya memakai fungsi konversi UTF-8/UTF-16 untuk WinAPI tanpa transformasi aneh. Microsoft perlu mendokumentasikan prosedur semacam ini di satu tempatIni sampai taraf tertentu bisa diduga, tetapi bahkan bagi saya yang pernah sekitar 10 tahun berkutat dengan pengembangan Windows dan hacking API Wine pada masa kebingungan W/A, ini tetap terasa baru
Windows itu seperti permainan kartu Munchkin: jika beberapa fitur kebetulan saling terkait, mereka bisa menyatu menjadi eksploit yang terasa acak sekaligus sangat kuat sampai sulit dipercaya. Saya senang bahwa subsistem ANSI sedang diubah ke UTF-8, dan secara teori itu bisa sangat mengurangi masalah seperti ini. Saya juga penasaran apakah tim Rust perlu melakukan perbaikan lain lagi pada API pembuatan proses
Tentu saja Rust tidak bisa mengendalikan apa yang terjadi di luar batas proses. Jika aplikasi yang dijalankan oleh Rust memakai API ANSI, masalahnya ada di sana, tetapi itu tanggung jawab aplikasi tersebut
Jika ingatan saya benar, “menghapus ANSI secara bertahap dan merekomendasikan penggunaan Wide Character API” sudah menjadi posisi resmi Microsoft sejak NT 3.5
Sayangnya, salah satu hambatan besar adalah cara Microsoft mengimplementasikan library runtime C/C++
msvcrt.dll. Fungsi wide nonstandar seperti_wfopen()dan_wgetenv()secara internal memakai fungsi W dari Win API, tetapi fungsi narrow standar sepertifopen()dangetenv()tidak dikonversi ke versi wide, melainkan langsung memakai fungsi A. Dan fungsi A biasanya tidak melaporkan kegagalan konversi Unicode, melainkan menimpanya dengan pendekatan best-fit. Orang yang memindahkan perangkat lunak C ke Windows biasanya tidak ingin mengganti semua pemakaian fungsi standar menjadi fungsi Microsoft yang tidak portabel. Dari titik itu, praktiknya sudah seperti menulis ulang totalactiveCodePagemenjadi UTF-8 di manifest aplikasi dan tetap memakai fungsi “ANSI”maindanfopendi-#definemenjadi padanan wide-nyaDengan begitu kita tidak bisa begitu saja memakai
char*dan string literal biasa, jadi didefinisikan tipetcharyang menjadichardi Linux danwchar_tdi Windows, serta makro_T()untuk string literal. Biasanya ini berjalan cukup mulus tanpa banyak dipikirkan-A, bukan varian-W. Saya tidak tahu apakah ada sesuatu yang aneh dirobots.txt, tetapi terasa janggal bahwa API yang direkomendasikan untuk memakai varian-Wpada kode baru justru secara default menampilkan API lawasmsvcrt.dlltelah digantikan oleh Universal C Runtime (UCRT)[1], dan UCRT mematuhi C99Ada dua cara untuk benar-benar memaksa code page “Ansi” menjadi UTF-8 pada aplikasi yang Anda tulis sendiri atau EXE yang Anda patch
Salah satunya memakai file manifest, dan ini berfungsi mulai build tertentu di Windows 10. Ini juga bisa diterapkan setelah proses build pada EXE apa pun, jadi dukungan UTF-8 bisa dipaksakan ke suatu program. Sangat berguna khususnya untuk program mode konsol. Cara lainnya adalah memakai hack yang digunakan alat jenis “App Locale”. Salah satu metodenya mencakup pemanggilan fungsi NTDLL yang tidak terdokumentasi. Saya tidak tahu persis fungsi mana yang dibutuhkan, tetapi
RtlInitNlsTablesdanRtlResetRtlTranslationsmungkin terkaitSaya ragu Microsoft bisa mengaktifkan UTF-8 sebagai default di semua edisi Windows. Ada banyak aplikasi lama yang mengasumsikan code page tertentu atau 1 byte per karakter, jadi bisa rusak.
Yang lebih subtil, ada juga aplikasi yang memakai ulang buffer lama dengan asumsi bahwa saat mengonversi dari wide character ke ANSI jumlah byte tidak akan bertambah. Di UTF-8 itu tidak berlaku, sementara di sebagian besar code page lama asumsi itu umumnya benar, jadi ini bisa memunculkan kerentanan baru. Sepertinya akan jauh lebih sedikit merusak jika Microsoft menghapus logika Best-Fit dari API Win32
xxxA, lalu mengganti karakter yang tidak bisa dipetakan dengan karakter sepertixyang tidak punya makna meta umum[0] https://tambre.ee/blog/adobe_after_effects_windows_utf-8/
Melihat masalah yang ditimbulkan oleh pemetaan Best-Fit, menjadikannya default juga masuk akal, tetapi Microsoft harus membantu pengguna menemukan cara agar kode lama tetap mudah dijalankan. Cara yang kurang masuk akal adalah menghapus semua pemetaan Best-Fit menuju karakter ASCII “khusus”, tetapi itu tidak membantu aplikasi yang menautkan CRT secara statis. Itu juga tidak benar-benar memperbaiki kerentanannya, jadi bukan solusi yang bagus. Kadang kerentanan keamanan memang menjadi pendorong untuk merusak kompatibilitas ke belakang
Microsoft setidaknya sudah mengetahui masalah ini sejak 1 tahun lalu. Alasannya, mereka merilis aturan analisis kode khusus bernama CA2101[1] yang secara eksplisit tidak menganjurkan penggunaan pemetaan best-fit
Penjelasan aturannya memang menyebut kerentanan keamanan, tetapi detailnya sengaja dibuat samar
[1] https://learn.microsoft.com/en-us/dotnet/fundamentals/code-a...
Tidak perlu mengubah semuanya dari
char *menjadiwchar *. Cukup konversi wide character yang diterima ke UTF-8, atau jika ingin tetap mengizinkan sekuens tidak valid seperti surrogate yang tidak berpasangan, konversikan ke sesuatu seperti WTF-8 milik Rust lalu tetap gunakancharTentu saja Anda harus berhati-hati agar tidak mencampur string ANSI atau OEMCP dengan string UTF-8, tetapi kalau hanya memakai UTF-8, semuanya jadi mudah. Pendekatan inilah yang direkomendasikan oleh situs klasik https://utf8everywhere.org/
Di komputer Windows pribadi saya, saya rupanya sudah menghindari bug ini secara tidak sengaja karena beberapa tahun terakhir mengaktifkan mode UTF-8. Itu adalah pengaturan yang disebutkan di bagian bawah artikel
Awalnya saya mengaktifkannya karena game-game asing lama menampilkan teks rusak, dan meskipun ditandai sebagai “Beta”, saya tidak merasakan bug atau efek samping apa pun
Saya penasaran apakah checkbox beta itu sama dengan mengatur
ActiveCodePageke UTF-8 di manifest, tetapi dari dokumentasi[0] terlihat jelas bahwa GDI tidak mengikuti code page per-proses dan hanya mengikuti satu code page global yang diatur oleh checkbox tersebutAgak disayangkan karena ini berarti aplikasi tidak bisa sepenuhnya opt-in ke UTF-8 di API
*Ahanya untuk aplikasinya sendiri. Meski begitu, saya rasa ini tetap bisa menjadi solusi sementara yang valid atau langkah defense-in-depth untuk masalah yang disorot artikel tersebut[0] https://learn.microsoft.com/en-us/windows/apps/design/global...
Astaga. Saya tahu API Windows menyediakan konversi best-fit semacam itu, tetapi saya tidak tahu bahwa di code page default saya, 949[1], itu adalah perilaku default dari banyak fungsi ANSI
Pada titik ini, ini rasanya seperti
getsdan seharusnya langsung dilarang. [1] Saya tahu ada code page UTF-8 65001. Dulu lama sekali benar-benar tidak layak dipakai, dan bahkan sekarang pun masih mengalami masalah kompatibilitas