来自可利用程序的 运行 时出现 Shellcode Segmentation Fault 错误

Shellcode Segmentation Fault error when run from exploitable program

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".I 运行 ./newdir 并且工作正常但是当我提取操作代码并尝试使用以下 c 程序测试此 shellcode 时。它不工作(没有分段错误)。我已经使用 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    [=13=]x8,%al
  40008a:   66 b9 f3 02             mov    [=13=]x2f3,%cx
  40008e:   cd 80                   int    [=13=]x80
  400090:   30 c0                   xor    %al,%al
  400092:   fe c0                   inc    %al
  400094:   30 db                   xor    %bl,%bl
  400096:   cd 80                   int    [=13=]x80

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

当我 运行 ./a.out 时,我得到了照片中的东西。我附上照片是因为我无法解释发生了什么。image

P.S- 我的问题已经解决了。但我想知道哪里出了问题。所以我使用了调试器,结果如下 `

(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    [=14=]x20,%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    [=14=]x0,%eax
   0x000000000000061d <+35>:    callq  *%rdx
   0x000000000000061f <+37>:    mov    [=14=]x0,%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    [=14=]x0,%eax
   0x55555555461d <main+35>:    callq  *%rdx
   0x55555555461f <main+37>:    mov    [=14=]x0,%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)

这里是调试信息。我找不到控件的位置 wrong.If 需要更多信息请询问。

下面是一个使用 x86-64 的工作示例;可以进一步优化大小。最后一个 0x00 null 可以用于执行 shellcode。

assemble & link:

$ 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   

如果 was the only problem, building your C test with gcc -fno-pie -no-pie 会起作用,因为那时 char sh[] 会在虚拟地址的低 32 位 space,所以将指针截断到 32 位的系统调用仍然会起作用.

运行 您的程序在 strace 下以查看它实际进行的系统调用。 (除了 strace 在 64 位代码中错误地解码 int 0x80 系统调用,解码就像您使用 64 位 syscall ABI 一样。调用编号和 arg 寄存器不同。)但至少你可以看到系统调用 return 值(对于 32 位 creat 和截断的 64 位指针,它将是 -EFAULT。)

您也可以 gdb 单步执行并检查系统调用 return 值。不过,让 strace 解码系统调用 inputs 真的很棒,所以我建议移植您的代码以使用 64 位 ABI,这样它就可以正常工作.

此外,它实际上能够利用 64 位进程,其中缓冲区溢出位于内存中低 32 位之外的地址。 (例如,像堆栈一样)。所以是的,你真的应该停止使用 int 0x80 或坚持使用 32 位代码。


您还依赖于在代码运行之前将寄存器置零,就像它们在进程启动时一样,但在从其他任何地方调用时却不是。

xor al,almov al,8 之前是完全没有意义的,因为异或归零 al 不会清除高位字节。写入 32 位寄存器会清除高 32 位,但不会写入 8 位或 16 位寄存器。如果是这样,在使用 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