Palo Alto Cortex XDR: Ön Tanımlı BIOC Kurallarını Çözme ve Atlatma
🇹🇷 Palo Alto Cortex XDR'ın davranışsal kurallarının (BIOC) şifresini çözme ve ccmcache istisnası gibi sabit kodlanmış global beyaz listeleri kullanarak EDR tespitlerini atlatma üzerine derinlemesine bir analiz.
Bu yazı, InfoGuard blogunda yayınlanan orijinal makalenin Türkçe çevirisidir.
Özet
Windows Cortex XDR ajanı, davranışsal tespitler için CLIPS kurallarını kullanır. Bu kurallar, içerik güncellemeleriyle birlikte şifrelenmiş olarak gönderilir. Biz bu kuralların şifresini çözdük ve bu kuralları atlatmak için suistimal edilebilecek, global beyaz listeler (whitelists) dahil olmak üzere çok sayıda sabit kodlanmış istisna keşfettik. Örneğin, bir işlemin (process) komut satırı argümanları :\Windows\ccmcache içeriyorsa, davranışsal tespitlerin yaklaşık yarısından muaf tutuluyor. Bu durum, bir saldırganın örneğin LSASS belleğini herhangi bir tespit tetiklemeden basit ve bilinen tekniklerle dökmesini (dump etmesini) mümkün kılıyor.
Başlangıçta Cortex Windows ajanının 8.7 ve 8.8 sürümlerini 1790-16658 içerik sürümüyle inceledik. Palo Alto, Şubat 2026 sonunda 2160 içerik sürümüyle birlikte Ajan Sürümü 9.1‘de bu global beyaz listeleri kaldırdı.
Düz metin kuralları ve şifre çözme betikleri GitHub üzerinde mevcuttur.
Giriş
Palo Alto Cortex XDR gibi EDR/XDR ajanları; statik imza tabanlı tespitler, yerel dosya analizi veya makine öğrenimi tabanlı tespitler gibi çeşitli yöntemler kullanır. Bunlar arasında en önemlilerinden biri Davranışsal İhlal Göstergeleri (Behavioral Indicators of Compromise - BIOCs) kurallarıdır. Yakın zamanda gerçekleştirdiğimiz bir Red Team operasyonu sırasında, Cortex XDR ajanının (sürüm 8.8), daha önce tespit edilmeyen bazı teknikleri tespit ettiğini fark ettik. Cortex portalı, uyarının tam olarak neyin tetiklediğine dair sınırlı ayrıntı sunuyor. Elastic veya HarfangLab gibi bazı istisnalar dışında, çoğu üretici tespit kural setlerini kapalı tutar. Bu nedenle, içerik güncellemeleri aracılığıyla düzenli olarak güncellenen asıl kurallara erişmeye çalıştık.
Kuralları Bulma ve Şifrelerini Çözme
İçerik güncellemeleri çok sayıda dosya içerir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
ls content-1790-16658
ace-sandbox-plugin-dev-win-x86_64.zip network_inspect_policies_encrypted-64.zip
ace-sandbox-plugin-no-ocr-prod-win-x86_64.zip network_inspect_policies_encrypted_7_5-64.zip
ace-sandbox-plugin-prod-win-x86_64.zip network_inspect_policies_encrypted_pre_2025_ev-64.zip
agent_scripts_win_arm64.zip network_inspect_policies_slowroll-64.zip
agent_scripts_win_x64.zip network_inspect_policies_threat_hunting.zip
agent_scripts_win_x86.zip network_inspect_pre_2025_ev-64.zip
cert.zip network_inspect_slowroll-64.zip
collector-64-legacy.zip nmap-win32.zip
collector-64.zip payload-32-one-dir-openssl3.zip
content_processed.zip payload-32-one-dir.zip
content_raw.zip payload-32.zip
cwp-compliance.zip payload-64-one-dir.zip
cyber.zip payload-64.zip
dse_config.zip payload-win-arm64-one-dir.zip
dse_ng.zip payload-win-x86_64-one-dir-openssl3.zip
dse.zip payload-win-x86_64-one-dir.zip
edrdotnet_slowroll.zip periodic_scripts.zip
edrdotnet.zip pki-fedramp.zip
env.zip pki-gov-fedramp.zip
infra.zip pki.zip
ivanti-content-win.zip recognizer_plugin_32.zip
ivanti-deltas-win.zip recognizer_plugin_64.zip
local_analysis_plugin_32.zip recognizer_plugin_arm64.zip
local_analysis_plugin_64.zip threat_hunting_ng.zip
local_analysis_plugin_arm64.zip threat_hunting.zip
manifest.json tsf_collector.zip
ml_plugin_32.zip va-scanner-winx64.zip
ml_plugin_64.zip va-scanner-winx86.zip
ml_plugin_8_4_32.zip winpmem-32.zip
ml_plugin_8_4_64.zip winpmem-64.zip
ml_plugin_arm64.zip xdrhealth-32.zip
model_doc_ole_7_2.zip xdrhealth-64.zip
model_doc_openXml_7_2.zip xdrhealth-ARM64.zip
model_js_8_8.zip yara_plugin_32.zip
model_macro_7_1.zip yara_plugin_64.zip
model_pe_7_1.zip yara_plugin_8_4_32.zip
model_powershell_7_3.zip yara_plugin_8_4_64.zip
model_powershell_8_4.zip yara_plugin_arm64.zip
model_vbs_8_6.zip yara_signature_rules_encrypted_mitre.zip
network_inspect-64.zip yara_signature_rules_encrypted.zip
network_inspect_7_5-64.zip
Bu dosyalar C:\ProgramData\Cyvera\LocalSystem\Download\content\ dizinine açılır. SafeBreach’in bu blog yazısında belirttiği üzere, davranışsal kuralların meta verileri dse_rules_config.lua dosyasında saklanır. Bu dosyanın içeriği, blog yazısında anlatıldığı gibi beyaz listeleri suistimal ederek Mimikatz tespitlerinden kaçınmak için zaten kullanılabiliyordu. Ancak asıl tespit mantığı ve diğer istisnalar bu dosyada yer almıyor.
İçerik şu şekilde görünmektedir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
["bioc.ntsystemdebugcontrol_get_eprocess"] = {
versions = {"8_8_0","8_8_0_999"},
signatureConfiguration = {
default = {
settings = {
action = "silent",
friendlyName = "ntsystemdebugcontrol_get_eprocess",
technique_id = {"T1055"},
tactic_id = {"TA0004","TA0005"},
mth_action = "report",
mth_severity = 1,
severity = 4,
external_description = "Lsass Dump Attempt",
module = 2
}
}
}
},
Kuralların nerede saklandığını tahmin etmek zor değil, ancak bunlar şifrelenmiştir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PS C:\ProgramData\Cyvera\LocalSystem\Download\content> ls dse*
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 6/18/2025 12:16 AM 195276 dse.lua
-a---- 6/18/2025 12:16 AM 23703 dse_common.lua
-a---- 6/18/2025 12:16 AM 3228 dse_config_schema.json
-a---- 6/18/2025 12:16 AM 133964 dse_internals.json
-a---- 6/18/2025 12:16 AM 2998 dse_modules.json
-a---- 6/18/2025 12:16 AM 1308480 dse_rules_8_4_0_windows_encrypt.clp
-a---- 6/18/2025 12:16 AM 1308752 dse_rules_8_5_0_windows_encrypt.clp
-a---- 6/18/2025 12:16 AM 1311456 dse_rules_8_6_0_windows_encrypt.clp
-a---- 6/18/2025 12:16 AM 1313808 dse_rules_8_7_0_windows_encrypt.clp
-a---- 6/18/2025 12:16 AM 1319536 dse_rules_8_8_0_windows_encrypt.clp
-a---- 6/18/2025 12:16 AM 1319920 dse_rules_8_9_0_windows_encrypt.clp
-a---- 6/18/2025 12:16 AM 15273694 dse_rules_config.lua
Düz Metin Kuralları Elde Etme
Bu dosyaların nerede ve nasıl deşifre edildiğini belirlemek için, dse_rules_8_7_0_windows_encrypt.clp dosyası üzerindeki okuma işlemi için ProcMon kullanarak yığın izleme (stack trace) aldım:
Neyse ki, cysvc.dll hata ayıklama dizelerini (debug strings) içeriyordu ve bunlar küçük bir betik yardımıyla IDA Pro’daki fonksiyonları yeniden adlandırmak için kullanıldı.
dse::ClipsEngineFilter::DecryptClpData() adlı bir fonksiyon kulağa oldukça vaat edici geliyordu. EDR’nin kendi kendine koruma mekanizmalarını atlatmak için WinDBG’yi Kernel-Debugger olarak kullanarak bu fonksiyona bir kesme noktası (breakpoint) koydum. Ardından, fonksiyonun dört giriş parametresinin amacını anlamak için kaynak kodu (decompiled code) analiz ettim. Bu noktada, kaynak kodunu yorumlama ve parametrelerin amacını saptama konusunda LLM’lerin (Büyük Dil Modelleri) oldukça etkili olduğunu gördük.
Aşağıda görüldüğü gibi, ilk parametre şifrelenmiş içeriktir:
1
2
3
4
5
6
7
8
9
10
kd> dps rcx L1
000001ff`12ff4f80 000001ff`27c90020
kd> db 000001ff`27c90020
000001ff`27c90020 6f c4 62 6e dd 4e d9 99-16 32 5a e2 0a e4 b5 07 o.bn.N...2Z.....
000001ff`27c90030 cf 78 be c5 ec 7d 8f c6-29 5a f4 69 a9 fc 79 cb .x...}..)Z.i..y.
000001ff`27c90040 29 42 7c 9d d4 93 09 ff-d3 00 90 e5 f1 7d f7 ba )B|..........}..
000001ff`27c90050 b1 e7 07 f4 a8 2d c5 00-62 95 f5 cc 0e ff 48 5e .....-..b.....H^
000001ff`27c90060 bd d3 e4 73 65 12 96 31-aa 0c 27 d0 70 8b b6 84 ...se..1..'.p...
000001ff`27c90070 7c bf e2 3e 80 7d d8 2a-a0 c3 29 5e c4 3e b8 d8 |..>.}.*..)^.>..
000001ff`27c90080 9f 62 01 58 a0 3f 26 38-97 b1 f8 e2 15 c2 7f d2 .b.X.?&8........
1
2
3
4
5
6
7
8
$ hexdump -C dse_rules_8_7_0_windows_encrypt.clp
00000000 6f c4 62 6e dd 4e d9 99 16 32 5a e2 0a e4 b5 07 |o.bn.N...2Z.....|
00000010 cf 78 be c5 ec 7d 8f c6 29 5a f4 69 a9 fc 79 cb |.x...}..)Z.i..y.|
00000020 29 42 7c 9d d4 93 09 ff d3 00 90 e5 f1 7d f7 ba |)B|..........}..|
00000030 b1 e7 07 f4 a8 2d c5 00 62 95 f5 cc 0e ff 48 5e |.....-..b.....H^|
00000040 bd d3 e4 73 65 12 96 31 aa 0c 27 d0 70 8b b6 84 |...se..1..'.p...|
00000050 7c bf e2 3e 80 7d d8 2a a0 c3 29 5e c4 3e b8 d8 ||..>.}.*..)^.>..|
00000060 9f 62 01 58 a0 3f 26 38 97 b1 f8 e2 15 c2 7f d2 |.b.X.?&8........|
İkinci parametre, şifre çözme anahtarının bir parçasını içeren bir JSON belgesini içerirken, üçüncü parametre şifreleme ile ilgili değildir.
Dördüncü parametre ise fonksiyonun tamamlanmasının ardından deşifre edilmiş içeriği barındırır:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kd> dps r9 L1
00000080`a47fd880 00000000`00000000
kd> pt
cysvc!CySvcServiceHandler+0x89a724:
0033:00007ffc`4f50e3b4 c3 ret
kd> dps 00000080`a47fd880
00000080`a47fd880 000001ff`18800020
kd> db 000001ff`18800020
000001ff`18800020 28 64 65 66 74 65 6d 70-6c 61 74 65 20 69 6e 74 (deftemplate int
000001ff`18800030 65 72 6e 61 6c 2e 64 65-62 75 67 5f 62 75 69 6c ernal.debug_buil
000001ff`18800040 64 5f 74 69 6d 65 73 74-61 6d 70 20 28 73 6c 6f d_timestamp (slo
000001ff`18800050 74 20 63 69 64 29 20 28-73 6c 6f 74 20 70 72 69 t cid) (slot pri
000001ff`18800060 6f 29 20 28 73 6c 6f 74-20 74 69 6d 65 73 74 61 o) (slot timesta
000001ff`18800070 6d 70 29 20 28 73 6c 6f-74 20 62 75 69 6c 64 5f mp) (slot build_
000001ff`18800080 74 69 6d 65 73 74 61 6d-70 29 29 0a 28 64 65 66 timestamp)).(def
000001ff`18800090 74 65 6d 70 6c 61 74 65-20 64 69 72 65 63 74 6f template directo
kd> .writemem C:\tmp\dse_decrypt_dump.txt 000001ff18800020 000001ff18800020+00852647
Düz metin CLIPS kuralları daha sonra .writemem kullanılarak bir dosyaya döküldü. Deşifre edilmiş kurallar GitHub üzerinde mevcuttur.
Şifre Çözme Anahtarlarını Elde Etme
Algoritma, anahtar (key) ve IV’nin saptanması, bir LLM’nin yardımıyla nispeten basit oldu.
Binary dosyasında sabit kodlanmış bir dize mevcuttur, ancak anahtarın yalnızca bir kısmı kullanılır (belki de bu bir gizleme tekniği olarak düşünülmüştür):
Başka bir parça ise diskte düz metin olarak saklanan bir lua dosyasındadır:
Bu iki dize birleştirildiğinde aşağıdaki anahtar materyali ortaya çıkar:
1
2
3
Algoritma: aes-256-cbc
Anahtar (Key): gstHaxzjfuS1u=EsVU#QbD#d@MPhj!58
IV: HXZnRN5f*Gg$akQD
CyberChef kullanarak anahtar materyalinin doğru olduğu onaylanabilir:
Anahtarların tüm kiracılar (tenants) ve sürümler arasında aynı olduğu görülüyor.
İstisnaları ve Beyaz Listeleri Suistimal Etme
Kuralların çoğunda, onları atlatmak için kullanılabilecek basit istisnalar bulunmaktadır. Aşağıdaki örnek, SysInternals’ın ProcDump aracını kullanarak LSASS belleğini dökmek için kullanılan iyi bilinen bir yöntemin nasıl uygulanacağını göstermektedir.
Normalde, bu faaliyet tespit edilir ve engellenir:
Şimdi tetiklenen kuralı kontrol edebiliriz:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(defrule bioc.sync.procdump.1
(read_virtual_memory
(cid ?cid)
(instance_id ?instance_id)
(user_generic_value1 ?user_generic_value1_4
&: (and
(integerp ?user_generic_value1_4)
(eq (bit_and ?user_generic_value1_4 ?*Is_lsass_process*) ?*Is_lsass_process*)
(eq (bit_and ?user_generic_value1_4 ?*is_werfault_process*) 0)))
(bytes_copied 4)
(base_address ?base_address_4)
(buffer "40000000")
(timestamp ?timestamp_4))
(read_virtual_memory
(cid ?cid)
(instance_id ?instance_id)
(user_generic_value1 ?user_generic_value1_3
&: (and
(integerp ?user_generic_value1_3)
(eq (bit_and ?user_generic_value1_3 ?*Is_lsass_process*) ?*Is_lsass_process*)
(eq (bit_and ?user_generic_value1_3 ?*is_werfault_process*) 0)))
(bytes_copied 4)
(base_address ?base_address_3
&: (eq (bit_and ?base_address_4 -4294967296) (bit_and ?base_address_3 -4294967296)))
(buffer "68000000")
(timestamp ?timestamp_3
&: (and
(>= ?timestamp_4 ?timestamp_3)
(is_in_time_frame 20000000 ?timestamp_4 ?timestamp_3))))
(read_virtual_memory
(cid ?cid)
(instance_id ?instance_id)
(user_generic_value1 ?user_generic_value1_2
&: (and
(integerp ?user_generic_value1_2)
(eq (bit_and ?user_generic_value1_2 ?*Is_lsass_process*) ?*Is_lsass_process*)
(eq (bit_and ?user_generic_value1_2 ?*is_werfault_process*) 0)))
(bytes_copied 8)
(base_address ?base_address_2
&: (eq (bit_and ?base_address_3 -4294967296) (bit_and ?base_address_2 -4294967296)))
(buffer ?buffer_2
&: (eq ?base_address_2 (parse_hex (hex_reverse_byte_order ?buffer_2))))
(timestamp ?timestamp_2
&: (and
(>= ?timestamp_3 ?timestamp_2)
(is_in_time_frame 20000000 ?timestamp_3 ?timestamp_2))))
(read_virtual_memory
(cid ?cid)
(instance_id ?instance_id)
(user_generic_value1 ?user_generic_value1_1
&: (and
(integerp ?user_generic_value1_1)
(eq (bit_and ?user_generic_value1_1 ?*Is_lsass_process*) ?*Is_lsass_process*)
(eq (bit_and ?user_generic_value1_1 ?*is_werfault_process*) 0)))
(bytes_copied 8)
(base_address ?base_address_1
&: (eq (bit_and ?base_address_2 -4294967296) (bit_and ?base_address_1 -4294967296)))
(timestamp ?timestamp_1
&: (and
(>= ?timestamp_2 ?timestamp_1)
(is_in_time_frame 20000000 ?timestamp_2 ?timestamp_1))))
(or
(process_start
(cid ?cid)
(instance_id ?instance_id)
(file_info_description ?file_info_description)
(command_line ?command_line)
(file_info_original_name ?file_info_original_name)
(process_image_path ?process_image_path
&: (and
(not
(or
(and
(contains_one_of ?process_image_path "windows\\system32" "windows\\syswow64")
(starts_with (file_name ?process_image_path) "werfault"))
(contains_one_of (lowcase ?file_info_description) "windows problem reporting" "windows fault reporting")))
(not
(and
(or
(eq ?file_info_original_name "rdrleakdiag.exe")
(eq (file_name ?process_image_path) "rdrleakdiag.exe"))
(not
(contains_one_of ?command_line "-fullmemdmp" "/fullmemdmp" "-memdmp" "/memdmp")))))))
(not (process_start (cid ?cid) (instance_id ?instance_id))))
(not (bioc.sync.procdump.1 (cid ?cid) (instance_id ?instance_id)))
(internal.debug_build_timestamp)
(not (internal.global_whitelist (cid ?cid)))
=>
(assert (bioc.sync.procdump.1 (cid ?cid) (instance_id ?instance_id))))
werfault için birkaç istisna mevcuttur:
(contains_one_of (lowcase ?file_info_description) "windows problem reporting" "windows fault reporting")))
Bu dosya açıklaması bilgisini (file info description) procdump64.exe‘ye ekledikten sonra (ismine test.exe dedik), bu kural artık tetiklenmiyor:
Ancak, LSASS dökümünü engellemek için birkaç kural mevcut olduğundan başka bir kural tetiklendi. Fakat yukarıdaki kural, birkaç kuralı tek tek atlatmaktan daha hızlı bir şekilde hedefe ulaşmamızı sağlayan bir başka ilginç istisna içeriyor:
(not (internal.global_whitelist (cid ?cid)))
global_whitelist (global beyaz liste) şu şekilde tanımlanmıştır:
1
2
3
4
5
(defrule internal.global_whitelist
?the_f <- (process_start (cid ?cid) (command_line ?command_line &: (contains_one_of ?command_line ":\\windows\\ccmcache\\")))
(not (internal.global_whitelist (cid ?cid)))
=>
(assert (internal.global_whitelist (cid ?cid) (prio ?*retention_priority_higher*) (dbg_fact_id (fact-index ?the_f)))))
Atlatma (bypass) yöntemi son derece basittir:
Bu komut satırı ile başlatılan bir implant (zararlı yazılım), Cortex tespit ve engelleme kurallarını tetiklemeden ana bilgisayarda neredeyse her şeyi yapabilir.
İfşa Süreci (Disclosure Timeline)
| Tarih | Olay |
|---|---|
| 2025‑07‑28 | Global beyaz listelerin suistimalini Palo Alto Networks‘e bildirdik. |
| 2025‑08‑11 | Palo Alto Networks Ofansif Güvenlik Direktörü bizimle iletişime geçti ve 90 günlük ifşa politikasının ertelenmesini, ayrıca kuralların deşifre edilmesiyle ilgili daha ayrıntılı bilgi talep etti. |
| 2025‑08‑20 | Palo Alto Networks Ofansif Güvenlik Direktörü, takvimi görüşmek üzere bir toplantı talep etti. |
| 2025‑09‑01 | Palo Alto ile toplantı yapıldı. Şubat 2026’da bir düzeltme yayınlamak istediklerini belirttiler. Cortex müşterilerini global beyaz listelerin suistimalinden korumak için ek süre tanıdık. |
| 2026‑01‑09 | Palo Alto, Şubat ayı sonuna kadar düzeltmeyi yayınlama yolunda ilerliyor. |
| 2026‑02‑24 | Kesin bir tarih sorduk. |
| 2026‑02‑24 | Palo Alto, düzeltmenin Cortex XDR Ajanı sürüm 9.1 ve İçerik sürümü 2160’da zaten yayınlandığını bildirdi. |
Düzeltmenin Analizi
Eski şifreleme anahtarları artık kuralları deşifre etmek için çalışmıyor. Ancak, anahtarın bir parçasının türetildiği cysvc.dll içindeki !7H1@j@%J8VqP9c7SgstHaxzjfuS1u=EsVU#QMKHgogc*X8*sXoho2*t&paX5NJ@ dizesi hala aynı. İkinci kısım ve “türetme” fonksiyonu biraz değişmiş.
Asıl sorun deşifre edilen kurallardaki global beyaz listelerdi ve bunları tamamen kaldırdılar. Artık aynı anda her türlü kuralı atlatabilen bir implant başlatmak mümkün değil. Ancak, kuralları bildikten sonra münferit kuralları atlatmak elbette hala çok daha kolay. Çoğunun suistimal edilebilecek istisnaları var.
Sonuç
Ofansif ve defansif güvenlik arasında her zaman bir kedi-fare oyunu olacaktır. Zararlı yazılım geliştirmede yaygın bir yaklaşım, EDR ajanlarını atlatmak için örneğin shellcode enjeksiyonu için yeni yöntemler kullanmak gibi yeni teknikler oluşturmaktır. Bu yazı, belirli EDR’leri hedeflerken tespitlerden kaçınmak için başka bir yöntemi açıklamaktadır. Cortex XDR’daki ön tanımlı davranışsal tespit kurallarının yaklaşık yarısı, kötü niyetli eylemleri gerçekleştiren işleme sadece :\Windows\ccmcache komut satırı argümanı eklenerek atlatılabiliyordu. Bu kurallara düz metin olarak doğrudan erişilememesi, “gizlilik yoluyla güvenlik” (security by obscurity) yaklaşımıyla kıyaslanabilir. Bu durum, üreticilerin tespit kurallarının gizli mi yoksa açık mı olması gerektiği sorusunu gündeme getirmektedir. Örneğin, Elastic ve HarfangLab açık kurallar kullanır; ancak bu bir ödünleşim (trade-off) yaratır, çünkü daha az yetenekli saldırganlar da bunları inceleyebilir. Savunmacılar araçlarını tanımalı ve siyah kutu bir tespit ve engelleme çözümüne körü körüne güvenmemelidir.








