CET - Intel Control-flow Enforcement Technology
Sissejuhatus
TODO
Mõisted
- CET - control-flow enforcement technology
- ROP - return oriented programming
- SHSTK - shadow stack
- IBT - Indirect Branch Tracking
- LPE - local privilege escalation
- PIE / PIC - Position-Independent Executable / Position-Independent Code
- GOT - Global Offset Table
- KARL - Kernel Address Randomized Link
- ASLR - Software/Kernel Layer
Tööpõhimõte - ROP
Väited
- ROP tehnika jaoks ei ole ausat kasutusjuhtumit, see on puhtalt eksploitimise eesmärgil kasutatav tehnika
- ROP vältimiseks on erinevaid võimalusi, üks on CET riistvara toetatud
- CET riistvara tugi leiab kasutust ka muudel eesmärkidel lisaks ROP vältimisele
Programmi töötamine
Väited
- kui arvutis hakkab tööle järgmine programm, st tekib uus protsess, siis muude ressursside hulgas eraldatakse mälu
- mälu eraldatakse erinevate maitsetega: 1. code, 2. data, 3. memory mapping segment, 4. heap, 5. stack
- linux puhul on stack vaikimisi 8 MB suur
- stack peal hoitakse järgmise funktsiooni väljakutsega seotud muutujaid st nende väärtusi, ja tagasipöördumise aadresse funktsiooni välja kutsunud programmi kohale vastavale mälu aadressile
- kui programm töötab, siis ta saab mingitel hetkedel sisendit ja kutsub välja funktsioone, stack paisub ja aheneb, töö käib
- protsessor töötab erinevates registrites olevate nö andmetega, assembler keeles
- olemas on 'memory safe' keeled-kompilaatorid nt go ja rust - nad konstrueerivad sellises vormis assemblerit, mida ei saa rop vajadusteks ära kasutada
- olemas on 'non-memory safe' keeled nt c - tavaline c kompilaator konstrueerub sellises vormis assemblerit, mida saab rop vajadusteks ära kasutada
Töötava protsessi mälu kasutuse hindamine
# grep -E 'Vm|Rss' /proc/921/status VmPeak: 21064 kB VmSize: 21064 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 4564 kB VmRSS: 4564 kB RssAnon: 1408 kB RssFile: 3156 kB RssShmem: 0 kB VmData: 1132 kB VmStk: 8324 kB VmExe: 844 kB VmLib: 6800 kB VmPTE: 64 kB VmSwap: 0 kB
kus
- VmStk - kogu stack maht (nn 8 MB)
- RssAnon - stack reaalselt kasutuses - anon sellepärast, et sellele ei vasta midagi failisüsteemis, ta on väga volatile
Programmi töötamise eksploitimine
Väited
- rop abil eksploitimine põhineb asjaolul et nö 'non-memory safe' keelest kompileeritud assemblerile vastavas stackis saab korraldada puhvrite (muutujate) kirjutamist üle ääre (spillover, overflow)
- overflow puhul on võimalik praktiliselt kirjutada uue väärtuse sellisele asukohale mälus, mida arvuti käsitleb nt tagasipöördumise aadressina - ja oskuslikult ülekirjutust tehes on võimalik nt saavutada shell
- reeglina iseenesest puhas rop ei esklaleeri õigusi, selleks rakendatakse järgmist eksploiti, nt lpe (local privilege escalation)
- rop puhul on võimalik mitu järjestlikult suunatud jump'i korraldada
- rop puhul ei ole vajalik arvuti mällu koodi lisada, tegeldakse olemasoleva koodi fragmentide sobiva ümberjärjestamisega, mille nö käivitamisel on meelepärane mõju
- kuna dünaamiliselt lingitud programmi puhul on kasutada suur hulk süsteemseid teeke, siis mälus oleva koodi puudust ei ole
- rop põhineb asjaolul, et programmi sisendit piisavalt ei kontrollita - kui programmi täitmine jõuab juba stack'i siis on see suhteliselt libraalne territoorium - kui seal old-school c progammile vastav assebler kirjutab, siis ka kirjutatake (sh toimub 'buffer overflow' ehk 'buffer spillover')
- kui käivitub kontrollimatu funktsiooni rekursioon siis tõenäoliselt ammendub 8 MB stack maht ja toimub nn 'stack overflow' - kernel krahhib protsessi
Tööpõhimõte - Linux
CET algab protsessori toest, nt https://www.intel.com/content/www/us/en/products/sku/232391/intel-xeon-gold-6448h-processor-60m-cache-2-40-ghz/specifications.html puhul muu hulgas öeldakse
- Intel® Control-Flow Enforcement Technology
ning töötava arvuti käest küsides, 'user_shstk' on näitaja
# lscpu | grep -i shstk Flags: fpu vme de pse .. user_shstk ...
seejärel kerneli tugi, nt
# grep SHADOW /boot/config-6.17.0-23-generic CONFIG_X86_USER_SHADOW_STACK=y CONFIG_ARCH_HAS_USER_SHADOW_STACK=y ...
seejärel rakendustarkvara programmi tugi - rida 'Properties: x86 feature: IBT, SHSTK'
# readelf -n /usr/sbin/nginx
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x00000020 NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: IBT, SHSTK
x86 ISA needed: x86-64-baseline
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 9d51609b493789d993848c98e203e9a13dba3157
Displaying notes found in: .note.ABI-tag
Owner Data size Description
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
OS: Linux, ABI: 3.2.0
kusjuures kerneli ja programmi vahele jäävad teegid peavad ka toetama
# cat hu.sh
for lib in $(ldd /usr/sbin/nginx | grep -o '/lib[^ ]*'); do
echo -n "$lib: "
readelf -n "$lib" 2>/dev/null | grep -q "SHSTK" && echo "READY" || echo "MISSING HARDENING"
done
# sh hu.sh
/lib/x86_64-linux-gnu/libcrypt.so.1: READY
/lib/x86_64-linux-gnu/libpcre2-8.so.0: READY
/lib/x86_64-linux-gnu/libssl.so.3: READY
/lib/x86_64-linux-gnu/libcrypto.so.3: READY
/lib/x86_64-linux-gnu/libz.so.1: READY
/lib/x86_64-linux-gnu/libc.so.6: READY
/lib64/ld-linux-x86-64.so.2: READY
ning kui töötava protsessi juures on shstk aktiivne, see paistab nii (vastasel juhul on : järel tühi)
# ps U www-data
PID TTY STAT TIME COMMAND
920 ? S 0:00 nginx: worker process
921 ? S 0:00 nginx: worker process
...
# cat /proc/921/status | grep -i thread_fe
x86_Thread_features: shstk
x86_Thread_features_locked: shstk wrss
Väited
- tänapäeval on keeruline leida uut intel või amd protsessoriga arvutit mis ei toetaks cet tehnoloogiat
- Ubuntu 24.04 platvormil on vaikimisi kõik cet jaoks vajalik olemas v.a. rakenduse systemd service seadistusest sisselülitamine
- 2026 aasta kevade seisuga virtualiseerimise platvorm Proxmox PVE v. 9 kasutab qemu v. 11 ja seal on füüsilise protsessori kasutamisel virtuaalse arvuti protsessorine (valik 'host') kasutada cet tehnoloogia
Kasulikud lisamaterjalid
- https://en.wikipedia.org/wiki/Control-flow_integrity
- https://ubuntu.com/blog/whats-new-in-security-for-ubuntu-24-04-lts
- https://forum.proxmox.com/threads/qemu-11-0-available-on-pve-test-and-pve-no-subscription-as-of-now.183494/
Tööpõhimõte - muud operatsioonisüsteemid
Windows
Väited
CET riistvara põhine, ammu olemas (viimased kümme aastat)
MacOS
Väited
- M1 jt platvormidel sisuliselt CET tulemus saavutatakse teiste võtetega - TODO
OpenBSD
Väited
- OpenBSD puhul saavutatakse CET tulemus tarkvaraliselt - retguard, https://isopenbsdsecu.re/mitigations/retguard/
- OpenBSD puhul olulised süsteemsed teegid kirjutatakse failisüsteemis füüsiliselt ringi, st nad sisaldavad sama komplekti tarkust, aga uues järjekorras
- kui protsessi käivitamisel laaditakse üldine teek mällu, siis laaditakse ta suurte plokkidena, ja tänu ümberjärjestamise juhuslikkusele ja unikaalsusele ei ole nö ettevalmistatud rünne hästi võimalik - iga openbsd arvuti on selles mõttes unikaalne; ja järgmise reboodiga on ta jällegi uus
# dmesg -s ... reordering: ld.so libc libcrypto sshd sshd-session ssh-agent. # date Wed May 20 22:29:40 EEST 2026 # uptime 10:29PM up 12 days, 5:28, 6 users, load averages: 0.77, 0.57, 0.51 # ls -ld /usr/sbin/sshd -r-x--x--x 1 root bin 559968 May 8 17:01 /usr/sbin/sshd
Haavatavuse näide
Haavatavuse ilmestamise programm rop_lab.c, tõenäoliselt on see märkimisväärne lihtsustus, aga ta illustreerib rop haavatavuse põhimõtet ning haavatavuse ärahoidmist
$ cat rop_lab.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// This is our "Gadget". The program never calls this function honestly!
void malicious_gadget() {
printf("\n⚡ [ATTACK SUCCESS] Control flow hijacked! Malicious code executing.\n");
exit(0);
}
void vulnerable_function(char *str) {
char buffer[16];
// VULNERABILITY: strcpy does not check bounds.
// It will overwrite the buffer, the frame pointer, and the Return Address!
strcpy(buffer, str);
printf("[CPU] Function executing normally inside buffer layout.\n");
}
int main() {
// We are crafting a malicious payload payload manually.
// 16 bytes to fill the buffer + 8 bytes to smash the saved frame pointer
// + 8 bytes containing the exact memory address of malicious_gadget()
char payload[32];
// Fill the padding area with 'A's (0x41)
memset(payload, 'A', 24);
// Get the exact memory address of our target gadget
unsigned long target = (unsigned long)malicious_gadget;
// Append the target address onto the end of our overflow payload
memcpy(payload + 24, &target, 8);
printf("[Lab] Target Gadget Address is at: %p\n", (void*)target);
printf("[Lab] Launching attack payload against vulnerable function...\n");
vulnerable_function(payload);
printf("[CPU] Returned safely to main. (This should not happen if hacked!)\n");
return 0;
}
kus
- malicious_gadget() on protsessi mälus olev nö ärakasutatav järgnevus - et ära kasutada, tuleb sattuda sobivale aadressile - võib olla see järgnevus pole üldse algselt programmeeritud isesesiva funktsioonina, aga ta nii praktiliselt toimib kui sobivalt pöörduda-kasutada
- vulnerable_function - haavatav funktsioon - asutakse ära kasutama tema potensiaali kirjutada üle rohkem stack mälu sisu kui on ette kujutatud
- main() - programmi töö algus, valmistatakse ette sobiva sisuga payload (mälu sisu) ja paigutatakse kohale
- tulemusena funktsioonist vulnerable_function tagasi pöördudes ei saabuta main() 'printf ...' juurde, aga gadget juurde
Väljakutsuvalt liberaalse binary kompileerimiseks sobib öelda
$ gcc -fno-stack-protector -z execstack -fcf-protection=none rop_lab.c -o lab_unhardened
kus
- -fno-stack-protector - ei moodustata nö tarkvarapõhist stack kaitset
- -z execstack - lisaks lülitatakse sisse stack'is oleva koodi käivitamise võimalus
- -fcf-protection=none - lülitatakse välja igasugune hardware-assisted st cet põhine stack kaitse
cet põhine kaitse
$ gcc -fno-stack-protector -fcf-protection=full rop_lab.c -o lab_hardened
kus
- -fcf-protection=full - sisse on lülitatud maksimaalne võimalik hardware-assisted st cet põhine stack kaitse
- -fno-stack-protector - ei moodustata nö tarkvarapõhist stack kaitset selleks, et katses pääseks mõjule cet põhine kaitse
Kui käivitada cet-võimestatud binary't nö tavalisel viisil ning cet riistvara toega arvutis, siis ta töötab haavatavalt
$ lscpu | grep shstk Flags: .. user_shstk ... $ ./lab_hardened [Lab] Target Gadget Address is at: 0x6552a7afc1c9 [Lab] Launching attack payload against vulnerable function... [CPU] Function executing normally inside buffer layout. ⚡ [ATTACK SUCCESS] Control flow hijacked! Malicious code executing.
Kui lülitada sisse cet kaitse, siis hoiab kernel ära haavatavuse mõjulepääsu
$ export GLIBC_TUNABLES=glibc.cpu.hwcaps=SHSTK $ ./lab_hardened [Lab] Target Gadget Address is at: 0x59f889ed41c9 [Lab] Launching attack payload against vulnerable function... [CPU] Function executing normally inside buffer layout. Segmentation fault (core dumped)
Samal ajal kirjutatakse kerneli logisse
# dmesg -T | tail -n 1 [Wed May 20 20:31:35 2026] lab_hardened[2872] control protection ip:59f889ed421e sp:7ffe4f9f7648 ssp:76edde5fffe0 error:1(near ret) in lab_hardened[121e,59f889ed4000+1000]
kus
- sp - stack pointer väärtus
- ssp - shadow stack pointer väärtus
- nad ei klapi
Kasutamine - Ubuntu 24.04 ja zabbix agent2
Näiteks zabbix agent kaudu haavatavuse esilekutsumine ja haavatavuse vältimine. Moodustada UserParameters abil kontroll
# cat /etc/zabbix/zabbix_agent2.d/misc.conf UserParameter=rop_hardened,/home/imre/20260520/lab_hardened 1>>/home/tmp/rop_hardened.log 2>&1 # systemctl restart zabbix-agent2 # zabbix_get -k rop_hardened -s 127.0.0.1
Tulemusena programmi ja seal sisalduva nö eksploidi käivitamine
# tail -n 5 /home/tmp/rop_hardened.log [Lab] Target Gadget Address is at: 0x616af0eed1c9 [Lab] Launching attack payload against vulnerable function... [CPU] Function executing normally inside buffer layout. ⚡ [ATTACK SUCCESS] Control flow hijacked! Malicious code executing.
Programmis sisalduva eksploidi töötamise takistamiseks sobib kasutada zabbix agent2 systemd service unit seadistustes GLIB_TUNABLES abil
# systemctl edit zabbix-agent2 [Service] Environment="GLIBC_TUNABLES=glibc.cpu.hwcaps=SHSTK" # systemctl restart zabbix-agent2
Tulemusena ütleb kernel segmentation fault rikkumise avastamisel
# tail -n 6 /home/tmp/rop_hardened.log [Lab] Target Gadget Address is at: 0x616af0eed1c9 [Lab] Launching attack payload against vulnerable function... [CPU] Function executing normally inside buffer layout. ⚡ [ATTACK SUCCESS] Control flow hijacked! Malicious code executing. Segmentation fault (core dumped) # dmesg -T | tail -n 1 [Wed May 20 20:50:28 2026] lab_hardened[3417] control protection ip:62ee74e0421e sp:7ffeadc19f28 ssp:7e27011fffe0 error:1(near ret) in lab_hardened[121e,62ee74e04000+1000]
coredump
süsteemi logisse kirjutatakse
2026-05-20T20:50:28.063977+03:00 zabbix-pub-01 kernel: lab_hardened[3417] control protection ip:62ee74e0421e sp:7ffeadc19f28 ssp:7e27011fffe0 error:1(near ret) in lab_hardened[121e,62ee74e04000+1000] 2026-05-20T20:50:28.073376+03:00 zabbix-pub-01 systemd[1]: Started systemd-coredump@11-3418-0.service - Process Core Dump (PID 3418/UID 0). 2026-05-20T20:50:28.134245+03:00 zabbix-pub-01 systemd-coredump[3420]: Process 3417 (lab_hardened) of user 111 dumped core.#012#012Stack trace of thread 3417:#012#0 0x000062ee74e0421e n/a (/home/imre/20260520/lab_hardened + 0x121e)#012ELF object binary architecture: AMD x86-64 2026-05-20T20:50:28.136589+03:00 zabbix-pub-01 systemd[1]: systemd-coredump@11-3418-0.service: Deactivated successfully. 2026-05-20T20:50:28.139121+03:00 zabbix-pub-01 systemd[1]: systemd-coredump@11-3418-0.service: Triggering OnSuccess= dependencies. 2026-05-20T20:50:28.145170+03:00 zabbix-pub-01 systemd[1]: Starting apport-coredump-hook@11-3418-0.service... 2026-05-20T20:50:28.274024+03:00 zabbix-pub-01 systemd[1]: apport-coredump-hook@11-3418-0.service: Deactivated successfully. 2026-05-20T20:50:28.274268+03:00 zabbix-pub-01 systemd[1]: Finished apport-coredump-hook@11-3418-0.service. 2026-05-20T20:52:17.413974+03:00 zabbix-pub-01 kernel: NOTICE: Automounting of tracing to debugfs is deprecated and will be removed in 2030
ning
# coredumpctl list lab_hardened
TIME PID UID GID SIG COREFILE EXE SIZE
Wed 2026-05-20 15:08:59 EEST 1080 1000 1000 SIGSEGV present /home/imre/20260520/lab_hardened 18.5K
Wed 2026-05-20 15:09:26 EEST 1165 1000 1000 SIGSEGV present /home/imre/20260520/lab_hardened 18.5K
Wed 2026-05-20 15:45:00 EEST 1677 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 15:45:01 EEST 1696 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 15:45:55 EEST 1811 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 15:45:57 EEST 1827 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 15:51:15 EEST 1908 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 15:52:54 EEST 1939 1000 1000 SIGSEGV present /home/imre/20260520/lab_hardened 18.5K
Wed 2026-05-20 20:31:35 EEST 2872 1000 1000 SIGSEGV present /home/imre/20260520/lab_hardened 18.5K
Wed 2026-05-20 20:43:23 EEST 2976 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 20:43:31 EEST 2994 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
Wed 2026-05-20 20:50:28 EEST 3417 111 112 SIGSEGV present /home/imre/20260520/lab_hardened 18.0K
# coredumpctl dump lab_hardened --output=lab_crash.core
PID: 3417 (lab_hardened)
UID: 111 (zabbix)
GID: 112 (zabbix)
Signal: 11 (SEGV)
Timestamp: Wed 2026-05-20 20:50:28 EEST (8min ago)
Command Line: /home/imre/20260520/lab_hardened
Executable: /home/imre/20260520/lab_hardened
Control Group: /system.slice/zabbix-agent2.service
Unit: zabbix-agent2.service
Slice: system.slice
Boot ID: 3c8da9f759024317bf94b1831190ee44
Machine ID: b5cb741b1516242b193018946930aed8
Hostname: zabbix-pub-01
Storage: /var/lib/systemd/coredump/core.lab_hardened.111.3c8da9f759024317bf94b1831190ee44.3417.1779299428000000.zst (present)
Size on Disk: 18.0K
Message: Process 3417 (lab_hardened) of user 111 dumped core.
Stack trace of thread 3417:
#0 0x000062ee74e0421e n/a (/home/imre/20260520/lab_hardened + 0x121e)
ELF object binary architecture: AMD x86-64
More than one entry matches, ignoring rest.
# ls -ld /var/lib/systemd/coredump/*
-rw-r-----+ 1 root root 19024 May 20 15:08 /var/lib/systemd/coredump/core.lab_hardened.1000.3c8da9f759024317bf94b1831190ee44.1080.1779278939000000.zst
-rw-r-----+ 1 root root 19025 May 20 15:09 /var/lib/systemd/coredump/core.lab_hardened.1000.3c8da9f759024317bf94b1831190ee44.1165.1779278966000000.zst
-rw-r-----+ 1 root root 19016 May 20 15:52 /var/lib/systemd/coredump/core.lab_hardened.1000.3c8da9f759024317bf94b1831190ee44.1939.1779281573000000.zst
-rw-r-----+ 1 root root 19014 May 20 20:31 /var/lib/systemd/coredump/core.lab_hardened.1000.3c8da9f759024317bf94b1831190ee44.2872.1779298295000000.zst
-rw-r----- 1 root root 18468 May 20 15:45 /var/lib/systemd/coredump/core.lab_hardened.111.3c8da9f759024317bf94b1831190ee44.1677.1779281100000000.zst
...
core uurimiseks sobib öelda
# gdb ./lab_hardened lab_crash.core
GNU gdb (Ubuntu 15.1-1ubuntu1~24.04.1) 15.1
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
./lab_hardened: No such file or directory.
[New LWP 3417]
This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
Downloading executable for /root/lab_crash.core
...
(gdb) info registers
rax 0x38 56
rbx 0x7ffeadc1a088 140731813568648
rcx 0x0 0
rdx 0x0 0
rsi 0x62ee74e05050 108776302596176
rdi 0x7e2701405710 138705989818128
rbp 0x4141414141414141 0x4141414141414141
rsp 0x7ffeadc19f28 0x7ffeadc19f28
r8 0x7e2701403b20 138705989810976
r9 0x0 0
r10 0x1 1
r11 0x3 3
r12 0x1 1
r13 0x0 0
r14 0x62ee74e06da0 108776302603680
r15 0x7e2701611000 138705991962624
rip 0x62ee74e0421e 0x62ee74e0421e
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fs_base 0x7e27015c5740 138705991653184
gs_base 0x0 0
(gdb)
kus
- TODO
Kasulikud lisamaterjalid
- teksti koostamisel on kasutatud ohtralt gemini google abi