
Обход ASLR без утечки информации
В этой статье я расскажу о применении техники, описанной Samuel Groß в его Remote iPhone Exploitation Part 2: Bringing Light into the Darkness -- a Remote ASLR Bypass, для обхода ASLR на Linux x86_64.
Чтобы это продемонстрировать, я решу pwnable-задание с Buckeye CTF — guess_god.
Я постараюсь сделать материал максимально доступным для новичков, так что не стесняйтесь пропускать любые разделы, если чувствуете себя достаточно уверенно и хотите сразу перейти к эксплойту.

Я не участвовал в CTF, но заинтересовался этим заданием примерно за 2 часа до конца соревнования благодаря Guray00, который просил помощи в дискорде fibonhack по поводу каких-то криптографических шалостей.
Я не смог ему помочь, но зато посмотрел на pwnable-задания и решил, что будет полезно разобраться в блогпосте от P0 и, возможно, получить тот самый баунти.
Address Space Layout Randomization (ASLR) — это техника компьютерной безопасности, которая заключается в случайном размещении базового адреса исполняемого файла, а также позиций библиотек, кучи и стека в адресном пространстве процесса.
В Linux вы можете просмотреть маппинги процесса, зная его pid, через procfs, прочитав файл /proc/<pid>/maps.
Если вы — процесс и хотите узнать собственные маппинги памяти, вы можете прочитать /proc/self/maps.
Например, можно попробовать прочитать /proc/self/maps с помощью cat:```
root@088ec31b2ce9:/home/ctf/challenge# cat /proc/self/maps
55faeb01c000-55faeb01e000 r--p 00000000 fe:01 2497233 /usr/bin/cat
55faeb01e000-55faeb023000 r-xp 00002000 fe:01 2497233 /usr/bin/cat
55faeb023000-55faeb026000 r--p 00007000 fe:01 2497233 /usr/bin/cat
55faeb026000-55faeb027000 r--p 00009000 fe:01 2497233 /usr/bin/cat
55faeb027000-55faeb028000 rw-p 0000a000 fe:01 2497233 /usr/bin/cat
55faeb115000-55faeb136000 rw-p 00000000 00:00 0 [heap]
7fe15dfb1000-7fe15dfd5000 rw-p 00000000 00:00 0
7fe15dfd5000-7fe15dffb000 r--p 00000000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so
7fe15dffb000-7fe15e166000 r-xp 00026000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so
7fe15e166000-7fe15e1b2000 r--p 00191000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so
7fe15e1b2000-7fe15e1b5000 r--p 001dc000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so
7fe15e1b5000-7fe15e1b8000 rw-p 001df000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so
7fe15e1b8000-7fe15e1c3000 rw-p 00000000 00:00 0
7fe15e1c7000-7fe15e1c8000 r--p 00000000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so
7fe15e1c8000-7fe15e1ef000 r-xp 00001000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so
7fe15e1ef000-7fe15e1f9000 r--p 00028000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so
7fe15e1f9000-7fe15e1fb000 r--p 00031000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so
7fe15e1fb000-7fe15e1fd000 rw-p 00033000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so
7fff4388f000-7fff438b0000 rw-p 00000000 00:00 0 [stack]
7fff43989000-7fff4398d000 r--p 00000000 00:00 0 [vvar]
7fff4398d000-7fff4398f000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
root@088ec31b2ce9:/home/ctf/challenge# cat /proc/self/maps 55ffc0b1b000-55ffc0b1d000 r--p 00000000 fe:01 2497233 /usr/bin/cat 55ffc0b1d000-55ffc0b22000 r-xp 00002000 fe:01 2497233 /usr/bin/cat 55ffc0b22000-55ffc0b25000 r--p 00007000 fe:01 2497233 /usr/bin/cat 55ffc0b25000-55ffc0b26000 r--p 00009000 fe:01 2497233 /usr/bin/cat 55ffc0b26000-55ffc0b27000 rw-p 0000a000 fe:01 2497233 /usr/bin/cat 55ffc2108000-55ffc2129000 rw-p 00000000 00:00 0 [heap] 7f1ec6e0f000-7f1ec6e33000 rw-p 00000000 00:00 0 7f1ec6e33000-7f1ec6e59000 r--p 00000000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec6e59000-7f1ec6fc4000 r-xp 00026000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec6fc4000-7f1ec7010000 r--p 00191000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec7010000-7f1ec7013000 r--p 001dc000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec7013000-7f1ec7016000 rw-p 001df000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec7016000-7f1ec7021000 rw-p 00000000 00:00 0 7f1ec7025000-7f1ec7026000 r--p 00000000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec7026000-7f1ec704d000 r-xp 00001000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec704d000-7f1ec7057000 r--p 00028000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec7057000-7f1ec7059000 r--p 00031000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec7059000-7f1ec705b000 rw-p 00033000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7ffc72fa4000-7ffc72fc5000 rw-p 00000000 00:00 0 [stack] 7ffc72fe7000-7ffc72feb000 r--p 00000000 00:00 0 [vvar] 7ffc72feb000-7ffc72fed000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
### Шаблоны раскладки памяти
Если сделать это несколько раз, можно сделать вывод:
* Базовый адрес PIE бинарника должен находиться в диапазоне 0x00005500_00000000-0x00005700_00000000, то есть 2 ТБ возможных адресов.
* Куча находится рядом с бинарником.
* Библиотеки попадают в диапазон 0x00007f00_00000000 - 0x00007fff_ffffffff, 1 ТБ возможных адресов.
* Стек находится (в большинстве случаев) в диапазоне 0x00007ffc_00000000 - 0x00007fff_ffffffff, 16 ГБ возможных адресов.
* Диапазон 0xffffffffff600000 - 0xffffffffff601000 всегда отображён, вы можете прочитать [эту статью](http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2019/02/13/vsyscall-and-vdso), если вам интересно, что это.
## 1.3 Как обойти ASLR без информационной утечки
Давайте обсудим, что можно сделать для обхода ASLR, когда информационная утечка невозможна.
Это моя попытка обобщить то, что я вынес из поста в блоге Saelo.
Для обхода ASLR вам нужно:
* Техника распыления памяти, позволяющая отобразить непрерывную память заданного размера в заданном диапазоне адресов.
Как он говорит, есть два способа сделать это:
1. Используя утечку памяти (не информационную утечку!) — баг, при котором фрагмент памяти «забывается» и никогда не освобождается; нужно запускать его несколько раз, пока не утечёт нужный объём памяти.
2. Найдя и используя «усиливающий гаджет» (amplification gadget): фрагмент кода, который берёт существующий блок данных и копирует его, возможно несколько раз, что позволяет атакующему распылить большой объём памяти, отправив лишь относительно небольшое количество байт.
* Оракул `isAddressMapped`, который по данному адресу сообщает, отображается ли этот адрес.
### PoC обхода ASLR в Linux
Давайте попробуем воспроизвести PoC от saelo, чтобы полностью сломать ASLR в Linux.