代码之家  ›  专栏  ›  技术社区  ›  Pushpam Kumar

从可利用程序运行时出现外壳代码分段错误

  •  0
  • Pushpam Kumar  · 技术社区  · 7 年前
    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和工作得很好,但当我提取op代码并尝试使用以下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、 出去,我得到了一些像照片中的东西。我附上照片,因为我无法解释发生了什么。 image

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

    (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 回复  |  直到 7 年前
        1
  •  2
  •   InfinitelyManic    7 年前

    下面是一个使用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
    

    对象转储:

    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外壳代码。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   
    
        2
  •  2
  •   Peter Cordes    7 年前

    如果 int 0x80 in 64-bit code 唯一的问题是用 gcc -fno-pie -no-pie 会有用的,因为 char sh[] 将位于低32位的虚拟地址空间中,因此将指针截断为32位的系统调用仍然有效。

    运行您的程序 strace 查看系统实际调用的内容。(除非 斯特拉斯 解码 int 0x80 64位代码中的syscalls错误,解码时就像使用了64位 syscall ABI公司。呼叫号码和arg寄存器不同。)但至少可以看到系统调用返回值 -EFAULT 对于32位 creat 使用截断的64位指针。)

    你也可以 gdb 单步执行并检查系统调用返回值。有 斯特拉斯 解码系统调用 输入 但是,这真的很好,所以我建议您将代码移植到64位ABI,这样它就可以正常工作了。

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


    您还需要在代码运行之前将寄存器归零 ,就像在进程启动时一样,但从其他任何地方调用时都不会。

    xor al,al 之前 mov al,8 完全没有意义,因为xor归零 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位 压敏电阻 是一个很好的选择(或者如果你归零 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