
Linux ELF x32/x64 эксплойт обхода ASLR DEP/NX с распылением стека
Эксплойт для обхода ASLR и DEP/NX в Linux ELF x32/x64 с помощью stack-spraying

Свойства:
Зависимости:
Ограничения:
Возможно, вы слышали об атаке Heap Spraying? Stack Spraying похож, однако считался непрактичным для большинства случаев, особенно для ASLR на x86-64.
Моя работа докажет обратное.
Для 32-битных систем существует 2^32 (4 294 967 296) теоретических адресов, тем не менее, ядро позволяет контролировать только около половины битов (2^(32/2) = 65 536) для выполнения в виртуализированной памяти, что означает, что если мы контролируем более 50 000 символов в стеке, мы почти наверняка попадем в наш shellcode, независимо от адреса, благодаря перенаправлению и перетрансляции ядра. Согласно моим тестам, даже 100 или 10 символов достаточно, если вызываемая функция не содержит других созданий переменных, что позволит выполнить атаку в стиле ROP.
Этого можно достичь с помощью переменных оболочки, которые не имеют строгого ограничения длины, но практический предел составляет около ста тысяч, иначе это насытит TTY.
Итак, для успешной эксплуатации с любым shellcode необходимо поместить NOP sled после shellcode в переменную оболочки и просто эксплуатировать бинарный файл со случайным адресом. Обратите внимание, что NOP-sled не обязателен, это просто для универсализации эксплойта.
В 64-битной системе ситуация иная, но не настолько, как я обнаружил.
Конечно, вам не нужно покрывать все 2^64 возможностей, на самом деле ядро допускает только 48 бит, плюс часть их предсказуема и статична, что оставляет нам около 2^(4x8+5) (137 438 953 472) возможностей.
Я упомянул ограничение размера переменных оболочки, но есть также ограничение по количеству, которое составляет около 10, что позволяет нам хранить shellcode из 1 000 000 символов, оставляя нам лишь несколько десятков тысяч возможностей, которые можно быстро и автоматически проверить. Однако в этот раз вам понадобится перебор и использование NOP-sled'ов, чтобы ускорить процесс.
Тем не менее, ASLR как на 32, так и на 64-битных системах может быть легко обойден за несколько минут и несколькими строками shell...
DEP/NX, с другой стороны, может быть обойден на x32 с помощью техники return-to-libc в сочетании со статистическими исследованиями различных ОС, точнее, их ограничений и реализаций ASLR, что может привести к успешной эксплуатации по двум причинам. Первая — ASLR не настолько случаен в своем выборе и имеет некоторые константы и слабую энтропию (легко угадать адрес libC, и каждая ОС имеет свои константы). Вторая — распыление аргумента shell для libC в окружение (легко найти и передать его libC).
В заключение, DEP/NX на 32-битных системах ослаблен из-за ASLR.
Более подробное описание можно найти в выпуске Hakin9-12-14.
Если вы эксплуатировали хотя бы одно переполнение буфера в своей жизни, можете пропустить, но на всякий случай:
apt install gcc libc6-dev-i386 || kill -9 $$
chmod u+x ASLRay.sh
sudo gcc -z execstack test.c -o test
sudo gcc -m32 -z execstack test.c -o test32
sudo chmod +s test test32
source ASLRay.sh test32 1024
source ASLRay.sh test 1024
source ASLRay.sh test 1024 \x31\x80...your_shellcode_here
sudo gcc -m32 test.c -o test32x
sudo chmod +s test test32
source ASLRay.sh test32x 1024
Чтобы доказать, что NOP-sled не обязателен для Debian x32:
!!! ВНИМАНИЕ !!! это изменит ваш /etc/passwd и права доступа к /etc/shadow, рекомендуется выполнение в виртуальной машине
chmod u+x PoC.sh
source PoC.sh
grep ALI /etc/passwd
Если все еще не работает, просто добавьте несколько NOP (\x90) в начале.
Чтобы доказать, что даже переменная окружения не нужна для Debian x32:
chmod u+x PoC2.sh
source PoC2.sh
Таким образом, вы можете просто поместить ваш shellcode в переменную и передать случайные адреса в регистры для получения оболочки с ASLR, это связано с тем, что в конкретном контексте функция имеет только одну переменную, которая будет перезаписана, поэтому стек будет вытолкнут в EIP прямо с нашим shellcode, что больше похоже на атаку ROP.
Для Arch/Ubuntu вам также потребуется отключить защиту от переполнения стека, и перебор может занять гораздо больше времени (задержка выполнения, вероятно, из-за системного вызова brk(NULL/0) и/или канарейки):
sudo gcc -z execstack -fno-stack-protector test.c -o test
sudo gcc -m32 -z execstack -fno-stack-protector test.c -o test32
sudo gcc -m32 -fno-stack-protector test.c -o test32x
В Debian 10 эта проблема была частично исправлена, в частности из-за AppArmor.
Всегда полагайтесь на множество защит, а не на одну.
Нам нужны новые механизмы безопасности системы.
«Оттуда, где мы стоим, дождь кажется случайным. Если бы мы могли стоять где-то еще, мы бы увидели порядок в нем.»
Тони Хиллерман, Coyote Waits