WorstFit: Windows ANSI’nin gizli Transformers’larını ortaya çıkarmak
(blog.orange.tw)- Windows’un Best-Fit karakter dönüşümü, UTF-16 dizelerini ANSI kod sayfasına çevirirken benzer görünen karakterlerle değiştirir; bu davranış Path Traversal, Argument Injection ve RCE’ye yol açabilen WorstFit saldırı yüzeyini oluşturur
- Sorun; ANSI API, C/C++ çalışma zamanı, derleyicinin eklediği başlangıç kodu ve geliştiricilerin wide olmayan karakter API’lerini kullanmasının üst üste geldiği yapıda ortaya çıkar;
GetCommandLineA,GetEnvironmentVariableA,getenv,int main()yolları bundan etkilenir - CVE-2024-4577’de Chinese/Japanese kod sayfalarında U+00AD
-karakterine dönüşerek PHP-CGI yamasını baypas etti; Filename Smuggling’de ise¥,₩ve fullwidth slash karakterleri/veya\karakterine dönüşerek yol karışıklığı yaratır - Argument Splitting, fullwidth çift tırnak veya Yen/Won işaretinin komut satırı ayrıştırma karakterlerine dönüşmesiyle
wget.exe,tar.exe,openssl.exe,java.exegibi CLI araçlarına argüman enjekte edilmesini sağlayabilir; PHP, Python, Node.js ve Rust’taki yaygın argüman escape yöntemleri tek başına bunu engellemekte zorlanır - Azaltma için Windows’un UTF-8 seçeneği açılmalı ya da geliştiriciler Wide Character API ile
_wgetcwd,_wgetenv,wmain()gibi wide karakter yollarını kullanmalıdır; Microsoft tüm Windows sürümlerinde UTF-8’i varsayılan olarak açana kadar benzer sorunlar tekrarlanabilir
Windows kodlama yapısı ve Best-Fit
- Windows başlangıçta ANSI kod sayfalarını kullanıyordu ve dil bölgesine göre 1252, 932, 936, 949, 950 gibi kod sayfaları farklıydı
- ACP (ANSI Code Page), dosya işlemleri ve ortam değişkenleri gibi çoğu uygulama ve sistem ayarında kullanılır
- OEMCP (Original Equipment Manufacturer Code Page), ağırlıklı olarak konsolda okuma/yazma gibi cihaz iletişimlerinde kullanılır
chcp, ACP’yi değil OEMCP’yi gösterdiği için bu araştırmanın odağındaki ACP’yi doğrulamak için uygun bir araç değildir
- Windows 1990’ların ortasında Unicode’a geçti ve günümüzde çekirdek API’ler UTF-16 tabanlı wide character kullanır
- Dosya sistemi, sistem bilgisi ve metin işleme gibi çekirdek API’ler wide karakter API’lerine dönüştürüldü
- UTF-8 özelliği mevcut olsa da çoğu dilde varsayılan olarak açık değildir; yazıda beta aşamasında olarak ifade edilir
- Geriye dönük uyumluluk nedeniyle Windows API, ANSI ve Unicode sürümlerini birlikte sunar
- ANSI API’ler
GetEnvironmentVariableAgibiAsonekine sahiptir - Unicode API’ler
GetEnvironmentVariableWgibiWsonekine sahiptir - ANSI API çağrıldığında Windows, dahili UTF-16 dizeleri
RtlUnicodeStringToAnsiStringveyaWideCharToMultiByteile ANSI dizelere dönüştürür
- ANSI API’ler
Best-Fit’in WorstFit’e dönüşme biçimi
- Best-Fit, UTF-16 karakterleri hedef ANSI kod sayfasında tam olarak ifade edilemediğinde bunları benzer görünen veya benzer hissedilen karakterlere eşleyen davranıştır
- Örneğin Windows-1252’de
∞U+221E,8olarak eşlenir √π⁷≤∞, ANSI API’den geçtiğinde"vp7=8"gibi değişebilir
- Örneğin Windows-1252’de
- Eşleme her kod sayfasında farklı çalışır
¥U+00A5, Japanese 932 kod sayfasında\olarak eşlenir- Central European 1250 kod sayfasında
Yolarak eşlenir - Diğer kod sayfalarının çoğunda değişmeden kalır
- Yalnızca Windows API’nin doğrudan çağrılmasında değil, CRT fonksiyonlarında ve yaygın
mainfonksiyonu yollarında da aynı dönüşüm gerçekleşirgetenvgibi wide olmayan CRT fonksiyonlarında Best-Fit dönüşümü uygulanır- Argümanlar ve ortam değişkenleri
int main(int argc, char* argv[], char* envp[])biçiminde alındığında da dönüşüm devreye girer - Bunun nedeni, derleyicinin eklediği CRT başlangıç kodu ile ANSI Windows API kullanımının birleşmesidir
- Eşlemeleri kontrol etmek için Best-fit Mapping Grepper ve Unicode.org’un WindowsBestFit ham eşleme verileri referans alınabilir
İlk WorstFit vakası: PHP-CGI CVE-2024-4577
- CVE-2024-4577, Chinese/Japanese kod sayfalarına ayarlanmış PHP-CGI sunucularının yalnızca
?%ADsisteğiyle ele geçirilebilmesini sağlayan bir WorstFit saldırı örneğidir- Etkilenen kod sayfaları 932 (Japanese), 936 (Simplified Chinese), 950 (Traditional Chinese)
- Tehdit karakteri
U+00AD
- 2012’deki PHP-CGI zafiyeti, Apache’nin sorgu dizesini CGI programının ilk argümanı olarak otomatik işlemesiyle ortaya çıkan bir argument injection sorunuydu
?-seklendiğinde sayfa kaynak kodunun sızdırılması ve RCE mümkün oluyordu- PHP yaması, sorgu dizesi dash ile başlıyorsa argüman ayrıştırmayı durduracak şekildeydi
- Best-Fit nedeniyle U+00AD soft hyphen, Chinese/Japanese kod sayfalarında
-karakterine dönüştü ve mevcut yama baypas edildi?%ADs, PHP-CGI açısından-sgibi davranabilir- Bu vaka sayesinde araştırma ekibi Best-Fit terimiyle ilk kez karşılaştı
Filename Smuggling: yol karakterlerinin dönüşmesi sorunu
- Filename Smuggling, dosya adında bulunan Unicode karakterlerinin ANSI API yolunda
/veya\karakterine dönüşerek path traversal oluşturabildiği bir saldırıdır- İlgili API’ler arasında
GetCurrentDirectoryA,getcwd,FindFirstFileA,findfirst*,GetFullPathNameAvb. bulunur - Etkilenen kod sayfaları 874, 125x, 932 (JP), 949 (KR)
- Tehdit karakterleri
/U+FF0F,\U+FF3C,¥U+00A5 (JP),₩U+20A9 (KR)
- İlgili API’ler arasında
- Chrome V8’in Developer Shell’i olan
d8.exe, iç uygulamasında geçerli çalışma dizinini almak içinGetCurrentDirectoryA()kullanır- Kötü amaçlı Unicode karakterleri içeren bir çalışma dizini oluşturulabiliyorsa, ANSI API erişimi sırasında path traversal payload’una dönüşür
- Örnek olarak istenmeyen
C:/windows/win.inierişimi mümkün olabilir
- mruby’nin
Dir.getwd()Windows uygulaması, ANSI CRT fonksiyonu_getcwd()’ye dayanır- Dönüş değeri kirlenebilir ve Path Traversal’a yol açabilir
Cuckoo Sandbox: Path Traversal’dan RCE’ye
- Python’ın Windows dosya sistemine erişimi, dizgenin wide mı yoksa narrow mı olduğuna bağlı olarak wide API veya ANSI API kullanabiliyordu
- PEP 529 sonrasında Windows dosya sistemi kodlaması UTF-8 olarak standartlaştırıldı
- Python 2 ve Python 3.6 öncesi Python 3, WorstFit saldırılarına açık durumda kaldı
- Cuckoo Sandbox otomatikleştirilmiş bir zararlı yazılım analiz platformudur ve en güncel resmî sürümü Python 2.7’ye bağımlıdır
- Cuckoo, Cuckoo Host ve VM Cluster’dan oluşur
- Yüklenen örnek VM’de izole şekilde çalıştırılır; ağ paketleri, bırakılan dosyalar ve loglar kendi mekanizmasıyla senkronize edilir
- Zararlı yazılım Unicode dosya adına sahip bırakılan bir dosya oluşturursa, Cuckoo Host’un Python yol işlemesinde Path Traversal oluşabilir
- Örnek PoC,
AAAA\u00a5..\u00a5..\u00a5..\u00a5..\u00a5..\u00a5conf\u00a5cuckoo.confyolunu oluşturur - Analiz bittikten sonra kullanıcı web arayüzünde indirme düğmesine bastığında Python dosya işlemi tetiklenir
- Cuckoo Host, dönüştürülmüş
../içeren yolu işleyerek saldırgana hassas veriler gönderebilir
- Örnek PoC,
- Saldırgan
cuckoo.confdosyasını indirip Flask PIN hesaplaması için gereken hassas bilgileri toplayarak Sandbox Host üzerinde RCE elde edebilir- Demo videosu Video 11 olarak sunulmuştur
Argument Splitting: Komut satırı ayrıştırmasını değiştiren Best-Fit
- Argument Splitting,
GetCommandLineAçıktısında veya Unicode olmayanint main()yolunda komut satırı dizgesinin değişerek argümanların ayrıldığı bir saldırıdır- İlgili API ve yollar:
GetCommandLineA,int main() - Etkilenen code page’ler: 874, 125x, 932(JP), 949(KR)
- Tehdit oluşturan karakterler:
"U+FF02,\U+FF3C,¥U+00A5(JP),₩U+20A9(KR)
- İlgili API ve yollar:
- Örnek PHP kodu, URL’yi
escapeshellarg()ile güvenli şekilde sarıpwget.exe -qçalıştırsa da" --use-askpass=calc "girdisiylecalc.exeçalıştırmak mümkündür- Aynı girdi Node.js, Rust, Python’a çevrilse de savunma sağlanmaz
- Python’ın güncel sürümündeki
subprocess.run(["wget", "-q", ...])örneğinde de çalışır
- Windows, yeni sürece tüm komut satırını tek bir dizge olarak geçirir ve çalıştırılabilir dosya bunu doğrudan ayrıştırır
- UNIX türevlerinde olduğu gibi argüman dizisinin her zaman aktarıldığı bir yapı değildir
CreateProcessAPI’silpCommandLineparametresini doğrudan alır
- Genel komut satırı ayrıştırmasında önemli karakterler boşluk·tab, double quote ve backslash’tir
- Boşluk ve tab, quote mode’da değilken argümanları ayırır
"quote mode’u değiştirir\belirli dizilerde double quote ve backslash’i escape eder
- Çoğu dilin standart kütüphanesi kullanıcı argümanlarını bu kurallara göre escape eder, ancak escape işlemi Best-Fit dönüşümünden önce biter
- PHP
escapeshellarg, double quote’u boşluğa çevirir, argümanı quote içine alır ve backslash’i işler - Python
subprocess, Microsoft CRT komut satırı ayrıştırma kurallarına uygun şekildelist2cmdlineile escape eder - Sonraki ANSI dönüşümünde
"U+FF02,"U+0022’ye dönüşürse özgün komut satırı sözdizimi değişir
- PHP
- Yalnızca
int main()kullanan programlar da savunmasız olabilir- Derleyici ikili dosyada
mainCRTStartupoluşturur ve bu başlangıç fonksiyonu CRT kütüphanesine bağlanır - CRT içi komut satırını ANSI API ile alıp ayrıştırırsa Best-Fit dönüşümü devreye girer
- Bu davranış nedeniyle saldırıyı yalnızca belirli bir programlama dilinin standart kütüphanesiyle tamamen engellemek zordur
- Derleyici ikili dosyada
Argument Splitting gerçek vakaları
- ElFinder, PHP backend tabanlı açık kaynaklı bir web dosya yöneticisidir ve varsayılan olarak Windows sunucularını ve arşiv oluşturma/çıkarma işlemlerini destekler
- Arşiv işlemesi shell command çalıştırarak uygulanmıştır ve argümanlar
escapeshellargile escape edilir - tar biçimi işlemede Windows’un yerleşik
tar.exearacı kullanılır aaa" "--use-compress-program=calc" "bbb.targibi bir tar dosya adıyla--use-compress-programargümanı enjekte edilerek keyfî komut çalıştırma mümkündür- Demo, İngilizce yapılandırılmış Windows server ve Code Page 1252 temel alınarak yapılmıştır; 125x code page’leri ve Code Page 874’te de çalışması gerektiği belirtilmiştir
- Demo videosu Video 12 olarak sunulmuştur
- Arşiv işlemesi shell command çalıştırarak uygulanmıştır ve argümanlar
- TortoiseGit’te kullanılan değiştirilmiş
plink.exevakasında, clone girdisine kötü amaçlı URI verilirse kod çalıştırma tetiklenebilir- Ayrıntılar curated list içinde görülebilir
- Demo videosu Video 13
- RStudio, SVN sürüm kontrolünü destekler; kötü amaçlı hazırlanmış bir klasörde SVN projesi varsa tek tıklamayla hesap makinesi çalıştırmak mümkündür
- Ayrıntılar curated list içinde görülebilir
- Demo videosu Video 14
- Microsoft Excel vakası, Argument Splitting ile Windows’un “Open-With” özelliğini birleştiren CVE-2024-49026’dır
- Windows, dosya uzantılarına göre handler table tutar; bu,
ftypeveassocile kontrol edilebilir - Dosya adı handler programının argümanlarının bir parçası hâline geldiğinden, saldırı dosya adı üzerinden uygulanabilir
- Nokta, slash, backslash ve double quote karakterleri fullwidth biçimlerine çevrilmiş bir dosya adıyla
Excel.exeüzerinde argument injection tetiklenir - Excel’in kendisinde ek sömürüye uygun argümanlar bulunmadığından RCE elde etmek için NTLM Relay ve RBCD/ADCS birlikte kullanılır
- Demo videosu Video 15
- Windows, dosya uzantılarına göre handler table tutar; bu,
Ortam Değişkeni Karmaşası
- Ortam Değişkeni Karmaşası,
GetEnvironmentVariableA,GetEnvironmentStringsA,char *getenv()ortam değişkenlerinin Best-Fit dönüşümünden geçmiş sürümünü döndürdüğünde ortaya çıkar- Etkilenen kod sayfası ve tehdit karakterleri belirli değildir
- Apache HTTPd örneğinde 0x00-0xFF aralığı devreye girer
- Bu saldırının mümkün olması için ortam değişkenlerinin kullanıcı tarafından kontrol edilebilmesi gerekir
- Üst sürecin oluşturduğu alt sürece bilgi aktardığı durumlar buna örnektir
- CGI’de query string, HTTP header gibi HTTP isteği bilgilerinin önemli bir kısmı ortam değişkenleri olarak aktarılır
- WAF atlatma örneği, CGI betiğinin bir routing service gibi davrandığı durumu ele alır
- Apache yapılandırmasında,
REQUEST_URIiçinde/admingeçen istekleri reddederek/cgi.pl/adminiçin uzaktan erişimi engelleyen bir kural bulunur - Windows Perl’in WorstFit davranışı nedeniyle
adminiçindeki bazı karakterler Best-Fit equivalent ile değiştirilirse kural atlatılabilir - Code Page 1250’de
àU+00E0, ANSI dönüşümü sırasındaakarakterine dönüşür /cgi.pl/%E0dministeği sunucu tarafındaki kurala göre farklı bir yol gibi görünür; ancak Perl CGI betiğiPATH_INFOdeğerini ANSI API ile okuduğunda/adminolarak işlenir
- Apache yapılandırmasında,
- Windows üzerinde PHP-CGI’de belirli yapılandırmalarda dosya varlığı doğrulama oracle’ı ve potansiyel LFI doğrulanmıştır
- Bunun nedeni
PATH_INFOve diğer path ile ilgili ortam değişkenlerinin işlenme biçimidir /index.php/foo/baristeği Apache açısındanREDIRECT_URL,REQUEST_URI,PATH_INFO,PATH_TRANSLATEDgibi ortam değişkenleri olarak aktarılır- Yalnızca bu bilgiyle PHP dosya adı ile ek
PATH_INFOsınırını net biçimde ayırmak zordur;php-cgi.exebunu yorumlar
- Bunun nedeni
- Japonca kod sayfasında
¥kullanıldığında web sunucusu ile PHP-CGI’nin path yorumlaması farklılaşır- Web sunucusu
/..¥..¥windows/win.ini/foodeğerinin tamamını ekPATH_INFOolarak işler - PHP-CGI ise
REQUEST_URI=/index.php/..\..\windows/win.ini/foogibi dönüştürülmüş bir değer alır ve gerçek PHP dosyası ilePATH_INFOdeğerini ayırma sürecinde karışıklık yaşar - Apache’de var olmayan dosyalar ile var olan dosyaların yanıt farkından file existence oracle mümkün olur
- IIS’te
doc_rootdirective’i ayarlanmışsa/index.php/..¥..¥..¥windows/win.ini/gibi bir path ileC:\Windows\win.inidosyasını include edip okumaya dayalı LFI mümkün olur - Dahil edilen dosya çalıştırılabilir durumdaysa veya kullanıcının kontrol edebildiği kod içeriyorsa potansiyel RCE’ye yol açabilir; ancak bu senaryo gerçek uygulamalarda nadir görülen bir bug’a daha yakın sınıflandırılır
- Web sunucusu
Açıklama ve Düzeltme Sürecindeki Zorluklar
- Araştırma ekibi, programlama dilleri, açık kaynak projeleri ve Windows’un yerleşik CLI programlarındaki çeşitli sorunları ilgili upstream maintainer’lara bildirdi
- En fazla tartışma Argument Splitting konusunda yaşandı
- Bazı vendor’lar kullanıcı girdisini komut satırına aktarmanın başlı başına bir zafiyet olduğunu değerlendirdi
- Sorumluluğun kime ait olduğunun belirsiz olması da sorun yarattı
- Sorunlu kod, derleme sırasında otomatik eklenen
mainCRTStartup()ile MSVCRT/UCRT içindeki ANSI API çağrılarına yayılıyor - Bunun geliştiricinin
wmain()kullanmamasından mı, yoksa CRT’nin komut satırını yanlış bölüpmain()fonksiyonuna hatalı argümanlar iletmesinden mi kaynaklandığını ayırmak zor - Bazı projeler yalnızca kaynak kod sağlıyor; Windows prebuilt executable dosyaları ise internetteki üçüncü taraf gönüllüler tarafından dağıtılıyor
- Sorunlu kod, derleme sırasında otomatik eklenen
- Düzeltme, yalnızca
main()fonksiyonunu wide-character sürüme çevirmekten ibaret değil- Fonksiyon imzası değiştiğinde değişken tanımları ve argüman ayrıştırma mantığı
char *temelindenwchar_t *temeline yeniden yazılmalı - Bu süreç zahmetli ve hataya açık
- Fonksiyon imzası değiştiğinde değişken tanımları ve argüman ayrıştırma mantığı
- Curl, bunun bir Windows özelliği olduğunu söyleyerek düzeltme planı olmadığını belirtti; Microsoft’un port ettiği Curl ise entry’yi
wmain()olarak düzelttiği için Windows’un yerleşikcurl.exedosyası etkilenmiyor- Curl resmi build binary’leri Argument Splitting saldırısından etkileniyor
- Tam rapor HackerOne üzerinde yayımlandı
- OpenSSL,
OPENSSL_WIN32_UTF8ortam değişkeniyle argümanları wide character biçiminde işleyebiliyor- Asıl amaç UI’da UTF-8 görüntüleme sorununu düzeltmekti, ancak Argument Splitting saldırısını da hafifletiyor
- Varsayılan OpenSSL kullanımında geliştiriciler çoğu zaman bu ortam değişkenini ayarlamaları gerektiğini bilmiyor;
-engineargümanı kullanılarak keyfi kod çalıştırma mümkün olabiliyor
- Perl’in resmi dağıtımı Windows prebuilt executable sunmuyor; Strawberry Perl ve ActiveState Perl gibi üçüncü taraf installer’lar yaygın olarak kullanılıyor
- İki dağıtım da Argument Splitting saldırısından etkileniyor
- Perl maintainer’ı ile yapılan görüşmeler sonucunda bunun “Perl bug’ından çok Microsoft bug’ına yakın” olduğu sonucuna varıldı ve konu şu anda çözülmemiş durumda
- Microsoft’a MSRC üzerinden üç bildirim yapıldı ve hepsi başlangıçta ciddiyet kriterlerini karşılamadığı gerekçesiyle reddedildi
- Birkaç kez yeniden açıldıktan sonra yalnızca Excel örneği üçüncü denemeden sonra kabul edildi
- Diğer örnekler hâlâ çözülmemiş durumda
- MSRC, bunun ayrı bir uygulamanın güvenilmeyen girdiyi komut satırına koyup çalıştırmasına dayanan bir zafiyete bağlı olduğunu; bunu istismar edilebilir kılan technique’in kendisinin zafiyet şartlarını karşılamadığını belirtti
- CERT/CC’den de yardım istendi ve Microsoft birkaç ay sonra
GetCommandLineAbelgelerine güvenlik uyarısı ekledi- Uyarı yalnızca
GetCommandLineAiçin eklendi; dikkat gerektiren başka ANSI API’ler de var
- Uyarı yalnızca
Bildirilen Etkilenen Hedefler ve Durumları
- Açıklama sürecinde doğrulanıp bildirilen kalemler şunlardır
- 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
Azaltma önlemleri ve kalan saldırı yüzeyi
- WorstFit saldırısı işletim sistemi düzeyinde bir sorun olduğundan, Microsoft tüm Windows sürümlerinde UTF-8’i varsayılan olarak etkinleştirene kadar benzer sorunlar tekrar ortaya çıkmaya devam edebilir
- Kullanıcıların yapabileceği şey, Windows’un UTF-8 seçeneğini kontrol edip etkinleştirmektir
- Bu özellik hâlâ beta aşamasında olarak işaretleniyor ve yan etkilerinin olup olmadığı kesin değil
- Geliştiriciler mümkün olduğunca Wide Character API kullanmalıdır
- CRT de
_wgetcwd,_wgetenvgibi wide character sürümlerini sunar - non-wide yollar kullanılmaya devam edilirse iç uygulama ANSI API’yi çağırabilir ve WorstFit saldırılarına açık kalabilir
- CRT de
- Windows’un geriye dönük uyumluluğu nedeniyle ANSI API’nin gizli olduğu daha fazla yer olabilir
- Örneğin
RegQueryValueAgibi Windows Registry sorguları etkilenebilir, ancak savunmasız senaryoların bulunması gerekir - Araştırma ekibi Active Directory’de de Best-Fit davranışı gözlemledi
- Örneğin
1 yorum
Hacker News yorumları
Bu oldukça çetrefilli bir sorun. Microsoft’un “best fit” kod eşlemesi, geniş Unicode’u ASCII’ye dönüştüren, açıkta olsa da fiilen “hissiyata dayalı” çalışan bir eşleyici ve sistemin geneline yayılmış durumda.
Bu eşleyici pek çok yerde varsayılan olarak bağlanıyor ve Microsoft’un geriye dönük uyumluluğa bakış biçimi nedeniyle dâhil edilmeye devam edecek gibi görünüyor. Exploit’ler çoğunlukla sıra dışı kod noktalarının eğik çizgi, tire, tırnak işareti gibi karakterlere “hissiyata göre” eşlenmesinden çıkıyor. Modern dil içinde doğru Unicode olarak denetleniyorlar, ama shell komutuna veya Win32 API’ye geçince denetimi devrettikten sonra farklı bir şekilde daraltılarak dönüştürülüyorlar. curl bakımcısının dediği gibi burada “curl mağdur”; mesele suçlunun kim olduğu. Sunucu, kullanıcı girdisini doğrularken ve sistem kütüphanesine geçirirken onu farklı biçimde ezip büzüyorsa sonunda sorun çıkar. Win32 tarafında best fit dönüşümünü kapatmaya yarayan bir seçenek çözüm olabilir, ama Windows uzmanı olmadığım için bu bir tahmin. Öyle olsa bile resmi API’lerle ya da bunu hâlâ kapatmamış yazılımlarla etkileşim sürer.
"a"ile değil"w"ile biten işlevleri kullanmaktır. Bu yöntem"\\?\"öneki eklenirse ya da manifest doğru ayarlanırsa 260 karakteri aşan yol sorununu da beraber çözer; Windows XP’den beri mümkündür ve önerilmektedir.Unicode olmayan API’nin hâlâ neden bu kadar yaygın kullanıldığını pek bilmiyorum. Bunun Windows 98 veya Windows 2000’i destekleme isteğinden kaynaklandığını hayal etmek zor.
Ayrıca gereken şey bir tür linting. Modern uygulamalarda ANSI WinAPI işlevlerini çağırmak için genelde bir neden yok. Locale’i UTF-8’e ayarlayıp yalnızca 8 bitlik işlevleri kullanma yolu da olabilir, ama ne kadar iyi çalıştığını bilmiyorum.
argv,printf,std::cout’un UTF-8 ile çalışmasını ve tuhaf dönüşümler olmadan yalnızca WinAPI için UTF-8/UTF-16 dönüştürme işlevlerinin kullanılmasını sağlayan bazı ayarlar ve header’lar olduğunu da biliyorum. Microsoft’un bu prosedürü tek bir yerde belgelemesi gerekiyor.Bu bir dereceye kadar tahmin edilebilir, ama W/A karmaşasının ortaya çıktığı dönemlerde yaklaşık 10 yıl Windows geliştirme ve Wine API hack’leri yapmış biri olarak benim için de yeniydi.
Windows, Munchkin kart oyunu gibi: çeşitli özellikler tesadüfen birbirine denk gelince inanılması güç derecede rastgele ve güçlü exploit’lerde birleşebiliyor. ANSI alt sistemini UTF-8’e dönüştürüyor olmaları sevindirici; teoride bu tür sorunların çoğunu hafifletebilir. Rust ekibinin süreç oluşturma API’sine bir düzeltme daha yapmak zorunda kalıp kalmayacağını da merak ediyorum.
Elbette Rust süreç sınırının ötesinde olup biteni kontrol edemez. Rust’ın çalıştırdığı uygulama ANSI API kullanırsa sorun o tarafta ortaya çıkar, ama bu o uygulamanın sorumluluğudur.
“ANSI’yi aşamalı olarak kaldırıp Wide Character API kullanımını önermek”, doğru hatırlıyorsam NT 3.5 zamanından beri Microsoft’un resmi tutumuydu.
Ne yazık ki büyük engellerden biri Microsoft’un C/C++ çalışma zamanı kütüphanesi
msvcrt.dll’nin uygulanış biçimi._wfopen(),_wgetenv()gibi standart dışı wide işlevler içeride Win API’nin W işlevlerini kullanıyor; fakatfopen(),getenv()gibi standart narrow işlevler wide sürüme dönüştürmek yerine doğrudan A işlevlerini kullanıyor. A işlevleri de genelde Unicode dönüşüm hatasını bildirmek yerine best-fit yöntemiyle üstünü örtüyor. C ile yazılmış yazılımı Windows’a port eden biri, standart işlevlerin tamamını Microsoft’a özgü taşınabilir olmayan işlevlerle değiştirmek istemez. O noktadan sonra bu fiilen baştan yazmak olur.activeCodePagedeğerini UTF-8 yapıp yalnızca “ANSI” işlevleri kullanın deniyor gibiydi.mainvefopengibi standart işlevler wide karşılıklarına#defineedilir.Böyle olunca
char*ve süslemesiz string literal’ları öylece kullanamazsınız; bu yüzden Linux’tachar, Windows’tawchar_tolantchartürünü ve string literal’lar için_T()makrosunu tanımlarsınız. Genellikle fazla düşünmeden iyi çalışır.-Wvaryantı değil-Avaryantının önce çıkması.robots.txtiçinde tuhaf bir şey mi var bilmiyorum, ama yeni kodda-Wvaryantını kullanmayı öneren bir API’nin varsayılan olarak legacy API’yi döndürmesi garip.msvcrt.dll, Universal C Runtime (UCRT)[1] ile değiştirildi ve UCRT C99 ile uyumlu.Kendi yazdığınız uygulamalarda veya patch’lediğiniz EXE’lerde “Ansi” kod sayfasını fiilen UTF-8’e zorlamanın iki yolu var.
Biri manifest dosyası kullanmak; Windows 10’un belirli bir build’inden itibaren çalışıyor. Derlemeden sonra herhangi bir EXE’ye de uygulanabildiği için bir programa zorla UTF-8 desteği ekleyebilirsiniz. Özellikle konsol modu programları için kullanışlı. Diğeri “App Locale” türü araçların kullandığı hack’i kullanmak. Yöntemlerden biri NTDLL’nin belgelenmemiş bir işlev çağrısını içeriyor. Tam olarak hangi işlevin gerektiğini bilmiyorum ama
RtlInitNlsTablesveRtlResetRtlTranslationsilgili olabilir.Microsoft'un tüm Windows sürümlerinde UTF-8'i varsayılan olarak açma ihtimalinden pek emin değilim. Belirli bir kod sayfasını ya da karakter başına 1 bayt varsayan çok sayıda eski uygulama olduğu için bozulabilirler.
Daha incelikli olarak, wide karakterden ANSI'ye dönüştürürken bayt sayısının artmayacağını varsayıp mevcut tamponu yeniden kullanan uygulamalar da var. UTF-8'de bu doğru değil; mevcut kod sayfalarının çoğunda ise genelde doğru olduğu için yeni güvenlik açıkları ortaya çıkabilir. Bence Win32
xxxAAPI'lerinden Best-Fit mantığını kaldırıp, eşlenemeyen karakterleri ortak meta anlamı olmayanxgibi bir karakterle değiştirmek çok daha az kırıcı olur.[0] https://tambre.ee/blog/adobe_after_effects_windows_utf-8/
Best-Fit eşlemenin yol açtığı sorunlara bakınca bunu varsayılan yapmak da makul, ama Microsoft'un kullanıcıların eski kodu kolayca çalıştırmanın bir yolunu bulmasına yardım etmesi gerekir. Daha az makul bir yöntem, Best-Fit eşlemede “özel” ASCII karakterlerine giden tüm eşlemeleri kaldırmak olabilir; ancak bu, CRT'yi statik bağlayan uygulamalara yardımcı olmaz. Güvenlik açığını da gidermediği için iyi bir çözüm değil. Bazen güvenlik açıkları geriye dönük uyumluluğu bozmayı zorlamak için motivasyon olur.
Microsoft bu sorundan en az 1 yıldır haberdardı. Çünkü best-fit eşleme kullanımını açıkça önermeyen CA2101[1] adlı özel bir kod analizi kuralı yayımladı.
Kural açıklamasında güvenlik açıklarından söz ediliyordu, ancak ayrıntılar bilinçli olarak muğlak bırakılmıştı.
[1] https://learn.microsoft.com/en-us/dotnet/fundamentals/code-a...
Her şeyi
char *'danwchar *'a çevirmek gerekmiyor. Alınan wide karakterleri UTF-8'e dönüştürüp ya da eşleşmemiş surrogate gibi geçersiz dizilere bile izin vermek istiyorsanız Rust'taki WTF-8 benzeri bir şeye dönüştürüpcharkullanmaya devam edebilirsiniz.Elbette ANSI veya OEMCP dizgelerini UTF-8 dizgeleriyle karıştırmamaya dikkat etmek gerekir; ama sadece UTF-8 kullanırsanız iş kolay. Klasik https://utf8everywhere.org/ sitesinin önerdiği yaklaşım da bu.
Kişisel Windows bilgisayarımda birkaç yıldır UTF-8 modunu açmış olduğum için bu hatadan tesadüfen kaçınmışım. Yazının alt kısmında gösterilen ayar.
Eski yabancı oyunlar bozuk karakterler gösterdiği için açmıştım; “Beta” olarak işaretli olmasına rağmen herhangi bir hata ya da yan etki hissetmedim.
Beta onay kutusunun manifest'te
ActiveCodePagedeğerini UTF-8 olarak ayarlamakla aynı olup olmadığını merak ediyordum; belgelere[0] bakınca GDI'nin süreç başına kod sayfasını izlemediği, yalnızca onay kutusunun ayarladığı tek bir global kod sayfasını izlediği açıkça belirtilmiş.Kendi uygulamanızda
*AAPI'leri için tamamen UTF-8'e opt-in yapamamak biraz üzücü. Yine de yazıda vurgulanan sorunlar için bunun hâlâ geçerli bir geçici çözüm ya da savunmayı derinleştirme aracı olabileceğini düşünüyorum.[0] https://learn.microsoft.com/en-us/windows/apps/design/global...
Aman Tanrım. Windows API'nin bu tür best-fit dönüşümü sağladığını biliyordum, ama varsayılan kod sayfam olan 949'da[1] bunun çeşitli ANSI işlevlerinin varsayılan davranışı olduğunu bilmiyordum.
Bu noktada
getsgibi düpedüz yasaklanmalı. [1] UTF-8 kod sayfası 65001'in var olduğunu biliyorum. Uzun süre gerçekten kullanılamayacak düzeydeydi ve hâlâ uyumluluk sorunları yaşıyor.