Ошибка Сегментации Shellcode при запуске из эксплуатируемой программы

BITS 64
section     .text
global      _start

_start:
jmp short two

one:
pop     rbx
xor     al,al
xor     cx,cx
mov     al,8
mov     cx,0755
int     0x80
xor     al,al
inc     al
xor     bl,bl                               
int     0x80

two:
call one
db  'H'`

Это мой ассемблерный код. Тогда я использовал две команды. "nasm -f elf64 newdir.s -o newdir.o" и "ld newdir.o -o newdir". Я запускаю./newdir и работал нормально, но когда я извлек оп-код и попытался проверить этот шелл-код, используя следующую программу на языке c. Это не работает (нет ошибки сегментации). Я скомпилировал, используя cmd gcc newdir -z execstack

#include <stdio.h>
char sh[]="\xeb\x16\x5b\x30\xc0\x66\x31\xc9\xb0\x08\x66\xb9\xf3\x02\xcd\x80\x30\xc0\xfe\xc0\x30\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48";
void main(int argc, char **argv)
{
    int (*func)();
    func = (int (*)()) sh;
    (int)(*func)();
}

objdump -d newdir

newdir:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:   eb 16                   jmp    400098 <two>

0000000000400082 <one>:
  400082:   5b                      pop    %rbx
  400083:   30 c0                   xor    %al,%al
  400085:   66 31 c9                xor    %cx,%cx
  400088:   b0 08                   mov    $0x8,%al
  40008a:   66 b9 f3 02             mov    $0x2f3,%cx
  40008e:   cd 80                   int    $0x80
  400090:   30 c0                   xor    %al,%al
  400092:   fe c0                   inc    %al
  400094:   30 db                   xor    %bl,%bl
  400096:   cd 80                   int    $0x80

0000000000400098 <two>:
  400098:   e8 e5 ff ff ff          callq  400082 <one>
  40009d:   48                      rex.W

когда я бегу./a.out, я получаю что-то вроде на фотографии. Я прилагаю фото, потому что я не могу объяснить, что происходит. образ

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

(gdb) list
1   char shellcode[] = "\xeb\x16\x5b\x30\xc0\x66\x31\xc9\xb0\x08\x66\xb9\xf3\x02\xcd\x80\x30\xc0\xfe\xc0\x30\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48";
2   int main (int argc, char **argv)
3   {
4           int (*ret)();              
5           ret = (int(*)())shellcode; 
6                                      
7           (int)(*ret)();   
8           }           (gdb) disassemble main
Dump of assembler code for function main:
   0x00000000000005fa <+0>: push   %rbp
   0x00000000000005fb <+1>: mov    %rsp,%rbp
   0x00000000000005fe <+4>: sub    $0x20,%rsp
   0x0000000000000602 <+8>: mov    %edi,-0x14(%rbp)
   0x0000000000000605 <+11>:    mov    %rsi,-0x20(%rbp)
   0x0000000000000609 <+15>:    lea    0x200a20(%rip),%rax        # 0x201030 <shellcode>
   0x0000000000000610 <+22>:    mov    %rax,-0x8(%rbp)
   0x0000000000000614 <+26>:    mov    -0x8(%rbp),%rdx
   0x0000000000000618 <+30>:    mov    $0x0,%eax
   0x000000000000061d <+35>:    callq  *%rdx
   0x000000000000061f <+37>:    mov    $0x0,%eax
   0x0000000000000624 <+42>:    leaveq 
   0x0000000000000625 <+43>:    retq   
End of assembler dump.
(gdb) b 7
Breakpoint 1 at 0x614: file test.c, line 7.
(gdb) run
Starting program: /root/Desktop/Progs/shell/a.out 

Breakpoint 1, main (argc=1, argv=0x7fffffffe2b8) at test.c:7
7           (int)(*ret)();   
(gdb) info registers rip
rip            0x555555554614   0x555555554614 <main+26>
(gdb) x/5i $rip
=> 0x555555554614 <main+26>:    mov    -0x8(%rbp),%rdx
   0x555555554618 <main+30>:    mov    $0x0,%eax
   0x55555555461d <main+35>:    callq  *%rdx
   0x55555555461f <main+37>:    mov    $0x0,%eax
   0x555555554624 <main+42>:    leaveq 
(gdb) s
(Control got stuck here, so i pressed ctrl+c)
^C
 Program received signal SIGINT, Interrupt.
 0x0000555555755048 in shellcode ()
(gdb) x/5i 0x0000555555755048 
=> 0x555555755048 <shellcode+24>:   callq  0x555555755032 <shellcode+2>
   0x55555575504d <shellcode+29>:   rex.W add %al,(%rax)
   0x555555755050:  add    %al,(%rax)
   0x555555755052:  add    %al,(%rax)
   0x555555755054:  add    %al,(%rax)

Вот отладочная информация. Я не могу найти, где управление идет не так. Если вам нужна дополнительная информация, пожалуйста, спросите.

2 ответа

Если int 0x80 в 64-битном коде была единственная проблема, построение вашего C-теста с gcc -fno-pie -no-pie сработало бы, потому что тогда char sh[] будет в низком 32-битном виртуальном адресном пространстве, поэтому системные вызовы, которые усекают указатели до 32-битных, все равно будут работать.

Запустите вашу программу под strace чтобы увидеть, какие системные вызовы он на самом деле делает. (Кроме этого strace декодирует int 0x80 Системные вызовы неправильно в 64-битном коде, декодирование, как если бы вы использовали 64-битный syscall ABI. Номера вызовов и регистры arg разные. Но, по крайней мере, вы можете видеть значения, возвращаемые системным вызовом (которые будут -EFAULT для 32-битных creat с усеченным 64-битным указателем.)

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

Кроме того, он фактически сможет использовать 64-битные процессы, в которых переполнение буфера находится в памяти по адресу за пределами младших 32 бит. (например, как стек). Так что да, вы должны действительно прекратить использование int 0x80 или придерживаться 32-битного кода.


Вы также зависите от того, будут ли регистры обнуляться перед выполнением кода, как будто они запускаются при запуске процесса, но не при вызове из других источников.

xor al,al до mov al,8 совершенно бессмысленно, потому что xor-zeroing al не очищает верхние байты. Запись 32-битных регистров очищает верхние 32, но не запись 8 или 16-битных регистров. И если это произойдет, вам не понадобится обнуление xor перед использованием mov который также только для записи.

Если вы хотите установить RAX=8 без нулевых байтов в машинном коде, вы можете

  • push 8 / pop rax (3 байта)
  • xor eax,eax / mov al,8 (4 байта)
  • Или с нулевым rcx регистр, lea eax, [rcx+8] (3 байта)

Настройка CX на 0755 не так просто, потому что константа не вписывается в imm8. Ваш 16-битный mov хороший выбор (или был бы, если бы вы обнулили rcx первый.

xor  ecx,ecx
lea  eax, [rcx+8]   ; SYS_creat = 8 from unistd_32.h
mov  cx, 0755       ; mode
int  0x80           ; invoke 32-bit ABI

xor  ebx,ebx
lea  eax, [rbx+1]   ; SYS_exit = 1
int  0x80

Ниже приведен рабочий пример использования x86-64; который может быть дополнительно оптимизирован для размера. Последний 0x00 null подходит для выполнения шеллкода.

собрать и ссылку:

$ nasm -felf64 -g -F dwarf pushpam_001.s -o pushpam_001.o && ld pushpam_001.o -o pushpam_001

Код:

BITS 64
section     .text
global      _start

_start:
jmp short two

one:
        pop   rdi               ; pathname

        xor rax, rax
        add al, 85              ; creat syscall 64-bit Linux

        xor rsi, rsi
        add si, 0755            ; mode - octal
        syscall

        xor rax, rax
        add ax, 60
        xor rdi, rdi
        syscall

two:
call one
db  'H',0

objdump:

pushpam_001:     file format elf64-x86-64
0000000000400080 <_start>:
  400080:       eb 1c                   jmp    40009e <two>
0000000000400082 <one>:
  400082:       5f                      pop    rdi
  400083:       48 31 c0                xor    rax,rax
  400086:       04 55                   add    al,0x55
  400088:       48 31 f6                xor    rsi,rsi
  40008b:       66 81 c6 f3 02          add    si,0x2f3
  400090:       0f 05                   syscall
  400092:       48 31 c0                xor    rax,rax
  400095:       66 83 c0 3c             add    ax,0x3c
  400099:       48 31 ff                xor    rdi,rdi
  40009c:       0f 05                   syscall
000000000040009e <two>:
  40009e:       e8 df ff ff ff 48 00               

             .....H.

извлечение кодировки: есть много других способов сделать это.

$ for i in `objdump  -d pushpam_001  | grep "^ " | cut -f2`; do echo -n '\x'$i; done; echo
\xeb\x1c\x5f\x48\x31\xc0\x04\x55\x48\x31\xf6\x66\x81\xc6\xf3\x02\x0f\x05\x48\x31\xc0\x66\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdf\xff\xff\xff\x48\x00\x.....H.

C shellcode.c - частичный

...
unsigned char code[] = \
"\xeb\x1c\x5f\x48\x31\xc0\x04\x55\x48\x31\xf6\x66\x81\xc6\xf3\x02\x0f\x05\x48\x31\xc0\x66\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdf\xff\xff\xff\x48\x00";  
...

окончательный:

./shellcode 

--wxrw---t 1 david david     0 Jan 31 12:25 H   
Другие вопросы по тегам