zoukankan      html  css  js  c++  java
  • 《黑客攻防-系统实战》--shellcode

    shellcode

      shellcode 是一组可注入的指令,可以在被攻击得到程序内运行,因为shellcode要直接操作寄存器和程序函数,所以通常用汇编语言编写并被翻译为十六进制操作码,因此不能用高级语言编写shellcode, 即使细微的差别有可能导致shellcode无法准确执行,这些导致编写shellcode难度的原因

      shellcode最初的作用是漏洞利用程序的特殊部分,破解漏洞就是预先把shellcode注入到缓冲区,然后欺骗目标程序执行它

    理解系统调用

      写shellcode的目的就是想让目标程序以不同于设计者预期的方式运行,而操纵程序的方式之一就是强制它产生系统调用,通过系统调用可以获取一些特权操作,访问系统内核,

      调用系统调用方法:1)使用C库包装(libc) 2)使用汇编指令(把适当的参数加载到寄存器,然后调用软中断)执行系统调用

    系统调用的过程

      linux环境程序通过int 0x80软中断来执行系统调用,程序执行int  0x80时,CPU切换到内核模式并执行相应的系统调用,使用fastcall约定, 提高寄存器的使用率

    __fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,
          剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。
          __fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上”@”前缀,在函数名后加上”@”和参数的字节数。 __cdecl (The C
    default calling convention)即C调用约定按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的。
          另外,在函数名修饰约定方面也有所不同。 _cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小
          会比调用_stdcall函数的大 __stdcall是Pascal方式清理C方式压栈,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,
          在函数名后加上”@”和参数的字节数。
    int f(void *p) –>> _f@4(在外部汇编语言里可以用这个名字引用这个函数) 参考: https://blog.csdn.net/sunriver2000/article/details/84913380

    调用过程:

      1)系统调用编号载入EAX

      2)把系统调用参数压入栈中(注意:最多支持6个参数,分别保存在:EBX,ECX,EDX,ESI,EDI,EBP,  超过六个,通过第一个指定数据结构传递)

      3)执行int 0x80指令

      4)CPU切换到内核模式

      5)执行系统调用

    举个例子:

      

    1 #include <stdio.h>
    2 
    3 int main()
    4 {
    5     exit(0);
    6     return 0;
    7 }

    exit() -> _exit()

    反汇编看一下:

     call   *%gs:0x10     ;系统调用从这里进入,会调用到int80

    mov 0x4(%esp), %ebx; 退出把系统调用参数加载到ebx, 系统调用之前压栈

    编写shellcode

    注意:

      shellcode大小:由于较小的shellcode 可以注入更多的缓冲区,可以用来攻击更多的程序,所以要使得shellcode尽量保持简单,紧凑

      当攻击问题程序的时候,需要把shellcode复制到缓存区,另外还要加上调用shellcode的指令, 所以必须要小

    分析程序:

      前面exit系统调用分析主要完成三个动作:

      1)把0放到EBX

      2)把1放到EAX

      3)执行int  0x80 指令来产生系统调用

    1. hello.c

     1 section .data                           ;section declaration
     2 msg     db      "Hello, world!",0xA     ;our dear string
     3 len     equ     $ - msg                 ;length of our dear string
     4 section .text                           ;section declaration
     5                        ;we must export the entry point to the ELF linker or
     6    global _start       ;loader. They conventionally recognize _start as their
     7                        ;entry point. Use ld -e foo to override the default.
     8 _start:
     9 ;write our string to stdout
    10        mov     eax,4   ;system call number (sys_write)
    11        mov     ebx,1   ;first argument: file handle (stdout)
    12        mov     ecx,msg ;second argument: pointer to message to write
    13        mov     edx,len ;third argument: message length
    14        int     0x80    ;call kernel
    15 ;and exit
    16        mov     eax,1   ;system call number (sys_exit)
    17        xor     ebx,ebx ;first syscall argument: exit code
    18        int     0x80    ;call kernel

    2. objdump -d hello

     1 foobar:     fiobjdump -d foobarle format elf32-i386
     2 
     3 
     4 Disassembly of section .text:
     5 
     6 08049000 <.text>:
     7  8049000:    b8 04 00 00 00           mov    $0x4,%eax
     8  8049005:    bb 01 00 00 00           mov    $0x1,%ebx
     9  804900a:    b9 00 a0 04 08           mov    $0x804a000,%ecx
    10  804900f:    ba 0e 00 00 00           mov    $0xe,%edx
    11  8049014:    cd 80                    int    $0x80
    12  8049016:    b8 01 00 00 00           mov    $0x1,%eax
    13  804901b:    31 db                    xor    %ebx,%ebx
    14  804901d:    cd 80                    int    $0x80

    3. 把操作码写到字符串数组中执行

    char shellcode[] = "xb8x04x00x00x00"

            "xbbx01x00x00x00"

            "xb9x00xa0x04x08"

            "xbax0ex00x00x00"

            "xcdx80"

            "xb8x01x00x00x00"

            "x31xdb"

            "xcdx80"

     

    gcc -o wack wack.c -m32 -z execstack

    跳板技术(转https://zhuanlan.zhihu.com/p/88459547

    程序每次运行后在内存中的指令地址都是变化的,所以shellcode入口地址也是动态的,所以为了能够动态找到shellcode的位置,引入了跳板技术。

    如图所示,左边表示存储返回地址的栈帧填充为shellcode入口地址,这种方式下次运行时入口地址将发生变化导致失败,右边表示跳板技术后,通过esp来定位shellcode,这种方式可保证下次运行exp依然有效。

     

     

    跳板技术是用来动态跳转shellcode的,shellcode代码需要从函数返回后esp的栈顶位置开始,然后函数返回到JMP ESP指令处,指令执行后跳到esp位置进入shellcode入口。

    注: 对于不同的返回指令的不同,函数返回后esp的指向也有所不同。一般执行ret指令后esp+4,此时shellcode放在存放返回地址的栈帧的下一位置。若是ret N指令,执行后esp+4+N,则shellcode需要放在计算出的对应位置处才行。JMP ESP指令的地址要已知,在xp中JMP ESP可以通过加载kernel32.dll、user32.dll、mfc32.dll等这些经常被加载到内存中的库中寻找,一般地址都是确定的。利用C实现查找代码如下:

     1 # include <stdio.h>
     2 #include <windows.h>
     3  
     4 main()
     5 {
     6     HINSTANCE hLib;
     7     hLib = LoadLibrary("user32.dll");
     8     if(!hLib)
     9     {
    10         printf("Load dll error!
    ");
    11         exit(0);
    12     }
    13  
    14     byte* ptr = (byte*) hLib;
    15     int address;
    16     int position;
    17     bool done_flag = false;
    18  
    19     for(position=0; !done_flag; position++)
    20     {
    21         try
    22         {
    23             if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)
    24             {
    25              // jmp esp 的机器码 为 0xFFE4
    26                 address = (int)ptr + position;
    27                 printf("Find OPcode at 0x%08lX
    ", address);
    28             }
    29         }
    30         catch(...)
    31         {
    32             address = (int)ptr + position;
    33             printf("End of 0x%08lX
    ", address);
    34             done_flag = true;
    35         }
    36     }
    37 }

     

    抬高栈顶保护shellcode 

    如果shellcode放在返回地址栈帧之前,那么在函数返回后栈顶位置会在shellcode下方,虽然出栈后的数据不被清空,但是却会受入栈操作的影响,所以shellcode中若存在push操作,很有可能破坏shellcode结构:

     

    所以要在shellcode开头适当先抬高栈顶让shellcode在栈顶下方,这样push就不会影响shellcode。

    抬高栈顶可以用sub esp, N,N大于shellcode长度即可。

     

  • 相关阅读:
    u-boot 内核 启动参数
    模块移除 命令rmmod 的实现
    led 的 platform驱动实现
    kconfig语法
    通过编程语言操作数据库
    linux 下 postgres 的使用总结
    maven 项目遇到的问题(不断更新中)
    从svn中check out maven项目 所遇到的一系列问题:
    java多线程学习
    内连接,外连接,交叉连接--数据库查询语句学习
  • 原文地址:https://www.cnblogs.com/mysky007/p/12866894.html
Copyright © 2011-2022 走看看