немного продолженние темы по Stack overflow: Stack clashing vs jumping vs smashing.
В Кернеле есть фича для автоматического расширения стэка (рассматриваем stack grows down варианты x86_64, arm etc.):
1. если stack pointer (esp, rsp) доходит вниз до начала стэк фрейма и внизу уже незамапленная область, то происходит Page fault.
2. Кернел обрабатывает PF, экспандит стэк путем уменьшение адреса начала стэка
3. Соответственно, если внизу замапленна область другого процесса, то это приводит к stack clash.
В 2010-м году, Линус каммитает фикс с защитой в один PAGE_SIZE (1 << 12 = 4096 B, PAGE_SHIFT = 12 [x86_64, arm, misp etc.]), чтобы при попытке экспандии стэка, была проверка на "попадет ли esp/rsp в stack_guard_page" (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=320b2b8de12698082609ebbc1a17165727f4c893).
В 2017-м году (v4.12) один кернел разраб увеличивает эту область до 1 MB (256UL << PAGE_SHIFT) (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1be7107fbe18eed3e319a6c3e83c78254b693acb)
Эта текущий гэп, через который надо "перепрыгнуть" для того, кто пишит эксплоиты, чтобы сделать stack clashing.
Ну и Stack smashing - это когда мы перезатираем stack другой области памяти или даже при execstack вызываем шеллкод, как пример, в стэке.
#linux_mm
В Кернеле есть фича для автоматического расширения стэка (рассматриваем stack grows down варианты x86_64, arm etc.):
1. если stack pointer (esp, rsp) доходит вниз до начала стэк фрейма и внизу уже незамапленная область, то происходит Page fault.
2. Кернел обрабатывает PF, экспандит стэк путем уменьшение адреса начала стэка
3. Соответственно, если внизу замапленна область другого процесса, то это приводит к stack clash.
В 2010-м году, Линус каммитает фикс с защитой в один PAGE_SIZE (1 << 12 = 4096 B, PAGE_SHIFT = 12 [x86_64, arm, misp etc.]), чтобы при попытке экспандии стэка, была проверка на "попадет ли esp/rsp в stack_guard_page" (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=320b2b8de12698082609ebbc1a17165727f4c893).
В 2017-м году (v4.12) один кернел разраб увеличивает эту область до 1 MB (256UL << PAGE_SHIFT) (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1be7107fbe18eed3e319a6c3e83c78254b693acb)
Эта текущий гэп, через который надо "перепрыгнуть" для того, кто пишит эксплоиты, чтобы сделать stack clashing.
Ну и Stack smashing - это когда мы перезатираем stack другой области памяти или даже при execstack вызываем шеллкод, как пример, в стэке.
#linux_mm
Немного про Stack clashing, smashing, jumping.
-- stack clashing: в архитектуре (amd64, i386/x86_64), где стэк растет вниз, области памяти стэка и кучи/замапленной памяти могут встретится ("clash"). Линукс кернел позволяет динамично расширять user-process стэк до предела RLIMIT_STACK если %rsp достиг до конца фрейма (до %rbp получается), CPU вызывает PAGE FAULT, OS хендлит это и вызывает функцию
-- stack jumping -- как раз таки перепрыгивание через stack guard page. Интересно, считается ли NOP slide stack jumping? 😒
-- stack smashing -- перезаписывание стэка произвольным значением, например, адреса возврата программы в случае крэша
Мораль: не используйте
#linux_mm #systemd
-- stack clashing: в архитектуре (amd64, i386/x86_64), где стэк растет вниз, области памяти стэка и кучи/замапленной памяти могут встретится ("clash"). Линукс кернел позволяет динамично расширять user-process стэк до предела RLIMIT_STACK если %rsp достиг до конца фрейма (до %rbp получается), CPU вызывает PAGE FAULT, OS хендлит это и вызывает функцию
expand_downwards()
, где есть проверка на Stack Guard Pages. (Писал про это выше)-- stack jumping -- как раз таки перепрыгивание через stack guard page. Интересно, считается ли NOP slide stack jumping? 😒
-- stack smashing -- перезаписывание стэка произвольным значением, например, адреса возврата программы в случае крэша
ret
можно захэндлить и перезатереть еще одной %rip
, чтобы он прыгнул в твой шеллкод посреди NOP.Мораль: не используйте
alloca()
и бережно аллоцируйте в стэк :)#linux_mm #systemd
*ret2libc. Part 1.*
_"..exploiting buffer overflows should be an art."_ @ Solar Designer
Продолжаем тематику моего изучения buffer overflow. В этой части, расскажу, что перед тем как сразу идти на эксплоиты как какой-то scriptkiddie 🙂 я бы хотел понять "почему и для чего?". На этот раз, мы сталкиваемся с реальным миром, где у нас не выключено `gcc -execstack`, где есть защита со стороны хардвара (CPU -> NX bit). Вот начал копаться в ret2libc с видео туториала LiveOverflow YT канала. За 10:37 минут, Фабиан рассказал по быстрому как вместо того, чтобы загружать пэйлоад с `/bin/sh` CPU инструкциями, который не будет работать в реальном мире, обойти защиту NX bit [1]. Перед тем как дойти до части NX, давайте почитаем сообщение об открытии *ret2libc* в 1997-м году от автора Solar Designer [2] (Alexander Peslyak). Это привело меня в чувство ностальгии, которой мне наиву не встретить из-за того, что в 1997 solar было 20 лет.
https://insecure.org/sploits/linux.libc.return.lpr.sploit.html
В туториале от LiveOverflow упоминается про ROP (return oriented programming), я про него слышал, как возможность обхода ASLR путем `jmp|call *some instr with pointer`, но пока закончим с ROP. Дальше в *ret2libc part 2* продолжим на тему stack buffer overflow + адрес нужной нам функции в libc.so. На выходных, думаю, продолжить. Stay tuned.
*********************
[1] *W^X* - Write XOR Execute фича, первая появившаяся в OpenBSD (2003 г), где страницы помечены флагом с ИЛИ Writeable, ИЛИ Executable, совокупные привелегии запрещены. Это как раз таки является защитой для нашего shellcode execution в стэке в прошлом посте. Не знал про это. В терминологии Windows упоминается как *DEP* (Data Execution Prevention), у Линукса - это идет вместе с патчем *PaX* (анонимные контрибьюторы, которые также являются автором ASLR 👽)
Имплементация для этого фичей является *NX bit*. Intel - XD bit (eXecute Disable), AMD - EVP bit (Execution Virus Protection), ARM - XN bit (eXecute Never).
В Вики упоминается: _" a feature normally only found in Harvard architecture processors. However, the NX bit is being increasingly used in conventional von Neumann architecture processors, for security reasons."_.
Тут я задался вопросом: "а что такое это
[2] - Solar Designer также являтся автором *john the ripper* (тулзой для крэкинга пароля), openwall, 1st heap-buffer-overflow exploit, ret2libc. Мне понравился его креативный доклад с философвской/политической/рациональной точки зрения на ИБ.
https://www.youtube.com/watch?v=4Y91dJ--1NM.
[3] von Neuman arch vs Harvard arch. --- TL;DR: Насколько понял, это две концептуальные модели микроархитектур, которые являются основой существующих ARM, AMD, x86 etc. Насколько понял разница в том, что если в von Neuman для процесса нужно сделать 2 cycles для загрузки CPU инструкции и данных, так как физический используется 1 шина (bus), где для Harvard arch. используется 2 шины и загрузка инструкции и данных выполняется за 1 cycle. Intel считается "pure von Neuman arch". Также существует Advanced Harvard arch. Но не углублялся в детали. Узнал, что у von Neuman есть инструкции и это напоминает текущие Intel инстр.:
#linux_mm #ret2libc
_"..exploiting buffer overflows should be an art."_ @ Solar Designer
Продолжаем тематику моего изучения buffer overflow. В этой части, расскажу, что перед тем как сразу идти на эксплоиты как какой-то scriptkiddie 🙂 я бы хотел понять "почему и для чего?". На этот раз, мы сталкиваемся с реальным миром, где у нас не выключено `gcc -execstack`, где есть защита со стороны хардвара (CPU -> NX bit). Вот начал копаться в ret2libc с видео туториала LiveOverflow YT канала. За 10:37 минут, Фабиан рассказал по быстрому как вместо того, чтобы загружать пэйлоад с `/bin/sh` CPU инструкциями, который не будет работать в реальном мире, обойти защиту NX bit [1]. Перед тем как дойти до части NX, давайте почитаем сообщение об открытии *ret2libc* в 1997-м году от автора Solar Designer [2] (Alexander Peslyak). Это привело меня в чувство ностальгии, которой мне наиву не встретить из-за того, что в 1997 solar было 20 лет.
https://insecure.org/sploits/linux.libc.return.lpr.sploit.html
В туториале от LiveOverflow упоминается про ROP (return oriented programming), я про него слышал, как возможность обхода ASLR путем `jmp|call *some instr with pointer`, но пока закончим с ROP. Дальше в *ret2libc part 2* продолжим на тему stack buffer overflow + адрес нужной нам функции в libc.so. На выходных, думаю, продолжить. Stay tuned.
*********************
[1] *W^X* - Write XOR Execute фича, первая появившаяся в OpenBSD (2003 г), где страницы помечены флагом с ИЛИ Writeable, ИЛИ Executable, совокупные привелегии запрещены. Это как раз таки является защитой для нашего shellcode execution в стэке в прошлом посте. Не знал про это. В терминологии Windows упоминается как *DEP* (Data Execution Prevention), у Линукса - это идет вместе с патчем *PaX* (анонимные контрибьюторы, которые также являются автором ASLR 👽)
Имплементация для этого фичей является *NX bit*. Intel - XD bit (eXecute Disable), AMD - EVP bit (Execution Virus Protection), ARM - XN bit (eXecute Never).
В Вики упоминается: _" a feature normally only found in Harvard architecture processors. However, the NX bit is being increasingly used in conventional von Neumann architecture processors, for security reasons."_.
Тут я задался вопросом: "а что такое это
von Neuman arch
?" [3]. Нашел в мануал Intel, что NX bit - это 63-й бит (most significant bit) в адресе, который задает флаг включен ли W^X или нет. Кстати, в Линуксе эту фичу можно управлять сисколлом `mprotect`. Интересно, что можно изменять RWX правила даже на существующих адрес маппинге процесса. Хмм.. Также LiverOverflow упоминает, что во многих IoT девайсах нету PaX, то есть отсутствует защита ASLR, NX. Надо бы проверить :)[2] - Solar Designer также являтся автором *john the ripper* (тулзой для крэкинга пароля), openwall, 1st heap-buffer-overflow exploit, ret2libc. Мне понравился его креативный доклад с философвской/политической/рациональной точки зрения на ИБ.
https://www.youtube.com/watch?v=4Y91dJ--1NM.
[3] von Neuman arch vs Harvard arch. --- TL;DR: Насколько понял, это две концептуальные модели микроархитектур, которые являются основой существующих ARM, AMD, x86 etc. Насколько понял разница в том, что если в von Neuman для процесса нужно сделать 2 cycles для загрузки CPU инструкции и данных, так как физический используется 1 шина (bus), где для Harvard arch. используется 2 шины и загрузка инструкции и данных выполняется за 1 cycle. Intel считается "pure von Neuman arch". Также существует Advanced Harvard arch. Но не углублялся в детали. Узнал, что у von Neuman есть инструкции и это напоминает текущие Intel инстр.:
```
--------------------------------------
von Neuman | Intel (32-bt)
--------------------------------------
MAR (Memory Addr Reg)|%esp?
MDR (Memory Data Reg)| %edx
AC (Accumulator)| %eax
PC (Program Counter) | %ecx
CIR (Current Instr Reg)%eip
```
#linux_mm #ret2libc
insecure.org
lpr LIBC RETURN exploit
Solar Designer has done it again! Here he proves the viability of overflow exploits returning into libc functions. He includes lpr and color_xterm exploits.
_Linux OOM killer, Part 1._
Надо разобраться как работает Out-of-memory killer в ядре. Так как, это Linux Memory Management (является самой сложной частью ядра[2]), то надо также пройтись по механизмам работы и траблшутинга ядра с памятью.
`read()` сисколл считывает до 2-х GB памяти в x86, x86_64 арх.
Допустим 3 кейса, если запустить Питон скрипт с `
1) и с RAM >= X, то по сисколлам будет следующее `
2) и с RAM < X, то мы получим ENOMEM при `mmap`. Еще надо учитывать, что у нас стоит дефолтное значение `vm.overcommit_memory = 0` [3]
3) и с RAM >= X, но тут мы форкаем процесс в N раз, да так, что N * X > RAM.
В начале, address space child процессов помечены как COW (copy-on-write) - шарят один и тот же address space, что и парент, до тех пор пока мы не начали использовать эту память. Ну или аналогичный юзкейз можно сделать и без форков, а когда другие процессы мапят память безвозвратно `
Если прогуглить "Linux OOM killer", то прочитывая статьи по ссылкам lwn.net etc., то выстраивается некая хронология по которой можно понять траекторию развития этой важной фичи ядра. В *mm/oom_kill.c* учитывается архитектура MMU - NUMA vs SMP[4], есть ли cpusets[5], в каком cgroups находится процесс, какие эвристические метрики у процесса `
[1] https://lwn.net/Articles/317814/
[2] "Understanding Linux Kernel, 3-edition, 29p”
[3] https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
[4] NUMA (non-uniform memory access) - изоляция на уровне железа микропроцессоров с DRAM по локальным шинам, тем самым увеличивая КПД за счет эффективных cache hit-miss в L1, L2 и зашаренных L3 уровней.
[5] cpuset - изоляция на уровне софта путем `
[6] https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L862-L913
[7] Livelock - разновидность deadlock, только здесь процесс меняет свое состоение (если `read` -> uninterr. sleep (D), sleep (S), running (R) etc.), но при этом блочится из-за нехватки ресурсов. Интересное узнал, что одним из классических решении deadlock-а является *Banker's algorithm* (E. Dijkstra, 1962-1963) по схеме работы банка: "Приходит клиент в банк, просит денег, банкир проверяет хватит ли банку отдать сумму клиенту, и при этом оставить в запасе еще у себя денег". Но данный алгоритм в ядре не используется из-за динамичности памяти. Используется методы синхронизации RCU (read-copy-update), описанных в "linux/kernel/rcu".
#linux_mm
Надо разобраться как работает Out-of-memory killer в ядре. Так как, это Linux Memory Management (является самой сложной частью ядра[2]), то надо также пройтись по механизмам работы и траблшутинга ядра с памятью.
`read()` сисколл считывает до 2-х GB памяти в x86, x86_64 арх.
Допустим 3 кейса, если запустить Питон скрипт с `
open("/dev/urandom", "rb").read(X)
` в системе без swap:1) и с RAM >= X, то по сисколлам будет следующее `
mmap(XGB) = 0xdeadbeef; => read() = 2GB; read() = 2GB; ... => munmap(0xdeadbeef);
`. Т.е. мы замаплим файл и будем возвращать в юзерспейс по 2 гига пока не считаем весь файл < X.2) и с RAM < X, то мы получим ENOMEM при `mmap`. Еще надо учитывать, что у нас стоит дефолтное значение `vm.overcommit_memory = 0` [3]
3) и с RAM >= X, но тут мы форкаем процесс в N раз, да так, что N * X > RAM.
В начале, address space child процессов помечены как COW (copy-on-write) - шарят один и тот же address space, что и парент, до тех пор пока мы не начали использовать эту память. Ну или аналогичный юзкейз можно сделать и без форков, а когда другие процессы мапят память безвозвратно `
munmap / free
`. В итоге, получается, что ядро отдает `mmap` область памяти для процессов, которые по 2 Гига продолжают считывать в память и когда истекает физическая память с Page Fault, то выходит на охоту OOM killer, чтобы убить жирные процессы, ceteris paribus. Но и получается такие моменты, когда в системе происходит момент, когда OOM killer в своем рекурсивном `goto retry`
не может убить процесс[6] (через SIGKILL), и система "зависает", что технический говоря, входит в livelock[7].Если прогуглить "Linux OOM killer", то прочитывая статьи по ссылкам lwn.net etc., то выстраивается некая хронология по которой можно понять траекторию развития этой важной фичи ядра. В *mm/oom_kill.c* учитывается архитектура MMU - NUMA vs SMP[4], есть ли cpusets[5], в каком cgroups находится процесс, какие эвристические метрики у процесса `
/proc/xxx/oom_score
` etc. Вот, в этих критериях и развитии OOM killer-а надо разобраться. Stay tuned.[1] https://lwn.net/Articles/317814/
[2] "Understanding Linux Kernel, 3-edition, 29p”
[3] https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
[4] NUMA (non-uniform memory access) - изоляция на уровне железа микропроцессоров с DRAM по локальным шинам, тем самым увеличивая КПД за счет эффективных cache hit-miss в L1, L2 и зашаренных L3 уровней.
[5] cpuset - изоляция на уровне софта путем `
mbind(), set_mempolicy()
` для микропроцессеров и memory node. Эффективна в NUMA архитекутре.[6] https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L862-L913
[7] Livelock - разновидность deadlock, только здесь процесс меняет свое состоение (если `read` -> uninterr. sleep (D), sleep (S), running (R) etc.), но при этом блочится из-за нехватки ресурсов. Интересное узнал, что одним из классических решении deadlock-а является *Banker's algorithm* (E. Dijkstra, 1962-1963) по схеме работы банка: "Приходит клиент в банк, просит денег, банкир проверяет хватит ли банку отдать сумму клиенту, и при этом оставить в запасе еще у себя денег". Но данный алгоритм в ядре не используется из-за динамичности памяти. Используется методы синхронизации RCU (read-copy-update), описанных в "linux/kernel/rcu".
#linux_mm
lwn.net
Taming the OOM killer
Under desperately low memory conditions, the out-of-memory (OOM) killer
kicks in and picks a process to kill using a set of heuristics which has
evolved over time. This may be pretty annoying for users who may have
wanted a different process to be killed.…
kicks in and picks a process to kill using a set of heuristics which has
evolved over time. This may be pretty annoying for users who may have
wanted a different process to be killed.…
exploit.c
8.2 KB
SecCon_2020 CTF, kstack: #rop SMEP bypass (SMAP disabled), #userfaultfd #kUAF #doublefree #setxattr #uaf #linux
P.S.: After getting shell, exploit crashes due to misaligned RSP. So proper mmap for fake stack is required. Only this part. Exploitation is correct. Note that SMAP is disabled in this task
Exploit was written per "smallkirby" writeup
P.S.: After getting shell, exploit crashes due to misaligned RSP. So proper mmap for fake stack is required. Only this part. Exploitation is correct. Note that SMAP is disabled in this task
Exploit was written per "smallkirby" writeup
https://lwn.net/Articles/925371/
EEVDF replaced, in v6.6 update, Linux kernel scheduler CFS, which had been since v2.6.23.
AFAIU, it computes the process taken "fair" time by new metric "lag" that's calculated with factors like process priority, "virtual deadline" with process allocated time consideration.
Interesting, how much "old" stuff can be optimized with other algorithms' alternatives?
EEVDF algo was est. in 1995
#linux
EEVDF replaced, in v6.6 update, Linux kernel scheduler CFS, which had been since v2.6.23.
AFAIU, it computes the process taken "fair" time by new metric "lag" that's calculated with factors like process priority, "virtual deadline" with process allocated time consideration.
Interesting, how much "old" stuff can be optimized with other algorithms' alternatives?
EEVDF algo was est. in 1995
#linux
lwn.net
An EEVDF CPU scheduler for Linux
The kernel's completely fair scheduler
(CFS) has the job of managing the allocation of CPU time for most of
the processes running on most Linux systems. CFS was merged for the 2.6.23
release in 2007 and has, with numerous ongoing tweaks, handled the job…
(CFS) has the job of managing the allocation of CPU time for most of
the processes running on most Linux systems. CFS was merged for the 2.6.23
release in 2007 and has, with numerous ongoing tweaks, handled the job…
I wrote my 1st blog post on my website and started with:
Mutt setup with Gmail labels for Linux kernel emails
https://novitoll.com/posts/2024-4-09/mutt.html
This is my 1st experience with mutt, so configs are not advanced per se.
#linux
Mutt setup with Gmail labels for Linux kernel emails
https://novitoll.com/posts/2024-4-09/mutt.html
This is my 1st experience with mutt, so configs are not advanced per se.
#linux